Преглед на файлове

Inlined Projections class. Added ETA method to Itinerary.

peter_backlund преди 17 години
родител
ревизия
20ae393bdf

+ 70
- 3
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Cargo.java Целия файл

@@ -2,6 +2,7 @@ package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4 4
 import se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent;
5
+import static se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent.Type.*;
5 6
 import se.citerus.dddsample.tracking.core.domain.model.location.CustomsZone;
6 7
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7 8
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
@@ -9,6 +10,7 @@ import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
9 10
 import se.citerus.dddsample.tracking.core.domain.patterns.entity.EntitySupport;
10 11
 
11 12
 import java.util.Date;
13
+import java.util.Iterator;
12 14
 
13 15
 /**
14 16
  * A Cargo. This is the central class in the domain model,
@@ -93,14 +95,79 @@ public class Cargo extends EntitySupport<Cargo,TrackingId> {
93 95
    * @return Estimated time of arrival.
94 96
    */
95 97
   public Date estimatedTimeOfArrival() {
96
-    return Projections.estimatedTimeOfArrival(delivery, itinerary, routeSpecification);
98
+    if (onTrack()) {
99
+      return itinerary.estimatedTimeOfArrival();
100
+    } else {
101
+      return null;
102
+    }
97 103
   }
98 104
 
99 105
   /**
100 106
    * @return Next expected activity.
101 107
    */
102 108
   public HandlingActivity nextExpectedActivity() {
103
-    return Projections.nextExpectedActivity(delivery, itinerary, routeSpecification);
109
+    /*
110
+     TODO Capture:
111
+
112
+     Cargo is misdirected but has been rerouted. Next expected acivity should be to load according to first leg
113
+     of new itinerary.
114
+
115
+     and
116
+
117
+     even if a cargo is misdirected, we expect it to be unloaded at next stop.
118
+
119
+    */
120
+    if (!onTrack()) {
121
+      return null;
122
+    }
123
+
124
+    final Location lastKnownLocation = delivery.lastKnownLocation();
125
+
126
+    switch (delivery.transportStatus()) {
127
+      case IN_PORT:
128
+        if (itinerary.firstLeg().loadLocation().sameAs(lastKnownLocation)) {
129
+          final Leg firstLeg = itinerary.firstLeg();
130
+          return new HandlingActivity(LOAD, firstLeg.loadLocation(), firstLeg.voyage());
131
+        } else {
132
+          for (Iterator<Leg> it = itinerary.legs().iterator(); it.hasNext();) {
133
+            final Leg leg = it.next();
134
+            if (leg.unloadLocation().sameAs(lastKnownLocation)) {
135
+              if (it.hasNext()) {
136
+                final Leg nextLeg = it.next();
137
+                return new HandlingActivity(LOAD, nextLeg.loadLocation(), nextLeg.voyage());
138
+              } else {
139
+                return new HandlingActivity(CLAIM, leg.unloadLocation());
140
+              }
141
+            }
142
+          }
143
+
144
+          return null;
145
+        }
146
+
147
+      case NOT_RECEIVED:
148
+        final Leg leg = itinerary.firstLeg();
149
+        return new HandlingActivity(RECEIVE, leg.loadLocation());
150
+
151
+      case ONBOARD_CARRIER:
152
+        for (Leg leg1 : itinerary.legs()) {
153
+          if (leg1.loadLocation().sameAs(lastKnownLocation)) {
154
+            return new HandlingActivity(UNLOAD, leg1.unloadLocation(), leg1.voyage());
155
+          }
156
+        }
157
+
158
+        return null;
159
+
160
+      case CLAIMED:
161
+      default:
162
+        return null;
163
+    }
164
+  }
165
+
166
+  /**
167
+   * @return True if the cargo is assigned to a route and is following that route.
168
+   */
169
+  public boolean onTrack() {
170
+    return delivery.onTrack(itinerary, routeSpecification);
104 171
   }
105 172
 
106 173
   /**
@@ -200,7 +267,7 @@ public class Cargo extends EntitySupport<Cargo,TrackingId> {
200 267
   public void handled(final HandlingActivity handlingActivity) {
201 268
     Validate.notNull(handlingActivity, "Handling activity is required");
202 269
 
203
-    // Delivery and Projections are value object, so they are replaced with new or derived ones
270
+    // Delivery is a value object, so it's replaced with a new one
204 271
     this.delivery = Delivery.whenHandled(handlingActivity);
205 272
   }
206 273
 

+ 7
- 1
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Itinerary.java Целия файл

@@ -196,6 +196,13 @@ public class Itinerary extends ValueObjectSupport<Itinerary> {
196 196
   }
197 197
 
198 198
   /**
199
+   * @return Estimated time of arrival
200
+   */
201
+  public Date estimatedTimeOfArrival() {
202
+    return new Date(finalUnloadTime().getTime());
203
+  }
204
+
205
+  /**
199 206
    * @param location a location
200 207
    * @return Unload time at this location, or null if the location isn't on this itinerary.
201 208
    */
@@ -217,5 +224,4 @@ public class Itinerary extends ValueObjectSupport<Itinerary> {
217 224
     // Needed by Hibernate
218 225
     legs = null;
219 226
   }
220
-
221 227
 }

+ 0
- 119
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Projections.java Целия файл

@@ -1,119 +0,0 @@
1
-package se.citerus.dddsample.tracking.core.domain.model.cargo;
2
-
3
-import static se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent.Type.*;
4
-import se.citerus.dddsample.tracking.core.domain.model.location.Location;
5
-import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
6
-import se.citerus.dddsample.tracking.core.domain.patterns.valueobject.ValueObjectSupport;
7
-
8
-import java.util.Date;
9
-import java.util.Iterator;
10
-
11
-/**
12
- * These are projections about the future handling of the cargo,
13
- * when it will arrive and what the next step is.
14
- * <p/>
15
- * It is updated on routing changes as well as handling.
16
- */
17
-class Projections extends ValueObjectSupport<Projections> {
18
-
19
-  private static final Date ETA_UNKOWN = null;
20
-  private static final HandlingActivity NO_ACTIVITY = null;
21
-
22
-  /**
23
-   * @param delivery delivery
24
-   * @param itinerary itinerary
25
-   * @param routeSpecification routeSpecification
26
-   * @return Estimated time of arrival, or null if not known.
27
-   */
28
-  static Date estimatedTimeOfArrival(final Delivery delivery, final Itinerary itinerary, final RouteSpecification routeSpecification) {
29
-    if (delivery.onTrack(itinerary, routeSpecification)) {
30
-      return new Date(itinerary.finalUnloadTime().getTime());
31
-    } else {
32
-      return ETA_UNKOWN;
33
-    }
34
-  }
35
-
36
-  /**
37
-   * @param delivery delivery
38
-   * @param itinerary itinerary
39
-   * @param routeSpecification routeSpecification 
40
-   * @return The next expected handling activity.
41
-   */
42
-  static HandlingActivity nextExpectedActivity(final Delivery delivery, final Itinerary itinerary, final RouteSpecification routeSpecification) {
43
-    /*
44
-     TODO Capture:
45
-
46
-     Cargo is misdirected but has been rerouted. Next expected acivity should be to load according to first leg
47
-     of new itinerary.
48
-
49
-     and
50
-
51
-     even if a cargo is misdirected, we expect it to be unloaded at next stop.
52
-
53
-    */
54
-    if (!delivery.onTrack(itinerary, routeSpecification)) {
55
-      return NO_ACTIVITY;
56
-    }
57
-
58
-    final Location lastKnownLocation = delivery.lastKnownLocation();
59
-    switch (delivery.transportStatus()) {
60
-      case IN_PORT:
61
-        if (itinerary.firstLeg().loadLocation().sameAs(lastKnownLocation)) {
62
-          return loadInFirstLocation(itinerary);
63
-        } else {
64
-          return loadOrClaimInNextLocation(itinerary, lastKnownLocation);
65
-        }
66
-
67
-      case NOT_RECEIVED:
68
-        return receiveInFirstLocation(itinerary);
69
-
70
-      case ONBOARD_CARRIER:
71
-        return unloadInNextLocation(itinerary, lastKnownLocation);
72
-
73
-      case CLAIMED:
74
-      default:
75
-        return NO_ACTIVITY;
76
-    }
77
-  }
78
-
79
-  private static HandlingActivity receiveInFirstLocation(final Itinerary itinerary) {
80
-    final Leg leg = itinerary.firstLeg();
81
-    return new HandlingActivity(RECEIVE, leg.loadLocation());
82
-  }
83
-
84
-  private static HandlingActivity loadInFirstLocation(final Itinerary itinerary) {
85
-    final Leg leg = itinerary.firstLeg();
86
-    return new HandlingActivity(LOAD, leg.loadLocation(), leg.voyage());
87
-  }
88
-
89
-  private static HandlingActivity loadOrClaimInNextLocation(final Itinerary itinerary, final Location activityLocation) {
90
-    for (final Iterator<Leg> it = itinerary.legs().iterator(); it.hasNext();) {
91
-      final Leg leg = it.next();
92
-      if (leg.unloadLocation().sameAs(activityLocation)) {
93
-        if (it.hasNext()) {
94
-          final Leg nextLeg = it.next();
95
-          return new HandlingActivity(LOAD, nextLeg.loadLocation(), nextLeg.voyage());
96
-        } else {
97
-          return new HandlingActivity(CLAIM, leg.unloadLocation());
98
-        }
99
-      }
100
-    }
101
-
102
-    return NO_ACTIVITY;
103
-  }
104
-
105
-  private static HandlingActivity unloadInNextLocation(final Itinerary itinerary, final Location activityLocation) {
106
-    for (final Leg leg : itinerary.legs()) {
107
-      if (leg.loadLocation().sameAs(activityLocation)) {
108
-        return new HandlingActivity(UNLOAD, leg.unloadLocation(), leg.voyage());
109
-      }
110
-    }
111
-
112
-    return NO_ACTIVITY;
113
-  }
114
-
115
-  Projections() {
116
-    // Needed by Hibernate
117
-  }
118
-
119
-}

+ 0
- 14
dddsample/tracking/core/src/main/resources/se/citerus/dddsample/tracking/core/infrastructure/persistence/hibernate/Cargo.hbm.xml Целия файл

@@ -15,20 +15,6 @@
15 15
       <property name="id" column="tracking_id"/>
16 16
     </component>
17 17
 
18
-    <component name="projections">
19
-      <property name="estimatedTimeOfArrival" column="eta" not-null="false"/>
20
-      <component name="nextExpectedActivity" update="true">
21
-        <many-to-one name="location" column="next_expected_location_id" foreign-key="next_expected_location_fk" cascade="none"/>
22
-        <property name="type" column="next_expected_handling_event_type">
23
-          <type name="org.hibernate.type.EnumType">
24
-            <param name="enumClass">se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent$Type</param>
25
-            <param name="type">12</param><!-- 12 is java.sql.Types.VARCHAR -->
26
-          </type>
27
-        </property>
28
-        <many-to-one name="voyage" column="next_expected_voyage_id" foreign-key="next_expected_voyage_fk" cascade="none"/>
29
-      </component>
30
-    </component>
31
-
32 18
     <component name="delivery" lazy="true">
33 19
       <property name="calculatedAt" column="calculated_at" not-null="true"/>
34 20
       <component name="mostRecentHandlingActivity">

+ 1
- 30
dddsample/tracking/core/src/test/java/se/citerus/dddsample/tracking/core/domain/model/cargo/DeliveryTest.java Целия файл

@@ -17,7 +17,6 @@ import java.util.Date;
17 17
 public class DeliveryTest extends TestCase {
18 18
 
19 19
   Delivery delivery;
20
-  Projections projections;
21 20
   Itinerary itinerary;
22 21
   RouteSpecification routeSpecification;
23 22
 
@@ -30,7 +29,6 @@ public class DeliveryTest extends TestCase {
30 29
       Leg.deriveLeg(DALLAS_TO_HELSINKI, DALLAS, STOCKHOLM)
31 30
     );
32 31
     delivery = Delivery.initial();
33
-    projections = new Projections(delivery, itinerary, routeSpecification);
34 32
     Thread.sleep(1);
35 33
   }
36 34
 
@@ -42,9 +40,6 @@ public class DeliveryTest extends TestCase {
42 40
     assertEquals(Location.UNKNOWN, delivery.lastKnownLocation());
43 41
     assertEquals(NOT_RECEIVED, delivery.transportStatus());
44 42
     assertTrue(delivery.calculatedAt().before(new Date()));
45
-
46
-    assertEquals(new HandlingActivity(RECEIVE, HANGZOU), projections.nextExpectedActivity());
47
-    assertEquals(DALLAS_TO_HELSINKI.schedule().arrivalTimeAt(STOCKHOLM), projections.estimatedTimeOfArrival());
48 43
   }
49 44
 
50 45
   public void testUpdateOnHandlingHappyPath() {
@@ -52,7 +47,6 @@ public class DeliveryTest extends TestCase {
52 47
 
53 48
     HandlingActivity handlingActivity = new HandlingActivity(RECEIVE, HANGZOU);
54 49
     Delivery newDelivery = Delivery.whenHandled(handlingActivity);
55
-    Projections newProjections = new Projections(newDelivery, itinerary, routeSpecification);
56 50
 
57 51
     // Changed on handling
58 52
     assertEquals(Voyage.NONE, newDelivery.currentVoyage());
@@ -60,13 +54,11 @@ public class DeliveryTest extends TestCase {
60 54
     assertEquals(IN_PORT, newDelivery.transportStatus());
61 55
 
62 56
     // Changed on handling and/or (re-)routing
63
-    assertEquals(new HandlingActivity(LOAD, HANGZOU, HONGKONG_TO_NEW_YORK), newProjections.nextExpectedActivity());
64 57
     assertFalse(newDelivery.isMisdirected(itinerary, routeSpecification));
65 58
     assertFalse(newDelivery.isUnloadedAtDestination(routeSpecification));
66 59
 
67 60
     // Changed on (re-)routing
68 61
     assertEquals(ROUTED, newDelivery.routingStatus(itinerary, routeSpecification));
69
-    assertEquals(DALLAS_TO_HELSINKI.schedule().arrivalTimeAt(STOCKHOLM), newProjections.estimatedTimeOfArrival());
70 62
 
71 63
     // Updated on every calculation
72 64
     assertTrue(delivery.calculatedAt().before(newDelivery.calculatedAt()));
@@ -75,18 +67,15 @@ public class DeliveryTest extends TestCase {
75 67
 
76 68
     handlingActivity = new HandlingActivity(LOAD, HANGZOU, HONGKONG_TO_NEW_YORK);
77 69
     newDelivery = Delivery.whenHandled(handlingActivity);
78
-    newProjections = new Projections(newDelivery, itinerary, routeSpecification);
79 70
 
80 71
     assertEquals(HONGKONG_TO_NEW_YORK, newDelivery.currentVoyage());
81 72
     assertEquals(HANGZOU, newDelivery.lastKnownLocation());
82 73
     assertEquals(ONBOARD_CARRIER, newDelivery.transportStatus());
83 74
 
84
-    assertEquals(new HandlingActivity(UNLOAD, NEWYORK, HONGKONG_TO_NEW_YORK), newProjections.nextExpectedActivity());
85 75
     assertFalse(newDelivery.isMisdirected(itinerary, routeSpecification));
86 76
     assertFalse(newDelivery.isUnloadedAtDestination(routeSpecification));
87 77
 
88 78
     assertEquals(ROUTED, newDelivery.routingStatus(itinerary, routeSpecification));
89
-    assertEquals(DALLAS_TO_HELSINKI.schedule().arrivalTimeAt(STOCKHOLM), newProjections.estimatedTimeOfArrival());
90 79
 
91 80
     assertTrue(delivery.calculatedAt().before(newDelivery.calculatedAt()));
92 81
 
@@ -96,18 +85,15 @@ public class DeliveryTest extends TestCase {
96 85
 
97 86
     handlingActivity = new HandlingActivity(UNLOAD, STOCKHOLM, DALLAS_TO_HELSINKI);
98 87
     newDelivery = Delivery.whenHandled(handlingActivity);
99
-    newProjections = new Projections(newDelivery, itinerary, routeSpecification);
100 88
 
101 89
     assertEquals(Voyage.NONE, newDelivery.currentVoyage());
102 90
     assertEquals(STOCKHOLM, newDelivery.lastKnownLocation());
103 91
     assertEquals(IN_PORT, newDelivery.transportStatus());
104 92
 
105
-    assertEquals(new HandlingActivity(CLAIM, STOCKHOLM), newProjections.nextExpectedActivity());
106 93
     assertFalse(newDelivery.isMisdirected(itinerary, routeSpecification));
107 94
     assertTrue(newDelivery.isUnloadedAtDestination(routeSpecification));
108 95
 
109 96
     assertEquals(ROUTED, newDelivery.routingStatus(itinerary, routeSpecification));
110
-    assertEquals(DALLAS_TO_HELSINKI.schedule().arrivalTimeAt(STOCKHOLM), newProjections.estimatedTimeOfArrival());
111 97
 
112 98
     assertTrue(delivery.calculatedAt().before(newDelivery.calculatedAt()));
113 99
 
@@ -115,18 +101,15 @@ public class DeliveryTest extends TestCase {
115 101
 
116 102
     handlingActivity = new HandlingActivity(CLAIM, STOCKHOLM);
117 103
     newDelivery = Delivery.whenHandled(handlingActivity);
118
-    newProjections = new Projections(newDelivery, itinerary, routeSpecification);
119 104
 
120 105
     assertEquals(Voyage.NONE, newDelivery.currentVoyage());
121 106
     assertEquals(STOCKHOLM, newDelivery.lastKnownLocation());
122 107
     assertEquals(CLAIMED, newDelivery.transportStatus());
123 108
 
124
-    assertNull(newProjections.nextExpectedActivity());
125 109
     assertFalse(newDelivery.isMisdirected(itinerary, routeSpecification));
126 110
     assertTrue(newDelivery.isUnloadedAtDestination(routeSpecification));
127 111
 
128 112
     assertEquals(ROUTED, newDelivery.routingStatus(itinerary, routeSpecification));
129
-    assertEquals(DALLAS_TO_HELSINKI.schedule().arrivalTimeAt(STOCKHOLM), newProjections.estimatedTimeOfArrival());
130 113
 
131 114
     assertTrue(delivery.calculatedAt().before(newDelivery.calculatedAt()));
132 115
   }
@@ -135,47 +118,35 @@ public class DeliveryTest extends TestCase {
135 118
     // Unload in Hamburg, which is the wrong location
136 119
     HandlingActivity handlingActivity = new HandlingActivity(UNLOAD, HAMBURG, DALLAS_TO_HELSINKI);
137 120
     Delivery newDelivery = Delivery.whenHandled(handlingActivity);
138
-    Projections newProjections = new Projections(newDelivery, itinerary, routeSpecification);
139 121
 
140 122
     assertEquals(Voyage.NONE, newDelivery.currentVoyage());
141 123
     assertEquals(HAMBURG, newDelivery.lastKnownLocation());
142 124
     assertEquals(IN_PORT, newDelivery.transportStatus());
143 125
 
144 126
     // Next handling activity is undefined. Need a new itinerary to know what to do.
145
-    assertNull(newProjections.nextExpectedActivity());
146
-    
127
+
147 128
     assertTrue(newDelivery.isMisdirected(itinerary, routeSpecification));
148 129
     assertFalse(newDelivery.isUnloadedAtDestination(routeSpecification));
149 130
 
150 131
     assertEquals(ROUTED, newDelivery.routingStatus(itinerary, routeSpecification));
151 132
 
152
-    // ETA is undefined at this time
153
-    assertNull(newProjections.estimatedTimeOfArrival());
154
-
155 133
     assertTrue(delivery.calculatedAt().before(newDelivery.calculatedAt()));
156 134
 
157 135
     // New route specification, old itinerary
158 136
     RouteSpecification newRouteSpecification = routeSpecification.withOrigin(HAMBURG);
159
-    newProjections = new Projections(newDelivery, itinerary, newRouteSpecification);
160 137
     assertEquals(MISROUTED, newDelivery.routingStatus(itinerary, newRouteSpecification));
161 138
 
162 139
     // TODO is it really misdirected at this point?
163 140
     assertTrue(newDelivery.isMisdirected(itinerary, newRouteSpecification));
164 141
 
165
-    assertNull(newProjections.nextExpectedActivity());
166
-
167 142
     Itinerary newItinerary = new Itinerary(
168 143
       Leg.deriveLeg(DALLAS_TO_HELSINKI, HAMBURG, STOCKHOLM)
169 144
     );
170 145
 
171
-    newProjections = new Projections(newDelivery, newItinerary, newRouteSpecification);
172
-
173 146
     assertEquals(ROUTED, newDelivery.routingStatus(newItinerary, newRouteSpecification));
174 147
     // TODO is it really misdirected here?
175 148
     assertTrue(newDelivery.isMisdirected(newItinerary, newRouteSpecification));
176 149
     assertEquals(IN_PORT, newDelivery.transportStatus());
177
-    //assertEquals(new HandlingActivity(LOAD, HAMBURG, DALLAS_TO_HELSINKI), newProjections.nextExpectedActivity());
178
-    assertNull(newProjections.nextExpectedActivity());
179 150
   }
180 151
 
181 152
 }