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

Introduced Voyage, Schedule and VoyageNumber. CarrierMovement is now a value object, CarrierMovementId is dropped.

Leg now has load/unload location and time, and a reference to a Voyage.

HandlingEvent references a Voyage instead of a CarrierMovement.

DeliveryHistory is renamed to Delivery.

(Yes, it's very broken right now, but it compiles)
peter_backlund 18 лет назад
Родитель
Сommit
e8005fc51f
23 измененных файлов: 455 добавлений и 258 удалений
  1. 5
    5
      dddsample/src/main/java/se/citerus/dddsample/application/remoting/BookingServiceFacadeImpl.java
  2. 6
    6
      dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/LegDTO.java
  3. 3
    3
      dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/assembler/CargoRoutingDTOAssembler.java
  4. 12
    11
      dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/assembler/ItineraryCandidateDTOAssembler.java
  5. 9
    7
      dddsample/src/main/java/se/citerus/dddsample/application/routing/ExternalRoutingService.java
  6. 16
    14
      dddsample/src/main/java/se/citerus/dddsample/application/ws/HandlingEventServiceEndpointImpl.java
  7. 14
    23
      dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/Cargo.java
  8. 10
    10
      dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/Itinerary.java
  9. 42
    30
      dddsample/src/main/java/se/citerus/dddsample/domain/model/cargo/Leg.java
  10. 61
    37
      dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/CarrierMovement.java
  11. 0
    13
      dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/CarrierMovementRepository.java
  12. 69
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/Schedule.java
  13. 64
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/Voyage.java
  14. 34
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/VoyageNumber.java
  15. 13
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/VoyageRepository.java
  16. 17
    16
      dddsample/src/main/java/se/citerus/dddsample/domain/model/handling/HandlingEvent.java
  17. 32
    33
      dddsample/src/main/java/se/citerus/dddsample/domain/model/handling/HandlingEventFactory.java
  18. 6
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/service/DomainEventNotifier.java
  19. 2
    2
      dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownCargoException.java
  20. 0
    20
      dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownCarrierMovementIdException.java
  21. 20
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownVoyageException.java
  22. 8
    16
      dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/TrackingServiceImpl.java
  23. 12
    12
      dddsample/src/main/java/se/citerus/dddsample/ui/CargoTrackingViewAdapter.java

+ 5
- 5
dddsample/src/main/java/se/citerus/dddsample/application/remoting/BookingServiceFacadeImpl.java Просмотреть файл

@@ -12,7 +12,7 @@ import se.citerus.dddsample.domain.model.cargo.Cargo;
12 12
 import se.citerus.dddsample.domain.model.cargo.CargoRepository;
13 13
 import se.citerus.dddsample.domain.model.cargo.Itinerary;
14 14
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
15
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementRepository;
15
+import se.citerus.dddsample.domain.model.carrier.VoyageRepository;
16 16
 import se.citerus.dddsample.domain.model.location.Location;
17 17
 import se.citerus.dddsample.domain.model.location.LocationRepository;
18 18
 import se.citerus.dddsample.domain.model.location.UnLocode;
@@ -35,7 +35,7 @@ public class BookingServiceFacadeImpl implements BookingServiceFacade {
35 35
   private BookingService bookingService;
36 36
   private LocationRepository locationRepository;
37 37
   private CargoRepository cargoRepository;
38
-  private CarrierMovementRepository carrierMovementRepository;
38
+  private VoyageRepository voyageRepository;
39 39
   private final Logger logger = Logger.getLogger(BookingServiceFacadeImpl.class);
40 40
 
41 41
   @Transactional(readOnly = true)
@@ -60,7 +60,7 @@ public class BookingServiceFacadeImpl implements BookingServiceFacade {
60 60
 
61 61
   @Transactional(readOnly = false)
62 62
   public void assignCargoToRoute(String trackingId, ItineraryCandidateDTO itineraryCandidateDTO) {
63
-    final Itinerary itinerary = new ItineraryCandidateDTOAssembler().fromDTO(itineraryCandidateDTO, carrierMovementRepository, locationRepository);
63
+    final Itinerary itinerary = new ItineraryCandidateDTOAssembler().fromDTO(itineraryCandidateDTO, voyageRepository, locationRepository);
64 64
 
65 65
     final Cargo cargo = cargoRepository.find(new TrackingId(trackingId));
66 66
     if (cargo == null) {
@@ -109,7 +109,7 @@ public class BookingServiceFacadeImpl implements BookingServiceFacade {
109 109
     this.cargoRepository = cargoRepository;
110 110
   }
111 111
 
112
-  public void setCarrierMovementRepository(CarrierMovementRepository carrierMovementRepository) {
113
-    this.carrierMovementRepository = carrierMovementRepository;
112
+  public void setCarrierMovementRepository(VoyageRepository voyageRepository) {
113
+    this.voyageRepository = voyageRepository;
114 114
   }
115 115
 }

+ 6
- 6
dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/LegDTO.java Просмотреть файл

@@ -7,25 +7,25 @@ import java.io.Serializable;
7 7
  */
8 8
 public final class LegDTO implements Serializable {
9 9
 
10
-  private final String carrierMovementId;
10
+  private final String voyageNumber;
11 11
   private final String from;
12 12
   private final String to;
13 13
 
14 14
   /**
15 15
    * Constructor.
16 16
    *
17
-   * @param carrierMovementId
17
+   * @param voyageNumber
18 18
    * @param from
19 19
    * @param to
20 20
    */
21
-  public LegDTO(final String carrierMovementId, final String from, final String to) {
22
-    this.carrierMovementId = carrierMovementId;
21
+  public LegDTO(final String voyageNumber, final String from, final String to) {
22
+    this.voyageNumber = voyageNumber;
23 23
     this.from = from;
24 24
     this.to = to;
25 25
   }
26 26
 
27
-  public String getCarrierMovementId() {
28
-    return carrierMovementId;
27
+  public String getVoyageNumber() {
28
+    return voyageNumber;
29 29
   }
30 30
 
31 31
   public String getFrom() {

+ 3
- 3
dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/assembler/CargoRoutingDTOAssembler.java Просмотреть файл

@@ -17,9 +17,9 @@ public class CargoRoutingDTOAssembler {
17 17
     );
18 18
     for (Leg leg : cargo.itinerary().legs()) {
19 19
       dto.addLeg(
20
-        leg.carrierMovement().carrierMovementId().idString(),
21
-        leg.from().unLocode().idString(),
22
-        leg.to().unLocode().idString()
20
+        leg.voyage().voyageNumber().idString(),
21
+        leg.loadLocation().unLocode().idString(),
22
+        leg.unloadLocation().unLocode().idString()
23 23
       );
24 24
     }
25 25
     return dto;

+ 12
- 11
dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/assembler/ItineraryCandidateDTOAssembler.java Просмотреть файл

@@ -4,14 +4,15 @@ import se.citerus.dddsample.application.remoting.dto.ItineraryCandidateDTO;
4 4
 import se.citerus.dddsample.application.remoting.dto.LegDTO;
5 5
 import se.citerus.dddsample.domain.model.cargo.Itinerary;
6 6
 import se.citerus.dddsample.domain.model.cargo.Leg;
7
-import se.citerus.dddsample.domain.model.carrier.CarrierMovement;
8
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
9
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementRepository;
7
+import se.citerus.dddsample.domain.model.carrier.Voyage;
8
+import se.citerus.dddsample.domain.model.carrier.VoyageNumber;
9
+import se.citerus.dddsample.domain.model.carrier.VoyageRepository;
10 10
 import se.citerus.dddsample.domain.model.location.Location;
11 11
 import se.citerus.dddsample.domain.model.location.LocationRepository;
12 12
 import se.citerus.dddsample.domain.model.location.UnLocode;
13 13
 
14 14
 import java.util.ArrayList;
15
+import java.util.Date;
15 16
 import java.util.List;
16 17
 
17 18
 /**
@@ -28,20 +29,20 @@ public class ItineraryCandidateDTOAssembler {
28 29
   }
29 30
 
30 31
   protected LegDTO toLegDTO(final Leg leg) {
31
-    final CarrierMovementId carrierMovementId = leg.carrierMovement().carrierMovementId();
32
-    final UnLocode from = leg.from().unLocode();
33
-    final UnLocode to = leg.to().unLocode();
34
-    return new LegDTO(carrierMovementId.idString(), from.idString(), to.idString());
32
+    final VoyageNumber voyageNumber = leg.voyage().voyageNumber();
33
+    final UnLocode from = leg.loadLocation().unLocode();
34
+    final UnLocode to = leg.unloadLocation().unLocode();
35
+    return new LegDTO(voyageNumber.idString(), from.idString(), to.idString());
35 36
   }
36 37
 
37
-  public Itinerary fromDTO(ItineraryCandidateDTO itineraryCandidateDTO, CarrierMovementRepository carrierMovementRepository, LocationRepository locationRepository) {
38
+  public Itinerary fromDTO(ItineraryCandidateDTO itineraryCandidateDTO, VoyageRepository voyageRepository, LocationRepository locationRepository) {
38 39
     final List<Leg> legs = new ArrayList<Leg>(itineraryCandidateDTO.getLegs().size());
39 40
     for (LegDTO legDTO : itineraryCandidateDTO.getLegs()) {
40
-      final CarrierMovementId carrierMovementId = new CarrierMovementId(legDTO.getCarrierMovementId());
41
-      final CarrierMovement carrierMovement = carrierMovementRepository.find(carrierMovementId);
41
+      final VoyageNumber voyageNumber = new VoyageNumber(legDTO.getVoyageNumber());
42
+      final Voyage voyage = voyageRepository.find(voyageNumber);
42 43
       final Location from = locationRepository.find(new UnLocode(legDTO.getFrom()));
43 44
       final Location to = locationRepository.find(new UnLocode(legDTO.getTo()));
44
-      legs.add(new Leg(carrierMovement, from, to));
45
+      legs.add(new Leg(voyage, from, to, new Date(), new Date()));  // TODO better dates
45 46
     }
46 47
     return new Itinerary(legs);
47 48
   }

+ 9
- 7
dddsample/src/main/java/se/citerus/dddsample/application/routing/ExternalRoutingService.java Просмотреть файл

@@ -4,8 +4,8 @@ import org.springframework.transaction.annotation.Transactional;
4 4
 import se.citerus.dddsample.domain.model.cargo.Itinerary;
5 5
 import se.citerus.dddsample.domain.model.cargo.Leg;
6 6
 import se.citerus.dddsample.domain.model.cargo.RouteSpecification;
7
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
8
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementRepository;
7
+import se.citerus.dddsample.domain.model.carrier.VoyageNumber;
8
+import se.citerus.dddsample.domain.model.carrier.VoyageRepository;
9 9
 import se.citerus.dddsample.domain.model.location.Location;
10 10
 import se.citerus.dddsample.domain.model.location.LocationRepository;
11 11
 import se.citerus.dddsample.domain.model.location.UnLocode;
@@ -15,6 +15,7 @@ import se.citerus.routingteam.TransitEdge;
15 15
 import se.citerus.routingteam.TransitPath;
16 16
 
17 17
 import java.util.ArrayList;
18
+import java.util.Date;
18 19
 import java.util.List;
19 20
 
20 21
 /**
@@ -27,7 +28,7 @@ public class ExternalRoutingService implements RoutingService {
27 28
 
28 29
   private GraphTraversalService graphTraversalService;
29 30
   private LocationRepository locationRepository;
30
-  private CarrierMovementRepository carrierMovementRepository;
31
+  private VoyageRepository voyageRepository;
31 32
 
32 33
   @Transactional(readOnly = true)
33 34
   public List<Itinerary> fetchRoutesForSpecification(RouteSpecification routeSpecification) {
@@ -62,9 +63,10 @@ public class ExternalRoutingService implements RoutingService {
62 63
 
63 64
   private Leg toLeg(TransitEdge edge) {
64 65
     return new Leg(
65
-      carrierMovementRepository.find(new CarrierMovementId(edge.getCarrierMovementId())),
66
+      voyageRepository.find(new VoyageNumber(edge.getCarrierMovementId())),
66 67
       locationRepository.find(new UnLocode(edge.getFromUnLocode())),
67
-      locationRepository.find(new UnLocode(edge.getToUnLocode()))
68
+      locationRepository.find(new UnLocode(edge.getToUnLocode())),
69
+      new Date(), new Date()  // TODO better dates
68 70
     );
69 71
   }
70 72
 
@@ -76,7 +78,7 @@ public class ExternalRoutingService implements RoutingService {
76 78
     this.locationRepository = locationRepository;
77 79
   }
78 80
 
79
-  public void setCarrierMovementRepository(CarrierMovementRepository carrierMovementRepository) {
80
-    this.carrierMovementRepository = carrierMovementRepository;
81
+  public void setCarrierMovementRepository(VoyageRepository voyageRepository) {
82
+    this.voyageRepository = voyageRepository;
81 83
   }
82 84
 }

+ 16
- 14
dddsample/src/main/java/se/citerus/dddsample/application/ws/HandlingEventServiceEndpointImpl.java Просмотреть файл

@@ -8,14 +8,14 @@ import org.springframework.transaction.TransactionStatus;
8 8
 import org.springframework.transaction.support.TransactionCallbackWithoutResult;
9 9
 import org.springframework.transaction.support.TransactionTemplate;
10 10
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
11
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
11
+import se.citerus.dddsample.domain.model.carrier.VoyageNumber;
12 12
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
13 13
 import se.citerus.dddsample.domain.model.handling.HandlingEventFactory;
14 14
 import se.citerus.dddsample.domain.model.location.UnLocode;
15 15
 import se.citerus.dddsample.domain.service.HandlingEventService;
16
-import se.citerus.dddsample.domain.service.UnknownCarrierMovementIdException;
16
+import se.citerus.dddsample.domain.service.UnknownCargoException;
17 17
 import se.citerus.dddsample.domain.service.UnknownLocationException;
18
-import se.citerus.dddsample.domain.service.UnknownTrackingIdException;
18
+import se.citerus.dddsample.domain.service.UnknownVoyageException;
19 19
 
20 20
 import javax.jws.WebService;
21 21
 import java.text.ParseException;
@@ -31,21 +31,23 @@ public class HandlingEventServiceEndpointImpl implements HandlingEventServiceEnd
31 31
   private final Log logger = LogFactory.getLog(getClass());
32 32
   protected static final String ISO_8601_FORMAT = "yyyy-mm-dd HH:MM:SS.SSS";
33 33
 
34
-  public void register(final String completionTime, final String trackingId, final String carrierMovementId,
34
+  public void register(final String completionTime, final String trackingId, final String voyageNumberString,
35 35
                        final String unlocode, final String eventType) {
36 36
     try {
37 37
       final Date date = parseIso8601Date(completionTime);
38 38
       final TrackingId tid = new TrackingId(trackingId);
39
-      final CarrierMovementId cid;
40
-      if (StringUtils.isNotEmpty(carrierMovementId)) {
41
-        cid = new CarrierMovementId(carrierMovementId);
39
+
40
+      final VoyageNumber voyageNumber;
41
+      if (StringUtils.isNotEmpty(voyageNumberString)) {
42
+        voyageNumber = new VoyageNumber(voyageNumberString);
42 43
       } else {
43
-        cid = null;
44
+        voyageNumber = null;
44 45
       }
46
+
45 47
       final HandlingEvent.Type type = parseEventType(eventType);
46 48
       final UnLocode ul = new UnLocode(unlocode);
47 49
 
48
-      doRegister(date, tid, cid, type, ul);
50
+      doRegister(date, tid, voyageNumber, type, ul);
49 51
     } catch (IllegalArgumentException iae) {
50 52
       handleIllegalArgument(iae);
51 53
     } catch (ParseException pe) {
@@ -58,17 +60,17 @@ public class HandlingEventServiceEndpointImpl implements HandlingEventServiceEnd
58 60
   }
59 61
 
60 62
   // TODO this entire step would be well suited to move to a consumer of asynchronous messages
61
-  private void doRegister(final Date date, final TrackingId tid, final CarrierMovementId cid, final HandlingEvent.Type type, final UnLocode ul) {
63
+  private void doRegister(final Date date, final TrackingId tid, final VoyageNumber voyageNumber, final HandlingEvent.Type type, final UnLocode ul) {
62 64
     // Using programmatic demarcation here due to weaving conflicts
63 65
     // between jax-ws and Spring transaction annotations
64 66
     transactionTemplate.execute(new TransactionCallbackWithoutResult() {
65 67
         protected void doInTransactionWithoutResult(TransactionStatus status) {
66 68
             try {
67
-                HandlingEvent event = handlingEventFactory.createHandlingEvent(date, tid, cid, ul, type);
69
+                HandlingEvent event = handlingEventFactory.createHandlingEvent(date, tid, voyageNumber, ul, type);
68 70
                 handlingEventService.register(event);
69
-            } catch (UnknownCarrierMovementIdException e) {
71
+            } catch (UnknownVoyageException e) {
70 72
                 handleUnknownCarrierMovementId(e);
71
-            } catch (UnknownTrackingIdException e) {
73
+            } catch (UnknownCargoException e) {
72 74
                 handleUnknownTrackingId(e);
73 75
             } catch (UnknownLocationException e) {
74 76
                 handleUnknownLocation(e);
@@ -113,7 +115,7 @@ public class HandlingEventServiceEndpointImpl implements HandlingEventServiceEnd
113 115
     logger.error(e, e);
114 116
   }
115 117
 
116
-  private void handleUnknownCarrierMovementId(UnknownCarrierMovementIdException e) {
118
+  private void handleUnknownCarrierMovementId(UnknownVoyageException e) {
117 119
     logger.error(e, e);
118 120
   }
119 121
 

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

@@ -40,8 +40,7 @@ public final class Cargo implements Entity<Cargo> {
40 40
   private Location origin;
41 41
   private Location destination;
42 42
   private Itinerary itinerary;
43
-  private DeliveryHistory deliveryHistory;
44
-  private boolean misdirected;
43
+  private Delivery delivery;
45 44
 
46 45
   /**
47 46
    * @param trackingId tracking id
@@ -56,7 +55,6 @@ public final class Cargo implements Entity<Cargo> {
56 55
     this.trackingId = trackingId;
57 56
     this.origin = origin;
58 57
     this.destination = destination;
59
-    updateState();
60 58
   }
61 59
 
62 60
   /**
@@ -94,8 +92,8 @@ public final class Cargo implements Entity<Cargo> {
94 92
   /**
95 93
    * @return The delivery history. Never null.
96 94
    */
97
-  public DeliveryHistory deliveryHistory() {
98
-    return DomainObjectUtils.nullSafe(this.deliveryHistory, DeliveryHistory.EMPTY_DELIVERY_HISTORY);
95
+  public Delivery deliveryHistory() {
96
+    return DomainObjectUtils.nullSafe(this.delivery, Delivery.EMPTY_DELIVERY);
99 97
   }
100 98
 
101 99
   /**
@@ -106,18 +104,6 @@ public final class Cargo implements Entity<Cargo> {
106 104
   }
107 105
 
108 106
   /**
109
-   * Updates the state of the cargo.
110
-   */
111
-  public void updateState() {
112
-    final HandlingEvent lastEvent = deliveryHistory().lastEvent();
113
-    if (lastEvent == null) {
114
-      this.misdirected = false;
115
-    } else {
116
-      this.misdirected = !itinerary().isExpected(lastEvent);
117
-    }
118
-  }
119
-
120
-  /**
121 107
    * @return Last known location of the cargo, or Location.UNKNOWN if the delivery history is empty.
122 108
    */
123 109
   public Location lastKnownLocation() {
@@ -153,11 +139,11 @@ public final class Cargo implements Entity<Cargo> {
153 139
   }
154 140
 
155 141
   /**
156
-   * @param deliveryHistory Cargo delivery history
142
+   * @param delivery Cargo delivery history
157 143
    */
158
-  void setDeliveryHistory(final DeliveryHistory deliveryHistory) {
159
-    Validate.notNull(deliveryHistory);
160
-    this.deliveryHistory = deliveryHistory;
144
+  void setDeliveryHistory(final Delivery delivery) {
145
+    Validate.notNull(delivery);
146
+    this.delivery = delivery;
161 147
   }
162 148
 
163 149
   /**
@@ -172,7 +158,12 @@ public final class Cargo implements Entity<Cargo> {
172 158
    * @return <code>true</code> if the cargo has been misdirected,
173 159
    */
174 160
   public boolean isMisdirected() {
175
-    return misdirected;
161
+    final HandlingEvent lastEvent = deliveryHistory().lastEvent();
162
+    if (lastEvent == null) {
163
+      return false;
164
+    } else {
165
+      return !itinerary().isExpected(lastEvent);
166
+    }
176 167
   }
177 168
 
178 169
   /**
@@ -183,7 +174,7 @@ public final class Cargo implements Entity<Cargo> {
183 174
    * @return True if the cargo has been unloaded at the final destination.
184 175
    */
185 176
   public boolean isUnloadedAtDestination() {
186
-    for (HandlingEvent event : deliveryHistory().eventsOrderedByCompletionTime()) {
177
+    for (HandlingEvent event : deliveryHistory().history()) {
187 178
       if (HandlingEvent.Type.UNLOAD.equals(event.type())
188 179
         && destination.equals(event.location())) {
189 180
         return true;

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

@@ -32,7 +32,7 @@ public class Itinerary implements ValueObject<Itinerary> {
32 32
     Validate.notEmpty(legs);
33 33
     Validate.noNullElements(legs);
34 34
     
35
-    this.legs = Collections.unmodifiableList(legs);
35
+    this.legs = legs;
36 36
   }
37 37
 
38 38
   /**
@@ -51,7 +51,7 @@ public class Itinerary implements ValueObject<Itinerary> {
51 51
    * @return the legs of this itinerary, as an <b>immutable</b> list.
52 52
    */
53 53
   public List<Leg> legs() {
54
-    return legs;
54
+    return Collections.unmodifiableList(legs);
55 55
   }
56 56
 
57 57
   /**
@@ -68,24 +68,24 @@ public class Itinerary implements ValueObject<Itinerary> {
68 68
     if (event.type() == HandlingEvent.Type.RECEIVE) {
69 69
       //Check that the first leg's origin is the event's location
70 70
       final Leg leg = legs.get(0);
71
-      return (leg.from().equals(event.location()));
71
+      return (leg.loadLocation().equals(event.location()));
72 72
     }
73 73
 
74 74
     if (event.type() == HandlingEvent.Type.LOAD) {
75
-      //Check that the there is one leg with same from location and carrier movement
75
+      //Check that the there is one leg with same load location and voyage
76 76
       for (Leg leg : legs) {
77
-        if (leg.from().equals(event.location())
78
-          && leg.carrierMovement().equals(event.carrierMovement()))
77
+        if (leg.loadLocation().sameIdentityAs(event.location()) &&
78
+            leg.voyage().sameIdentityAs(event.voyage()))
79 79
           return true;
80 80
       }
81 81
       return false;
82 82
     }
83 83
 
84 84
     if (event.type() == HandlingEvent.Type.UNLOAD) {
85
-      //Check that the there is one leg with same to loc and carrier movement
85
+      //Check that the there is one leg with same unload location and voyage
86 86
       for (Leg leg : legs) {
87
-        if (leg.to().equals(event.location())
88
-          && leg.carrierMovement().equals(event.carrierMovement()))
87
+        if (leg.unloadLocation().equals(event.location()) &&
88
+            leg.voyage().equals(event.voyage()))
89 89
           return true;
90 90
       }
91 91
       return false;
@@ -94,7 +94,7 @@ public class Itinerary implements ValueObject<Itinerary> {
94 94
     if (event.type() == HandlingEvent.Type.CLAIM) {
95 95
       //Check that the last leg's destination is from the event's location
96 96
       final Leg leg = legs.get(legs.size() - 1);
97
-      return (leg.to().equals(event.location()));
97
+      return (leg.unloadLocation().equals(event.location()));
98 98
     }
99 99
 
100 100
     //HandlingEvent.Type.CUSTOMS;

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

@@ -4,56 +4,66 @@ import org.apache.commons.lang.Validate;
4 4
 import org.apache.commons.lang.builder.EqualsBuilder;
5 5
 import org.apache.commons.lang.builder.HashCodeBuilder;
6 6
 import se.citerus.dddsample.domain.model.ValueObject;
7
-import se.citerus.dddsample.domain.model.carrier.CarrierMovement;
7
+import se.citerus.dddsample.domain.model.carrier.Voyage;
8 8
 import se.citerus.dddsample.domain.model.location.Location;
9 9
 
10
+import java.util.Date;
11
+
10 12
 /**
11 13
  * An itinerary consists of one or more legs.
12 14
  */
13 15
 public final class Leg implements ValueObject<Leg> {
14 16
 
15
-  private CarrierMovement carrierMovement;
16
-  private Location from;
17
-  private Location to;
18
-
19
-  /**
20
-   * Constructor.
21
-   *
22
-   * @param carrierMovement
23
-   * @param from
24
-   * @param to
25
-   */
26
-  public Leg(final CarrierMovement carrierMovement, final Location from, final Location to) {
27
-    Validate.noNullElements(new Object[]{carrierMovement, from, to});
28
-    this.carrierMovement = carrierMovement;
29
-    this.from = from;
30
-    this.to = to;
17
+  private Voyage voyage;
18
+  private Location loadLocation;
19
+  private Location unloadLocation;
20
+  private Date loadTime;
21
+  private Date unloadTime;
22
+
23
+  public Leg(Voyage voyage, Location loadLocation, Location unloadLocation, Date loadTime, Date unloadTime) {
24
+    Validate.noNullElements(new Object[] {voyage, loadLocation, unloadLocation, loadTime, unloadTime});
25
+    
26
+    this.voyage = voyage;
27
+    this.loadLocation = loadLocation;
28
+    this.unloadLocation = unloadLocation;
29
+    this.loadTime = loadTime;
30
+    this.unloadTime = unloadTime;
31
+  }
32
+
33
+  public Voyage voyage() {
34
+    return voyage;
35
+  }
36
+
37
+  public Location loadLocation() {
38
+    return loadLocation;
31 39
   }
32 40
 
33
-  public Location from() {
34
-    return from;
41
+  public Location unloadLocation() {
42
+    return unloadLocation;
35 43
   }
36 44
 
37
-  public Location to() {
38
-    return to;
45
+  public Date loadTime() {
46
+    return new Date(loadTime.getTime());
39 47
   }
40 48
 
41
-  public CarrierMovement carrierMovement() {
42
-    return carrierMovement;
49
+  public Date unloadTime() {
50
+    return new Date(unloadTime.getTime());
43 51
   }
44 52
 
45 53
   @Override
46 54
   public boolean sameValueAs(final Leg other) {
47 55
     return other != null && new EqualsBuilder().
48
-      append(this.carrierMovement, other.carrierMovement).
49
-      append(this.from, other.from).
50
-      append(this.to, other.to).
56
+      append(this.voyage, other.voyage).
57
+      append(this.loadLocation, other.loadLocation).
58
+      append(this.unloadLocation, other.unloadLocation).
59
+      append(this.loadTime, other.loadTime).
60
+      append(this.unloadTime, other.unloadTime).
51 61
       isEquals();
52 62
   }
53 63
 
54 64
   @Override
55 65
   public Leg copy() {
56
-    return new Leg(carrierMovement, from, to);
66
+    return new Leg(voyage(), loadLocation(), unloadLocation(), loadTime(), unloadTime());
57 67
   }
58 68
 
59 69
   @Override
@@ -69,9 +79,11 @@ public final class Leg implements ValueObject<Leg> {
69 79
   @Override
70 80
   public int hashCode() {
71 81
     return new HashCodeBuilder().
72
-      append(carrierMovement).
73
-      append(from).
74
-      append(to).
82
+      append(voyage).
83
+      append(loadLocation).
84
+      append(unloadLocation).
85
+      append(loadTime).
86
+      append(unloadTime).
75 87
       toHashCode();
76 88
   }
77 89
 

+ 61
- 37
dddsample/src/main/java/se/citerus/dddsample/domain/model/carrier/CarrierMovement.java Просмотреть файл

@@ -1,7 +1,9 @@
1 1
 package se.citerus.dddsample.domain.model.carrier;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import se.citerus.dddsample.domain.model.Entity;
4
+import org.apache.commons.lang.builder.EqualsBuilder;
5
+import org.apache.commons.lang.builder.HashCodeBuilder;
6
+import se.citerus.dddsample.domain.model.ValueObject;
5 7
 import se.citerus.dddsample.domain.model.location.Location;
6 8
 
7 9
 import java.util.Date;
@@ -10,82 +12,104 @@ import java.util.Date;
10 12
 /**
11 13
  * A carrier movement is a vessel voyage from one location to another.
12 14
  */
13
-public final class CarrierMovement implements Entity<CarrierMovement> {
15
+public final class CarrierMovement implements ValueObject<CarrierMovement> {
14 16
 
15
-  private CarrierMovementId carrierMovementId;
16
-  private Location from;
17
-  private Location to;
17
+  private Location departureLocation;
18
+  private Location arrivalLocation;
18 19
   private Date departureTime;
19 20
   private Date arrivalTime;
20 21
 
21 22
   // Null object pattern 
22 23
   public static final CarrierMovement NONE = new CarrierMovement(
23
-    new CarrierMovementId(""), Location.UNKNOWN, Location.UNKNOWN,
24
-    new Date(0), new Date(0));
24
+    Location.UNKNOWN, Location.UNKNOWN,
25
+    new Date(0), new Date(0)
26
+  );
25 27
 
26 28
   /**
27 29
    * Constructor.
28 30
    *
29
-   * @param carrierMovementId carrier movement id
30
-   * @param from from location
31
-   * @param to to location
31
+   * @param departureLocation location of departure
32
+   * @param arrivalLocation location of arrival
32 33
    * @param departureTime time of departure
33 34
    * @param arrivalTime time of arrival
34 35
    */
35
-  public CarrierMovement(final CarrierMovementId carrierMovementId,
36
-                         final Location from,
37
-                         final Location to,
38
-                         final Date departureTime,
39
-                         final Date arrivalTime) {
40
-    Validate.noNullElements(new Object[]{carrierMovementId, from, to, departureTime, arrivalTime});
36
+  public CarrierMovement(Location departureLocation,
37
+                         Location arrivalLocation,
38
+                         Date departureTime,
39
+                         Date arrivalTime) {
40
+    Validate.noNullElements(new Object[]{departureLocation, arrivalLocation, departureTime, arrivalTime});
41 41
     this.departureTime = departureTime;
42 42
     this.arrivalTime = arrivalTime;
43
-    this.carrierMovementId = carrierMovementId;
44
-    this.from = from;
45
-    this.to = to;
43
+    this.departureLocation = departureLocation;
44
+    this.arrivalLocation = arrivalLocation;
46 45
   }
47 46
 
48
-  public CarrierMovementId carrierMovementId() {
49
-    return carrierMovementId;
50
-  }
51
-
52
-  public Location from() {
53
-    return from;
47
+  /**
48
+   * @return Departure location.
49
+   */
50
+  public Location departureLocation() {
51
+    return departureLocation;
54 52
   }
55 53
 
56
-  public Location to() {
57
-    return to;
54
+  /**
55
+   * @return Arrival location.
56
+   */
57
+  public Location arrivalLocation() {
58
+    return arrivalLocation;
58 59
   }
59 60
 
61
+  /**
62
+   * @return Time of departure.
63
+   */
60 64
   public Date departureTime() {
61 65
     return new Date(departureTime.getTime());
62 66
   }
63 67
 
68
+  /**
69
+   * @return Time of arrival.
70
+   */
64 71
   public Date arrivalTime() {
65 72
     return new Date(arrivalTime.getTime());
66 73
   }
67 74
 
68 75
   @Override
69
-  public boolean sameIdentityAs(final CarrierMovement other) {
70
-    return carrierMovementId.sameValueAs(other.carrierMovementId);
71
-  }
72
-
73
-  @Override
74 76
   public boolean equals(final Object o) {
75 77
     if (this == o) return true;
76 78
     if (o == null || getClass() != o.getClass()) return false;
77 79
 
78 80
     final CarrierMovement that = (CarrierMovement) o;
79 81
 
80
-    return sameIdentityAs(that);
82
+    return sameValueAs(that);
81 83
   }
82 84
 
83
-  /**
84
-   * @return Hashcode of carrier movement id.
85
-   */
86 85
   @Override
87 86
   public int hashCode() {
88
-    return carrierMovementId.hashCode();
87
+    return new HashCodeBuilder().
88
+      append(this.departureLocation).
89
+      append(this.departureTime).
90
+      append(this.arrivalLocation).
91
+      append(this.arrivalTime).
92
+      toHashCode();
93
+  }
94
+
95
+  @Override
96
+  public boolean sameValueAs(CarrierMovement other) {
97
+    return other != null && new EqualsBuilder().
98
+      append(this.departureLocation, other.departureLocation).
99
+      append(this.departureTime, other.departureTime).
100
+      append(this.arrivalLocation, other.arrivalLocation).
101
+      append(this.arrivalTime, other.arrivalTime).
102
+      isEquals();
103
+  }
104
+
105
+  @Override
106
+  public CarrierMovement copy() {
107
+    return new CarrierMovement(
108
+      departureLocation(),
109
+      arrivalLocation(),
110
+      departureTime(),
111
+      arrivalTime()
112
+    );
89 113
   }
90 114
 
91 115
   CarrierMovement() {

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

@@ -1,13 +0,0 @@
1
-package se.citerus.dddsample.domain.model.carrier;
2
-
3
-public interface CarrierMovementRepository {
4
-
5
-  /**
6
-   * Finds a carrier movement using given id.
7
-   *
8
-   * @param carrierMovementId Id
9
-   * @return The carrier movement.
10
-   */
11
-  CarrierMovement find(CarrierMovementId carrierMovementId);
12
-
13
-}

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

@@ -0,0 +1,69 @@
1
+package se.citerus.dddsample.domain.model.carrier;
2
+
3
+import org.apache.commons.lang.Validate;
4
+import org.apache.commons.lang.builder.HashCodeBuilder;
5
+import se.citerus.dddsample.domain.model.ValueObject;
6
+
7
+import java.util.ArrayList;
8
+import java.util.Collections;
9
+import java.util.List;
10
+
11
+/**
12
+ * A voyage schedule.
13
+ * 
14
+ */
15
+public class Schedule implements ValueObject<Schedule> {
16
+
17
+  private List<CarrierMovement> carrierMovements = Collections.EMPTY_LIST;
18
+
19
+  public static final Schedule EMPTY = new Schedule();
20
+
21
+  public Schedule(List<CarrierMovement> carrierMovements) {
22
+    Validate.notNull(carrierMovements);
23
+    Validate.noNullElements(carrierMovements);
24
+      
25
+    this.carrierMovements = carrierMovements;
26
+  }
27
+
28
+  /**
29
+   * @return Carrier movements.
30
+   */
31
+  public List<CarrierMovement> carrierMovements() {
32
+    return Collections.unmodifiableList(carrierMovements);
33
+  }
34
+
35
+  @Override
36
+  public boolean sameValueAs(Schedule other) {
37
+    return other != null && this.carrierMovements.equals(other.carrierMovements);
38
+  }
39
+
40
+  @Override
41
+  public Schedule copy() {
42
+    final List<CarrierMovement> copyCarrierMovements = new ArrayList(carrierMovements.size());
43
+    for (CarrierMovement carrierMovement : carrierMovements) {
44
+      copyCarrierMovements.add(carrierMovement.copy());
45
+    }
46
+
47
+    return new Schedule(copyCarrierMovements);
48
+  }
49
+
50
+  @Override
51
+  public boolean equals(Object o) {
52
+    if (this == o) return true;
53
+    if (o == null || getClass() != o.getClass()) return false;
54
+
55
+    final Schedule that = (Schedule) o;
56
+
57
+    return sameValueAs(that);
58
+  }
59
+
60
+  @Override
61
+  public int hashCode() {
62
+    return new HashCodeBuilder().append(this.carrierMovements).toHashCode();
63
+  }
64
+
65
+  Schedule() {
66
+    // Needed by Hibernate
67
+  }
68
+
69
+}

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

@@ -0,0 +1,64 @@
1
+package se.citerus.dddsample.domain.model.carrier;
2
+
3
+import se.citerus.dddsample.domain.model.Entity;
4
+
5
+/**
6
+ * A Voyage.
7
+ */
8
+public class Voyage implements Entity<Voyage> {
9
+
10
+  private VoyageNumber voyageNumber;
11
+  private Schedule schedule;
12
+
13
+  // Null object pattern
14
+  public static final Voyage NONE = new Voyage(
15
+    new VoyageNumber(""), Schedule.EMPTY
16
+  );
17
+
18
+  public Voyage(VoyageNumber voyageNumber, Schedule schedule) {
19
+    this.voyageNumber = voyageNumber;
20
+    this.schedule = schedule;
21
+  }
22
+
23
+  /**
24
+   * @return Voyage number.
25
+   */
26
+  public VoyageNumber voyageNumber() {
27
+    return voyageNumber;
28
+  }
29
+
30
+  /**
31
+   * @return Schedule.
32
+   */
33
+  public Schedule schedule() {
34
+    return schedule;
35
+  }
36
+
37
+  @Override
38
+  public int hashCode() {
39
+    return voyageNumber.hashCode();
40
+  }
41
+
42
+  @Override
43
+  public boolean equals(Object o) {
44
+    if (this == o) return true;
45
+    if (o == null || getClass() != o.getClass()) return false;
46
+
47
+    final Voyage that = (Voyage) o;
48
+
49
+    return sameIdentityAs(that);
50
+  }
51
+
52
+  @Override
53
+  public boolean sameIdentityAs(Voyage other) {
54
+    return other != null && this.voyageNumber.sameValueAs(other.voyageNumber);
55
+  }
56
+
57
+  Voyage() {
58
+    // Needed by Hibernate
59
+  }
60
+
61
+  // Needed by Hibernate
62
+  private Long id;
63
+
64
+}

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

@@ -0,0 +1,34 @@
1
+package se.citerus.dddsample.domain.model.carrier;
2
+
3
+import org.apache.commons.lang.Validate;
4
+import se.citerus.dddsample.domain.model.ValueObject;
5
+
6
+/**
7
+ * Identifies a voyage.
8
+ * 
9
+ */
10
+public class VoyageNumber implements ValueObject<VoyageNumber> {
11
+
12
+  private String number;
13
+
14
+  public VoyageNumber(String number) {
15
+    Validate.notNull(number);
16
+    
17
+    this.number = number;
18
+  }
19
+
20
+  @Override
21
+  public boolean sameValueAs(VoyageNumber other) {
22
+    return other != null && this.number.equals(other.number);
23
+  }
24
+
25
+  @Override
26
+  public VoyageNumber copy() {
27
+    return new VoyageNumber(number);
28
+  }
29
+
30
+  public String idString() {
31
+    return number;
32
+  }
33
+  
34
+}

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

@@ -0,0 +1,13 @@
1
+package se.citerus.dddsample.domain.model.carrier;
2
+
3
+public interface VoyageRepository {
4
+
5
+  /**
6
+   * Finds a voyage using voyage number.
7
+   *
8
+   * @param voyageNumber voyage number
9
+   * @return The voyage, or null if not found.
10
+   */
11
+  Voyage find(VoyageNumber voyageNumber);
12
+
13
+}

+ 17
- 16
dddsample/src/main/java/se/citerus/dddsample/domain/model/handling/HandlingEvent.java Просмотреть файл

@@ -6,6 +6,7 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
6 6
 import se.citerus.dddsample.domain.model.DomainEvent;
7 7
 import se.citerus.dddsample.domain.model.cargo.Cargo;
8 8
 import se.citerus.dddsample.domain.model.carrier.CarrierMovement;
9
+import se.citerus.dddsample.domain.model.carrier.Voyage;
9 10
 import se.citerus.dddsample.domain.model.location.Location;
10 11
 import se.citerus.dddsample.domain.shared.DomainObjectUtils;
11 12
 
@@ -40,7 +41,7 @@ public final class HandlingEvent implements DomainEvent<HandlingEvent> {
40 41
   };
41 42
 
42 43
   private Type type;
43
-  private CarrierMovement carrierMovement;
44
+  private Voyage voyage;
44 45
   private Location location;
45 46
   private Date completionTime;
46 47
   private Date registrationTime;
@@ -81,40 +82,40 @@ public final class HandlingEvent implements DomainEvent<HandlingEvent> {
81 82
     public boolean prohibitsCarrierMovement() {
82 83
       return !requiresCarrierMovement();
83 84
     }
85
+
84 86
   }
85
-  
87
+
86 88
   /**
87 89
    * @param cargo            cargo
88 90
    * @param completionTime   completion time, the reported time that the event actually happened (e.g. the receive took place).
89 91
    * @param registrationTime registration time, the time the message is received
90
-   * @param type             type of event. Legal values are LOAD and UNLOAD
92
+   * @param type             type of event
91 93
    * @param location         where the event took place
92
-   * @param carrierMovement  carrier movement.
94
+   * @param voyage           the voyage
93 95
    */
94
-  public HandlingEvent(final Cargo cargo, final Date completionTime, final Date registrationTime, final Type type,
95
-                       final Location location, final CarrierMovement carrierMovement) {
96
-    Validate.noNullElements(new Object[] {cargo, completionTime, registrationTime, type, location, carrierMovement});
96
+  public HandlingEvent(Cargo cargo, Date completionTime, Date registrationTime, Type type,
97
+                       Location location, Voyage voyage) {
98
+    Validate.noNullElements(new Object[] {cargo, completionTime, registrationTime, type, location, voyage});
97 99
     if (type.prohibitsCarrierMovement()) {
98 100
       throw new IllegalArgumentException("Carrier movement is not allowed with event type " + type);
99 101
     }
100 102
 
103
+    this.voyage = voyage;
101 104
     this.completionTime = completionTime;
102 105
     this.registrationTime = registrationTime;
103 106
     this.type = type;
104 107
     this.location = location;
105 108
     this.cargo = cargo;
106
-    this.carrierMovement = null;
107
-    this.carrierMovement = carrierMovement;
108 109
   }
109 110
 
110 111
   /**
111 112
    * @param cargo            cargo
112 113
    * @param completionTime   completion time, the reported time that the event actually happened (e.g. the receive took place).
113 114
    * @param registrationTime registration time, the time the message is received
114
-   * @param type             type of event. Legal values are LOAD and UNLOAD
115
+   * @param type             type of event
115 116
    * @param location         where the event took place
116 117
    */
117
-  public HandlingEvent(final Cargo cargo, final Date completionTime, final Date registrationTime, final Type type, final Location location) {
118
+  public HandlingEvent(Cargo cargo, Date completionTime, Date registrationTime, Type type, Location location) {
118 119
     Validate.noNullElements(new Object[] {cargo, completionTime, registrationTime, type, location});
119 120
     if (type.requiresCarrierMovement()) {
120 121
       throw new IllegalArgumentException("Carrier movement is required for event type " + type);
@@ -125,15 +126,15 @@ public final class HandlingEvent implements DomainEvent<HandlingEvent> {
125 126
     this.type = type;
126 127
     this.location = location;
127 128
     this.cargo = cargo;
128
-    this.carrierMovement = null;
129
+    this.voyage = null;
129 130
   }
130 131
 
131 132
   public Type type() {
132 133
     return this.type;
133 134
   }
134 135
 
135
-  public CarrierMovement carrierMovement() {
136
-    return DomainObjectUtils.nullSafe(this.carrierMovement, CarrierMovement.NONE);
136
+  public Voyage voyage() {
137
+    return DomainObjectUtils.nullSafe(this.voyage, Voyage.NONE);
137 138
   }
138 139
 
139 140
   public Date completionTime() {
@@ -165,7 +166,7 @@ public final class HandlingEvent implements DomainEvent<HandlingEvent> {
165 166
   public boolean sameEventAs(final HandlingEvent other) {
166 167
     return other != null && new EqualsBuilder().
167 168
       append(this.cargo, other.cargo).
168
-      append(this.carrierMovement, other.carrierMovement).
169
+      append(this.voyage, other.voyage).
169 170
       append(this.completionTime, other.completionTime).
170 171
       append(this.location, other.location).
171 172
       append(this.type, other.type).
@@ -176,7 +177,7 @@ public final class HandlingEvent implements DomainEvent<HandlingEvent> {
176 177
   public int hashCode() {
177 178
     return new HashCodeBuilder().
178 179
       append(cargo).
179
-      append(carrierMovement).
180
+      append(voyage).
180 181
       append(completionTime).
181 182
       append(location).
182 183
       append(type).

+ 32
- 33
dddsample/src/main/java/se/citerus/dddsample/domain/model/handling/HandlingEventFactory.java Просмотреть файл

@@ -4,15 +4,15 @@ import org.apache.commons.lang.Validate;
4 4
 import se.citerus.dddsample.domain.model.cargo.Cargo;
5 5
 import se.citerus.dddsample.domain.model.cargo.CargoRepository;
6 6
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
7
-import se.citerus.dddsample.domain.model.carrier.CarrierMovement;
8
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
9
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementRepository;
7
+import se.citerus.dddsample.domain.model.carrier.Voyage;
8
+import se.citerus.dddsample.domain.model.carrier.VoyageNumber;
9
+import se.citerus.dddsample.domain.model.carrier.VoyageRepository;
10 10
 import se.citerus.dddsample.domain.model.location.Location;
11 11
 import se.citerus.dddsample.domain.model.location.LocationRepository;
12 12
 import se.citerus.dddsample.domain.model.location.UnLocode;
13
-import se.citerus.dddsample.domain.service.UnknownCarrierMovementIdException;
13
+import se.citerus.dddsample.domain.service.UnknownCargoException;
14 14
 import se.citerus.dddsample.domain.service.UnknownLocationException;
15
-import se.citerus.dddsample.domain.service.UnknownTrackingIdException;
15
+import se.citerus.dddsample.domain.service.UnknownVoyageException;
16 16
 
17 17
 import java.util.Date;
18 18
 
@@ -22,69 +22,68 @@ import java.util.Date;
22 22
 public class HandlingEventFactory {
23 23
 
24 24
   private final CargoRepository cargoRepository;
25
-  private final CarrierMovementRepository carrierMovementRepository;
25
+  private final VoyageRepository voyageRepository;
26 26
   private final LocationRepository locationRepository;
27 27
 
28
-  public HandlingEventFactory(CargoRepository cargoRepository, CarrierMovementRepository carrierMovementRepository, LocationRepository locationRepository) {
28
+  public HandlingEventFactory(CargoRepository cargoRepository, VoyageRepository voyageRepository, LocationRepository locationRepository) {
29 29
     this.cargoRepository = cargoRepository;
30
-    this.carrierMovementRepository = carrierMovementRepository;
30
+    this.voyageRepository = voyageRepository;
31 31
     this.locationRepository = locationRepository;
32 32
   }
33 33
 
34 34
   /**
35 35
    * @param completionTime    when the event was completed, for example finished loading
36 36
    * @param trackingId        tracking id
37
-   * @param carrierMovementId carrier movement id, if applicable (may be null)
37
+   * @param voyageNumber      voyage number
38 38
    * @param unlocode          United Nations Location Code for the location of the event
39 39
    * @param type              type of event
40
-   * @throws UnknownCarrierMovementIdException
40
+   * @throws se.citerus.dddsample.domain.service.UnknownVoyageException
41 41
    *                                    if there's not carrier movement with this id
42
-   * @throws UnknownTrackingIdException if there's no cargo with this tracking id
42
+   * @throws se.citerus.dddsample.domain.service.UnknownCargoException if there's no cargo with this tracking id
43 43
    * @throws UnknownLocationException   if there's no location with this UN Locode
44 44
    * @return A handling event.
45 45
    */
46
-  public HandlingEvent createHandlingEvent(Date completionTime, TrackingId trackingId, CarrierMovementId carrierMovementId, UnLocode unlocode, HandlingEvent.Type type)
47
-    throws UnknownTrackingIdException, UnknownCarrierMovementIdException, UnknownLocationException {
46
+  public HandlingEvent createHandlingEvent(Date completionTime, TrackingId trackingId, VoyageNumber voyageNumber, UnLocode unlocode, HandlingEvent.Type type)
47
+    throws UnknownCargoException, UnknownVoyageException, UnknownLocationException {
48 48
 
49
-    // Carrier movement may be null for certain event types
49
+    // Voyage number may be null for certain event types
50 50
     Validate.noNullElements(new Object[]{completionTime, trackingId, unlocode, type});
51 51
 
52
-    final Cargo cargo = cargoRepository.find(trackingId);
53
-    if (cargo == null) throw new UnknownTrackingIdException(trackingId);
54
-
55
-    final CarrierMovement carrierMovement = findCarrierMovement(carrierMovementId);
56
-
52
+    final Cargo cargo = findCargo(trackingId);
53
+    final Voyage voyage = findVoyage(voyageNumber);
57 54
     final Location location = findLocation(unlocode);
55
+    
58 56
     if (location == null) throw new UnknownLocationException(unlocode);
59 57
 
60 58
     final Date registrationTime = new Date();
61 59
 
62
-    if (carrierMovement == null) {
60
+    if (voyage == null) {
63 61
       return new HandlingEvent(cargo, completionTime, registrationTime, type, location);   
64 62
     } else {
65
-      return new HandlingEvent(cargo, completionTime, registrationTime, type, location, carrierMovement);
63
+      return new HandlingEvent(cargo, completionTime, registrationTime, type, location, voyage);
66 64
     }
67 65
   }
68 66
 
69
-  private CarrierMovement findCarrierMovement(final CarrierMovementId carrierMovementId)
70
-    throws UnknownCarrierMovementIdException {
67
+  private Cargo findCargo(TrackingId trackingId) throws UnknownCargoException {
68
+    final Cargo cargo = cargoRepository.find(trackingId);
69
+    if (cargo == null) throw new UnknownCargoException(trackingId);
70
+    return cargo;
71
+  }
71 72
 
72
-    if (carrierMovementId == null) {
73
+  private Voyage findVoyage(VoyageNumber voyageNumber) throws UnknownVoyageException {
74
+    if (voyageNumber == null) {
73 75
       return null;
74 76
     }
75
-    final CarrierMovement carrierMovement = carrierMovementRepository.find(carrierMovementId);
76
-    if (carrierMovement == null) {
77
-      throw new UnknownCarrierMovementIdException(carrierMovementId);
77
+
78
+    final Voyage voyage = voyageRepository.find(voyageNumber);
79
+    if (voyage == null) {
80
+      throw new UnknownVoyageException(voyageNumber);
78 81
     }
79 82
 
80
-    return carrierMovement;
83
+    return voyage;
81 84
   }
82
-
85
+  
83 86
   private Location findLocation(final UnLocode unlocode) throws UnknownLocationException {
84
-    if (unlocode == null) {
85
-      return Location.UNKNOWN;
86
-    }
87
-
88 87
     final Location location = locationRepository.find(unlocode);
89 88
     if (location == null) {
90 89
       throw new UnknownLocationException(unlocode);

+ 6
- 0
dddsample/src/main/java/se/citerus/dddsample/domain/service/DomainEventNotifier.java Просмотреть файл

@@ -19,4 +19,10 @@ public interface DomainEventNotifier {
19 19
    * @param event handling event
20 20
    */
21 21
   void cargoWasHandled(HandlingEvent event);
22
+
23
+  //void cargoWasMisdirected(Cargo cargo);
24
+
25
+  //void cargoHasArrived(Cargo cargo);
26
+
27
+  //void scheduleWasChanged(Voyage voyage);
22 28
 }

dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownTrackingIdException.java → dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownCargoException.java Просмотреть файл

@@ -5,11 +5,11 @@ import se.citerus.dddsample.domain.model.cargo.TrackingId;
5 5
 /**
6 6
  * Thrown when trying to register an event with an unknown tracking id.
7 7
  */
8
-public final class UnknownTrackingIdException extends Exception {
8
+public final class UnknownCargoException extends Exception {
9 9
 
10 10
   private final TrackingId trackingId;
11 11
 
12
-  public UnknownTrackingIdException(final TrackingId trackingId) {
12
+  public UnknownCargoException(final TrackingId trackingId) {
13 13
     this.trackingId = trackingId;
14 14
   }
15 15
 

+ 0
- 20
dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownCarrierMovementIdException.java Просмотреть файл

@@ -1,20 +0,0 @@
1
-package se.citerus.dddsample.domain.service;
2
-
3
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
4
-
5
-/**
6
- * Thrown when trying to register an event with an unknown carrier movement id.
7
- */
8
-public class UnknownCarrierMovementIdException extends Exception {
9
-
10
-  private final CarrierMovementId carrierMovementId;
11
-
12
-  public UnknownCarrierMovementIdException(final CarrierMovementId carrierMovementId) {
13
-    this.carrierMovementId = carrierMovementId;
14
-  }
15
-
16
-  @Override
17
-  public String getMessage() {
18
-    return "No carrier movement with id " + carrierMovementId.idString() + " exists in the system";
19
-  }
20
-}

+ 20
- 0
dddsample/src/main/java/se/citerus/dddsample/domain/service/UnknownVoyageException.java Просмотреть файл

@@ -0,0 +1,20 @@
1
+package se.citerus.dddsample.domain.service;
2
+
3
+import se.citerus.dddsample.domain.model.carrier.VoyageNumber;
4
+
5
+/**
6
+ * Thrown when trying to register an event with an unknown carrier movement id.
7
+ */
8
+public class UnknownVoyageException extends Exception {
9
+
10
+  private final VoyageNumber voyageNumber;
11
+
12
+  public UnknownVoyageException(VoyageNumber voyageNumber) {
13
+    this.voyageNumber = voyageNumber;
14
+  }
15
+
16
+  @Override
17
+  public String getMessage() {
18
+    return "No voyage with number " + voyageNumber.idString() + " exists in the system";
19
+  }
20
+}

+ 8
- 16
dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/TrackingServiceImpl.java Просмотреть файл

@@ -6,14 +6,17 @@ import org.apache.commons.logging.LogFactory;
6 6
 import se.citerus.dddsample.domain.model.cargo.Cargo;
7 7
 import se.citerus.dddsample.domain.model.cargo.CargoRepository;
8 8
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
9
+import se.citerus.dddsample.domain.service.DomainEventNotifier;
9 10
 import se.citerus.dddsample.domain.service.TrackingService;
10 11
 
11 12
 public class TrackingServiceImpl implements TrackingService {
12 13
 
14
+  private final DomainEventNotifier domainEventNotifier;
13 15
   private final CargoRepository cargoRepository;
14 16
   private final Log logger = LogFactory.getLog(getClass());
15 17
 
16
-  public TrackingServiceImpl(CargoRepository cargoRepository) {
18
+  public TrackingServiceImpl(DomainEventNotifier domainEventNotifier, CargoRepository cargoRepository) {
19
+    this.domainEventNotifier = domainEventNotifier;
17 20
     this.cargoRepository = cargoRepository;
18 21
   }
19 22
 
@@ -38,27 +41,16 @@ public class TrackingServiceImpl implements TrackingService {
38 41
       return;
39 42
     }
40 43
 
41
-    cargo.updateState();
44
+    // TODO publish events here
42 45
 
43
-    // Using a listener pattern and registering handlers for different scenarios
44
-    // would be more in line with the open-close principle (?)
45 46
     if (cargo.isMisdirected()) {
46
-      handleMisdirectedCargo(cargo);
47
+      //domainEventNotifier.cargoWasMisdirected(cargo);
47 48
     }
48 49
 
49 50
     if (cargo.isUnloadedAtDestination()) {
50
-      notifyCustomerOfAvailability(cargo);
51
+      //domainEventNotifier.cargoHasArrived(cargo);
51 52
     }
52
-  }
53
-
54
-  private void notifyCustomerOfAvailability(Cargo cargo) {
55
-    logger.info("Cargo " + cargo.trackingId() + " has been unloaded " +
56
-                "at its final destination " + cargo.destination());
57
-  }
58
-
59
-  private void handleMisdirectedCargo(Cargo cargo) {
60
-    logger.info("Cargo " + cargo.trackingId() + " has been misdirected. " +
61
-                "Last event was " + cargo.deliveryHistory().lastEvent());
53
+    
62 54
   }
63 55
 
64 56
 }

+ 12
- 12
dddsample/src/main/java/se/citerus/dddsample/ui/CargoTrackingViewAdapter.java Просмотреть файл

@@ -2,8 +2,8 @@ package se.citerus.dddsample.ui;
2 2
 
3 3
 import org.springframework.context.MessageSource;
4 4
 import se.citerus.dddsample.domain.model.cargo.Cargo;
5
-import se.citerus.dddsample.domain.model.cargo.DeliveryHistory;
6
-import se.citerus.dddsample.domain.model.carrier.CarrierMovement;
5
+import se.citerus.dddsample.domain.model.cargo.Delivery;
6
+import se.citerus.dddsample.domain.model.carrier.Voyage;
7 7
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
8 8
 import se.citerus.dddsample.domain.model.location.Location;
9 9
 
@@ -35,7 +35,7 @@ public final class CargoTrackingViewAdapter {
35 35
     this.locale = locale;
36 36
     this.cargo = cargo;
37 37
 
38
-    final List<HandlingEvent> handlingEvents = cargo.deliveryHistory().eventsOrderedByCompletionTime();
38
+    final List<HandlingEvent> handlingEvents = cargo.deliveryHistory().history();
39 39
     this.events = new ArrayList<HandlingEventViewAdapter>(handlingEvents.size());
40 40
     for (HandlingEvent handlingEvent : handlingEvents) {
41 41
       events.add(new HandlingEventViewAdapter(handlingEvent));
@@ -61,16 +61,16 @@ public final class CargoTrackingViewAdapter {
61 61
    * @return A translated string describing the cargo status. 
62 62
    */
63 63
   public String getStatusText() {
64
-    final DeliveryHistory deliveryHistory = cargo.deliveryHistory();
65
-    final String code = "cargo.status." + deliveryHistory.status().name();
64
+    final Delivery delivery = cargo.deliveryHistory();
65
+    final String code = "cargo.status." + delivery.status().name();
66 66
 
67 67
     final Object[] args;
68
-    switch (deliveryHistory.status()) {
68
+    switch (delivery.status()) {
69 69
       case IN_PORT:
70
-        args = new Object[] {getDisplayText(deliveryHistory.currentLocation())};
70
+        args = new Object[] {getDisplayText(delivery.currentLocation())};
71 71
         break;
72 72
       case ONBOARD_CARRIER:
73
-        args = new Object[] {deliveryHistory.currentCarrierMovement().carrierMovementId().idString()};
73
+        args = new Object[] {delivery.currentVoyage().voyageNumber().idString()};
74 74
         break;
75 75
       case CLAIMED:
76 76
       case NOT_RECEIVED:
@@ -150,11 +150,11 @@ public final class CargoTrackingViewAdapter {
150 150
     }
151 151
 
152 152
     /**
153
-     * @return Carrier movement id, or empty string if not applicable.
153
+     * @return Voyage number, or empty string if not applicable.
154 154
      */
155
-    public String getCarrierMovement() {
156
-      final CarrierMovement cm = handlingEvent.carrierMovement();
157
-      return cm.carrierMovementId().idString();
155
+    public String getVoyageNumber() {
156
+      final Voyage voyage = handlingEvent.voyage();
157
+      return voyage.voyageNumber().idString();
158 158
     }
159 159
 
160 160
     /**