package net.java.pathfinder.api; import java.util.*; import javax.ejb.Stateless; import javax.inject.Inject; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import net.java.pathfinder.internal.GraphDao; @Stateless @Path("/graph-traversal") public class GraphTraversalService { @Inject private GraphDao dao; private final Random random = new Random(); private static final long ONE_MIN_MS = 1000 * 60; private static final long ONE_DAY_MS = ONE_MIN_MS * 60 * 24; @GET @Path("/shortest-path") @Produces({"application/json", "application/xml; qs=.75"}) // TODO Add internationalized messages for constraints. public List<TransitPath> findShortestPath( @NotNull @Size(min = 5, max = 5) @QueryParam("origin") String originUnLocode, @NotNull @Size(min = 5, max = 5) @QueryParam("destination") String destinationUnLocode, @QueryParam("deadline") String deadline) { Date date = nextDate(new Date()); List<String> allVertices = dao.listLocations(); allVertices.remove(originUnLocode); allVertices.remove(destinationUnLocode); int candidateCount = getRandomNumberOfCandidates(); List<TransitPath> candidates = new ArrayList<>( candidateCount); for (int i = 0; i < candidateCount; i++) { allVertices = getRandomChunkOfLocations(allVertices); List<TransitEdge> transitEdges = new ArrayList<>( allVertices.size() - 1); String firstLegTo = allVertices.get(0); Date fromDate = nextDate(date); Date toDate = nextDate(fromDate); date = nextDate(toDate); transitEdges.add(new TransitEdge( dao.getVoyageNumber(originUnLocode, firstLegTo), originUnLocode, firstLegTo, fromDate, toDate)); for (int j = 0; j < allVertices.size() - 1; j++) { String current = allVertices.get(j); String next = allVertices.get(j + 1); fromDate = nextDate(date); toDate = nextDate(fromDate); date = nextDate(toDate); transitEdges.add(new TransitEdge(dao.getVoyageNumber(current, next), current, next, fromDate, toDate)); } String lastLegFrom = allVertices.get(allVertices.size() - 1); fromDate = nextDate(date); toDate = nextDate(fromDate); transitEdges.add(new TransitEdge( dao.getVoyageNumber(lastLegFrom, destinationUnLocode), lastLegFrom, destinationUnLocode, fromDate, toDate)); candidates.add(new TransitPath(transitEdges)); } return candidates; } private Date nextDate(Date date) { return new Date(date.getTime() + ONE_DAY_MS + (random.nextInt(1000) - 500) * ONE_MIN_MS); } private int getRandomNumberOfCandidates() { return 3 + random.nextInt(3); } private List<String> getRandomChunkOfLocations(List<String> allLocations) { Collections.shuffle(allLocations); int total = allLocations.size(); int chunk = total > 4 ? 1 + new Random().nextInt(5) : total; return allLocations.subList(0, chunk); } }