ソースを参照

Merged changes from 1.0 branch back to trunk

peter_backlund 18 年 前
コミット
d834457a58
共有26 個のファイルを変更した238 個の追加209 個の削除を含む
  1. バイナリ
      dddsample/doc/tracking.jpg
  2. 3
    6
      dddsample/pom.xml
  3. 2
    0
      dddsample/src/main/java/se/citerus/dddsample/application/messaging/HandlingEventMessageDelegate.java
  4. 0
    1
      dddsample/src/main/java/se/citerus/dddsample/application/messaging/JmsDomainEventNotifierImpl.java
  5. 7
    2
      dddsample/src/main/java/se/citerus/dddsample/application/remoting/BookingServiceFacadeImpl.java
  6. 4
    4
      dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/assembler/CargoRoutingDTOAssembler.java
  7. 33
    15
      dddsample/src/main/java/se/citerus/dddsample/application/ws/HandlingEventServiceEndpointImpl.java
  8. 2
    1
      dddsample/src/main/java/se/citerus/dddsample/domain/model/Specification.java
  9. 0
    1
      dddsample/src/main/java/se/citerus/dddsample/domain/model/handling/HandlingEventRepository.java
  10. 0
    10
      dddsample/src/main/java/se/citerus/dddsample/domain/model/location/Location.java
  11. 0
    4
      dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/BookingServiceImpl.java
  12. 0
    2
      dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/HandlingEventServiceImpl.java
  13. 3
    7
      dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/TrackingServiceImpl.java
  14. 2
    45
      dddsample/src/main/resources/context-remote.xml
  15. 7
    0
      dddsample/src/main/resources/context-service.xml
  16. 1
    1
      dddsample/src/main/resources/log4j.properties
  17. 3
    0
      dddsample/src/main/webapp/WEB-INF/jsp/cargo/track.jsp
  18. 2
    2
      dddsample/src/main/webapp/style.css
  19. 34
    5
      dddsample/src/site/apt/characterization.apt
  20. 110
    7
      dddsample/src/site/apt/download.apt
  21. 8
    3
      dddsample/src/site/apt/index.apt
  22. 7
    11
      dddsample/src/site/apt/roadmap.apt
  23. 2
    2
      dddsample/src/site/site.xml
  24. 6
    6
      dddsample/src/test/java/se/citerus/dddsample/application/service/dto/assembler/CargoRoutingDTOAssemblerTest.java
  25. 2
    0
      dddsample/src/test/java/se/citerus/dddsample/application/ws/HandlinEventServiceEndpointTest.java
  26. 0
    74
      dddsample/src/test/java/se/citerus/dddsample/domain/service/RoutingScenarioTest.java

バイナリ
dddsample/doc/tracking.jpg ファイルの表示


+ 3
- 6
dddsample/pom.xml ファイルの表示

@@ -1,13 +1,10 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<project xmlns="http://maven.apache.org/POM/4.0.0"
3
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
1
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5 2
   <modelVersion>4.0.0</modelVersion>
6 3
   <groupId>se.citerus</groupId>
7 4
   <artifactId>dddsample</artifactId>
8 5
   <packaging>war</packaging>
9 6
   <name>DDDSample</name>
10
-  <version>1.0-SNAPSHOT</version>
7
+  <version>1.1-SNAPSHOT</version>
11 8
   <description>This application shows a few key concepts of
12 9
     Domain Driven Design implemented in Enterprise Java.
13 10
   </description>
@@ -18,7 +15,7 @@
18 15
       <url>scp://shell.sf.net/home/groups/d/dd/dddsample/htdocs</url>
19 16
     </site>
20 17
   </distributionManagement>
21
-  <ciManagement/>
18
+  <ciManagement />
22 19
   <repositories>
23 20
     <repository>
24 21
       <id>maven2-repository.dev.java.net</id>

+ 2
- 0
dddsample/src/main/java/se/citerus/dddsample/application/messaging/HandlingEventMessageDelegate.java ファイルの表示

@@ -2,6 +2,7 @@ package se.citerus.dddsample.application.messaging;
2 2
 
3 3
 import org.apache.commons.logging.Log;
4 4
 import org.apache.commons.logging.LogFactory;
5
+import org.springframework.transaction.annotation.Transactional;
5 6
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
6 7
 import se.citerus.dddsample.domain.service.TrackingService;
7 8
 
@@ -22,6 +23,7 @@ public class HandlingEventMessageDelegate implements MessageListener {
22 23
   private TrackingService trackingService;
23 24
   private final Log logger = LogFactory.getLog(getClass());
24 25
 
26
+  @Transactional(readOnly = true)  
25 27
   public void onMessage(final Message message) {
26 28
     if (logger.isDebugEnabled()) {
27 29
       logger.debug("Received message " + message);

+ 0
- 1
dddsample/src/main/java/se/citerus/dddsample/application/messaging/JmsDomainEventNotifierImpl.java ファイルの表示

@@ -18,7 +18,6 @@ public final class JmsDomainEventNotifierImpl implements DomainEventNotifier {
18 18
 
19 19
   public void cargoWasHandled(final HandlingEvent event) {
20 20
     jmsOperations.send(destination, new MessageCreator() {
21
-      // TODO: richer message type
22 21
       public Message createMessage(final Session session) throws JMSException {
23 22
         final MapMessage message = session.createMapMessage();
24 23
         message.setStringProperty(TRACKING_ID_KEY, event.cargo().trackingId().idString());

+ 7
- 2
dddsample/src/main/java/se/citerus/dddsample/application/remoting/BookingServiceFacadeImpl.java ファイルの表示

@@ -1,5 +1,6 @@
1 1
 package se.citerus.dddsample.application.remoting;
2 2
 
3
+import org.springframework.transaction.annotation.Transactional;
3 4
 import se.citerus.dddsample.application.remoting.dto.CargoRoutingDTO;
4 5
 import se.citerus.dddsample.application.remoting.dto.ItineraryCandidateDTO;
5 6
 import se.citerus.dddsample.application.remoting.dto.LocationDTO;
@@ -35,30 +36,33 @@ public class BookingServiceFacadeImpl implements BookingServiceFacade {
35 36
   private CargoRepository cargoRepository;
36 37
   private CarrierMovementRepository carrierMovementRepository;
37 38
 
39
+  @Transactional(readOnly = true)
38 40
   public List<LocationDTO> listShippingLocations() {
39 41
     final List<Location> allLocations = locationRepository.findAll();
40 42
     final LocationDTOAssembler assembler = new LocationDTOAssembler();
41 43
     return assembler.toDTOList(allLocations);
42 44
   }
43 45
 
46
+  @Transactional(readOnly = false)
44 47
   public String registerNewCargo(String origin, String destination) {
45 48
     TrackingId trackingId = bookingService.bookNewCargo(new UnLocode(origin), new UnLocode(destination));
46 49
     return trackingId.idString();
47 50
   }
48 51
 
52
+  @Transactional(readOnly = true)
49 53
   public CargoRoutingDTO loadCargoForRouting(String trackingId) {
50
-    // TODO lock
51 54
     final Cargo cargo = cargoRepository.find(new TrackingId(trackingId));
52 55
     final CargoRoutingDTOAssembler assembler = new CargoRoutingDTOAssembler();
53 56
     return assembler.toDTO(cargo);
54 57
   }
55 58
 
59
+  @Transactional(readOnly = false)
56 60
   public void assignCargoToRoute(String trackingId, ItineraryCandidateDTO itineraryCandidateDTO) {
57 61
     final Itinerary itinerary = new ItineraryCandidateDTOAssembler().fromDTO(itineraryCandidateDTO, carrierMovementRepository, locationRepository);
58 62
     bookingService.assignCargoToRoute(new TrackingId(trackingId), itinerary);
59
-    // TODO unlock
60 63
   }
61 64
 
65
+  @Transactional(readOnly = true)
62 66
   public List<CargoRoutingDTO> listAllCargos() {
63 67
     final List<Cargo> cargoList = cargoRepository.findAll();
64 68
     final List<CargoRoutingDTO> dtoList = new ArrayList<CargoRoutingDTO>(cargoList.size());
@@ -69,6 +73,7 @@ public class BookingServiceFacadeImpl implements BookingServiceFacade {
69 73
     return dtoList;
70 74
   }
71 75
 
76
+  @Transactional(readOnly = true)
72 77
   public List<ItineraryCandidateDTO> requestPossibleRoutesForCargo(String trackingId) throws RemoteException {
73 78
     final List<Itinerary> itineraries = bookingService.requestPossibleRoutesForCargo(new TrackingId(trackingId));
74 79
 

+ 4
- 4
dddsample/src/main/java/se/citerus/dddsample/application/remoting/dto/assembler/CargoRoutingDTOAssembler.java ファイルの表示

@@ -12,14 +12,14 @@ public class CargoRoutingDTOAssembler {
12 12
   public CargoRoutingDTO toDTO(final Cargo cargo) {
13 13
     final CargoRoutingDTO dto = new CargoRoutingDTO(
14 14
       cargo.trackingId().idString(),
15
-      cargo.origin().toString(),
16
-      cargo.destination().toString()
15
+      cargo.origin().unLocode().idString(),
16
+      cargo.destination().unLocode().idString()
17 17
     );
18 18
     for (Leg leg : cargo.itinerary().legs()) {
19 19
       dto.addLeg(
20 20
         leg.carrierMovement().carrierMovementId().idString(),
21
-        leg.from().toString(),
22
-        leg.to().toString()
21
+        leg.from().unLocode().idString(),
22
+        leg.to().unLocode().idString()
23 23
       );
24 24
     }
25 25
     return dto;

+ 33
- 15
dddsample/src/main/java/se/citerus/dddsample/application/ws/HandlingEventServiceEndpointImpl.java ファイルの表示

@@ -3,12 +3,17 @@ package se.citerus.dddsample.application.ws;
3 3
 import org.apache.commons.lang.StringUtils;
4 4
 import org.apache.commons.logging.Log;
5 5
 import org.apache.commons.logging.LogFactory;
6
+import org.springframework.transaction.PlatformTransactionManager;
7
+import org.springframework.transaction.TransactionStatus;
8
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
9
+import org.springframework.transaction.support.TransactionTemplate;
6 10
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
7 11
 import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
8 12
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
9 13
 import se.citerus.dddsample.domain.model.location.UnLocode;
10 14
 import se.citerus.dddsample.domain.service.HandlingEventService;
11 15
 import se.citerus.dddsample.domain.service.UnknownCarrierMovementIdException;
16
+import se.citerus.dddsample.domain.service.UnknownLocationException;
12 17
 import se.citerus.dddsample.domain.service.UnknownTrackingIdException;
13 18
 
14 19
 import javax.jws.WebService;
@@ -20,41 +25,49 @@ import java.util.Date;
20 25
 public class HandlingEventServiceEndpointImpl implements HandlingEventServiceEndpoint {
21 26
 
22 27
   private HandlingEventService handlingEventService;
28
+  private TransactionTemplate transactionTemplate;
23 29
   private final Log logger = LogFactory.getLog(getClass());
24 30
   protected static final String ISO_8601_FORMAT = "yyyy-mm-dd HH:MM:SS.SSS";
25 31
 
26 32
   public void register(final String completionTime, final String trackingId, final String carrierMovementId,
27 33
                        final String unlocode, final String eventType) {
28 34
     try {
29
-      Date date = parseIso8601Date(completionTime);
30
-      TrackingId tid = new TrackingId(trackingId);
31
-      CarrierMovementId cid;
35
+      final Date date = parseIso8601Date(completionTime);
36
+      final TrackingId tid = new TrackingId(trackingId);
37
+      final CarrierMovementId cid;
32 38
       if (StringUtils.isNotEmpty(carrierMovementId)) {
33 39
         cid = new CarrierMovementId(carrierMovementId);
34 40
       } else {
35 41
         cid = null;
36 42
       }
37
-      HandlingEvent.Type type = parseEventType(eventType);
43
+      final HandlingEvent.Type type = parseEventType(eventType);
38 44
 
39
-      UnLocode ul = new UnLocode(unlocode);
45
+      final UnLocode ul = new UnLocode(unlocode);
40 46
 
41
-      handlingEventService.register(date, tid, cid, ul, type);
47
+      // Using programmatic demarcation here due to weaving conflicts
48
+      // between jax-ws and Spring transaction annotations
49
+      transactionTemplate.execute(new TransactionCallbackWithoutResult() {
50
+          protected void doInTransactionWithoutResult(TransactionStatus status) {
51
+              try {
52
+
53
+                  handlingEventService.register(date, tid, cid, ul, type);
54
+
55
+              } catch (UnknownCarrierMovementIdException e) {
56
+                  handleUnknownCarrierMovementId(e);
57
+              } catch (UnknownTrackingIdException e) {
58
+                  handleUnknownTrackingId(e);
59
+              } catch (UnknownLocationException e) {
60
+                  handleOtherError(e);
61
+              }
62
+          }
63
+      });
42 64
 
43 65
     } catch (IllegalArgumentException iae) {
44 66
       handleIllegalArgument(iae);
45
-
46 67
     } catch (ParseException pe) {
47 68
       handleInvalidDateFormat(completionTime);
48
-
49
-    } catch (UnknownTrackingIdException utid) {
50
-      handleUnknownTrackingId(utid);
51
-
52
-    } catch (UnknownCarrierMovementIdException ucmi) {
53
-      handleUnknownCarrierMovementId(ucmi);
54
-
55 69
     } catch (InvalidEventTypeException iete) {
56 70
       handleInvalidEventType(iete);
57
-
58 71
     } catch (Exception e) {
59 72
       handleOtherError(e);
60 73
     }
@@ -99,4 +112,9 @@ public class HandlingEventServiceEndpointImpl implements HandlingEventServiceEnd
99 112
   public void setHandlingEventService(final HandlingEventService handlingEventService) {
100 113
     this.handlingEventService = handlingEventService;
101 114
   }
115
+
116
+  public void setTransactionManager(PlatformTransactionManager transactionManager) {
117
+      transactionTemplate = new TransactionTemplate(transactionManager);
118
+  }
119
+
102 120
 }

+ 2
- 1
dddsample/src/main/java/se/citerus/dddsample/domain/model/Specification.java ファイルの表示

@@ -1,6 +1,7 @@
1 1
 package se.citerus.dddsample.domain.model;
2 2
 
3 3
 public interface Specification<T> {
4
-  // TODO replace with Specification project dependency
4
+
5 5
   boolean isSatisfiedBy(T t);
6
+    
6 7
 }

+ 0
- 1
dddsample/src/main/java/se/citerus/dddsample/domain/model/handling/HandlingEventRepository.java ファイルの表示

@@ -17,7 +17,6 @@ public interface HandlingEventRepository {
17 17
   void save(final HandlingEvent event);
18 18
 
19 19
 
20
-  // TODO: remove this in 1.0 branch, it's not used anywhere
21 20
   /**
22 21
    * @param trackingId cargo tracking id
23 22
    * @return All handling events for this cargo, ordered by completion time.

+ 0
- 10
dddsample/src/main/java/se/citerus/dddsample/domain/model/location/Location.java ファイルの表示

@@ -80,16 +80,6 @@ public final class Location implements Entity<Location> {
80 80
     return unLocode.hashCode();
81 81
   }
82 82
 
83
-  /**
84
-   * @return Unlocode and name, on the format "SESTO (Stockholm)"
85
-   */
86
-  @Override
87
-  public String toString() {
88
-    // TODO: this feels like presentation logic and is very inconsistent, move to DTO assembler
89
-    return unLocode.idString() + " (" + name + ")";
90
-  }
91
-
92
-
93 83
   Location() {
94 84
     // Needed by Hibernate
95 85
   }

+ 0
- 4
dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/BookingServiceImpl.java ファイルの表示

@@ -3,7 +3,6 @@ package se.citerus.dddsample.domain.service.impl;
3 3
 import org.apache.commons.lang.Validate;
4 4
 import org.apache.commons.logging.Log;
5 5
 import org.apache.commons.logging.LogFactory;
6
-import org.springframework.transaction.annotation.Transactional;
7 6
 import se.citerus.dddsample.domain.model.cargo.*;
8 7
 import se.citerus.dddsample.domain.model.location.Location;
9 8
 import se.citerus.dddsample.domain.model.location.LocationRepository;
@@ -22,7 +21,6 @@ public final class BookingServiceImpl implements BookingService {
22 21
 
23 22
   private final Log logger = LogFactory.getLog(getClass());
24 23
 
25
-  @Transactional(readOnly = false)
26 24
   public TrackingId bookNewCargo(final UnLocode originUnLocode, final UnLocode destinationUnLocode) {
27 25
     Validate.notNull(originUnLocode);
28 26
     Validate.notNull(destinationUnLocode);
@@ -38,7 +36,6 @@ public final class BookingServiceImpl implements BookingService {
38 36
     return cargo.trackingId();
39 37
   }
40 38
 
41
-  @Transactional(readOnly = true)
42 39
   public List<Itinerary> requestPossibleRoutesForCargo(TrackingId trackingId) {
43 40
     Validate.notNull(trackingId);
44 41
     
@@ -48,7 +45,6 @@ public final class BookingServiceImpl implements BookingService {
48 45
     return routingService.fetchRoutesForSpecification(routeSpecification);
49 46
   }
50 47
 
51
-  @Transactional(readOnly = false)
52 48
   public void assignCargoToRoute(final TrackingId trackingId, final Itinerary newItinerary) {
53 49
     Validate.notNull(trackingId);
54 50
     Validate.notNull(newItinerary);

+ 0
- 2
dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/HandlingEventServiceImpl.java ファイルの表示

@@ -1,7 +1,6 @@
1 1
 package se.citerus.dddsample.domain.service.impl;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import org.springframework.transaction.annotation.Transactional;
5 4
 import se.citerus.dddsample.domain.model.cargo.Cargo;
6 5
 import se.citerus.dddsample.domain.model.cargo.CargoRepository;
7 6
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
@@ -24,7 +23,6 @@ public final class HandlingEventServiceImpl implements HandlingEventService {
24 23
   private LocationRepository locationRepository;
25 24
   private DomainEventNotifier domainEventNotifier;
26 25
 
27
-  @Transactional(readOnly = false)
28 26
   public void register(final Date completionTime, final TrackingId trackingId, final CarrierMovementId carrierMovementId,
29 27
                        final UnLocode unlocode, final HandlingEvent.Type type)
30 28
     throws UnknownCarrierMovementIdException, UnknownTrackingIdException, UnknownLocationException {

+ 3
- 7
dddsample/src/main/java/se/citerus/dddsample/domain/service/impl/TrackingServiceImpl.java ファイルの表示

@@ -3,7 +3,6 @@ package se.citerus.dddsample.domain.service.impl;
3 3
 import org.apache.commons.lang.Validate;
4 4
 import org.apache.commons.logging.Log;
5 5
 import org.apache.commons.logging.LogFactory;
6
-import org.springframework.transaction.annotation.Transactional;
7 6
 import se.citerus.dddsample.domain.model.cargo.Cargo;
8 7
 import se.citerus.dddsample.domain.model.cargo.CargoRepository;
9 8
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
@@ -15,20 +14,18 @@ public class TrackingServiceImpl implements TrackingService {
15 14
 
16 15
   private final Log logger = LogFactory.getLog(getClass());
17 16
 
18
-  @Transactional(readOnly = true)
19 17
   public Cargo track(final TrackingId trackingId) {
20 18
     Validate.notNull(trackingId);
21 19
 
22 20
     return cargoRepository.find(trackingId);
23 21
   }
24 22
 
25
-  @Transactional(readOnly = true)
26 23
   public void inspectCargo(final TrackingId trackingId) {
27 24
     Validate.notNull(trackingId);
28 25
 
29 26
     final Cargo cargo = cargoRepository.find(trackingId);
30 27
     if (cargo == null) {
31
-      logger.warn("Can't notify listeners for non-existing cargo " + trackingId);
28
+      logger.warn("Can't inspect non-existing cargo " + trackingId);
32 29
       return;
33 30
     }
34 31
 
@@ -41,14 +38,13 @@ public class TrackingServiceImpl implements TrackingService {
41 38
   }
42 39
 
43 40
   private void notifyCustomerOfAvailability(Cargo cargo) {
44
-    // TODO: more elaborate notifications
45 41
     logger.info("Cargo " + cargo.trackingId() + " has been unloaded " +
46
-      "at its final destination " + cargo.destination());
42
+                "at its final destination " + cargo.destination());
47 43
   }
48 44
 
49 45
   private void handleMisdirectedCargo(Cargo cargo) {
50 46
     logger.info("Cargo " + cargo.trackingId() + " has been misdirected. " +
51
-      "Last event was " + cargo.deliveryHistory().lastEvent());
47
+                "Last event was " + cargo.deliveryHistory().lastEvent());
52 48
   }
53 49
 
54 50
   public void setCargoRepository(CargoRepository cargoRepository) {

+ 2
- 45
dddsample/src/main/resources/context-remote.xml ファイルの表示

@@ -4,16 +4,13 @@
4 4
        xmlns:ws="http://jax-ws.dev.java.net/spring/core"
5 5
        xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
6 6
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
7
-       xmlns:aop="http://www.springframework.org/schema/aop"
8 7
        xsi:schemaLocation="
9 8
         http://jax-ws.dev.java.net/spring/core https://jax-ws.dev.java.net/spring/core.xsd
10 9
         http://jax-ws.dev.java.net/spring/servlet https://jax-ws.dev.java.net/spring/servlet.xsd
11
-        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
12 10
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
13 11
 
14 12
 
15 13
   <!-- Handling event registration web service -->
16
-
17 14
   
18 15
   <wss:bindings id="jax-ws.http">
19 16
     <wss:bindings>
@@ -27,51 +24,11 @@
27 24
 
28 25
   <bean id="handlingEventServiceEndpoint" class="se.citerus.dddsample.application.ws.HandlingEventServiceEndpointImpl">
29 26
     <property name="handlingEventService" ref="handlingEventService"/>
27
+    <property name="transactionManager" ref="transactionManager"/>
30 28
   </bean>
31 29
 
32 30
 
33
-  <!-- Booking service facade -->
34
-
35
-  
36
-  <!-- Hibernate interceptor -->
37
-  <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
38
-    <property name="sessionFactory" ref="sessionFactory"/>
39
-  </bean>
40
-
41
-  <!-- Facade wrapped with Hibernate interceptor -->
42
-  <bean id="bookingServiceFacade" class="org.springframework.aop.framework.ProxyFactoryBean">
43
-    <property name="interceptorNames">
44
-      <list>
45
-        <value>hibernateInterceptor</value>
46
-      </list>
47
-    </property>
48
-    <property name="target">
49
-      <bean class="se.citerus.dddsample.application.remoting.BookingServiceFacadeImpl">
50
-        <property name="bookingService" ref="bookingService"/>
51
-        <property name="cargoRepository" ref="cargoRepository"/>
52
-        <property name="locationRepository" ref="locationRepository"/>
53
-        <property name="carrierMovementRepository" ref="carrierMovementRepository"/>
54
-      </bean>
55
-    </property>
56
-  </bean>
57
-
58
-  <!-- Wrap all methods with Hibernate interceptor
59
-  TODO: add necessary aspectj deps and replace config above with this
60
-  
61
-  <bean id="bookingServiceFacade" class="se.citerus.dddsample.application.remote.BookingServiceFacadeImpl">
62
-    <property name="bookingService" ref="bookingService"/>
63
-    <property name="cargoRepository" ref="cargoRepository"/>
64
-    <property name="locationRepository" ref="locationRepository"/>
65
-    <property name="carrierMovementRepository" ref="carrierMovementRepository"/>
66
-  </bean>
67
-
68
-  <aop:config>
69
-    <aop:advisor advice-ref="hibernateInterceptor"
70
-                 pointcut="execution (* se.citerus.dddsample.application.remote.BookingServiceFacadeImpl(..))"/>
71
-  </aop:config>
72
-  -->
73
-
74
-  <!-- RMI exposure -->
31
+  <!-- RMI exposed booking service facade -->
75 32
   <bean id="rmiBookingServiceFacade" class="org.springframework.remoting.rmi.RmiServiceExporter">
76 33
     <property name="serviceInterface" value="se.citerus.dddsample.application.remoting.BookingServiceFacade"/>
77 34
     <property name="service" ref="bookingServiceFacade"/>

+ 7
- 0
dddsample/src/main/resources/context-service.xml ファイルの表示

@@ -33,4 +33,11 @@
33 33
     <property name="graphTraversalService" ref="graphTraversalService"/>
34 34
   </bean>
35 35
 
36
+  <bean id="bookingServiceFacade" class="se.citerus.dddsample.application.remoting.BookingServiceFacadeImpl">
37
+    <property name="bookingService" ref="bookingService"/>
38
+    <property name="cargoRepository" ref="cargoRepository"/>
39
+    <property name="locationRepository" ref="locationRepository"/>
40
+    <property name="carrierMovementRepository" ref="carrierMovementRepository"/>
41
+  </bean>
42
+  
36 43
 </beans>

+ 1
- 1
dddsample/src/main/resources/log4j.properties ファイルの表示

@@ -1,4 +1,4 @@
1
-log4j.rootLogger=info, stdout, logfile
1
+log4j.rootLogger=info, stdout
2 2
 
3 3
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
4 4
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

+ 3
- 0
dddsample/src/main/webapp/WEB-INF/jsp/cargo/track.jsp ファイルの表示

@@ -29,6 +29,9 @@
29 29
     </table>
30 30
   </form:form>
31 31
   </div>
32
+  <c:if test="${cargo == null}">
33
+    <p><em>Hint: try tracking "XYZ" or "JKL".</em></p>  
34
+  </c:if>
32 35
 
33 36
   <c:if test="${cargo != null}">
34 37
     <div id="result">

+ 2
- 2
dddsample/src/main/webapp/style.css ファイルの表示

@@ -130,9 +130,9 @@ textarea,
130 130
 select {
131 131
   padding: 1px;
132 132
   font: 400 1em verdana, sans-serif;
133
-  color: #999;
133
+  color: black;
134 134
   background: #EEE;
135
-  border: 1px solid #CCC;
135
+  border: 1px solid #555;
136 136
 }
137 137
 
138 138
 input:focus,

+ 34
- 5
dddsample/src/site/apt/characterization.apt ファイルの表示

@@ -29,7 +29,15 @@
29 29
 
30 30
 {Aggregates}
31 31
 
32
-    In real life most things are connected, directly or indirectly. Mimicking this approach when building large software systems tend to bring unnecessary complexity and poor performance. DDD provides tactics to help you sort these things out, aggregates being one of the most important ones. Aggregates help with decoupling of large structures by setting rules for relations between entities. Aggregates can also have properties, methods, and invariants that doesn't fit within one single class. Java and other OO-languages typically miss specific language constructs to handle aggregates and in the sample application responsibilities that belong to an aggregate is most often implemented in the aggregate root.

    <<<{{{xref/se/citerus/dddsample/domain/model/cargo/package-summary.html}cargo}}>>>: cargo is the central aggregate in the sample application. <<<Cargo>>> is the aggregate root and the aggregate also contains the <Value Objects> <<<DeliveryHistory>>>, <<<Itinereray>>>, <<<Leg>>> and a few more classes. 

    <<<{{{xref/se/citerus/dddsample/domain/model/handling/package-summary.html}handling}}>>>: handling is another important aggregate. It contains the HandlingEvents that are registered throughout a cargo's progress from <<<RECEIVED>>> to <<<CLAIMED>>>. The <<<HandlingEvent>>>s have a relation to the <<<Cargo>>> for which the event belongs, this is allowed since <<<HandlingEvent>>> is an aggregate root and so is <<<Cargo>>>. 

    The main reason for not making <<<HandlingEvent>>> part of the cargo aggregate is performance. <<<HandlingEvent>>>s are received from external parties and systems, e.g. warehouse management systems, port handling systems, that call our <<<{{{xref/se/citerus/dddsample/domain/service/HandlingEventService.html}HandlingEventService}}>>> webservice. The number of events can be very high and it is important that our webservice can dispatch the remote calls quickly. To be able to support this use case we need to handle the remote webservice calls asynchronously, i.e. we do not want to load the big cargo structure for each received <<<HandlingEvent>>>. Since all relationships in an aggregate must be handled synchronously we put the <<<HandlingEvent>>> in an aggregate of its own and we are able processes the events quickly and at the same time eliminate dead-locking situations in the system.

    <Editors note: We are aware that this example may need a little more work to drive the full benefits of aggregates home. This is one of the problems with a small sample app, real-world complexity is hard to simulate.>
32
+    In real life most things are connected, directly or indirectly. Mimicking this approach when building large software systems tend to bring unnecessary complexity and poor performance. DDD provides tactics to help you sort these things out, aggregates being one of the most important ones. Aggregates help with decoupling of large structures by setting rules for relations between entities. Aggregates can also have properties, methods, and invariants that doesn't fit within one single class. Java and other OO-languages typically miss specific language constructs to handle aggregates and in the sample application responsibilities that belong to an aggregate is most often implemented in the aggregate root.
33
+
34
+    <<<{{{xref/se/citerus/dddsample/domain/model/cargo/package-summary.html}cargo}}>>>: cargo is the central aggregate in the sample application. <<<Cargo>>> is the aggregate root and the aggregate also contains the <Value Objects> <<<DeliveryHistory>>>, <<<Itinereray>>>, <<<Leg>>> and a few more classes. 
35
+
36
+    <<<{{{xref/se/citerus/dddsample/domain/model/handling/package-summary.html}handling}}>>>: handling is another important aggregate. It contains the HandlingEvents that are registered throughout a cargo's progress from <<<RECEIVED>>> to <<<CLAIMED>>>. The <<<HandlingEvent>>>s have a relation to the <<<Cargo>>> for which the event belongs, this is allowed since <<<HandlingEvent>>> is an aggregate root and so is <<<Cargo>>>. 
37
+
38
+    The main reason for not making <<<HandlingEvent>>> part of the cargo aggregate is performance. <<<HandlingEvent>>>s are received from external parties and systems, e.g. warehouse management systems, port handling systems, that call our <<<{{{xref/se/citerus/dddsample/domain/service/HandlingEventService.html}HandlingEventService}}>>> webservice. The number of events can be very high and it is important that our webservice can dispatch the remote calls quickly. To be able to support this use case we need to handle the remote webservice calls asynchronously, i.e. we do not want to load the big cargo structure for each received <<<HandlingEvent>>>. Since all relationships in an aggregate must be handled synchronously we put the <<<HandlingEvent>>> in an aggregate of its own and we are able processes the events quickly and at the same time eliminate dead-locking situations in the system.
39
+
40
+    <Editors note: We are aware that this example may need a little more work to drive the full benefits of aggregates home. This is one of the problems with a small sample app, real-world complexity is hard to simulate.>
33 41
     
34 42
 [images/aggregates.gif]
35 43
 
@@ -47,10 +55,31 @@
47 55
 
48 56
 *Domain services
49 57
 
50
-    Domain services are a natural part of the domain and provide services such as message forwarding etc. In the sample application the <<<{{{xref/se/citerus/dddsample/domain/service/RoutingService.html}RoutingService}}>>> provides access to the routing system and is used to find possible routes for a give specification.
58
+    Domain services are expressed in terms of the ubiquitous language and the domain types, i.e.
59
+    the method arguments and the return values are proper domain classes. Sometimes, only the service
60
+    interface (<what> the service does) is part of the domain layer, but the implementation (<how> the service does it)
61
+    is part of the application layer. This is analogous to how repository interfaces are part of the domain layer, but the
62
+    Hibernate implementations are not.
51 63
 
52
-*Application services
64
+    A good example of that is the <<<{{{xref/se/citerus/dddsample/domain/service/RoutingService.html}RoutingService}}>>>,
65
+    which provides access to the routing system and is used to find possible routes for a give specification.
66
+    The {{{xref/se/citerus/dddsample/application/routing/ExternalRoutingService.html}implementation}} communicates with
67
+    another team's context and translates to and from an external API and data model.
68
+
69
+    On the other hand, if the service is possible to implement strictly using the domain layer,
70
+    both the interface and the implementation are part of the domain layer. That is the case for the
71
+    <<<{{{xref/se/citerus/dddsample/domain/service/impl/BookingServiceImpl.html}BookingService}}>>>, for example.
53 72
 
54
-    The application services in the sample application are responsible for driving workflow and coordinating transaction management (by use of the declarative transaction management support in Spring). They also provide a high-level abstraction for clients to use when interacting with the domain. These services are typically designed to support specific use cases or stories. The <<<{{{xref/se/citerus/dddsample/domain/service/TrackingService.html}TrackingService}}>>> is used by the public web application for tracking cargo and the <<<{{{xref/se/citerus/dddsample/domain/service/BookingService.html}BookingService}}>>> is used by the internal administration application for booking new cargo.
73
+*Application services
55 74
 
56
-    The services are all defined in types of the domain, i.e. the method arguments and the return values are proper domain classes. In some situation, e.g. when dealing with graphs of lazy-loaded domain objects or when passing services' return values over network boundaries, the services are wrapped in facades. The facades handle ORM session management issues and/or convert the domain objects to more portable {{{http://martinfowler.com/eaaCatalog/dataTransferObject.html}Data Transfer Objects}}) that can be tailored to specific use cases. See <<<{{{xref/se/citerus/dddsample/application/remoting/BookingServiceFacadeImpl.html}BookingServiceFacadeImpl}}>>> for an example.
75
+    The application services in the sample application are responsible for driving workflow and coordinating
76
+    transaction management (by use of the declarative transaction management support in Spring).
77
+    They also provide a high-level abstraction for clients to use when interacting with the domain.
78
+    These services are typically designed to support specific use cases or fulfill technical requirements (web services, etc).
79
+
80
+    In some situations, e.g. when dealing with graphs of lazy-loaded
81
+    domain objects or when passing services' return values over network boundaries, the services are wrapped in facades.
82
+    The facades handle ORM session management issues and/or convert the domain objects to more portable
83
+    {{{http://martinfowler.com/eaaCatalog/dataTransferObject.html}Data Transfer Objects}}) that can be tailored
84
+    to specific use cases.
85
+    See <<<{{{xref/se/citerus/dddsample/application/remoting/BookingServiceFacadeImpl.html}BookingServiceFacadeImpl}}>>> for an example.

+ 110
- 7
dddsample/src/site/apt/download.apt ファイルの表示

@@ -2,17 +2,120 @@
2 2
   Download
3 3
   --------
4 4
 
5
-Deployable WAR archive of main application
5
+Prerequisites
6 6
 
7
-  <<COMING SOON>> - for now, use source archive and run <<<mvn package>>> to build
7
+  * Java 5 or later
8 8
 
9
-Source code for main application
9
+  []
10 10
 
11
-  {{{http://downloads.sourceforge.net/dddsample/dddsample-1.0-SNAPSHOT-src.zip?use_mirror=osdn} Download from Sourceforge}}
11
+  Optional:
12 12
 
13
-  Also, you can {{{source-repository.html}track Subversion}} directly.
13
+  * {{{http://maven.apache.org}Maven}} 2.0.9 or later (for development)
14 14
 
15
-Incident logging application
15
+  * A servlet container, such as {{{http://tomcat.apache.org}Tomcat}} (for deploying the web archive)
16 16
 
17
-  <<COMING SOON>>
17
+Downloads
18 18
 
19
+    There are three different {{{http://sourceforge.net/project/showfiles.php?group_id=210606}downloads}} available:
20
+    the {{{http://downloads.sourceforge.net/dddsample/dddsample-1.0-src.zip?use_mirror=osdn} source package}},
21
+    the {{{http://downloads.sourceforge.net/dddsample/IncidentLoggingApplication.zip?use_mirror=osdn} Incident Logging Application}}
22
+    and the {{{http://downloads.sourceforge.net/dddsample/dddsample-1.0.war?use_mirror=osdn} pre-built web archive}}.
23
+
24
+    The project uses Maven for build and management.
25
+
26
+* Source package
27
+
28
+    Download {{{http://downloads.sourceforge.net/dddsample/dddsample-1.0-src.zip?use_mirror=osdn} here}}.
29
+
30
+    This is a complete checkout of the core application source code.
31
+
32
+    To build a web archive from scratch (to be found in the target directory):
33
+
34
+-----------------
35
+mvn clean package
36
+-----------------
37
+
38
+    To build and run the application in an embedded Jetty:
39
+
40
+-------------
41
+mvn jetty:run
42
+-------------
43
+
44
+    The public tracking interface is available at {{http://localhost:8080/dddsample}} (try tracking cargos XYZ and JKL, for example)
45
+    and the booking and routing administration interface can be found at {{http://localhost:8080/dddsample/admin/list.html}}.
46
+    The administration interface is used for booking and routing cargo.
47
+
48
+    An RMI registry will be started on port <<<1099>>>, in addition to the Jetty container on port <<<8080>>>, so those ports
49
+    need to be available or you have to reconfigure the application.
50
+
51
+    <<NOTE>>: running some Maven targets (<<<jetty:run>>> for example) currently do not work in IntelliJ with the embedded Maven runner.
52
+    Workaround: either run Maven from command line, or swich to external Maven runner in IntelliJ.
53
+
54
+    <<NOTE>>: the application currently can't be run offline, due to an unresolved problem with XSD validation.
55
+    Workaround: run application online.
56
+
57
+    Also, you can {{{source-repository.html}track Subversion}} directly.
58
+    Use the {{{http://svnbook.red-bean.com/en/1.0/re27.html}<<<svn switch>>>}} command on the source package to start tracking trunk or a stable branch.
59
+
60
+* Incident Logging Application
61
+
62
+    Download {{{http://downloads.sourceforge.net/dddsample/IncidentLoggingApplication.zip?use_mirror=osdn} here}}.
63
+
64
+    This is a simple, standalone Swing client that's used for registering handling events. It communicates with the core
65
+    application via a Web Service interface. Unpack and run:
66
+
67
+----------------------------------------
68
+cd IncidentLoggingApplication
69
+
70
+java -jar IncidentLoggingApplication.jar
71
+----------------------------------------
72
+
73
+    <<NOTE>>: before you start the Incident Logging Application, the core application must be running on the
74
+    WSDL URL host in the file <<<app.properties>>>, which defaults to <<<localhost:8080>>>.
75
+    Edit this file to point at the host where the core application is running.
76
+
77
+    The source code for this application is currently only available {{{source-repository.html}in Subversion}}.
78
+
79
+* Pre-built web archive 
80
+
81
+    Download {{{http://downloads.sourceforge.net/dddsample/dddsample-1.0.war?use_mirror=osdn} here}}
82
+
83
+    This is a pre-built standard .war, ready to be deployed in a standard servlet container such as Tomcat. It is
84
+    offered as a convenience if you want a simple way to run the application without bothering with the build
85
+    environment. Developers who are interested in how DDD is applied in the application should download the source
86
+    archive instead.
87
+
88
+    The same caveats for running the application that are listed in the source package section above apply to this package as well.
89
+
90
+IDE Setup
91
+
92
+    * IntelliJ 7 or later:
93
+
94
+      Maven support is integrated - simply open project using the <<<pom.xml>>>.
95
+
96
+    * Netbeans 6 or later:
97
+
98
+      Install the Maven plugin (Tools -> Plugins -> Available Plugins), then open project.
99
+
100
+    * Eclipse
101
+
102
+      Either install a Maven integration plugin ({{{http://code.google.com/p/q4e/} q4e}} recommended), or
103
+      use standalone Maven to {{{http://maven.apache.org/plugins/maven-eclipse-plugin/}generate project descriptor files}}.
104
+
105
+    * Other
106
+
107
+      Use standalone Maven to generate project descriptor files for your IDE.
108
+
109
+About Maven
110
+
111
+    Maven downloads all external library dependencies and plugins separately, which can amount to quite a large number of
112
+    small files that are downloaded sequentially. These are all cached locally, but the first time you run it you should
113
+    be prepared to wait 5-10 minutes for the build to complete, depending on your network conditions.
114
+
115
+    A good way to get going is to execute the following command, and then go grab a cup of coffee:
116
+
117
+---------------------------
118
+mvn clean package jetty:run
119
+---------------------------
120
+
121
+    That will fill your local cache with most of what you need for development, in a one shot.

+ 8
- 3
dddsample/src/site/apt/index.apt ファイルの表示

@@ -31,8 +31,13 @@
31 31
 
32 32
     There's a lot of interest in new tools or frameworks for DDD.
33 33
 
34
-  Reimplementing the sample app using a new platform will give a side-by-side comparison
35
-  with the "conventional" implementation, which can demonstrate the value of the new platform
36
-  and provide validation or other feedback to the developers of the platform.
34
+    Reimplementing the sample app using a new platform will give a side-by-side comparison
35
+    with the "conventional" implementation, which can demonstrate the value of the new platform
36
+    and provide validation or other feedback to the developers of the platform.
37
+
38
+  []
39
+  
40
+  <This project is a joint effort by Eric Evans' company {{{http://www.domainlanguage.com}Domain Language}}
41
+  and Swedish software consulting company {{{http://www.citerus.se}Citerus}}.>
37 42
 
38 43
 

+ 7
- 11
dddsample/src/site/apt/roadmap.apt ファイルの表示

@@ -4,9 +4,12 @@
4 4
 
5 5
 Roadmap
6 6
 
7
-  This application is a work of progress.
7
+  This application is a work of progress, and these are some ideas for continued development:
8 8
 
9
-* 1.1
9
+  * Remodel Cargo-HandlingEvent aggregates to make boundaries
10
+    and asynchronous updates more explicit
11
+
12
+  * Make handling event registration completely asynchronous
10 13
 
11 14
   * Next expected event, for tracking
12 15
 
@@ -14,16 +17,9 @@ Roadmap
14 17
 
15 18
   * Departure/arrival time for carrier movements, ETA for itineraries
16 19
 
17
-  * Make handling event registration asynchronous
18
-
19 20
   * Improve web service interface
20 21
 
21
-* 2.0
22
-
23
-  * Remodel Cargo-HandlingEvent aggregates to make boundaries
24
-    and asynchronous updates more explicit
25
-
26
-  * Diversify interfaces
22
+  * Diversify user interfaces
27 23
 
28 24
   * More ways to register handing events (FTP CSV file upload etc)
29 25
 
@@ -31,4 +27,4 @@ Roadmap
31 27
 
32 28
   * Port to TimeAndMoney
33 29
 
34
-  * Notify on delay
30
+  * Notify on delayed delivery

+ 2
- 2
dddsample/src/site/site.xml ファイルの表示

@@ -10,15 +10,15 @@
10 10
   </poweredBy>
11 11
   <body>
12 12
     <links>
13
-      <item name="Domain Language" href="http://www.domainlanguage.org/" />
13
+      <item name="Domain Language" href="http://www.domainlanguage.com/" />
14 14
       <item name="Citerus" href="http://www.citerus.se/"/>
15 15
       <item name="DomainDrivenDesign.org" href="http://www.domaindrivendesign.org/"/>
16 16
     </links>
17 17
     <menu name="About the application">
18 18
       <item name="Introduction" href="index.html"/>
19
+      <item name="Download" href="download.html"/>
19 20
       <item name="Characterization" href="characterization.html"/>
20 21
       <item name="Patterns Reference" href="patterns-reference.html"/>
21
-      <item name="Download" href="download.html"/>
22 22
       <item name="Roadmap" href="roadmap.html" />
23 23
     </menu>
24 24
     <menu ref="reports"/>

+ 6
- 6
dddsample/src/test/java/se/citerus/dddsample/application/service/dto/assembler/CargoRoutingDTOAssemblerTest.java ファイルの表示

@@ -42,13 +42,13 @@ public class CargoRoutingDTOAssemblerTest extends TestCase {
42 42
 
43 43
     LegDTO legDTO = dto.getLegs().get(0);
44 44
     assertEquals("ABC", legDTO.getCarrierMovementId());
45
-    assertEquals("SESTO (Stockholm)", legDTO.getFrom());
46
-    assertEquals("CNSHA (Shanghai)", legDTO.getTo());
45
+    assertEquals("SESTO", legDTO.getFrom());
46
+    assertEquals("CNSHA", legDTO.getTo());
47 47
 
48 48
     legDTO = dto.getLegs().get(1);
49 49
     assertEquals("ABC", legDTO.getCarrierMovementId());
50
-    assertEquals("NLRTM (Rotterdam)", legDTO.getFrom());
51
-    assertEquals("AUMEL (Melbourne)", legDTO.getTo());
50
+    assertEquals("NLRTM", legDTO.getFrom());
51
+    assertEquals("AUMEL", legDTO.getTo());
52 52
   }
53 53
 
54 54
   public void testToDTO_NoItinerary() throws Exception {
@@ -58,8 +58,8 @@ public class CargoRoutingDTOAssemblerTest extends TestCase {
58 58
     final CargoRoutingDTO dto = assembler.toDTO(cargo);
59 59
 
60 60
     assertEquals("XYZ", dto.getTrackingId());
61
-    assertEquals("SESTO (Stockholm)", dto.getOrigin());
62
-    assertEquals("AUMEL (Melbourne)", dto.getFinalDestination());
61
+    assertEquals("SESTO", dto.getOrigin());
62
+    assertEquals("AUMEL", dto.getFinalDestination());
63 63
     assertTrue(dto.getLegs().isEmpty());
64 64
   }
65 65
 }

+ 2
- 0
dddsample/src/test/java/se/citerus/dddsample/application/ws/HandlinEventServiceEndpointTest.java ファイルの表示

@@ -2,6 +2,7 @@ package se.citerus.dddsample.application.ws;
2 2
 
3 3
 import junit.framework.TestCase;
4 4
 import static org.easymock.EasyMock.*;
5
+import se.citerus.dddsample.application.service.InMemTransactionManager;
5 6
 import se.citerus.dddsample.domain.model.cargo.TrackingId;
6 7
 import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
7 8
 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
@@ -24,6 +25,7 @@ public class HandlinEventServiceEndpointTest extends TestCase {
24 25
     handlingEventService = createMock(HandlingEventService.class);
25 26
     endpoint.setHandlingEventService(handlingEventService);
26 27
     sdf = new SimpleDateFormat(HandlingEventServiceEndpointImpl.ISO_8601_FORMAT);
28
+    endpoint.setTransactionManager(new InMemTransactionManager());
27 29
   }
28 30
 
29 31
   public void testRegisterValidEvent() throws Exception {

+ 0
- 74
dddsample/src/test/java/se/citerus/dddsample/domain/service/RoutingScenarioTest.java ファイルの表示

@@ -1,74 +0,0 @@
1
-package se.citerus.dddsample.domain.service;
2
-
3
-import junit.framework.TestCase;
4
-import se.citerus.dddsample.domain.model.cargo.*;
5
-import se.citerus.dddsample.domain.model.carrier.CarrierMovementId;
6
-import se.citerus.dddsample.domain.model.location.UnLocode;
7
-
8
-import java.util.Date;
9
-import java.util.List;
10
-
11
-public class RoutingScenarioTest extends TestCase {
12
-
13
-  RoutingService routingService;
14
-  CargoRepository cargoRepository;
15
-  HandlingEventService handlingEventService;
16
-
17
-  // TODO work on this
18
-  public void xtestCalculateRoute() throws Exception {
19
-
20
-    TrackingId trackingId = new TrackingId("XYZ123");
21
-    Cargo cargo = cargoRepository.find(trackingId);
22
-
23
-    Date twoWeeksFromNow = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 14);
24
-
25
-    RouteSpecification routeSpecification = RouteSpecification.forCargo(cargo, twoWeeksFromNow);
26
-
27
-    /*
28
-      The routing service calculates a number of possible routes that
29
-      satisfy the given specification (must arrive in three days, must not
30
-      cost more than $10,000 etc).
31
-     */
32
-    List<Itinerary> itineraryCandidates = routingService.fetchRoutesForSpecification(routeSpecification);
33
-
34
-    /*
35
-      Someone, or something, selects the most appropriate itinerary and
36
-      assigns that itinerary to the cargo.
37
-     */
38
-    Itinerary itinerary = stubbedItinerarySelection(itineraryCandidates);
39
-    cargo.attachItinerary(itinerary);
40
-
41
-    /*
42
-      A number of events occur, all of which are according to plan
43
-     */
44
-    handlingEventService.register(new Date(), trackingId, new CarrierMovementId("A001"), new UnLocode("SESTO"), null);
45
-    handlingEventService.register(new Date(), trackingId, new CarrierMovementId("B002"), null, null);
46
-    handlingEventService.register(new Date(), trackingId, new CarrierMovementId("C003"), null, null);
47
-
48
-    /*
49
-      Cargo should not be misdirected at this point.
50
-     */
51
-    assertFalse(cargo.isMisdirected());
52
-
53
-    /*
54
-      An unexpected event occur.
55
-     */
56
-    handlingEventService.register(null, null, null, null, null);
57
-
58
-    /*
59
-      Now the cargo is misdirected.
60
-     */
61
-    assertTrue(cargo.isMisdirected());
62
-  }
63
-
64
-  public void testRun() throws Exception
65
-  {
66
-    
67
-  }
68
-
69
-
70
-  private Itinerary stubbedItinerarySelection(List<Itinerary> itineraryCandidates) {
71
-    return itineraryCandidates.get(0);
72
-  }
73
-
74
-}