Bläddra i källkod

Route generation improvments.

Better date handling in route assigment.

Added voyage to handling activity, where applicable.

Next expected activity is now visible in the tracking interface.

Now possible to change destination of a cargo.

Minor touchups of the web pages.
peter_backlund 17 år sedan
förälder
incheckning
023a0e1916
19 ändrade filer med 235 tillägg och 61 borttagningar
  1. 22
    5
      dddsample/src/main/java/com/pathfinder/internal/GraphTraversalServiceImpl.java
  2. 1
    1
      dddsample/src/main/java/se/citerus/dddsample/application/impl/BookingServiceImpl.java
  3. 8
    7
      dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/Cargo.java
  4. 25
    15
      dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/HandlingActivity.java
  5. 1
    0
      dddsample/src/main/java/se/citerus/dddsample/infrastructure/routing/ExternalRoutingService.java
  6. 1
    2
      dddsample/src/main/java/se/citerus/dddsample/interfaces/booking/facade/internal/assembler/ItineraryCandidateDTOAssembler.java
  7. 35
    2
      dddsample/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java
  8. 19
    0
      dddsample/src/main/java/se/citerus/dddsample/interfaces/booking/web/RouteAssignmentCommand.java
  9. 1
    1
      dddsample/src/main/java/se/citerus/dddsample/interfaces/handling/HandlingReportParser.java
  10. 22
    0
      dddsample/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingViewAdapter.java
  11. 1
    1
      dddsample/src/main/resources/messages_en.properties
  12. 2
    2
      dddsample/src/main/webapp/WEB-INF/jsp/admin/list.jsp
  13. 53
    0
      dddsample/src/main/webapp/WEB-INF/jsp/admin/pickNewDestination.jsp
  14. 7
    1
      dddsample/src/main/webapp/WEB-INF/jsp/admin/selectItinerary.jsp
  15. 9
    3
      dddsample/src/main/webapp/WEB-INF/jsp/admin/show.jsp
  16. 3
    2
      dddsample/src/main/webapp/WEB-INF/jsp/pub/track.jsp
  17. 13
    8
      dddsample/src/main/webapp/index.jsp
  18. 8
    8
      dddsample/src/test/java/se/citerus/dddsample/scenario/CargoLifecycleScenarioTest.java
  19. 4
    3
      dddsample/src/test/resources/handling_events.csv

+ 22
- 5
dddsample/src/main/java/com/pathfinder/internal/GraphTraversalServiceImpl.java Visa fil

@@ -10,6 +10,8 @@ public class GraphTraversalServiceImpl implements GraphTraversalService {
10 10
 
11 11
   private GraphDAO dao;
12 12
   private Random random;
13
+  private static final long ONE_MIN_MS = 1000 * 60;
14
+  private static final long ONE_DAY_MS = ONE_MIN_MS * 60 * 24;
13 15
 
14 16
   public GraphTraversalServiceImpl(GraphDAO dao) {
15 17
     this.dao = dao;
@@ -19,6 +21,8 @@ public class GraphTraversalServiceImpl implements GraphTraversalService {
19 21
   public List<TransitPath> findShortestPath(final String originUnLocode,
20 22
                                             final String destinationUnLocode,
21 23
                                             final Properties limitations) {
24
+    Date date = nextDate(new Date());
25
+
22 26
     List<String> allVertices = dao.listLocations();
23 27
     allVertices.remove(originUnLocode);
24 28
     allVertices.remove(destinationUnLocode);
@@ -31,20 +35,29 @@ public class GraphTraversalServiceImpl implements GraphTraversalService {
31 35
       final List<TransitEdge> transitEdges = new ArrayList<TransitEdge>(allVertices.size() - 1);
32 36
       final String firstLegTo = allVertices.get(0);
33 37
 
38
+      Date fromDate = nextDate(date);
39
+      Date toDate = nextDate(fromDate);
40
+      date = nextDate(toDate);
41
+
34 42
       transitEdges.add(new TransitEdge(
35 43
         dao.getVoyageNumber(originUnLocode, firstLegTo),
36
-        originUnLocode, firstLegTo, new Date(), new Date()));
44
+        originUnLocode, firstLegTo, fromDate, toDate));
37 45
 
38 46
       for (int j = 0; j < allVertices.size() - 1; j++) {
39 47
         final String curr = allVertices.get(j);
40 48
         final String next = allVertices.get(j + 1);
41
-        transitEdges.add(new TransitEdge(dao.getVoyageNumber(curr, next), curr, next, new Date(), new Date()));
49
+        fromDate = nextDate(date);
50
+        toDate = nextDate(fromDate);
51
+        date = nextDate(toDate);
52
+        transitEdges.add(new TransitEdge(dao.getVoyageNumber(curr, next), curr, next, fromDate, toDate));
42 53
       }
43 54
 
44 55
       final String lastLegFrom = allVertices.get(allVertices.size() - 1);
56
+      fromDate = nextDate(date);
57
+      toDate = nextDate(fromDate);
45 58
       transitEdges.add(new TransitEdge(
46 59
         dao.getVoyageNumber(lastLegFrom, destinationUnLocode),
47
-        lastLegFrom, destinationUnLocode, new Date(), new Date()));
60
+        lastLegFrom, destinationUnLocode, fromDate, toDate));
48 61
 
49 62
       candidates.add(new TransitPath(transitEdges));
50 63
     }
@@ -52,14 +65,18 @@ public class GraphTraversalServiceImpl implements GraphTraversalService {
52 65
     return candidates;
53 66
   }
54 67
 
68
+  private Date nextDate(Date date) {
69
+    return new Date(date.getTime() + ONE_DAY_MS + (random.nextInt(1000) - 500) * ONE_MIN_MS);
70
+  }
71
+
55 72
   private int getRandomNumberOfCandidates() {
56
-    return 1 + random.nextInt(4);
73
+    return 3 + random.nextInt(3);
57 74
   }
58 75
 
59 76
   private List<String> getRandomChunkOfLocations(List<String> allLocations) {
60 77
     Collections.shuffle(allLocations);
61 78
     final int total = allLocations.size();
62
-    final int chunk = total > 4 ? (total - 4) + random.nextInt(5) : total;
79
+    final int chunk = total > 4 ? 1 + new Random().nextInt(5) : total;
63 80
     return allLocations.subList(0, chunk);
64 81
   }
65 82
 

+ 1
- 1
dddsample/src/main/java/se/citerus/dddsample/application/impl/BookingServiceImpl.java Visa fil

@@ -71,7 +71,7 @@ public final class BookingServiceImpl implements BookingService {
71 71
   public void assignCargoToRoute(final Itinerary itinerary, final TrackingId trackingId) {
72 72
     Validate.notNull(itinerary);
73 73
     Validate.notNull(trackingId);
74
-
74
+                                
75 75
     final Cargo cargo = cargoRepository.find(trackingId);
76 76
     if (cargo == null) {
77 77
       throw new IllegalArgumentException("Can't assign itinerary to non-existing cargo " + trackingId);

+ 8
- 7
dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/Cargo.java Visa fil

@@ -53,6 +53,7 @@ public class Cargo implements Entity<Cargo> {
53 53
   private Date eta;
54 54
   
55 55
   private static final Date ETA_UNKOWN = null;
56
+  private static final HandlingActivity NO_ACTIVITY = null;
56 57
 
57 58
   public Cargo(final TrackingId trackingId, final RouteSpecification routeSpecification) {
58 59
     Validate.notNull(trackingId, "Tracking id is required");
@@ -179,7 +180,7 @@ public class Cargo implements Entity<Cargo> {
179 180
    * @return the next expected activity
180 181
    */
181 182
   public HandlingActivity nextExpectedActivity() {
182
-    if (!onTrack()) return HandlingActivity.NONE;
183
+    if (!onTrack()) return NO_ACTIVITY;
183 184
 
184 185
     final HandlingEvent lastEvent = delivery().lastEvent();
185 186
 
@@ -190,11 +191,11 @@ public class Cargo implements Entity<Cargo> {
190 191
       case LOAD:
191 192
         for (Leg leg : itinerary().legs()) {
192 193
           if (leg.loadLocation().sameIdentityAs(lastEvent.location())) {
193
-            return new HandlingActivity(UNLOAD, leg.unloadLocation());
194
+            return new HandlingActivity(UNLOAD, leg.unloadLocation(), leg.voyage());
194 195
           }
195 196
         }
196 197
 
197
-        return HandlingActivity.NONE;
198
+        return NO_ACTIVITY;
198 199
 
199 200
       case UNLOAD:
200 201
         for (Iterator<Leg> it = itinerary().legs().iterator(); it.hasNext();) {
@@ -202,22 +203,22 @@ public class Cargo implements Entity<Cargo> {
202 203
           if (leg.unloadLocation().sameIdentityAs(lastEvent.location())) {
203 204
             if (it.hasNext()) {
204 205
               final Leg nextLeg = it.next();
205
-              return new HandlingActivity(LOAD, nextLeg.loadLocation());
206
+              return new HandlingActivity(LOAD, nextLeg.loadLocation(), nextLeg.voyage());
206 207
             } else {
207 208
               return new HandlingActivity(CLAIM, leg.unloadLocation());
208 209
             }
209 210
           }
210 211
         }
211 212
 
212
-        return HandlingActivity.NONE;
213
+        return NO_ACTIVITY;
213 214
 
214 215
       case RECEIVE:
215 216
         final Leg firstLeg = itinerary().legs().iterator().next();
216
-        return new HandlingActivity(LOAD, firstLeg.loadLocation());
217
+        return new HandlingActivity(LOAD, firstLeg.loadLocation(), firstLeg.voyage());
217 218
 
218 219
       case CLAIM:
219 220
       default:
220
-        return HandlingActivity.NONE;
221
+        return NO_ACTIVITY;
221 222
     }
222 223
   }
223 224
 

+ 25
- 15
dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/HandlingActivity.java Visa fil

@@ -6,6 +6,7 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
6 6
 import se.citerus.dddsample.domain.model.ValueObject;
7 7
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
8 8
 import se.citerus.dddsample.domain.model.location.Location;
9
+import se.citerus.dddsample.domain.model.voyage.Voyage;
9 10
 
10 11
 /**
11 12
  * A handling activity represents how and where a cargo can be handled,
@@ -15,33 +16,48 @@ import se.citerus.dddsample.domain.model.location.Location;
15 16
  */
16 17
 public class HandlingActivity implements ValueObject<HandlingActivity> {
17 18
 
19
+  // TODO make HandlingActivity a part of HandlingEvent too? There is some overlap. 
20
+
18 21
   private HandlingEvent.Type type;
19 22
   private Location location;
20
-  public static final HandlingActivity NONE = createNoneInstance();
23
+  private Voyage voyage;
21 24
 
22
-  HandlingActivity() {
23
-  }
25
+  public HandlingActivity(final HandlingEvent.Type type, final Location location) {
26
+    Validate.notNull(type, "Handling event type is required");
27
+    Validate.notNull(location, "Location is required");
24 28
 
25
-  private static HandlingActivity createNoneInstance() {
26
-    HandlingActivity none = new HandlingActivity();
27
-    none.location = Location.UNKNOWN;
28
-    return none;
29
+    this.type = type;
30
+    this.location = location;
29 31
   }
30 32
 
31
-  public HandlingActivity(final HandlingEvent.Type type, final Location location) {
33
+  public HandlingActivity(final HandlingEvent.Type type, final Location location, final Voyage voyage) {
32 34
     Validate.notNull(type, "Handling event type is required");
33 35
     Validate.notNull(location, "Location is required");
36
+    Validate.notNull(location, "Voyage is required");
34 37
 
35 38
     this.type = type;
36 39
     this.location = location;
40
+    this.voyage = voyage;
37 41
   }
38 42
 
43
+  public HandlingEvent.Type type() {
44
+    return type;
45
+  }
46
+
47
+  public Location location() {
48
+    return location;
49
+  }
50
+
51
+  public Voyage voyage() {
52
+    return voyage;
53
+  }
39 54
 
40 55
   @Override
41 56
   public boolean sameValueAs(final HandlingActivity other) {
42 57
     return other != null && new EqualsBuilder().
43 58
       append(this.type, other.type).
44 59
       append(this.location, other.location).
60
+      append(this.voyage, other.voyage).
45 61
       isEquals();
46 62
   }
47 63
 
@@ -50,6 +66,7 @@ public class HandlingActivity implements ValueObject<HandlingActivity> {
50 66
     return new HashCodeBuilder().
51 67
       append(this.type).
52 68
       append(this.location).
69
+      append(this.voyage).
53 70
       toHashCode();
54 71
   }
55 72
 
@@ -64,11 +81,4 @@ public class HandlingActivity implements ValueObject<HandlingActivity> {
64 81
     return sameValueAs(other);
65 82
   }
66 83
 
67
-  @Override
68
-  public String toString() {
69
-    if (this == NONE) return "No activity";
70
-
71
-    return type + " in " + location;
72
-  }
73
-
74 84
 }

+ 1
- 0
dddsample/src/main/java/se/citerus/dddsample/infrastructure/routing/ExternalRoutingService.java Visa fil

@@ -102,4 +102,5 @@ public class ExternalRoutingService implements RoutingService {
102 102
   public void setVoyageRepository(VoyageRepository voyageRepository) {
103 103
     this.voyageRepository = voyageRepository;
104 104
   }
105
+  
105 106
 }

+ 1
- 2
dddsample/src/main/java/se/citerus/dddsample/interfaces/booking/facade/internal/assembler/ItineraryCandidateDTOAssembler.java Visa fil

@@ -12,7 +12,6 @@ import se.citerus.dddsample.interfaces.booking.facade.dto.LegDTO;
12 12
 import se.citerus.dddsample.interfaces.booking.facade.dto.RouteCandidateDTO;
13 13
 
14 14
 import java.util.ArrayList;
15
-import java.util.Date;
16 15
 import java.util.List;
17 16
 
18 17
 /**
@@ -42,7 +41,7 @@ public class ItineraryCandidateDTOAssembler {
42 41
       final Voyage voyage = voyageRepository.find(voyageNumber);
43 42
       final Location from = locationRepository.find(new UnLocode(legDTO.getFrom()));
44 43
       final Location to = locationRepository.find(new UnLocode(legDTO.getTo()));
45
-      legs.add(new Leg(voyage, from, to, new Date(), new Date()));  // TODO better dates
44
+      legs.add(new Leg(voyage, from, to, legDTO.getLoadTime(), legDTO.getUnloadTime()));
46 45
     }
47 46
     return new Itinerary(legs);
48 47
   }

+ 35
- 2
dddsample/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java Visa fil

@@ -1,5 +1,7 @@
1 1
 package se.citerus.dddsample.interfaces.booking.web;
2 2
 
3
+import org.springframework.beans.propertyeditors.CustomDateEditor;
4
+import org.springframework.web.bind.ServletRequestDataBinder;
3 5
 import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
4 6
 import se.citerus.dddsample.interfaces.booking.facade.BookingServiceFacade;
5 7
 import se.citerus.dddsample.interfaces.booking.facade.dto.CargoRoutingDTO;
@@ -28,6 +30,12 @@ public final class CargoAdminController extends MultiActionController {
28 30
 
29 31
   private BookingServiceFacade bookingServiceFacade;
30 32
 
33
+  @Override
34
+  protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
35
+    super.initBinder(request, binder);
36
+    binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm"), false));
37
+  }
38
+
31 39
   public Map registrationForm(HttpServletRequest request, HttpServletResponse response) throws Exception {
32 40
     Map<String, Object> map = new HashMap<String, Object>();
33 41
     List<LocationDTO> dtoList = bookingServiceFacade.listShippingLocations();
@@ -84,8 +92,13 @@ public final class CargoAdminController extends MultiActionController {
84 92
   public void assignItinerary(HttpServletRequest request, HttpServletResponse response, RouteAssignmentCommand command) throws Exception {
85 93
     List<LegDTO> legDTOs = new ArrayList<LegDTO>(command.getLegs().size());
86 94
     for (RouteAssignmentCommand.LegCommand leg : command.getLegs()) {
87
-      // TODO actual dates
88
-      legDTOs.add(new LegDTO(leg.getVoyageNumber(), leg.getFromUnLocode(), leg.getToUnLocode(), new Date(), new Date()));
95
+      legDTOs.add(new LegDTO(
96
+        leg.getVoyageNumber(),
97
+        leg.getFromUnLocode(),
98
+        leg.getToUnLocode(),
99
+        leg.getFromDate(),
100
+        leg.getToDate())
101
+      );
89 102
     }
90 103
 
91 104
     RouteCandidateDTO selectedRoute = new RouteCandidateDTO(legDTOs);
@@ -96,6 +109,26 @@ public final class CargoAdminController extends MultiActionController {
96 109
     //response.sendRedirect("list.html");
97 110
   }
98 111
 
112
+  public Map pickNewDestination(HttpServletRequest request, HttpServletResponse response) throws Exception {
113
+    Map<String, Object> map = new HashMap<String, Object>();
114
+
115
+    List<LocationDTO> locations = bookingServiceFacade.listShippingLocations();
116
+    map.put("locations", locations);
117
+
118
+    String trackingId = request.getParameter("trackingId");
119
+    CargoRoutingDTO cargo = bookingServiceFacade.loadCargoForRouting(trackingId);
120
+    map.put("cargo", cargo);
121
+
122
+    return map;
123
+  }
124
+
125
+  public void changeDestination(HttpServletRequest request, HttpServletResponse response) throws Exception {
126
+    String trackingId = request.getParameter("trackingId");
127
+    String unLocode = request.getParameter("unlocode");
128
+    bookingServiceFacade.changeDestination(trackingId, unLocode);
129
+    response.sendRedirect("show.html?trackingId=" + trackingId);
130
+  }
131
+
99 132
   public void setBookingServiceFacade(BookingServiceFacade bookingServiceFacade) {
100 133
     this.bookingServiceFacade = bookingServiceFacade;
101 134
   }

+ 19
- 0
dddsample/src/main/java/se/citerus/dddsample/interfaces/booking/web/RouteAssignmentCommand.java Visa fil

@@ -4,6 +4,7 @@ import org.apache.commons.collections.Factory;
4 4
 import org.apache.commons.collections.ListUtils;
5 5
 
6 6
 import java.util.ArrayList;
7
+import java.util.Date;
7 8
 import java.util.List;
8 9
 
9 10
 public class RouteAssignmentCommand {
@@ -33,6 +34,8 @@ public class RouteAssignmentCommand {
33 34
     private String voyageNumber;
34 35
     private String fromUnLocode;
35 36
     private String toUnLocode;
37
+    private Date fromDate;
38
+    private Date toDate;
36 39
 
37 40
     public String getVoyageNumber() {
38 41
       return voyageNumber;
@@ -58,6 +61,22 @@ public class RouteAssignmentCommand {
58 61
       this.toUnLocode = toUnLocode;
59 62
     }
60 63
 
64
+    public Date getFromDate() {
65
+      return fromDate;
66
+    }
67
+
68
+    public void setFromDate(Date fromDate) {
69
+      this.fromDate = fromDate;
70
+    }
71
+
72
+    public Date getToDate() {
73
+      return toDate;
74
+    }
75
+
76
+    public void setToDate(Date toDate) {
77
+      this.toDate = toDate;
78
+    }
79
+
61 80
     public static Factory factory() {
62 81
       return new Factory() {
63 82
         public Object create() {

+ 1
- 1
dddsample/src/main/java/se/citerus/dddsample/interfaces/handling/HandlingReportParser.java Visa fil

@@ -22,7 +22,7 @@ import java.util.List;
22 22
  */
23 23
 public class HandlingReportParser {
24 24
 
25
-  public static final String ISO_8601_FORMAT = "yyyy-mm-dd HH:MM:SS.SSS";
25
+  public static final String ISO_8601_FORMAT = "yyyy-MM-dd HH:mm";
26 26
 
27 27
   public static UnLocode parseUnLocode(final String unlocode, final List<String> errors) {
28 28
     try {

+ 22
- 0
dddsample/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingViewAdapter.java Visa fil

@@ -3,6 +3,7 @@ package se.citerus.dddsample.interfaces.tracking;
3 3
 import org.springframework.context.MessageSource;
4 4
 import se.citerus.dddsample.domain.model.cargo.Cargo;
5 5
 import se.citerus.dddsample.domain.model.cargo.Delivery;
6
+import se.citerus.dddsample.domain.model.cargo.HandlingActivity;
6 7
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
7 8
 import se.citerus.dddsample.domain.model.location.Location;
8 9
 import se.citerus.dddsample.domain.model.voyage.Voyage;
@@ -109,6 +110,27 @@ public final class CargoTrackingViewAdapter {
109 110
     else return new SimpleDateFormat(FORMAT).format(eta);
110 111
   }
111 112
 
113
+  public String getNextExpectedActivity() {
114
+      HandlingActivity activity = cargo.nextExpectedActivity();
115
+      if (activity == null) {
116
+        return "";
117
+      }
118
+
119
+    String text = "Next expected activity is to ";
120
+    HandlingEvent.Type type = activity.type();
121
+    if (type.sameValueAs(HandlingEvent.Type.LOAD)) {
122
+        return
123
+          text + type.name().toLowerCase() + " cargo onto voyage " + activity.voyage().voyageNumber() +
124
+          " in " + activity.location().name();
125
+      } else if (type.sameValueAs(HandlingEvent.Type.UNLOAD)) {
126
+        return
127
+          text + type.name().toLowerCase() + " cargo off of " + activity.voyage().voyageNumber() +
128
+          " in " + activity.location().name();
129
+      } else {
130
+        return text + type.name().toLowerCase() + " cargo in " + activity.location().name();
131
+      }
132
+  }
133
+
112 134
   /**
113 135
    * @return True if cargo is misdirected.
114 136
    */

+ 1
- 1
dddsample/src/main/resources/messages_en.properties Visa fil

@@ -1,6 +1,6 @@
1 1
 cargo.status.NOT_RECEIVED=Not received
2 2
 cargo.status.IN_PORT=In port {0}
3
-cargo.status.ONBOARD_CARRIER=Onboard carrier {0}
3
+cargo.status.ONBOARD_CARRIER=Onboard voyage {0}
4 4
 cargo.status.CLAIMED=Claimed
5 5
 cargo.status.UNKNOWN=Unknown
6 6
 

+ 2
- 2
dddsample/src/main/webapp/WEB-INF/jsp/admin/list.jsp Visa fil

@@ -3,7 +3,7 @@
3 3
   <title>Cargo Administration</title>
4 4
 </head>
5 5
 <body>
6
-  <table>
6
+  <table border="1" width="600">
7 7
     <caption>All cargos</caption>
8 8
     <thead>
9 9
       <tr>
@@ -24,7 +24,7 @@
24 24
         </td>
25 25
         <td>${cargo.origin}</td>
26 26
         <td>${cargo.finalDestination}</td>
27
-        <td>${cargo.routed ? "Yes" : "No"}</td>
27
+        <td>${cargo.misrouted ? "Misrouted" : (cargo.routed ? "Yes" : "No")}</td>
28 28
       </tr>  
29 29
       </c:forEach>
30 30
     </tbody>

+ 53
- 0
dddsample/src/main/webapp/WEB-INF/jsp/admin/pickNewDestination.jsp Visa fil

@@ -0,0 +1,53 @@
1
+<html>
2
+<head>
3
+  <title>Cargo Administration</title>
4
+    <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/calendar.js"/>"></script>
5
+    <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/YAHOO.js"/>"></script>
6
+    <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/event.js"/>"></script>
7
+    <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/dom.js"/>"></script>
8
+    <style type="text/css" title="style" media="screen">
9
+      @import "<c:url value="/calendar.css"/>";
10
+    </style>
11
+  <style type="text/css">
12
+    td {
13
+      align: left;
14
+    }
15
+  </style>
16
+</head>
17
+<body>
18
+<div id="container">
19
+  <form action="<c:url value="/admin/changeDestination.html"/>" method="post">
20
+  <input type="hidden" name="trackingId" value="${cargo.trackingId}"/>
21
+  <table>
22
+    <caption>Change destination for cargo ${cargo.trackingId}</caption>
23
+    <tbody>
24
+      <tr>
25
+        <td>Current destination</td>
26
+        <td>
27
+            ${cargo.finalDestination}
28
+        </td>
29
+      </tr>
30
+      <tr>
31
+        <td>New destination</td>
32
+        <td>
33
+          <select name="unlocode">
34
+            <c:forEach items="${locations}" var="location">
35
+            <option value="${location.unLocode}">${location.unLocode}</option>
36
+            </c:forEach>
37
+          </select>
38
+        </td>
39
+      </tr>
40
+    </tbody>
41
+    <tfoot>
42
+      <tr>
43
+        <td> </td>
44
+        <td>
45
+          <input type="submit" value="Change destination"/>
46
+        </td>
47
+      </tr>
48
+    </tfoot>
49
+  </table>
50
+  </form>
51
+</div>
52
+</body>
53
+</html>

+ 7
- 1
dddsample/src/main/webapp/WEB-INF/jsp/admin/selectItinerary.jsp Visa fil

@@ -25,12 +25,14 @@
25 25
       <form action="${postUrl}" method="post">
26 26
         <input type="hidden" name="trackingId" value="${cargo.trackingId}"/>
27 27
         <table>
28
-          <caption>Route ${itStatus.index + 1}</caption>
28
+          <caption>Route candidate ${itStatus.index + 1}</caption>
29 29
           <thead>
30 30
             <tr>
31 31
               <td>Voyage</td>
32 32
               <td>From</td>
33
+              <td></td>
33 34
               <td>To</td>
35
+              <td></td>
34 36
             </tr>
35 37
           </thead>
36 38
           <tbody>
@@ -38,10 +40,14 @@
38 40
               <input type="hidden" name="legs[${legStatus.index}].voyageNumber" value="${leg.voyageNumber}"/>
39 41
               <input type="hidden" name="legs[${legStatus.index}].fromUnLocode" value="${leg.from}"/>
40 42
               <input type="hidden" name="legs[${legStatus.index}].toUnLocode" value="${leg.to}"/>
43
+              <input type="hidden" name="legs[${legStatus.index}].fromDate" value="<fmt:formatDate value="${leg.loadTime}" pattern="yyyy-MM-dd hh:mm"/>"/>
44
+              <input type="hidden" name="legs[${legStatus.index}].toDate" value="<fmt:formatDate value="${leg.unloadTime}" pattern="yyyy-MM-dd hh:mm"/>"/>
41 45
               <tr>
42 46
                 <td>${leg.voyageNumber}</td>
43 47
                 <td>${leg.from}</td>
48
+                <td><fmt:formatDate value="${leg.loadTime}" pattern="yyyy-MM-dd hh:mm"/></td>
44 49
                 <td>${leg.to}</td>
50
+                <td><fmt:formatDate value="${leg.unloadTime}" pattern="yyyy-MM-dd hh:mm"/></td>
45 51
               </tr>
46 52
             </c:forEach>
47 53
           </tbody>

+ 9
- 3
dddsample/src/main/webapp/WEB-INF/jsp/admin/show.jsp Visa fil

@@ -20,7 +20,10 @@
20 20
       <tr>
21 21
           <td></td>
22 22
           <td>
23
-            <a href="">Change destination</a>    
23
+           <c:url value="/admin/pickNewDestination.html" var="cdUrl">
24
+               <c:param name="trackingId" value="${cargo.trackingId}"/>
25
+           </c:url>
26
+            <a href="${cdUrl}">Change destination</a>    
24 27
           </td>
25 28
       </tr>
26 29
       <tr>
@@ -32,8 +35,11 @@
32 35
   <p></p>
33 36
   <c:choose>
34 37
     <c:when test="${cargo.routed}">
35
-      <c:if test="${carg.misrouted}">
36
-      <p><em>Cargo is misrouted - <a href="${selectUrl}">reroute this cargo</a></em></p>    
38
+      <c:if test="${cargo.misrouted}">
39
+          <c:url value="/admin/selectItinerary.html" var="selectUrl">
40
+            <c:param name="trackingId" value="${cargo.trackingId}"/>
41
+          </c:url>
42
+        <p><em>Cargo is misrouted - <a href="${selectUrl}">reroute this cargo</a></em></p>    
37 43
       </c:if>
38 44
       <table border="1">
39 45
         <caption>Itinerary</caption>

+ 3
- 2
dddsample/src/main/webapp/WEB-INF/jsp/pub/track.jsp Visa fil

@@ -36,6 +36,7 @@
36 36
     <div id="result">
37 37
     <h2>Cargo ${cargo.trackingId} is now: ${cargo.statusText}</h2>
38 38
     <p>Estimated time of arrival in ${cargo.destination}: ${cargo.eta}</p>
39
+    <p>${cargo.nextExpectedActivity}</p>
39 40
     <c:if test="${cargo.misdirected}">
40 41
       <p class="notify"><img src="${rc.contextPath}/images/error.png" alt="" />Cargo is misdirected</p>
41 42
     </c:if>
@@ -70,8 +71,8 @@
70 71
         <ul style="list-style-type: none;">
71 72
             <c:forEach items="${cargo.events}" var="leg">
72 73
             <li>
73
-                <p><img src="${rc.contextPath}/images/${leg.expected ? "tick" : "cross"}.png" alt=""/>
74
-                ${leg.description}</p>
74
+                <p><img style="vertical-align: top;" src="${rc.contextPath}/images/${leg.expected ? "tick" : "cross"}.png" alt=""/>
75
+                &nbsp;${leg.description}</p>
75 76
             </li>
76 77
             </c:forEach>
77 78
         </ul>

+ 13
- 8
dddsample/src/main/webapp/index.jsp Visa fil

@@ -8,12 +8,17 @@
8 8
     <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
9 9
     <title>DDDSample</title>
10 10
 </head>
11
-<body>
12
-<h1>Welcome to DDDSample</h1>
13
-
14
-<p>Public <a href="public/track">tracking</a> web interface</p>
15
-
16
-<p>Administrative <a href="admin/list">booking and routing</a> web interface</p>
17
-
11
+<body style="padding: 20px">
12
+<p><img src="images/web_logo.png"/></p>
13
+<p>Welcome to the <strong>DDDSample</strong> application.</p>
14
+<p>There are two web interfaces available:</p>
15
+<ul>
16
+<li>Public <a href="public/track">cargo tracking</a></li> 
17
+<li>Administration of <a href="admin/list">booking and routing</a>.</li>
18
+</ul>
19
+<p>The Incident Logging application, that is used to register handling events, is a stand-alone application and a separate download.</p>
20
+<p>Please visit the <a href="http://dddsample.sf.net">project website</a> for more information and a screencast demonstration of how the application works.</p>
21
+<p><i>This project is a joint effort by Eric Evans' company <a href="http://www.domainlanguage.com" class="externalLink">Domain Language</a>
22
+ and the Swedish software consulting company <a href="http://www.citerus.se" class="externalLink">Citerus</a>.</i></p>
18 23
 </body>
19
-</html>
24
+</html>

+ 8
- 8
dddsample/src/test/java/se/citerus/dddsample/scenario/CargoLifecycleScenarioTest.java Visa fil

@@ -106,7 +106,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
106 106
     assertEquals(RoutingStatus.NOT_ROUTED, cargo.routingStatus());
107 107
     assertFalse(cargo.isMisdirected());
108 108
     assertNull(cargo.estimatedTimeOfArrival());
109
-    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
109
+    assertNull(cargo.nextExpectedActivity());
110 110
 
111 111
     /* Use case 2: routing
112 112
 
@@ -152,7 +152,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
152 152
     assertEquals(HONGKONG, cargo.delivery().lastKnownLocation());
153 153
     assertEquals(ONBOARD_CARRIER, cargo.delivery().transportStatus());
154 154
     assertFalse(cargo.isMisdirected());
155
-    assertEquals(new HandlingActivity(UNLOAD, NEWYORK), cargo.nextExpectedActivity());
155
+    assertEquals(new HandlingActivity(UNLOAD, NEWYORK, CM003), cargo.nextExpectedActivity());
156 156
 
157 157
 
158 158
     /*
@@ -179,7 +179,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
179 179
     assertEquals(TOKYO, cargo.delivery().lastKnownLocation());
180 180
     assertEquals(IN_PORT, cargo.delivery().transportStatus());
181 181
     assertTrue(cargo.isMisdirected());
182
-    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
182
+    assertNull(cargo.nextExpectedActivity());
183 183
 
184 184
 
185 185
     // -- Cargo needs to be rerouted --
@@ -191,7 +191,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
191 191
 
192 192
     // The old itinerary does not satisfy the new specification
193 193
     assertEquals(RoutingStatus.MISROUTED, cargo.routingStatus());
194
-    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
194
+    assertNull(cargo.nextExpectedActivity());
195 195
 
196 196
     // Repeat procedure of selecting one out of a number of possible routes satisfying the route spec
197 197
     List<Itinerary> newItineraries = bookingService.requestPossibleRoutesForCargo(cargo.trackingId());
@@ -219,7 +219,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
219 219
     assertEquals(TOKYO, cargo.delivery().lastKnownLocation());
220 220
     assertEquals(ONBOARD_CARRIER, cargo.delivery().transportStatus());
221 221
     assertFalse(cargo.isMisdirected());
222
-    assertEquals(new HandlingActivity(UNLOAD, HAMBURG), cargo.nextExpectedActivity());
222
+    assertEquals(new HandlingActivity(UNLOAD, HAMBURG, CM003), cargo.nextExpectedActivity());
223 223
 
224 224
     // Unload in Hamburg
225 225
     handlingEventService.registerHandlingEvent(
@@ -231,7 +231,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
231 231
     assertEquals(HAMBURG, cargo.delivery().lastKnownLocation());
232 232
     assertEquals(IN_PORT, cargo.delivery().transportStatus());
233 233
     assertFalse(cargo.isMisdirected());
234
-    assertEquals(new HandlingActivity(LOAD, HAMBURG), cargo.nextExpectedActivity());
234
+    assertEquals(new HandlingActivity(LOAD, HAMBURG, CM005), cargo.nextExpectedActivity());
235 235
 
236 236
 
237 237
     // Load in Hamburg
@@ -244,7 +244,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
244 244
     assertEquals(HAMBURG, cargo.delivery().lastKnownLocation());
245 245
     assertEquals(ONBOARD_CARRIER, cargo.delivery().transportStatus());
246 246
     assertFalse(cargo.isMisdirected());
247
-    assertEquals(new HandlingActivity(UNLOAD, STOCKHOLM), cargo.nextExpectedActivity());
247
+    assertEquals(new HandlingActivity(UNLOAD, STOCKHOLM, CM005), cargo.nextExpectedActivity());
248 248
 
249 249
 
250 250
     // Unload in Stockholm
@@ -269,7 +269,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
269 269
     assertEquals(STOCKHOLM, cargo.delivery().lastKnownLocation());
270 270
     assertEquals(CLAIMED, cargo.delivery().transportStatus());
271 271
     assertFalse(cargo.isMisdirected());
272
-    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
272
+    assertNull(cargo.nextExpectedActivity());
273 273
   }
274 274
 
275 275
 

+ 4
- 3
dddsample/src/test/resources/handling_events.csv Visa fil

@@ -1,3 +1,4 @@
1
-2008-10-29 12:30:00.000	ZYX	0202	SESTO	LOAD
2
-2008-10-31 04:00:00.000	ZYX	V100	FIHEL	UNLOAD
3
-2008-10-31 08:12:00.000	ZYX	HELSINKI	UNLOAD
1
+2009-03-06 12:30	ABC123	0200T	USNYC	LOAD
2
+2009-03-08 04:00	ABC123	0200T	USDAL	UNLOAD
3
+2009-03-09 08:12	ABC123	0300A	USDAL	LOAD
4
+2009-03-12 19:25	ABC123	0300A	FIHEL	UNLOAD