feat: add legacy dispatch cycle demo
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package com.ft546.wcs.demo.center;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class CycleResult {
|
||||
private final int cycleNumber;
|
||||
private final List<String> processedVehicleIds;
|
||||
private final List<String> events;
|
||||
|
||||
public CycleResult(
|
||||
int cycleNumber,
|
||||
List<String> processedVehicleIds,
|
||||
List<String> events
|
||||
) {
|
||||
this.cycleNumber = cycleNumber;
|
||||
this.processedVehicleIds = Collections.unmodifiableList(
|
||||
new ArrayList<String>(processedVehicleIds)
|
||||
);
|
||||
this.events = Collections.unmodifiableList(new ArrayList<String>(events));
|
||||
}
|
||||
|
||||
public int getCycleNumber() {
|
||||
return cycleNumber;
|
||||
}
|
||||
|
||||
public List<String> getProcessedVehicleIds() {
|
||||
return processedVehicleIds;
|
||||
}
|
||||
|
||||
public List<String> getEvents() {
|
||||
return events;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.ft546.wcs.demo.center;
|
||||
|
||||
import com.ft546.wcs.demo.model.DecisionCode;
|
||||
import com.ft546.wcs.demo.model.DispatchQueueEntry;
|
||||
import com.ft546.wcs.demo.model.VehicleSnapshot;
|
||||
import com.ft546.wcs.demo.repository.InMemoryWcsState;
|
||||
import com.ft546.wcs.demo.simulation.SimulatedProtocolAdapter;
|
||||
import com.ft546.wcs.demo.traffic.TrafficController;
|
||||
import com.ft546.wcs.demo.traffic.TrafficDecision;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class LegacyDispatchCenter {
|
||||
private final InMemoryWcsState state;
|
||||
private final QueueAdmissionService admission;
|
||||
private final TrafficController traffic;
|
||||
private final SimulatedProtocolAdapter protocol;
|
||||
|
||||
public LegacyDispatchCenter(
|
||||
InMemoryWcsState state,
|
||||
QueueAdmissionService admission,
|
||||
TrafficController traffic,
|
||||
SimulatedProtocolAdapter protocol
|
||||
) {
|
||||
if (state == null || admission == null || traffic == null || protocol == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"state, admission, traffic and protocol are required"
|
||||
);
|
||||
}
|
||||
this.state = state;
|
||||
this.admission = admission;
|
||||
this.traffic = traffic;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public CycleResult runCycle() {
|
||||
int eventStart = state.getEvents().size();
|
||||
int cycleNumber = state.nextCycle();
|
||||
state.addEvent("CYCLE " + cycleNumber);
|
||||
|
||||
admission.createPendingQueue(state);
|
||||
|
||||
List<VehicleSnapshot> vehicles =
|
||||
new ArrayList<VehicleSnapshot>(state.getVehicles());
|
||||
Collections.sort(vehicles, new Comparator<VehicleSnapshot>() {
|
||||
@Override
|
||||
public int compare(VehicleSnapshot left, VehicleSnapshot right) {
|
||||
return left.getVehicleId().compareTo(right.getVehicleId());
|
||||
}
|
||||
});
|
||||
|
||||
List<String> processed = new ArrayList<String>();
|
||||
for (VehicleSnapshot frozenVehicle : vehicles) {
|
||||
processed.add(frozenVehicle.getVehicleId());
|
||||
Optional<DispatchQueueEntry> optional =
|
||||
state.findQueueByVehicle(frozenVehicle.getVehicleId());
|
||||
if (!optional.isPresent()) {
|
||||
continue;
|
||||
}
|
||||
DispatchQueueEntry queue = optional.get();
|
||||
if (queue.isIssued()) {
|
||||
processIssuedQueue(frozenVehicle, queue);
|
||||
} else {
|
||||
processUnissuedQueue(frozenVehicle, queue);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> cycleEvents = new ArrayList<String>(
|
||||
state.getEvents().subList(eventStart, state.getEvents().size())
|
||||
);
|
||||
return new CycleResult(cycleNumber, processed, cycleEvents);
|
||||
}
|
||||
|
||||
private void processUnissuedQueue(
|
||||
VehicleSnapshot vehicle,
|
||||
DispatchQueueEntry queue
|
||||
) {
|
||||
TrafficDecision decision = traffic.plan(
|
||||
vehicle,
|
||||
queue,
|
||||
state.getVehicles(),
|
||||
state.getActiveQueues()
|
||||
);
|
||||
if (decision.getCode() == DecisionCode.AVOIDANCE_CREATED) {
|
||||
DispatchQueueEntry avoidance = decision.getAvoidanceQueue().get();
|
||||
state.addQueue(avoidance);
|
||||
state.addEvent(
|
||||
"AVOID queue=" + avoidance.getQueueId() + " reason="
|
||||
+ decision.getReason()
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (decision.getCode() != DecisionCode.PATH_READY) {
|
||||
state.addEvent(
|
||||
"HOLD " + decision.getCode() + " queue=" + queue.getQueueId()
|
||||
+ " reason=" + decision.getReason()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state.addEvent("PATH queue=" + queue.getQueueId() + " " + decision.getPath());
|
||||
SimulatedProtocolAdapter.ProtocolResult result =
|
||||
protocol.send(queue, decision.getPath());
|
||||
if (!result.isSuccess()) {
|
||||
state.addEvent(
|
||||
"HOLD " + DecisionCode.HOLD_PROTOCOL_FAILURE + " queue="
|
||||
+ queue.getQueueId() + " reason=" + result.getMessage()
|
||||
);
|
||||
return;
|
||||
}
|
||||
queue.markIssued(decision.getPath());
|
||||
state.addEvent("SEND queue=" + queue.getQueueId() + " vehicle="
|
||||
+ queue.getVehicleId());
|
||||
}
|
||||
|
||||
private void processIssuedQueue(
|
||||
VehicleSnapshot vehicle,
|
||||
DispatchQueueEntry queue
|
||||
) {
|
||||
if (vehicle.getCurrentSite().equals(queue.getEndSite())) {
|
||||
complete(queue);
|
||||
return;
|
||||
}
|
||||
int index = queue.getPath().indexOf(vehicle.getCurrentSite());
|
||||
if (index < 0 || index + 1 >= queue.getPath().size()) {
|
||||
state.addEvent(
|
||||
"HOLD " + DecisionCode.HOLD_NO_PATH + " queue=" + queue.getQueueId()
|
||||
+ " reason=vehicle is outside issued path"
|
||||
);
|
||||
return;
|
||||
}
|
||||
String nextSite = queue.getPath().get(index + 1);
|
||||
state.updateVehicle(vehicle.at(nextSite, vehicle.getFloor()));
|
||||
state.addEvent(
|
||||
"MOVE vehicle=" + vehicle.getVehicleId() + " site=" + nextSite
|
||||
);
|
||||
if (nextSite.equals(queue.getEndSite())) {
|
||||
complete(queue);
|
||||
}
|
||||
}
|
||||
|
||||
private void complete(DispatchQueueEntry queue) {
|
||||
if (state.completeQueue(queue.getQueueId())) {
|
||||
state.addEvent(
|
||||
"COMPLETE queue=" + queue.getQueueId() + " vehicle="
|
||||
+ queue.getVehicleId()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.ft546.wcs.demo.center;
|
||||
|
||||
import com.ft546.wcs.demo.model.DispatchQueueEntry;
|
||||
import com.ft546.wcs.demo.model.DispatchTask;
|
||||
import com.ft546.wcs.demo.model.VehicleSnapshot;
|
||||
import com.ft546.wcs.demo.repository.InMemoryWcsState;
|
||||
import com.ft546.wcs.demo.traffic.GridMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class QueueAdmissionService {
|
||||
private final VehicleAssignmentService assignmentService;
|
||||
private final GridMap map;
|
||||
private int invocationCount;
|
||||
|
||||
public QueueAdmissionService(
|
||||
VehicleAssignmentService assignmentService,
|
||||
GridMap map
|
||||
) {
|
||||
if (assignmentService == null || map == null) {
|
||||
throw new IllegalArgumentException("assignment service and map are required");
|
||||
}
|
||||
this.assignmentService = assignmentService;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public Optional<DispatchQueueEntry> createPendingQueue(InMemoryWcsState state) {
|
||||
if (state == null) {
|
||||
throw new IllegalArgumentException("state must not be null");
|
||||
}
|
||||
invocationCount++;
|
||||
if (state.getPendingTasks().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
DispatchTask task = state.getPendingTasks().get(0);
|
||||
List<VehicleSnapshot> available = new ArrayList<VehicleSnapshot>();
|
||||
for (VehicleSnapshot vehicle : state.getVehicles()) {
|
||||
if (!state.findQueueByVehicle(vehicle.getVehicleId()).isPresent()) {
|
||||
available.add(vehicle);
|
||||
}
|
||||
}
|
||||
VehicleAssignmentDecision decision =
|
||||
assignmentService.select(task, available, map.getSites());
|
||||
if (!decision.getVehicle().isPresent()) {
|
||||
state.addEvent(
|
||||
"HOLD " + decision.getCode() + " task=" + task.getTaskId()
|
||||
+ " reason=" + decision.getReason()
|
||||
);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
VehicleSnapshot selected = decision.getVehicle().get();
|
||||
DispatchQueueEntry queue = DispatchQueueEntry.business(
|
||||
task,
|
||||
selected.getVehicleId()
|
||||
);
|
||||
state.admitTask(task, queue);
|
||||
state.addEvent(
|
||||
"ASSIGN task=" + task.getTaskId() + " vehicle="
|
||||
+ selected.getVehicleId() + " reason=" + decision.getReason()
|
||||
);
|
||||
return Optional.of(queue);
|
||||
}
|
||||
|
||||
public int getInvocationCount() {
|
||||
return invocationCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.ft546.wcs.demo.repository;
|
||||
|
||||
import com.ft546.wcs.demo.model.DispatchQueueEntry;
|
||||
import com.ft546.wcs.demo.model.DispatchTask;
|
||||
import com.ft546.wcs.demo.model.VehicleSnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public final class InMemoryWcsState {
|
||||
private final Map<String, VehicleSnapshot> vehicles =
|
||||
new LinkedHashMap<String, VehicleSnapshot>();
|
||||
private final Map<String, DispatchTask> pendingTasks =
|
||||
new LinkedHashMap<String, DispatchTask>();
|
||||
private final Set<String> knownTaskIds = new LinkedHashSet<String>();
|
||||
private final Map<String, DispatchQueueEntry> activeQueues =
|
||||
new LinkedHashMap<String, DispatchQueueEntry>();
|
||||
private final List<DispatchQueueEntry> history =
|
||||
new ArrayList<DispatchQueueEntry>();
|
||||
private final List<String> events = new ArrayList<String>();
|
||||
private int cycleNumber;
|
||||
|
||||
public void addVehicle(VehicleSnapshot vehicle) {
|
||||
if (vehicle == null) {
|
||||
throw new IllegalArgumentException("vehicle must not be null");
|
||||
}
|
||||
if (vehicles.containsKey(vehicle.getVehicleId())) {
|
||||
throw new IllegalArgumentException(
|
||||
"duplicate vehicle: " + vehicle.getVehicleId()
|
||||
);
|
||||
}
|
||||
vehicles.put(vehicle.getVehicleId(), vehicle);
|
||||
}
|
||||
|
||||
public void updateVehicle(VehicleSnapshot vehicle) {
|
||||
if (vehicle == null || !vehicles.containsKey(vehicle.getVehicleId())) {
|
||||
throw new IllegalArgumentException("cannot update unknown vehicle");
|
||||
}
|
||||
vehicles.put(vehicle.getVehicleId(), vehicle);
|
||||
}
|
||||
|
||||
public void addTask(DispatchTask task) {
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException("task must not be null");
|
||||
}
|
||||
if (!knownTaskIds.add(task.getTaskId())) {
|
||||
throw new IllegalArgumentException("duplicate task: " + task.getTaskId());
|
||||
}
|
||||
pendingTasks.put(task.getTaskId(), task);
|
||||
}
|
||||
|
||||
public void admitTask(DispatchTask task, DispatchQueueEntry queue) {
|
||||
if (task == null || !pendingTasks.containsKey(task.getTaskId())) {
|
||||
throw new IllegalArgumentException("task is not pending: " + task);
|
||||
}
|
||||
addQueue(queue);
|
||||
pendingTasks.remove(task.getTaskId());
|
||||
}
|
||||
|
||||
public void addQueue(DispatchQueueEntry queue) {
|
||||
if (queue == null) {
|
||||
throw new IllegalArgumentException("queue must not be null");
|
||||
}
|
||||
if (activeQueues.containsKey(queue.getQueueId())) {
|
||||
throw new IllegalArgumentException("duplicate queue: " + queue.getQueueId());
|
||||
}
|
||||
if (findQueueByVehicle(queue.getVehicleId()).isPresent()) {
|
||||
throw new IllegalStateException(
|
||||
"vehicle already has an active queue: " + queue.getVehicleId()
|
||||
);
|
||||
}
|
||||
activeQueues.put(queue.getQueueId(), queue);
|
||||
}
|
||||
|
||||
public boolean completeQueue(String queueId) {
|
||||
DispatchQueueEntry queue = activeQueues.remove(queueId);
|
||||
if (queue == null) {
|
||||
return false;
|
||||
}
|
||||
queue.markCompleted();
|
||||
history.add(queue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<VehicleSnapshot> getVehicles() {
|
||||
return Collections.unmodifiableList(
|
||||
new ArrayList<VehicleSnapshot>(vehicles.values())
|
||||
);
|
||||
}
|
||||
|
||||
public List<DispatchTask> getPendingTasks() {
|
||||
List<DispatchTask> result =
|
||||
new ArrayList<DispatchTask>(pendingTasks.values());
|
||||
Collections.sort(result, new Comparator<DispatchTask>() {
|
||||
@Override
|
||||
public int compare(DispatchTask left, DispatchTask right) {
|
||||
int priority = Integer.compare(right.getPriority(), left.getPriority());
|
||||
if (priority != 0) {
|
||||
return priority;
|
||||
}
|
||||
return left.getTaskId().compareTo(right.getTaskId());
|
||||
}
|
||||
});
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
public List<DispatchQueueEntry> getActiveQueues() {
|
||||
return Collections.unmodifiableList(
|
||||
new ArrayList<DispatchQueueEntry>(activeQueues.values())
|
||||
);
|
||||
}
|
||||
|
||||
public List<DispatchQueueEntry> getHistory() {
|
||||
return Collections.unmodifiableList(history);
|
||||
}
|
||||
|
||||
public Optional<DispatchQueueEntry> findQueueByVehicle(String vehicleId) {
|
||||
for (DispatchQueueEntry queue : activeQueues.values()) {
|
||||
if (queue.getVehicleId().equals(vehicleId)) {
|
||||
return Optional.of(queue);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void addEvent(String event) {
|
||||
if (event == null || event.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("event must not be blank");
|
||||
}
|
||||
events.add(event);
|
||||
}
|
||||
|
||||
public List<String> getEvents() {
|
||||
return Collections.unmodifiableList(events);
|
||||
}
|
||||
|
||||
public int nextCycle() {
|
||||
cycleNumber++;
|
||||
return cycleNumber;
|
||||
}
|
||||
|
||||
public int getCycleNumber() {
|
||||
return cycleNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.ft546.wcs.demo.simulation;
|
||||
|
||||
import com.ft546.wcs.demo.model.DispatchQueueEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class SimulatedProtocolAdapter {
|
||||
private final List<String> attemptedQueueIds = new ArrayList<String>();
|
||||
private String nextFailure;
|
||||
|
||||
public ProtocolResult send(DispatchQueueEntry queue, List<String> path) {
|
||||
if (queue == null || path == null || path.isEmpty()) {
|
||||
throw new IllegalArgumentException("queue and non-empty path are required");
|
||||
}
|
||||
attemptedQueueIds.add(queue.getQueueId());
|
||||
if (nextFailure != null) {
|
||||
String failure = nextFailure;
|
||||
nextFailure = null;
|
||||
return ProtocolResult.failure(failure);
|
||||
}
|
||||
return ProtocolResult.success();
|
||||
}
|
||||
|
||||
public void failNextSend(String reason) {
|
||||
if (reason == null || reason.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("failure reason must not be blank");
|
||||
}
|
||||
nextFailure = reason;
|
||||
}
|
||||
|
||||
public List<String> getAttemptedQueueIds() {
|
||||
return Collections.unmodifiableList(attemptedQueueIds);
|
||||
}
|
||||
|
||||
public static final class ProtocolResult {
|
||||
private final boolean success;
|
||||
private final String message;
|
||||
|
||||
private ProtocolResult(boolean success, String message) {
|
||||
this.success = success;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public static ProtocolResult success() {
|
||||
return new ProtocolResult(true, "accepted");
|
||||
}
|
||||
|
||||
public static ProtocolResult failure(String message) {
|
||||
return new ProtocolResult(false, message);
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package com.ft546.wcs.demo;
|
||||
|
||||
import com.ft546.wcs.demo.center.CycleResult;
|
||||
import com.ft546.wcs.demo.center.LegacyDispatchCenter;
|
||||
import com.ft546.wcs.demo.center.QueueAdmissionService;
|
||||
import com.ft546.wcs.demo.center.VehicleAssignmentService;
|
||||
import com.ft546.wcs.demo.model.DispatchQueueEntry;
|
||||
import com.ft546.wcs.demo.model.DispatchTask;
|
||||
import com.ft546.wcs.demo.model.Site;
|
||||
import com.ft546.wcs.demo.model.VehicleSnapshot;
|
||||
import com.ft546.wcs.demo.repository.InMemoryWcsState;
|
||||
import com.ft546.wcs.demo.simulation.SimulatedProtocolAdapter;
|
||||
import com.ft546.wcs.demo.traffic.GridMap;
|
||||
import com.ft546.wcs.demo.traffic.GridPathPlanner;
|
||||
import com.ft546.wcs.demo.traffic.TrafficController;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class LegacyDispatchCenterTest {
|
||||
|
||||
@Test
|
||||
void eachCycleAdmitsOnceAndProcessesVehiclesInStableOrder() {
|
||||
Fixture fixture = fixtureWithThreeVehicles();
|
||||
|
||||
CycleResult result = fixture.center.runCycle();
|
||||
|
||||
assertEquals(1, fixture.admission.getInvocationCount());
|
||||
assertEquals(Arrays.asList("1", "2", "3"), result.getProcessedVehicleIds());
|
||||
assertEquals(1, fixture.state.getActiveQueues().size());
|
||||
assertTrue(fixture.state.getActiveQueues().get(0).isIssued());
|
||||
}
|
||||
|
||||
@Test
|
||||
void failedProtocolSendRemainsPendingAndRetriesNextCycle() {
|
||||
Fixture fixture = fixtureWithOneVehicle();
|
||||
fixture.protocol.failNextSend("simulated PLC rejection");
|
||||
|
||||
fixture.center.runCycle();
|
||||
|
||||
DispatchQueueEntry pending = fixture.state.getActiveQueues().get(0);
|
||||
assertEquals(0, pending.getIssued());
|
||||
assertEquals(1, pending.getExecutionStatus());
|
||||
assertTrue(fixture.state.getEvents().toString().contains("HOLD_PROTOCOL_FAILURE"));
|
||||
|
||||
fixture.center.runCycle();
|
||||
|
||||
assertEquals(1, pending.getIssued());
|
||||
assertEquals(3, pending.getExecutionStatus());
|
||||
assertEquals(2, fixture.protocol.getAttemptedQueueIds().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void vehicleAtDestinationArchivesAndDeletesQueueExactlyOnce() {
|
||||
GridMap map = simpleMap();
|
||||
InMemoryWcsState state = new InMemoryWcsState();
|
||||
state.addVehicle(vehicle("1", "TARGET"));
|
||||
DispatchQueueEntry queue = DispatchQueueEntry.business(task(), "1");
|
||||
queue.markIssued(Arrays.asList("A", "TARGET"));
|
||||
state.addQueue(queue);
|
||||
Fixture fixture = fixture(map, state);
|
||||
|
||||
fixture.center.runCycle();
|
||||
fixture.center.runCycle();
|
||||
|
||||
assertTrue(fixture.state.getActiveQueues().isEmpty());
|
||||
assertEquals(1, fixture.state.getHistory().size());
|
||||
assertEquals(4, fixture.state.getHistory().get(0).getExecutionStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void channelConflictAddsAvoidanceQueueForBlockingVehicle() {
|
||||
GridMap map = simpleMap();
|
||||
map.setCacheSite("TARGET-CHANNEL", "CACHE");
|
||||
InMemoryWcsState state = new InMemoryWcsState();
|
||||
state.addVehicle(vehicle("1", "A"));
|
||||
state.addVehicle(vehicle("2", "BLOCKER"));
|
||||
state.addTask(task());
|
||||
Fixture fixture = fixture(map, state);
|
||||
|
||||
fixture.center.runCycle();
|
||||
|
||||
assertEquals(2, fixture.state.getActiveQueues().size());
|
||||
assertTrue(fixture.state.findQueueByVehicle("2").isPresent());
|
||||
assertEquals(
|
||||
DispatchQueueEntry.QueueType.AVOIDANCE,
|
||||
fixture.state.findQueueByVehicle("2").get().getQueueType()
|
||||
);
|
||||
assertTrue(fixture.state.getEvents().toString().contains("AVOID"));
|
||||
}
|
||||
|
||||
private Fixture fixtureWithThreeVehicles() {
|
||||
GridMap map = simpleMap();
|
||||
InMemoryWcsState state = new InMemoryWcsState();
|
||||
state.addVehicle(vehicle("3", "V3"));
|
||||
state.addVehicle(vehicle("2", "V2"));
|
||||
state.addVehicle(vehicle("1", "A"));
|
||||
state.addTask(task());
|
||||
return fixture(map, state);
|
||||
}
|
||||
|
||||
private Fixture fixtureWithOneVehicle() {
|
||||
GridMap map = simpleMap();
|
||||
InMemoryWcsState state = new InMemoryWcsState();
|
||||
state.addVehicle(vehicle("1", "A"));
|
||||
state.addTask(task());
|
||||
return fixture(map, state);
|
||||
}
|
||||
|
||||
private Fixture fixture(GridMap map, InMemoryWcsState state) {
|
||||
QueueAdmissionService admission = new QueueAdmissionService(
|
||||
new VehicleAssignmentService(),
|
||||
map
|
||||
);
|
||||
SimulatedProtocolAdapter protocol = new SimulatedProtocolAdapter();
|
||||
LegacyDispatchCenter center = new LegacyDispatchCenter(
|
||||
state,
|
||||
admission,
|
||||
new TrafficController(map, new GridPathPlanner()),
|
||||
protocol
|
||||
);
|
||||
return new Fixture(state, admission, protocol, center);
|
||||
}
|
||||
|
||||
private GridMap simpleMap() {
|
||||
GridMap map = new GridMap();
|
||||
map.addSite(new Site("A", 1, 0, 0, "START"));
|
||||
map.addSite(new Site("V2", 1, 0, 1, "V2-CHANNEL"));
|
||||
map.addSite(new Site("V3", 1, 0, 2, "V3-CHANNEL"));
|
||||
map.addSite(new Site("BLOCKER", 1, 1, 0, "TARGET-CHANNEL"));
|
||||
map.addSite(new Site("TARGET", 1, 2, 0, "TARGET-CHANNEL"));
|
||||
map.addSite(new Site("CACHE", 1, 1, 1, "CACHE"));
|
||||
map.connect("A", "BLOCKER");
|
||||
map.connect("BLOCKER", "TARGET");
|
||||
map.connect("BLOCKER", "CACHE");
|
||||
map.connect("V2", "A");
|
||||
map.connect("V3", "V2");
|
||||
return map;
|
||||
}
|
||||
|
||||
private DispatchTask task() {
|
||||
return new DispatchTask(
|
||||
"TASK-1",
|
||||
DispatchTask.TaskType.OUTBOUND,
|
||||
"A",
|
||||
"TARGET",
|
||||
1,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
private VehicleSnapshot vehicle(String id, String site) {
|
||||
return new VehicleSnapshot(id, 1, site, 5, 1, 80, true, true, false);
|
||||
}
|
||||
|
||||
private static final class Fixture {
|
||||
private final InMemoryWcsState state;
|
||||
private final QueueAdmissionService admission;
|
||||
private final SimulatedProtocolAdapter protocol;
|
||||
private final LegacyDispatchCenter center;
|
||||
|
||||
private Fixture(
|
||||
InMemoryWcsState state,
|
||||
QueueAdmissionService admission,
|
||||
SimulatedProtocolAdapter protocol,
|
||||
LegacyDispatchCenter center
|
||||
) {
|
||||
this.state = state;
|
||||
this.admission = admission;
|
||||
this.protocol = protocol;
|
||||
this.center = center;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user