package com.zy.core.network.fake;
|
|
import com.alibaba.fastjson.JSON;
|
import com.zy.asrs.entity.DeviceConfig;
|
import com.zy.core.News;
|
import com.zy.core.model.CommandResponse;
|
import com.zy.core.model.protocol.StationTaskBufferItem;
|
import com.zy.core.network.entity.ZyStationStatusEntity;
|
import com.zy.core.thread.support.StationTaskLocationRegistry;
|
import com.core.common.SpringUtils;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Random;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.locks.ReentrantLock;
|
|
public class FakeStationStateManager {
|
|
private final StationTaskLocationRegistry stationTaskLocationRegistry = SpringUtils.getBean(StationTaskLocationRegistry.class);
|
|
private interface StationMutation {
|
void apply(ZyStationStatusEntity status);
|
}
|
|
private interface StationRead<T> {
|
T apply(ZyStationStatusEntity status);
|
}
|
|
private final Map<Integer, List<ZyStationStatusEntity>> deviceStatusMap = new ConcurrentHashMap<Integer, List<ZyStationStatusEntity>>();
|
private final Map<Integer, DeviceConfig> deviceConfigMap = new ConcurrentHashMap<Integer, DeviceConfig>();
|
private final Map<Integer, ReentrantLock> stationLocks = new ConcurrentHashMap<Integer, ReentrantLock>();
|
|
private interface StationLockedMutation {
|
void apply(ZyStationStatusEntity status);
|
}
|
|
private interface StationLockedRead<T> {
|
T apply(ZyStationStatusEntity status);
|
}
|
|
private ReentrantLock getStationLock(Integer stationId) {
|
return stationLocks.computeIfAbsent(stationId, key -> new ReentrantLock());
|
}
|
|
public void lockStations(Integer... stationIds) {
|
if (stationIds == null || stationIds.length == 0) {
|
return;
|
}
|
Integer[] sorted = java.util.Arrays.copyOf(stationIds, stationIds.length);
|
java.util.Arrays.sort(sorted);
|
for (Integer stationId : sorted) {
|
if (stationId != null) {
|
getStationLock(stationId).lock();
|
}
|
}
|
}
|
|
public void unlockStations(Integer... stationIds) {
|
if (stationIds == null || stationIds.length == 0) {
|
return;
|
}
|
Integer[] sorted = java.util.Arrays.copyOf(stationIds, stationIds.length);
|
java.util.Arrays.sort(sorted);
|
for (int i = sorted.length - 1; i >= 0; i--) {
|
Integer stationId = sorted[i];
|
if (stationId != null) {
|
getStationLock(stationId).unlock();
|
}
|
}
|
}
|
|
private boolean mutateLockedStation(Integer deviceNo, Integer stationId, StationLockedMutation mutation) {
|
if (stationId == null || mutation == null) {
|
return false;
|
}
|
lockStations(stationId);
|
try {
|
ZyStationStatusEntity status = findStationStatus(deviceNo, stationId);
|
if (status == null) {
|
return false;
|
}
|
mutation.apply(status);
|
return true;
|
} finally {
|
unlockStations(stationId);
|
}
|
}
|
|
private <T> T readLockedStation(Integer deviceNo, Integer stationId, StationLockedRead<T> read) {
|
if (stationId == null || read == null) {
|
return null;
|
}
|
lockStations(stationId);
|
try {
|
ZyStationStatusEntity status = findStationStatus(deviceNo, stationId);
|
if (status == null) {
|
return null;
|
}
|
return read.apply(status);
|
} finally {
|
unlockStations(stationId);
|
}
|
}
|
|
private boolean updateStationDataWithinLock(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStaNo,
|
Boolean isLoading, String barcode, Boolean runBlock) {
|
ZyStationStatusEntity currentStatus = findStationStatus(deviceNo, stationId);
|
if (currentStatus == null) {
|
return false;
|
}
|
if (taskNo != null) {
|
currentStatus.setTaskNo(taskNo);
|
}
|
if (targetStaNo != null) {
|
currentStatus.setTargetStaNo(targetStaNo);
|
}
|
if (isLoading != null) {
|
currentStatus.setLoading(isLoading);
|
}
|
if (barcode != null) {
|
currentStatus.setBarcode(barcode);
|
}
|
if (runBlock != null) {
|
currentStatus.setRunBlock(runBlock);
|
}
|
syncTaskLocationInternal(deviceNo, currentStatus);
|
return true;
|
}
|
|
|
public void registerDevice(DeviceConfig deviceConfig) {
|
if (deviceConfigMap.containsKey(deviceConfig.getDeviceNo())) {
|
return;
|
}
|
deviceConfigMap.put(deviceConfig.getDeviceNo(), deviceConfig);
|
deviceStatusMap.put(deviceConfig.getDeviceNo(), new CopyOnWriteArrayList<ZyStationStatusEntity>());
|
}
|
|
public Map<Integer, List<ZyStationStatusEntity>> getDeviceStatusMap() {
|
return deviceStatusMap;
|
}
|
|
public Map<Integer, DeviceConfig> getDeviceConfigMap() {
|
return deviceConfigMap;
|
}
|
|
public List<ZyStationStatusEntity> getStatus(Integer deviceNo) {
|
List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
|
if (statusList == null) {
|
return new ArrayList<ZyStationStatusEntity>();
|
}
|
|
DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo);
|
if (statusList.isEmpty() && deviceConfig != null) {
|
List<ZyStationStatusEntity> init = JSON.parseArray(deviceConfig.getFakeInitStatus(),
|
ZyStationStatusEntity.class);
|
if (init != null) {
|
statusList.addAll(init);
|
for (ZyStationStatusEntity status : statusList) {
|
status.setAutoing(true);
|
status.setLoading(false);
|
status.setInEnable(true);
|
status.setOutEnable(true);
|
status.setIoMode(2);
|
status.setEmptyMk(false);
|
status.setFullPlt(false);
|
status.setRunBlock(false);
|
status.setPalletHeight(0);
|
status.setError(0);
|
status.setBarcode("");
|
}
|
}
|
}
|
|
return statusList;
|
}
|
|
public ZyStationStatusEntity findStationStatus(Integer deviceNo, Integer stationId) {
|
if (deviceNo == null || stationId == null) {
|
return null;
|
}
|
List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
|
if (statusList == null) {
|
return null;
|
}
|
return statusList.stream()
|
.filter(item -> item.getStationId().equals(stationId))
|
.findFirst().orElse(null);
|
}
|
|
public Integer getDeviceNoByStationId(Integer stationId) {
|
for (Map.Entry<Integer, List<ZyStationStatusEntity>> entry : deviceStatusMap.entrySet()) {
|
List<ZyStationStatusEntity> list = entry.getValue();
|
if (list == null) {
|
continue;
|
}
|
for (ZyStationStatusEntity entity : list) {
|
if (entity.getStationId() != null && entity.getStationId().equals(stationId)) {
|
return entry.getKey();
|
}
|
}
|
}
|
return null;
|
}
|
|
public Integer findCurrentStationIdByTask(Integer taskNo) {
|
for (List<ZyStationStatusEntity> list : deviceStatusMap.values()) {
|
if (list == null) {
|
continue;
|
}
|
for (ZyStationStatusEntity entity : list) {
|
Integer stationId = entity == null ? null : entity.getStationId();
|
Integer matchedStationId = stationId == null ? null : readStation(getDeviceNoByStationId(stationId), stationId,
|
new StationRead<Integer>() {
|
@Override
|
public Integer apply(ZyStationStatusEntity status) {
|
if (status.getTaskNo() != null && status.getTaskNo().equals(taskNo) && status.isLoading()) {
|
return status.getStationId();
|
}
|
return null;
|
}
|
});
|
if (matchedStationId != null) {
|
return matchedStationId;
|
}
|
}
|
}
|
return null;
|
}
|
|
public String getThreadImpl(Integer deviceNo) {
|
DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo);
|
return deviceConfig == null ? "" : deviceConfig.getThreadImpl();
|
}
|
|
public boolean isStationLoadingTask(Integer deviceNo, Integer stationId, Integer taskNo) {
|
Boolean result = readStation(deviceNo, stationId, new StationRead<Boolean>() {
|
@Override
|
public Boolean apply(ZyStationStatusEntity status) {
|
return status.getTaskNo() != null && status.getTaskNo().equals(taskNo) && status.isLoading();
|
}
|
});
|
return Boolean.TRUE.equals(result);
|
}
|
|
public boolean isStationClearedForTask(Integer deviceNo, Integer stationId, Integer taskNo) {
|
Boolean result = readStation(deviceNo, stationId, new StationRead<Boolean>() {
|
@Override
|
public Boolean apply(ZyStationStatusEntity status) {
|
boolean emptyStation = !status.isLoading()
|
&& (status.getTaskNo() == null || status.getTaskNo() <= 0);
|
return emptyStation;
|
}
|
});
|
return result == null || result;
|
}
|
|
public boolean isFinalStationOwnerConflict(Integer deviceNo, Integer stationId, Integer taskNo) {
|
Boolean result = readStation(deviceNo, stationId, new StationRead<Boolean>() {
|
@Override
|
public Boolean apply(ZyStationStatusEntity status) {
|
return status.isLoading()
|
&& taskNo != null
|
&& status.getTaskNo() != null
|
&& status.getTaskNo() > 0
|
&& !taskNo.equals(status.getTaskNo());
|
}
|
});
|
return Boolean.TRUE.equals(result);
|
}
|
|
public boolean isOccupiedByOtherLoadingTask(Integer deviceNo, Integer stationId, Integer taskNo) {
|
Boolean result = readStation(deviceNo, stationId, new StationRead<Boolean>() {
|
@Override
|
public Boolean apply(ZyStationStatusEntity status) {
|
return status.isLoading()
|
&& status.getTaskNo() != null
|
&& status.getTaskNo() > 0
|
&& (taskNo == null || !taskNo.equals(status.getTaskNo()));
|
}
|
});
|
return Boolean.TRUE.equals(result);
|
}
|
|
public ZyStationStatusEntity snapshotStation(Integer deviceNo, Integer stationId) {
|
return readStation(deviceNo, stationId, new StationRead<ZyStationStatusEntity>() {
|
@Override
|
public ZyStationStatusEntity apply(ZyStationStatusEntity status) {
|
return JSON.parseObject(JSON.toJSONString(status), ZyStationStatusEntity.class);
|
}
|
});
|
}
|
|
private boolean mutateStation(Integer deviceNo, Integer stationId, StationMutation mutation) {
|
if (mutation == null) {
|
return false;
|
}
|
return mutateLockedStation(deviceNo, stationId, new StationLockedMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity status) {
|
mutation.apply(status);
|
}
|
});
|
}
|
|
private <T> T readStation(Integer deviceNo, Integer stationId, StationRead<T> read) {
|
if (read == null) {
|
return null;
|
}
|
return readLockedStation(deviceNo, stationId, new StationLockedRead<T>() {
|
@Override
|
public T apply(ZyStationStatusEntity status) {
|
return read.apply(status);
|
}
|
});
|
}
|
|
public boolean updateStationDataWithHeldLock(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStaNo,
|
Boolean isLoading, String barcode, Boolean runBlock) {
|
return updateStationDataWithinLock(stationId, deviceNo, taskNo, targetStaNo, isLoading, barcode, runBlock);
|
}
|
|
public boolean updateStationDataInternal(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStaNo,
|
Boolean isLoading, String barcode, Boolean runBlock) {
|
return mutateLockedStation(deviceNo, stationId, new StationLockedMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity currentStatus) {
|
updateStationDataWithinLock(stationId, deviceNo, taskNo, targetStaNo, isLoading, barcode, runBlock);
|
}
|
});
|
}
|
|
public void syncTaskLocation(Integer deviceNo, Integer stationId) {
|
if (deviceNo == null || stationId == null) {
|
return;
|
}
|
readStation(deviceNo, stationId, new StationRead<Void>() {
|
@Override
|
public Void apply(ZyStationStatusEntity status) {
|
syncTaskLocationInternal(deviceNo, status);
|
return null;
|
}
|
});
|
}
|
|
public void removeTaskLocation(Integer taskNo, Integer deviceNo, Integer stationId) {
|
if (stationTaskLocationRegistry == null || taskNo == null || taskNo <= 0) {
|
return;
|
}
|
stationTaskLocationRegistry.remove(taskNo, deviceNo, stationId);
|
}
|
|
private void syncTaskLocationInternal(Integer deviceNo, ZyStationStatusEntity status) {
|
if (stationTaskLocationRegistry == null || deviceNo == null || status == null) {
|
return;
|
}
|
Integer taskNo = status.getTaskNo();
|
if (taskNo != null && taskNo > 0 && status.isLoading() && status.getStationId() != null) {
|
stationTaskLocationRegistry.update(taskNo, deviceNo, status.getStationId(), true,
|
status.isRunBlock(), System.currentTimeMillis());
|
}
|
}
|
|
public void clearTaskLocationIfMatches(Integer taskNo, Integer deviceNo, Integer stationId) {
|
if (taskNo == null || taskNo <= 0 || deviceNo == null || stationId == null) {
|
return;
|
}
|
readStation(deviceNo, stationId, new StationRead<Void>() {
|
@Override
|
public Void apply(ZyStationStatusEntity status) {
|
if (status.getTaskNo() == null || !taskNo.equals(status.getTaskNo()) || !status.isLoading()) {
|
removeTaskLocation(taskNo, deviceNo, stationId);
|
}
|
return null;
|
}
|
});
|
}
|
|
public void publishTaskLocation(Integer taskNo, Integer deviceNo, Integer stationId, boolean loading, boolean runBlock) {
|
if (stationTaskLocationRegistry == null || taskNo == null || taskNo <= 0 || deviceNo == null || stationId == null || !loading) {
|
return;
|
}
|
stationTaskLocationRegistry.update(taskNo, deviceNo, stationId, true, runBlock, System.currentTimeMillis());
|
}
|
|
public void generateStationData(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) {
|
mutateStation(deviceNo, stationId, new StationMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity status) {
|
News.info("仿真站点生成任务数据,设备号={},站点号={},原taskNo={},新taskNo={},原targetStaNo={},新targetStaNo={},原loading={},barcode={}",
|
deviceNo, stationId, status.getTaskNo(), taskNo, status.getTargetStaNo(), targetStationId,
|
status.isLoading(), status.getBarcode());
|
status.setTaskNo(taskNo);
|
status.setTargetStaNo(targetStationId);
|
status.setLoading(false);
|
}
|
});
|
}
|
|
public void generateFakeOutStationData(Integer deviceNo, Integer stationId) {
|
mutateStation(deviceNo, stationId, new StationMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity status) {
|
News.info("仿真出库站点数据生成,设备号={},站点号={},原taskNo={},原targetStaNo={},原loading={},原barcode={},动作=generateFakeOutStationData",
|
deviceNo, stationId, status.getTaskNo(), status.getTargetStaNo(), status.isLoading(), status.getBarcode());
|
status.setLoading(true);
|
News.info("仿真出库站点数据生成完成,设备号={},站点号={},新taskNo={},新targetStaNo={},新loading={},新barcode={}",
|
deviceNo, stationId, status.getTaskNo(), status.getTargetStaNo(), status.isLoading(), status.getBarcode());
|
}
|
});
|
}
|
|
public void resetStation(Integer deviceNo, Integer stationId) {
|
if (findStationStatus(deviceNo, stationId) == null) {
|
return;
|
}
|
clearStationForDispatch(deviceNo, stationId, "resetStation");
|
}
|
|
public void clearStationForDispatch(Integer deviceNo, Integer stationId, String reason) {
|
mutateStation(deviceNo, stationId, new StationMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity status) {
|
News.info("仿真站点状态清除,设备号={},站点号={},原taskNo={},原targetStaNo={},原loading={},原barcode={},动作={}",
|
deviceNo, stationId, status.getTaskNo(), status.getTargetStaNo(), status.isLoading(), status.getBarcode(), reason);
|
status.setTaskNo(0);
|
status.setTargetStaNo(0);
|
status.setLoading(false);
|
status.setBarcode("");
|
status.setRunBlock(false);
|
}
|
});
|
}
|
|
public void handoffBarcodeStation(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) {
|
mutateLockedStation(deviceNo, stationId, new StationLockedMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity status) {
|
News.info("仿真站点生成任务数据,设备号={},站点号={},原taskNo={},新taskNo={},原targetStaNo={},新targetStaNo={},原loading={},barcode={}",
|
deviceNo, stationId, status.getTaskNo(), taskNo, status.getTargetStaNo(), targetStationId,
|
status.isLoading(), status.getBarcode());
|
status.setTaskNo(taskNo);
|
status.setTargetStaNo(targetStationId);
|
status.setLoading(false);
|
News.info("仿真站点状态清除,设备号={},站点号={},原taskNo={},原targetStaNo={},原loading={},原barcode={},动作={}",
|
deviceNo, stationId, status.getTaskNo(), status.getTargetStaNo(), status.isLoading(), status.getBarcode(), "barcodeTaskHandoff");
|
status.setTaskNo(0);
|
status.setTargetStaNo(0);
|
status.setLoading(false);
|
status.setBarcode("");
|
status.setRunBlock(false);
|
}
|
});
|
}
|
|
public void updateStationBarcode(Integer deviceNo, Integer stationId, String barcode) {
|
mutateStation(deviceNo, stationId, new StationMutation() {
|
@Override
|
public void apply(ZyStationStatusEntity status) {
|
status.setBarcode(barcode);
|
}
|
});
|
}
|
|
public boolean generateStationBarcode(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo) {
|
ZyStationStatusEntity currentStatus = findStationStatus(currentStationDeviceNo, currentStationId);
|
if (currentStatus == null) {
|
return false;
|
}
|
|
Random random = new Random();
|
String barcodeTime = String.valueOf(System.currentTimeMillis());
|
String barcode = String.valueOf(random.nextInt(10)) + String.valueOf(random.nextInt(10))
|
+ barcodeTime.substring(7);
|
return updateStationDataInternal(currentStationId, currentStationDeviceNo, null, null, null, barcode, null);
|
}
|
|
public CommandResponse clearTaskBufferSlot(Integer deviceNo, Integer stationId, Integer slotIdx) {
|
if (deviceNo == null || stationId == null || slotIdx == null || slotIdx <= 0) {
|
return new CommandResponse(false, "清理缓存区槽位参数无效");
|
}
|
List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
|
if (statusList == null) {
|
return new CommandResponse(false, "未找到设备状态");
|
}
|
for (ZyStationStatusEntity status : statusList) {
|
if (status == null || !stationId.equals(status.getStationId())) {
|
continue;
|
}
|
List<StationTaskBufferItem> taskBufferItems = status.getTaskBufferItems();
|
if (taskBufferItems == null || taskBufferItems.isEmpty()) {
|
return new CommandResponse(true, "缓存区槽位已为空");
|
}
|
for (StationTaskBufferItem item : taskBufferItems) {
|
if (item != null && slotIdx.equals(item.getSlotIdx())) {
|
item.setTaskNo(0);
|
item.setTargetStaNo(0);
|
return new CommandResponse(true, "缓存区槽位清理成功");
|
}
|
}
|
return new CommandResponse(false, "未找到缓存区槽位");
|
}
|
return new CommandResponse(false, "未找到站点状态");
|
}
|
}
|