Просмотр исходного кода

Implemented cargo.nextExpectedActivity using lifecycle scenario test.

peter_backlund 17 лет назад
Родитель
Сommit
4fc923eb91

+ 54
- 2
dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/Cargo.java Просмотреть файл

@@ -4,11 +4,13 @@ import org.apache.commons.lang.Validate;
4 4
 import se.citerus.dddsample.domain.model.Entity;
5 5
 import static se.citerus.dddsample.domain.model.cargo.RoutingStatus.*;
6 6
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
7
+import static se.citerus.dddsample.domain.model.handling.HandlingEvent.Type.*;
7 8
 import se.citerus.dddsample.domain.model.location.Location;
8 9
 import se.citerus.dddsample.domain.shared.DomainObjectUtils;
9 10
 
10 11
 import java.util.Collections;
11 12
 import java.util.Date;
13
+import java.util.Iterator;
12 14
 import java.util.List;
13 15
 
14 16
 /**
@@ -158,7 +160,7 @@ public class Cargo implements Entity<Cargo> {
158 160
   public boolean isUnloadedAtDestination() {
159 161
     final HandlingEvent lastEvent = delivery.lastEvent();
160 162
     return lastEvent != null &&
161
-      HandlingEvent.Type.UNLOAD.sameValueAs(lastEvent.type()) &&
163
+      UNLOAD.sameValueAs(lastEvent.type()) &&
162 164
       routeSpecification.destination().sameIdentityAs(lastEvent.location());
163 165
   }
164 166
 
@@ -166,7 +168,57 @@ public class Cargo implements Entity<Cargo> {
166 168
    * @return estimated time of arrival
167 169
    */
168 170
   public Date estimatedTimeOfArrival() {
169
-    return new Date(eta.getTime());
171
+    if (eta != ETA_UNKOWN) {
172
+      return new Date(eta.getTime());
173
+    } else {
174
+      return ETA_UNKOWN;
175
+    }
176
+  }
177
+
178
+  /**
179
+   * @return the next expected activity
180
+   */
181
+  public HandlingActivity nextExpectedActivity() {
182
+    if (!onTrack()) return HandlingActivity.NONE;
183
+
184
+    final HandlingEvent lastEvent = delivery().lastEvent();
185
+
186
+    if (lastEvent == null) return new HandlingActivity(RECEIVE, origin());
187
+
188
+    switch (lastEvent.type()) {
189
+
190
+      case LOAD:
191
+        for (Leg leg : itinerary().legs()) {
192
+          if (leg.loadLocation().sameIdentityAs(lastEvent.location())) {
193
+            return new HandlingActivity(UNLOAD, leg.unloadLocation());
194
+          }
195
+        }
196
+
197
+        return HandlingActivity.NONE;
198
+
199
+      case UNLOAD:
200
+        for (Iterator<Leg> it = itinerary().legs().iterator(); it.hasNext();) {
201
+          final Leg leg = it.next();
202
+          if (leg.unloadLocation().sameIdentityAs(lastEvent.location())) {
203
+            if (it.hasNext()) {
204
+              final Leg nextLeg = it.next();
205
+              return new HandlingActivity(LOAD, nextLeg.loadLocation());
206
+            } else {
207
+              return new HandlingActivity(CLAIM, leg.unloadLocation());
208
+            }
209
+          }
210
+        }
211
+
212
+        return HandlingActivity.NONE;
213
+
214
+      case RECEIVE:
215
+        final Leg firstLeg = itinerary().legs().iterator().next();
216
+        return new HandlingActivity(LOAD, firstLeg.loadLocation());
217
+
218
+      case CLAIM:
219
+      default:
220
+        return HandlingActivity.NONE;
221
+    }
170 222
   }
171 223
 
172 224
   /**

+ 74
- 0
dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/HandlingActivity.java Просмотреть файл

@@ -0,0 +1,74 @@
1
+package se.citerus.dddsample.domain.model.cargo;
2
+
3
+import org.apache.commons.lang.Validate;
4
+import org.apache.commons.lang.builder.EqualsBuilder;
5
+import org.apache.commons.lang.builder.HashCodeBuilder;
6
+import se.citerus.dddsample.domain.model.ValueObject;
7
+import se.citerus.dddsample.domain.model.handling.HandlingEvent;
8
+import se.citerus.dddsample.domain.model.location.Location;
9
+
10
+/**
11
+ * A handling activity represents how and where a cargo can be handled,
12
+ * and can be used to express predictions about what is expected to
13
+ * happen to a cargo in the future.
14
+ *
15
+ */
16
+public class HandlingActivity implements ValueObject<HandlingActivity> {
17
+
18
+  private HandlingEvent.Type type;
19
+  private Location location;
20
+  public static final HandlingActivity NONE = createNoneInstance();
21
+
22
+  HandlingActivity() {
23
+  }
24
+
25
+  private static HandlingActivity createNoneInstance() {
26
+    HandlingActivity none = new HandlingActivity();
27
+    none.location = Location.UNKNOWN;
28
+    return none;
29
+  }
30
+
31
+  public HandlingActivity(final HandlingEvent.Type type, final Location location) {
32
+    Validate.notNull(type, "Handling event type is required");
33
+    Validate.notNull(location, "Location is required");
34
+
35
+    this.type = type;
36
+    this.location = location;
37
+  }
38
+
39
+
40
+  @Override
41
+  public boolean sameValueAs(final HandlingActivity other) {
42
+    return other != null && new EqualsBuilder().
43
+      append(this.type, other.type).
44
+      append(this.location, other.location).
45
+      isEquals();
46
+  }
47
+
48
+  @Override
49
+  public int hashCode() {
50
+    return new HashCodeBuilder().
51
+      append(this.type).
52
+      append(this.location).
53
+      toHashCode();
54
+  }
55
+
56
+  @Override
57
+  public boolean equals(final Object obj) {
58
+    if (obj == this) return true;
59
+    if (obj == null) return false;
60
+    if (obj.getClass() != this.getClass()) return false;
61
+
62
+    HandlingActivity other = (HandlingActivity) obj;
63
+
64
+    return sameValueAs(other);
65
+  }
66
+
67
+  @Override
68
+  public String toString() {
69
+    if (this == NONE) return "No activity";
70
+
71
+    return type + " in " + location;
72
+  }
73
+
74
+}

+ 48
- 31
dddsample/src/test/java/se/citerus/dddsample/scenario/CargoLifecycleScenarioTest.java Просмотреть файл

@@ -1,7 +1,10 @@
1 1
 package se.citerus.dddsample.scenario;
2 2
 
3 3
 import junit.framework.TestCase;
4
-import se.citerus.dddsample.application.*;
4
+import se.citerus.dddsample.application.ApplicationEvents;
5
+import se.citerus.dddsample.application.BookingService;
6
+import se.citerus.dddsample.application.CargoInspectionService;
7
+import se.citerus.dddsample.application.HandlingEventService;
5 8
 import se.citerus.dddsample.application.impl.BookingServiceImpl;
6 9
 import se.citerus.dddsample.application.impl.CargoInspectionServiceImpl;
7 10
 import se.citerus.dddsample.application.impl.HandlingEventServiceImpl;
@@ -102,7 +105,8 @@ public class CargoLifecycleScenarioTest extends TestCase {
102 105
     assertEquals(NOT_RECEIVED, cargo.delivery().transportStatus());
103 106
     assertEquals(RoutingStatus.NOT_ROUTED, cargo.routingStatus());
104 107
     assertFalse(cargo.isMisdirected());
105
-
108
+    assertNull(cargo.estimatedTimeOfArrival());
109
+    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
106 110
 
107 111
     /* Use case 2: routing
108 112
 
@@ -117,6 +121,8 @@ public class CargoLifecycleScenarioTest extends TestCase {
117 121
     cargo.assignToRoute(itinerary);
118 122
 
119 123
     assertEquals(RoutingStatus.ROUTED, cargo.routingStatus());
124
+    assertNotNull(cargo.estimatedTimeOfArrival());
125
+    assertEquals(new HandlingActivity(RECEIVE, HONGKONG), cargo.nextExpectedActivity());
120 126
 
121 127
     /*
122 128
       Use case 3: handling
@@ -132,22 +138,22 @@ public class CargoLifecycleScenarioTest extends TestCase {
132 138
 
133 139
       Handling begins: cargo is received in Hongkong.
134 140
       */
135
-    HandlingEventRegistrationAttempt attempt1 = new HandlingEventRegistrationAttempt(
136
-      new Date(), new Date(100), trackingId, null, RECEIVE, HONGKONG.unLocode()
141
+    handlingEventService.registerHandlingEvent(
142
+      new Date(100), trackingId, null, HONGKONG.unLocode(), RECEIVE
137 143
     );
138
-    handlingEventService.registerHandlingEvent(attempt1.getCompletionTime(), attempt1.getTrackingId(), attempt1.getVoyageNumber(), attempt1.getUnLocode(), attempt1.getType());
139 144
 
140 145
     // Next event: Load onto voyage CM003 in Hongkong
141
-    final HandlingEventRegistrationAttempt attempt = new HandlingEventRegistrationAttempt(
142
-      new Date(), new Date(200), trackingId, CM003.voyageNumber(), LOAD, HONGKONG.unLocode()
146
+    handlingEventService.registerHandlingEvent(
147
+      new Date(200), trackingId, CM003.voyageNumber(), HONGKONG.unLocode(), LOAD
143 148
     );
144
-    handlingEventService.registerHandlingEvent(attempt.getCompletionTime(), attempt.getTrackingId(), attempt.getVoyageNumber(), attempt.getUnLocode(), attempt.getType());
145 149
 
146 150
     // Check current state - should be ok
147 151
     assertEquals(CM003, cargo.delivery().currentVoyage());
148 152
     assertEquals(HONGKONG, cargo.delivery().lastKnownLocation());
149 153
     assertEquals(ONBOARD_CARRIER, cargo.delivery().transportStatus());
150 154
     assertFalse(cargo.isMisdirected());
155
+    assertEquals(new HandlingActivity(UNLOAD, NEWYORK), cargo.nextExpectedActivity());
156
+
151 157
 
152 158
     /*
153 159
       Here's an attempt to register a handling event that's not valid
@@ -156,25 +162,24 @@ public class CargoLifecycleScenarioTest extends TestCase {
156 162
 
157 163
       This attempt will be rejected and will not affet the cargo delivery in any way.
158 164
      */
159
-    VoyageNumber noSuchVoyageNumber = new VoyageNumber("XX000");
160
-    UnLocode noSuchUnLocode = new UnLocode("ZZZZZ");
161
-    HandlingEventRegistrationAttempt failingAttempt = new HandlingEventRegistrationAttempt(
162
-      new Date(), new Date(300), trackingId, noSuchVoyageNumber, LOAD, noSuchUnLocode
165
+    final VoyageNumber noSuchVoyageNumber = new VoyageNumber("XX000");
166
+    final UnLocode noSuchUnLocode = new UnLocode("ZZZZZ");
167
+    handlingEventService.registerHandlingEvent(
168
+      new Date(300), trackingId, noSuchVoyageNumber, noSuchUnLocode, LOAD
163 169
     );
164
-    handlingEventService.registerHandlingEvent(failingAttempt.getCompletionTime(), failingAttempt.getTrackingId(), failingAttempt.getVoyageNumber(), failingAttempt.getUnLocode(), failingAttempt.getType());
165 170
 
166 171
 
167 172
     // Cargo is now (incorrectly) unloaded in Tokyo
168
-    final HandlingEventRegistrationAttempt attempt7 = new HandlingEventRegistrationAttempt(
169
-      new Date(), new Date(400), trackingId, CM003.voyageNumber(), UNLOAD, TOKYO.unLocode()
173
+    handlingEventService.registerHandlingEvent(
174
+      new Date(400), trackingId, CM003.voyageNumber(), TOKYO.unLocode(), UNLOAD
170 175
     );
171
-    handlingEventService.registerHandlingEvent(attempt7.getCompletionTime(), attempt7.getTrackingId(), attempt7.getVoyageNumber(), attempt7.getUnLocode(), attempt7.getType());
172 176
 
173 177
     // Check current state - cargo is misdirected!
174 178
     assertEquals(NONE, cargo.delivery().currentVoyage());
175 179
     assertEquals(TOKYO, cargo.delivery().lastKnownLocation());
176 180
     assertEquals(IN_PORT, cargo.delivery().transportStatus());
177 181
     assertTrue(cargo.isMisdirected());
182
+    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
178 183
 
179 184
 
180 185
     // -- Cargo needs to be rerouted --
@@ -186,6 +191,7 @@ public class CargoLifecycleScenarioTest extends TestCase {
186 191
 
187 192
     // The old itinerary does not satisfy the new specification
188 193
     assertEquals(RoutingStatus.MISROUTED, cargo.routingStatus());
194
+    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
189 195
 
190 196
     // Repeat procedure of selecting one out of a number of possible routes satisfying the route spec
191 197
     List<Itinerary> newItineraries = bookingService.requestPossibleRoutesForCargo(cargo.trackingId());
@@ -195,71 +201,82 @@ public class CargoLifecycleScenarioTest extends TestCase {
195 201
     // New itinerary should satisfy new route
196 202
     assertEquals(RoutingStatus.ROUTED, cargo.routingStatus());
197 203
 
204
+    // TODO we can't handle the face that after a reroute, the cargo isn't misdirected anymore
205
+    //assertFalse(cargo.isMisdirected());
206
+    //assertEquals(new HandlingActivity(LOAD, TOKYO), cargo.nextExpectedActivity());
207
+
198 208
 
199 209
     // -- Cargo has been rerouted, shipping continues --
200 210
 
201 211
 
202 212
     // Load in Tokyo
203
-    HandlingEventRegistrationAttempt attempt2 = new HandlingEventRegistrationAttempt(
204
-      new Date(), new Date(500), trackingId, CM003.voyageNumber(), LOAD, TOKYO.unLocode()
213
+    handlingEventService.registerHandlingEvent(
214
+      new Date(500), trackingId, CM003.voyageNumber(), TOKYO.unLocode(), LOAD
205 215
     );
206
-    handlingEventService.registerHandlingEvent(attempt2.getCompletionTime(), attempt2.getTrackingId(), attempt2.getVoyageNumber(), attempt2.getUnLocode(), attempt2.getType());
207 216
 
208 217
     // Check current state - should be ok
209 218
     assertEquals(CM003, cargo.delivery().currentVoyage());
210 219
     assertEquals(TOKYO, cargo.delivery().lastKnownLocation());
211 220
     assertEquals(ONBOARD_CARRIER, cargo.delivery().transportStatus());
212 221
     assertFalse(cargo.isMisdirected());
222
+    assertEquals(new HandlingActivity(UNLOAD, HAMBURG), cargo.nextExpectedActivity());
213 223
 
214 224
     // Unload in Hamburg
215
-    HandlingEventRegistrationAttempt attempt3 = new HandlingEventRegistrationAttempt(
216
-      new Date(), new Date(600), trackingId, CM003.voyageNumber(), UNLOAD, HAMBURG.unLocode()
225
+    handlingEventService.registerHandlingEvent(
226
+      new Date(600), trackingId, CM003.voyageNumber(), HAMBURG.unLocode(), UNLOAD
217 227
     );
218
-    handlingEventService.registerHandlingEvent(attempt3.getCompletionTime(), attempt3.getTrackingId(), attempt3.getVoyageNumber(), attempt3.getUnLocode(), attempt3.getType());
219 228
 
220 229
     // Check current state - should be ok
221 230
     assertEquals(NONE, cargo.delivery().currentVoyage());
222 231
     assertEquals(HAMBURG, cargo.delivery().lastKnownLocation());
223 232
     assertEquals(IN_PORT, cargo.delivery().transportStatus());
224 233
     assertFalse(cargo.isMisdirected());
234
+    assertEquals(new HandlingActivity(LOAD, HAMBURG), cargo.nextExpectedActivity());
235
+
225 236
 
226 237
     // Load in Hamburg
227
-    HandlingEventRegistrationAttempt attempt4 = new HandlingEventRegistrationAttempt(
228
-      new Date(), new Date(700), trackingId, CM005.voyageNumber(), LOAD, HAMBURG.unLocode()
238
+    handlingEventService.registerHandlingEvent(
239
+      new Date(700), trackingId, CM005.voyageNumber(), HAMBURG.unLocode(), LOAD
229 240
     );
230
-    handlingEventService.registerHandlingEvent(attempt4.getCompletionTime(), attempt4.getTrackingId(), attempt4.getVoyageNumber(), attempt4.getUnLocode(), attempt4.getType());
231 241
 
232 242
     // Check current state - should be ok
233 243
     assertEquals(CM005, cargo.delivery().currentVoyage());
234 244
     assertEquals(HAMBURG, cargo.delivery().lastKnownLocation());
235 245
     assertEquals(ONBOARD_CARRIER, cargo.delivery().transportStatus());
236 246
     assertFalse(cargo.isMisdirected());
247
+    assertEquals(new HandlingActivity(UNLOAD, STOCKHOLM), cargo.nextExpectedActivity());
248
+
237 249
 
238 250
     // Unload in Stockholm
239
-    HandlingEventRegistrationAttempt attempt5 = new HandlingEventRegistrationAttempt(
240
-      new Date(), new Date(800), trackingId, CM005.voyageNumber(), UNLOAD, STOCKHOLM.unLocode()
251
+    handlingEventService.registerHandlingEvent(
252
+      new Date(800), trackingId, CM005.voyageNumber(), STOCKHOLM.unLocode(), UNLOAD
241 253
     );
242
-    handlingEventService.registerHandlingEvent(attempt5.getCompletionTime(), attempt5.getTrackingId(), attempt5.getVoyageNumber(), attempt5.getUnLocode(), attempt5.getType());
243 254
 
244 255
     // Check current state - should be ok
245 256
     assertEquals(NONE, cargo.delivery().currentVoyage());
246 257
     assertEquals(STOCKHOLM, cargo.delivery().lastKnownLocation());
247 258
     assertEquals(IN_PORT, cargo.delivery().transportStatus());
248 259
     assertFalse(cargo.isMisdirected());
260
+    assertEquals(new HandlingActivity(CLAIM, STOCKHOLM), cargo.nextExpectedActivity());
249 261
 
250 262
     // Finally, cargo is claimed in Stockholm. This ends the cargo lifecycle from our perspective.
251
-    HandlingEventRegistrationAttempt attempt6 = new HandlingEventRegistrationAttempt(
252
-      new Date(), new Date(900), trackingId, null, CLAIM, STOCKHOLM.unLocode()
263
+    handlingEventService.registerHandlingEvent(
264
+      new Date(900), trackingId, null, STOCKHOLM.unLocode(), CLAIM
253 265
     );
254
-    handlingEventService.registerHandlingEvent(attempt6.getCompletionTime(), attempt6.getTrackingId(), attempt6.getVoyageNumber(), attempt6.getUnLocode(), attempt6.getType());
255 266
 
256 267
     // Check current state - should be ok
257 268
     assertEquals(NONE, cargo.delivery().currentVoyage());
258 269
     assertEquals(STOCKHOLM, cargo.delivery().lastKnownLocation());
259 270
     assertEquals(CLAIMED, cargo.delivery().transportStatus());
260 271
     assertFalse(cargo.isMisdirected());
272
+    assertEquals(HandlingActivity.NONE, cargo.nextExpectedActivity());
261 273
   }
262 274
 
275
+
276
+
277
+
278
+
279
+
263 280
   /*
264 281
   * Utility stubs below.
265 282
   */