Przeglądaj źródła

Made Cargo-HandlingEvent relation bidirectional again, with DeliveryHistory in the middle.

Restored Cargo.lastKnownLocation() and Cargo.hasArrived().

All entities have sequential identifiers with no domain meaning. Equals and hashcode rely on business logic unrelated to persistence state.

Removed findDeliveryHistory from HaEvRepo since it's now OR-mapped.

Improved javadoc.
peter_backlund 18 lat temu
rodzic
commit
e0ca0b99c6
24 zmienionych plików z 345 dodań i 264 usunięć
  1. 17
    2
      dddsample/pom.xml
  2. 63
    26
      dddsample/src/main/java/se/citerus/dddsample/domain/Cargo.java
  3. 10
    4
      dddsample/src/main/java/se/citerus/dddsample/domain/CarrierMovement.java
  4. 11
    5
      dddsample/src/main/java/se/citerus/dddsample/domain/CarrierMovementId.java
  5. 12
    14
      dddsample/src/main/java/se/citerus/dddsample/domain/DeliveryHistory.java
  6. 39
    21
      dddsample/src/main/java/se/citerus/dddsample/domain/HandlingEvent.java
  7. 22
    11
      dddsample/src/main/java/se/citerus/dddsample/domain/Location.java
  8. 8
    7
      dddsample/src/main/java/se/citerus/dddsample/domain/TrackingId.java
  9. 4
    1
      dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepositoryHibernate.java
  10. 4
    1
      dddsample/src/main/java/se/citerus/dddsample/repository/CarrierMovementRepositoryHibernate.java
  11. 0
    8
      dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepository.java
  12. 0
    12
      dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepositoryHibernate.java
  13. 6
    10
      dddsample/src/main/java/se/citerus/dddsample/service/CargoServiceImpl.java
  14. 79
    69
      dddsample/src/main/java/se/citerus/dddsample/util/SampleDataGenerator.java
  15. 3
    1
      dddsample/src/main/resources/context-persistence.xml
  16. 0
    1
      dddsample/src/main/resources/context-service.xml
  17. 41
    35
      dddsample/src/test/java/se/citerus/dddsample/domain/CargoTest.java
  18. 2
    2
      dddsample/src/test/java/se/citerus/dddsample/domain/DeliveryHistoryTest.java
  19. 5
    2
      dddsample/src/test/java/se/citerus/dddsample/domain/HandlingEventTest.java
  20. 1
    1
      dddsample/src/test/java/se/citerus/dddsample/domain/TrackingScenarioTest.java
  21. 2
    1
      dddsample/src/test/java/se/citerus/dddsample/repository/AbstractRepositoryTest.java
  22. 3
    2
      dddsample/src/test/java/se/citerus/dddsample/repository/CargoRepositoryTest.java
  23. 5
    12
      dddsample/src/test/java/se/citerus/dddsample/repository/HandlingEventRepositoryTest.java
  24. 8
    16
      dddsample/src/test/java/se/citerus/dddsample/service/CargoServiceTest.java

+ 17
- 2
dddsample/pom.xml Wyświetl plik

@@ -102,12 +102,22 @@
102 102
     </dependency>
103 103
     <dependency>
104 104
       <groupId>org.springframework</groupId>
105
-      <artifactId>spring</artifactId>
105
+      <artifactId>spring-webmvc</artifactId>
106 106
       <version>2.5</version>
107 107
     </dependency>
108 108
     <dependency>
109 109
       <groupId>org.springframework</groupId>
110
-      <artifactId>spring-webmvc</artifactId>
110
+      <artifactId>spring-orm</artifactId>
111
+      <version>2.5</version>
112
+    </dependency>
113
+    <dependency>
114
+      <groupId>org.springframework</groupId>
115
+      <artifactId>spring-jdbc</artifactId>
116
+      <version>2.5</version>
117
+    </dependency>
118
+    <dependency>
119
+      <groupId>org.springframework</groupId>
120
+      <artifactId>spring-aop</artifactId>
111 121
       <version>2.5</version>
112 122
     </dependency>
113 123
     <dependency>
@@ -142,6 +152,11 @@
142 152
       <version>1.1</version>
143 153
     </dependency>
144 154
     <dependency>
155
+      <groupId>commons-dbcp</groupId>
156
+      <artifactId>commons-dbcp</artifactId>
157
+      <version>1.2.2</version>
158
+    </dependency>
159
+    <dependency>
145 160
       <groupId>hsqldb</groupId>
146 161
       <artifactId>hsqldb</artifactId>
147 162
       <version>1.8.0.7</version>

+ 63
- 26
dddsample/src/main/java/se/citerus/dddsample/domain/Cargo.java Wyświetl plik

@@ -1,23 +1,23 @@
1 1
 package se.citerus.dddsample.domain;
2 2
 
3
-import org.apache.commons.lang.builder.EqualsBuilder;
4
-import org.apache.commons.lang.builder.HashCodeBuilder;
5 3
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
6 4
 import org.apache.commons.lang.builder.ToStringStyle;
7 5
 
8
-import javax.persistence.EmbeddedId;
9
-import javax.persistence.Entity;
10
-import javax.persistence.ManyToOne;
6
+import javax.persistence.*;
11 7
 
12 8
 
13 9
 /**
14
- * A Cargo an entity identifed by TrackingId and is capable of getting its DeliveryHistory plus a number
15
- * of convenience operation for finding current destination etc.
10
+ * A Cargo.
11
+ *
16 12
  */
17 13
 @Entity
18 14
 public class Cargo {
19 15
 
20
-  @EmbeddedId
16
+  @Id
17
+  @GeneratedValue
18
+  private Long id;
19
+
20
+  @Embedded
21 21
   private TrackingId trackingId;
22 22
 
23 23
   @ManyToOne
@@ -26,22 +26,61 @@ public class Cargo {
26 26
   @ManyToOne
27 27
   private Location finalDestination;
28 28
 
29
+  @Embedded
30
+  private DeliveryHistory deliveryHistory;
31
+
29 32
   public Cargo(TrackingId trackingId, Location origin, Location finalDestination) {
30 33
     this.trackingId = trackingId;
31 34
     this.origin = origin;
32 35
     this.finalDestination = finalDestination;
36
+    this.deliveryHistory =  new DeliveryHistory();
33 37
   }
34 38
 
39
+  /**
40
+   * @return Tracking id.
41
+   */
35 42
   public TrackingId trackingId() {
36
-    return trackingId;
43
+    return this.trackingId;
37 44
   }
38 45
 
46
+  /**
47
+   * @return Origin location.
48
+   */
39 49
   public Location origin() {
40
-    return origin;
50
+    return this.origin;
41 51
   }
42 52
 
53
+  /**
54
+   * @return Final destination.
55
+   */
43 56
   public Location finalDestination() {
44
-    return finalDestination;
57
+    return this.finalDestination;
58
+  }
59
+
60
+  /**
61
+   * @return Delivery history.
62
+   */
63
+  public DeliveryHistory deliveryHistory() {
64
+    return this.deliveryHistory;
65
+  }
66
+
67
+  /**
68
+   * @return Last known location of the cargo, or Location.UNKNOWN if the delivery history is empty.
69
+   */
70
+  public Location lastKnownLocation() {
71
+    HandlingEvent lastEvent = deliveryHistory.lastEvent();
72
+    if (lastEvent != null) {
73
+      return lastEvent.location();
74
+    } else {
75
+      return Location.UNKNOWN;
76
+    }
77
+  }
78
+
79
+  /**
80
+   * @return True if the cargo has arrived at its final destination.
81
+   */
82
+  public boolean hasArrived() {
83
+    return finalDestination.equals(lastKnownLocation());
45 84
   }
46 85
 
47 86
   @Override
@@ -49,29 +88,27 @@ public class Cargo {
49 88
     return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
50 89
   }
51 90
 
91
+  /**
92
+   * @param object to compare
93
+   * @return True if tracking ids are equal.
94
+   */
52 95
   @Override
53
-  public boolean equals(Object obj) {
54
-    if (!(obj instanceof Cargo)) {
96
+  public boolean equals(Object object) {
97
+    if (!(object instanceof Cargo)) {
55 98
       return false;
56 99
     }
57
-    Cargo rhs = (Cargo) obj;
58
-    return new EqualsBuilder()
59
-      .append(trackingId, rhs.trackingId)
60
-      .append(origin, rhs.origin)
61
-      .append(finalDestination, rhs.finalDestination)
62
-      .isEquals();
100
+    Cargo other = (Cargo) object;
101
+    return trackingId.equals(other.trackingId);
63 102
   }
64 103
 
104
+  /**
105
+   * @return Hash code of tracking id.
106
+   */
65 107
   @Override
66 108
   public int hashCode() {
67
-    return new HashCodeBuilder(7, 39)
68
-    .append(trackingId)
69
-    .append(origin)
70
-    .append(finalDestination)
71
-    .toHashCode();
109
+    return trackingId.hashCode();
72 110
   }
73
-  
111
+
74 112
   // Needed by Hibernate
75 113
   Cargo() {}
76
-  
77 114
 }

+ 10
- 4
dddsample/src/main/java/se/citerus/dddsample/domain/CarrierMovement.java Wyświetl plik

@@ -1,14 +1,20 @@
1 1
 package se.citerus.dddsample.domain;
2 2
 
3
-import javax.persistence.EmbeddedId;
4
-import javax.persistence.Entity;
5
-import javax.persistence.ManyToOne;
3
+import javax.persistence.*;
6 4
 
7 5
 
6
+/**
7
+ * A carrier movement is a vessel voyage from one location to another.
8
+ *
9
+ */
8 10
 @Entity
9 11
 public class CarrierMovement {
10 12
 
11
-  @EmbeddedId
13
+  @Id
14
+  @GeneratedValue
15
+  private Long id;
16
+
17
+  @Embedded
12 18
   private CarrierMovementId carrierMovementId;
13 19
 
14 20
   @ManyToOne

+ 11
- 5
dddsample/src/main/java/se/citerus/dddsample/domain/CarrierMovementId.java Wyświetl plik

@@ -3,21 +3,26 @@ package se.citerus.dddsample.domain;
3 3
 import org.apache.commons.lang.builder.EqualsBuilder;
4 4
 import org.apache.commons.lang.builder.HashCodeBuilder;
5 5
 
6
+import javax.persistence.Column;
6 7
 import javax.persistence.Embeddable;
7
-import java.io.Serializable;
8 8
 
9 9
 /**
10
- * Identifies a particular carrier (vehicle).
10
+ * Identifies a particular carrier movement, such as a flight number.
11
+ *
11 12
  */
12 13
 @Embeddable
13
-public class CarrierMovementId implements Serializable {
14
+public class CarrierMovementId {
14 15
 
16
+  @Column(name = "carrier_movement_id")
15 17
   private String id;
16 18
 
17 19
   public CarrierMovementId(String id) {
18 20
     this.id = id;
19 21
   }
20 22
 
23
+  /**
24
+   * @return String representation of this carrier movement id.
25
+   */
21 26
   public String idString() {
22 27
     return id;
23 28
   }
@@ -32,6 +37,7 @@ public class CarrierMovementId implements Serializable {
32 37
     return HashCodeBuilder.reflectionHashCode(this);
33 38
   }
34 39
 
35
-  // needed by hibernate
36
-  public CarrierMovementId() {}
40
+  // Needed by hibernate
41
+  CarrierMovementId() {}
42
+
37 43
 }

+ 12
- 14
dddsample/src/main/java/se/citerus/dddsample/domain/DeliveryHistory.java Wyświetl plik

@@ -3,25 +3,21 @@ package se.citerus.dddsample.domain;
3 3
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
4 4
 import org.apache.commons.lang.builder.ToStringStyle;
5 5
 
6
+import javax.persistence.Embeddable;
7
+import javax.persistence.JoinColumn;
8
+import javax.persistence.OneToMany;
6 9
 import java.util.*;
7 10
 
8 11
 /**
9
- * The delivery history of a cargo. This is a value object.
12
+ * The delivery history of a cargo.
10 13
  *
11 14
  */
15
+@Embeddable
12 16
 public class DeliveryHistory {
13 17
 
14
-  private final Set<HandlingEvent> events;
15
-
16
- 
17
-
18
-  public DeliveryHistory() {
19
-    this(Collections.<HandlingEvent>emptySet());
20
-  }
21
-
22
-  public DeliveryHistory(Collection<HandlingEvent> events) {
23
-    this.events = new HashSet<HandlingEvent>(events);
24
-  }
18
+  @OneToMany
19
+  @JoinColumn(name = "cargo_id")
20
+  private Set<HandlingEvent> events = new HashSet<HandlingEvent>();
25 21
 
26 22
   /**
27 23
    * Adds the HandlingEvent to the sorted set.
@@ -35,7 +31,7 @@ public class DeliveryHistory {
35 31
   /**
36 32
    * @return An <b>unmodifiable</b> list of handling events, ordered by the time the events occured.
37 33
    */
38
-  public List<HandlingEvent> eventsOrderedByTime() {
34
+  public List<HandlingEvent> eventsOrderedByCompletionTime() {
39 35
     List<HandlingEvent> eventList = new ArrayList<HandlingEvent>(events);
40 36
     Collections.sort(eventList, HandlingEvent.BY_COMPLETION_TIME_COMPARATOR);
41 37
     return Collections.unmodifiableList(eventList);
@@ -48,7 +44,7 @@ public class DeliveryHistory {
48 44
     if (events.isEmpty()) {
49 45
       return null;
50 46
     } else {
51
-      List<HandlingEvent> orderedEvents = eventsOrderedByTime();
47
+      List<HandlingEvent> orderedEvents = eventsOrderedByCompletionTime();
52 48
       return orderedEvents.get(orderedEvents.size() - 1);
53 49
     }
54 50
   }
@@ -58,5 +54,7 @@ public class DeliveryHistory {
58 54
     return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
59 55
   }
60 56
 
57
+  // Needed by Hibernate
58
+  DeliveryHistory() {}
61 59
 
62 60
 }

+ 39
- 21
dddsample/src/main/java/se/citerus/dddsample/domain/HandlingEvent.java Wyświetl plik

@@ -1,15 +1,10 @@
1 1
 package se.citerus.dddsample.domain;
2 2
 
3
+import org.apache.commons.lang.builder.HashCodeBuilder;
4
+
5
+import javax.persistence.*;
3 6
 import java.util.Comparator;
4 7
 import java.util.Date;
5
-import java.util.UUID;
6
-
7
-import javax.persistence.Entity;
8
-import javax.persistence.EnumType;
9
-import javax.persistence.Enumerated;
10
-import javax.persistence.Id;
11
-import javax.persistence.JoinColumn;
12
-import javax.persistence.ManyToOne;
13 8
 
14 9
 /**
15 10
  * HandlingEvent links the type of handling with a CarrierMovement.
@@ -24,14 +19,15 @@ public class HandlingEvent {
24 19
   /**
25 20
    * Comparator used to be able to sort HandlingEvents according to their completion time
26 21
    */
27
-  public static final Comparator<HandlingEvent> BY_COMPLETION_TIME_COMPARATOR = new Comparator<HandlingEvent>(){
22
+  public static final Comparator<HandlingEvent> BY_COMPLETION_TIME_COMPARATOR = new Comparator<HandlingEvent>() {
28 23
     public int compare(HandlingEvent o1, HandlingEvent o2) {
29 24
       return o1.completionTime().compareTo(o2.completionTime());
30 25
     }
31 26
   };
32 27
 
33 28
   @Id
34
-  private String id;
29
+  @GeneratedValue
30
+  private Long id;
35 31
 
36 32
   @Enumerated(EnumType.STRING)
37 33
   private Type type;
@@ -47,7 +43,7 @@ public class HandlingEvent {
47 43
   private Date registrationTime;
48 44
 
49 45
   @ManyToOne
50
-  @JoinColumn
46
+  @JoinColumn(name = "cargo_id")
51 47
   private Cargo cargo;
52 48
 
53 49
   public enum Type {
@@ -55,7 +51,6 @@ public class HandlingEvent {
55 51
   }
56 52
 
57 53
   private HandlingEvent(Cargo cargo, Date completionTime, Date registrationTime, Type type) {
58
-    this.id = UUID.randomUUID().toString();
59 54
     this.registrationTime = registrationTime;
60 55
     this.completionTime = completionTime;
61 56
     this.type = type;
@@ -100,7 +95,7 @@ public class HandlingEvent {
100 95
     }
101 96
   }
102 97
 
103
-  public String id() {
98
+  public Long id() {
104 99
     return this.id;
105 100
   }
106 101
 
@@ -128,19 +123,42 @@ public class HandlingEvent {
128 123
     return this.cargo;
129 124
   }
130 125
 
126
+  /**
127
+   * @param object to compare
128
+   * @return True if location, completion time and type are equal.
129
+   */
131 130
   @Override
132
-  public boolean equals(Object obj) {
133
-    return (obj instanceof HandlingEvent) &&
134
-            sameIdentityAs((HandlingEvent) obj);
135
-  }
136
-
137
-  public boolean sameIdentityAs(HandlingEvent other) {
138
-    return other != null && id.equals(other.id);
131
+  public boolean equals(Object object) {
132
+    if (object == null) {
133
+      return false;
134
+    }
135
+    if (!(object instanceof HandlingEvent)) {
136
+      return false;
137
+    }
138
+    HandlingEvent other = (HandlingEvent) object;
139
+    return this.location.equals(other.location) &&
140
+           this.completionTime.equals(other.completionTime) &&
141
+           this.type.equals(other.type);
139 142
   }
140 143
 
144
+  /**
145
+   * @return Hash code calculated from the same properties as equals().
146
+   */
141 147
   @Override
142 148
   public int hashCode() {
143
-    return id.hashCode();
149
+    return new HashCodeBuilder(7, 39).
150
+            append(this.location).
151
+            append(this.completionTime).
152
+            append(this.type).
153
+            toHashCode();
154
+  }
155
+
156
+  /**
157
+   * @param other to compare
158
+   * @return True if the ids are equal.
159
+   */
160
+  public boolean sameIdentityAs(HandlingEvent other) {
161
+    return other != null && id.equals(other.id);
144 162
   }
145 163
 
146 164
   // Needed by Hibernate

+ 22
- 11
dddsample/src/main/java/se/citerus/dddsample/domain/Location.java Wyświetl plik

@@ -1,8 +1,5 @@
1 1
 package se.citerus.dddsample.domain;
2 2
 
3
-import org.apache.commons.lang.builder.EqualsBuilder;
4
-import org.apache.commons.lang.builder.HashCodeBuilder;
5
-
6 3
 import javax.persistence.Entity;
7 4
 import javax.persistence.GeneratedValue;
8 5
 import javax.persistence.Id;
@@ -20,28 +17,42 @@ public class Location {
20 17
 
21 18
   private String unlocode;
22 19
 
23
-  // Exclude the id field from equals() and hashcode()
24
-  private static final String[] excludedFields = {"id"};
25
-
26 20
   public Location(String unlocode) {
27 21
     this.unlocode = unlocode;
28 22
   }
29 23
 
24
+  /**
25
+   * @return United Nations Location Code for this location.
26
+   */
30 27
   public String unlocode() {
31 28
     return unlocode;
32 29
   }
33 30
 
31
+  /**
32
+   * @param object to compare
33
+   * @return True if unlocodes are equal.
34
+   */
34 35
   @Override
35
-  public boolean equals(Object obj) {
36
-    if (this == UNKNOWN || obj == UNKNOWN) {
37
-      return this == obj;
36
+  public boolean equals(Object object) {
37
+    if (object == null) {
38
+      return false;
39
+    }
40
+    if (this == UNKNOWN || object == UNKNOWN) {
41
+      return this == object;
42
+    }
43
+    if (!(object instanceof Location)) {
44
+      return false;
38 45
     }
39
-    return EqualsBuilder.reflectionEquals(this, obj, excludedFields);
46
+    Location other = (Location) object;
47
+    return this.unlocode.equals(other.unlocode);
40 48
   }
41 49
 
50
+  /**
51
+   * @return Hash code of unlocode.
52
+   */
42 53
   @Override
43 54
   public int hashCode() {
44
-    return HashCodeBuilder.reflectionHashCode(this, excludedFields);
55
+    return unlocode.hashCode();
45 56
   }
46 57
 
47 58
   @Override

+ 8
- 7
dddsample/src/main/java/se/citerus/dddsample/domain/TrackingId.java Wyświetl plik

@@ -3,25 +3,26 @@ package se.citerus.dddsample.domain;
3 3
 import org.apache.commons.lang.builder.EqualsBuilder;
4 4
 import org.apache.commons.lang.builder.HashCodeBuilder;
5 5
 
6
+import javax.persistence.Column;
6 7
 import javax.persistence.Embeddable;
7
-import java.io.Serializable;
8 8
 
9 9
 /**
10
- * TrackingId is a simple ID wrapper which implements Serializable for easier
11
- * integration with persistence frameworks.
12
- * 
10
+ * Identifies a particular cargo.
11
+ *
13 12
  */
14 13
 @Embeddable
15
-public class TrackingId implements Serializable {
16
-
17
-  private static final long serialVersionUID = 6273117599327914522L;
14
+public class TrackingId {
18 15
 
16
+  @Column(name = "tracking_id")
19 17
   private String id;
20 18
 
21 19
   public TrackingId(String id) {
22 20
     this.id = id;
23 21
   }
24 22
 
23
+  /**
24
+   * @return String representation of this tracking id.
25
+   */
25 26
   public String idString() {
26 27
     return id;
27 28
   }

+ 4
- 1
dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepositoryHibernate.java Wyświetl plik

@@ -12,7 +12,10 @@ public class CargoRepositoryHibernate extends HibernateRepository implements Car
12 12
 
13 13
 
14 14
   public Cargo find(TrackingId trackingId) {
15
-    return (Cargo) getSession().get(Cargo.class, trackingId);
15
+    return (Cargo) getSession().
16
+            createQuery("from Cargo where trackingId = ?").
17
+            setParameter(0, trackingId).
18
+            uniqueResult();
16 19
   }
17 20
 
18 21
   public void save(Cargo cargo) {

+ 4
- 1
dddsample/src/main/java/se/citerus/dddsample/repository/CarrierMovementRepositoryHibernate.java Wyświetl plik

@@ -12,7 +12,10 @@ import se.citerus.dddsample.domain.CarrierMovementId;
12 12
 public class CarrierMovementRepositoryHibernate extends HibernateRepository implements CarrierMovementRepository {
13 13
 
14 14
   public CarrierMovement find(CarrierMovementId carrierMovementId) {
15
-    return (CarrierMovement) getSession().get(CarrierMovement.class, carrierMovementId);
15
+    return (CarrierMovement) getSession().
16
+            createQuery("from CarrierMovement where carrierMovementId = ?").
17
+            setParameter(1, carrierMovementId).
18
+            uniqueResult();
16 19
   }
17 20
 
18 21
 }

+ 0
- 8
dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepository.java Wyświetl plik

@@ -1,8 +1,6 @@
1 1
 package se.citerus.dddsample.repository;
2 2
 
3
-import se.citerus.dddsample.domain.DeliveryHistory;
4 3
 import se.citerus.dddsample.domain.HandlingEvent;
5
-import se.citerus.dddsample.domain.TrackingId;
6 4
 
7 5
 /**
8 6
  * Handling event repository.
@@ -17,10 +15,4 @@ public interface HandlingEventRepository {
17 15
    */
18 16
   void save(HandlingEvent event);
19 17
 
20
-  /**
21
-   * @param trackingId cargo tracking id
22
-   * @return The delivery history of the cargo with the given tracking id.
23
-   */
24
-  DeliveryHistory findDeliveryHistory(TrackingId trackingId);
25
-
26 18
 }

+ 0
- 12
dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepositoryHibernate.java Wyświetl plik

@@ -1,11 +1,7 @@
1 1
 package se.citerus.dddsample.repository;
2 2
 
3 3
 import org.springframework.stereotype.Repository;
4
-import se.citerus.dddsample.domain.DeliveryHistory;
5 4
 import se.citerus.dddsample.domain.HandlingEvent;
6
-import se.citerus.dddsample.domain.TrackingId;
7
-
8
-import java.util.List;
9 5
 
10 6
 /**
11 7
  * Hibernate implementation of HandlingEventRepository.
@@ -18,12 +14,4 @@ public class HandlingEventRepositoryHibernate extends HibernateRepository implem
18 14
     getSession().save(event);
19 15
   }
20 16
 
21
-  public DeliveryHistory findDeliveryHistory(TrackingId trackingId) {
22
-    List list = getSession().createQuery(
23
-            "from HandlingEvent he where he.cargo.trackingId = :tid").
24
-            setParameter("tid", trackingId).
25
-            list();
26
-    return new DeliveryHistory(list);
27
-  }
28
-
29 17
 }

+ 6
- 10
dddsample/src/main/java/se/citerus/dddsample/service/CargoServiceImpl.java Wyświetl plik

@@ -1,9 +1,11 @@
1 1
 package se.citerus.dddsample.service;
2 2
 
3 3
 import org.springframework.transaction.annotation.Transactional;
4
-import se.citerus.dddsample.domain.*;
4
+import se.citerus.dddsample.domain.Cargo;
5
+import se.citerus.dddsample.domain.CarrierMovement;
6
+import se.citerus.dddsample.domain.HandlingEvent;
7
+import se.citerus.dddsample.domain.TrackingId;
5 8
 import se.citerus.dddsample.repository.CargoRepository;
6
-import se.citerus.dddsample.repository.HandlingEventRepository;
7 9
 import se.citerus.dddsample.service.dto.CargoWithHistoryDTO;
8 10
 import se.citerus.dddsample.service.dto.HandlingEventDTO;
9 11
 
@@ -11,7 +13,6 @@ import java.util.List;
11 13
 
12 14
 public class CargoServiceImpl implements CargoService {
13 15
   private CargoRepository cargoRepository;
14
-  private HandlingEventRepository handlingEventRepository;
15 16
 
16 17
   @Transactional(readOnly = true)
17 18
   public CargoWithHistoryDTO find(String trackingId) {
@@ -20,8 +21,7 @@ public class CargoServiceImpl implements CargoService {
20 21
     if (cargo == null) {
21 22
       return null;
22 23
     }
23
-    DeliveryHistory deliveryHistory = handlingEventRepository.findDeliveryHistory(tid);
24
-    HandlingEvent lastEvent = deliveryHistory.lastEvent();
24
+    HandlingEvent lastEvent = cargo.deliveryHistory().lastEvent();
25 25
     String currentLocation;
26 26
     if (lastEvent != null) {
27 27
       currentLocation = lastEvent.location().unlocode();
@@ -34,7 +34,7 @@ public class CargoServiceImpl implements CargoService {
34 34
             cargo.finalDestination().unlocode(),
35 35
             currentLocation
36 36
     );
37
-    final List<HandlingEvent> events = deliveryHistory.eventsOrderedByTime();
37
+    final List<HandlingEvent> events = cargo.deliveryHistory().eventsOrderedByCompletionTime();
38 38
     for (HandlingEvent event : events) {
39 39
       CarrierMovement cm = event.carrierMovement();
40 40
       String carrierIdString = (cm == null) ? "" : cm.carrierId().idString();
@@ -52,8 +52,4 @@ public class CargoServiceImpl implements CargoService {
52 52
     this.cargoRepository = cargoRepository;
53 53
   }
54 54
 
55
-  public void setHandlingEventRepository(HandlingEventRepository handlingEventRepository) {
56
-    this.handlingEventRepository = handlingEventRepository;
57
-  }
58
-
59 55
 }

+ 79
- 69
dddsample/src/main/java/se/citerus/dddsample/util/SampleDataGenerator.java Wyświetl plik

@@ -2,6 +2,10 @@ package se.citerus.dddsample.util;
2 2
 
3 3
 import org.springframework.beans.factory.BeanFactoryUtils;
4 4
 import org.springframework.jdbc.core.JdbcTemplate;
5
+import org.springframework.transaction.PlatformTransactionManager;
6
+import org.springframework.transaction.TransactionStatus;
7
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
8
+import org.springframework.transaction.support.TransactionTemplate;
5 9
 import org.springframework.web.context.WebApplicationContext;
6 10
 import org.springframework.web.context.support.WebApplicationContextUtils;
7 11
 
@@ -9,115 +13,121 @@ import javax.servlet.ServletContextEvent;
9 13
 import javax.servlet.ServletContextListener;
10 14
 import javax.sql.DataSource;
11 15
 import java.sql.Timestamp;
12
-import java.util.UUID;
13 16
 
14 17
 /**
15 18
  * Provides sample data.
16 19
  */
17 20
 public class SampleDataGenerator implements ServletContextListener {
18 21
 
19
-  public static void loadSampleData(JdbcTemplate jdbcTemplate) {
20
-    loadLocationData(jdbcTemplate);
21
-    loadCargoData(jdbcTemplate);
22
-    loadCarrierMovementData(jdbcTemplate);
23
-    loadHandlingEventData(jdbcTemplate);
24
-  }
25
-
26 22
   private static void loadHandlingEventData(JdbcTemplate jdbcTemplate) {
27 23
     String handlingEventSql =
28
-      "insert into HandlingEvent (id, completionTime, registrationTime, type, location_id, carrierMovement_id, cargo_id) " +
29
-      "values (?, ?, ?, ?, ?, ?, ?)";
24
+      "insert into HandlingEvent (completionTime, registrationTime, type, location_id, carrierMovement_id, cargo_id) " +
25
+      "values (?, ?, ?, ?, ?, ?)";
30 26
     Object[][] handlingEventArgs = {
31 27
         //XYZ (SESTO-FIHEL-DEHAM-CNHKG-JPTOK-AUMEL)
32
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(0), new Timestamp(1), "RECEIVE", 1, null, "XYZ"},  
33
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(10), new Timestamp(11), "LOAD", 1, "CAR_001", "XYZ"},
34
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(20), new Timestamp(21), "UNLOAD", 5, "CAR_001", "XYZ"},
35
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(30), new Timestamp(31), "LOAD", 5, "CAR_002", "XYZ"},
36
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(40), new Timestamp(41), "UNLOAD", 6, "CAR_002", "XYZ"},
37
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(50), new Timestamp(51), "LOAD", 6, "CAR_003", "XYZ"},
38
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(60), new Timestamp(61), "UNLOAD", 3, "CAR_003", "XYZ"},
39
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(70), new Timestamp(71), "LOAD", 3, "CAR_004", "XYZ"},
40
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(80), new Timestamp(81), "UNLOAD", 4, "CAR_004", "XYZ"},
41
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(90), new Timestamp(91), "LOAD", 4, "CAR_005", "XYZ"},
42
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(100), new Timestamp(101), "UNLOAD", 2, "CAR_005", "XYZ"},        
43
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(110), new Timestamp(111), "CLAIM", 2, null, "XYZ"},
44
-            
28
+        {ts(0),     ts((1)),    "RECEIVE",  1,  null,  1},
29
+        {ts((10)),  ts((11)),   "LOAD",     1,  1,     1},
30
+        {ts((20)),  ts((21)),   "UNLOAD",   5,  1,     1},
31
+        {ts((30)),  ts((31)),   "LOAD",     5,  2,     1},
32
+        {ts((40)),  ts((41)),   "UNLOAD",   6,  2,     1},
33
+        {ts((50)),  ts((51)),   "LOAD",     6,  3,     1},
34
+        {ts((60)),  ts((61)),   "UNLOAD",   3,  3,     1},
35
+        {ts((70)),  ts((71)),   "LOAD",     3,  4,     1},
36
+        {ts((80)),  ts((81)),   "UNLOAD",   4,  4,     1},
37
+        {ts((90)),  ts((91)),   "LOAD",     4,  5,     1},
38
+        {ts((100)), ts((101)),  "UNLOAD",   2,  5,     1},
39
+        {ts((110)), ts((111)),  "CLAIM",    2,  null,  1},
40
+
45 41
         //ZYX (AUMEL - USCHI - DEHAM -)
46
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(0), new Timestamp(1), "RECEIVE", 2, null, "ZYX"},  
47
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(10), new Timestamp(11), "LOAD", 2, "CAR_007", "ZYX"},
48
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(20), new Timestamp(21), "UNLOAD", 7, "CAR_007", "ZYX"},
49
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(30), new Timestamp(31), "LOAD", 7, "CAR_008", "ZYX"},
50
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(40), new Timestamp(41), "UNLOAD", 6, "CAR_008", "ZYX"},
51
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(50), new Timestamp(51), "LOAD", 6, "CAR_009", "ZYX"},
52
-        
42
+        {ts((0)),   ts((1)),    "RECEIVE",  2,  null,  3},
43
+        {ts((10)),  ts((11)),   "LOAD",     2,  7,     3},
44
+        {ts((20)),  ts((21)),   "UNLOAD",   7,  7,     3},
45
+        {ts((30)),  ts((31)),   "LOAD",     7,  8,     3},
46
+        {ts((40)),  ts((41)),   "UNLOAD",   6,  8,     3},
47
+        {ts((50)),  ts((51)),   "LOAD",     6,  9,     3},
48
+
53 49
         //ABC
54
-        {UUID.randomUUID().toString().getBytes(), new Timestamp(20), new Timestamp(21), "CLAIM", 2, null, "ABC"}
55
-        
50
+        {ts((20)),  ts((21)),   "CLAIM",    2,  null,  2}
51
+
56 52
         //CBA
57 53
     };
58
-    for (Object[] handlingEventArg : handlingEventArgs) {
59
-      jdbcTemplate.update(handlingEventSql, handlingEventArg);
60
-    }
54
+    executeUpdate(jdbcTemplate, handlingEventSql, handlingEventArgs);
61 55
   }
62 56
 
63 57
   private static void loadCarrierMovementData(JdbcTemplate jdbcTemplate) {
64
-    String carrierMovementSql = "insert into CarrierMovement (id, from_id, to_id) values (?,?,?)";
58
+    String carrierMovementSql = "insert into CarrierMovement (id, carrier_movement_id, from_id, to_id) values (?,?,?,?)";
65 59
     Object[][] carrierMovementArgs = {
66 60
      // SESTO-FIHEL-DEHAM-CNHKG-JPTOK-AUMEL
67
-      {"CAR_001",1,5}, 
68
-      {"CAR_002",5,6},
69
-      {"CAR_003",6,3},
70
-      {"CAR_004",3,4},
71
-      {"CAR_005",4,2},
72
-      
61
+      {1, "CAR_001",1,5},
62
+      {2, "CAR_002",5,6},
63
+      {3, "CAR_003",6,3},
64
+      {4, "CAR_004",3,4},
65
+      {5, "CAR_005",4,2},
66
+
73 67
       // FIHEL - SESTO
74
-      {"CAR_006",5,1},
75
-      
68
+      {6, "CAR_006",5,1},
69
+
76 70
       // AUMEL - USCHI - DEHAM - SESTO
77
-      {"CAR_007",2,7}, 
78
-      {"CAR_008",7,6},
79
-      {"CAR_009",6,1}
71
+      {7, "CAR_007",2,7},
72
+      {8, "CAR_008",7,6},
73
+      {9, "CAR_009",6,1}
80 74
     };
81
-    for (Object[] carrierMovementArg : carrierMovementArgs) {
82
-      jdbcTemplate.update(carrierMovementSql, carrierMovementArg);
83
-    }
75
+    executeUpdate(jdbcTemplate, carrierMovementSql, carrierMovementArgs);
84 76
   }
85 77
 
86 78
   private static void loadCargoData(JdbcTemplate jdbcTemplate) {
87
-    String cargoSql = "insert into Cargo (id, origin_id, finalDestination_id) values (?, ?, ?)";
79
+    String cargoSql = "insert into Cargo (id, tracking_id, origin_id, finalDestination_id) values (?, ?, ?, ?)";
88 80
     Object[][] cargoArgs = {
89
-      {"XYZ",1,2},
90
-      {"ABC",1,5},
91
-      {"ZYX",2,1},
92
-      {"CBA",5,1}
81
+      {1, "XYZ",1,2},
82
+      {2, "ABC",1,5},
83
+      {3, "ZYX",2,1},
84
+      {4, "CBA",5,1}
93 85
     };
94
-    for (Object[] cargoArg : cargoArgs) {
95
-      jdbcTemplate.update(cargoSql, cargoArg);
96
-    }
86
+    executeUpdate(jdbcTemplate, cargoSql, cargoArgs);
97 87
   }
98 88
 
99 89
   private static void loadLocationData(JdbcTemplate jdbcTemplate) {
100 90
     String locationSql = "insert into Location (id, unlocode) values (?, ?)";
101 91
     Object[][] locationArgs = {
102
-      {1L, "SESTO"},
103
-      {2L, "AUMEL"},
104
-      {3L, "CNHKG"},
105
-      {4L, "JPTOK"},
106
-      {5L, "FIHEL"},
107
-      {6L, "DEHAM"},
108
-      {7L, "USCHI"}
92
+      {1, "SESTO"},
93
+      {2, "AUMEL"},
94
+      {3, "CNHKG"},
95
+      {4, "JPTOK"},
96
+      {5, "FIHEL"},
97
+      {6, "DEHAM"},
98
+      {7, "USCHI"}
109 99
     };
110
-    for (Object[] locationArg : locationArgs) {
111
-      jdbcTemplate.update(locationSql, locationArg);
112
-    }
100
+    executeUpdate(jdbcTemplate, locationSql, locationArgs);
113 101
   }
114 102
 
115 103
   public void contextInitialized(ServletContextEvent event) {
116 104
     WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext());
117 105
     DataSource dataSource = (DataSource) BeanFactoryUtils.beanOfType(context, DataSource.class);
118
-    loadSampleData(new JdbcTemplate(dataSource));
106
+    PlatformTransactionManager transactionManager = (PlatformTransactionManager) BeanFactoryUtils.beanOfType(context, PlatformTransactionManager.class);
107
+    loadSampleData(new JdbcTemplate(dataSource), new TransactionTemplate(transactionManager));
119 108
   }
120 109
 
121 110
   public void contextDestroyed(ServletContextEvent event) {}
122 111
 
112
+  public static void loadSampleData(final JdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate) {
113
+    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
114
+      protected void doInTransactionWithoutResult(TransactionStatus status) {
115
+        loadLocationData(jdbcTemplate);
116
+        loadCargoData(jdbcTemplate);
117
+        loadCarrierMovementData(jdbcTemplate);
118
+        loadHandlingEventData(jdbcTemplate);
119
+      }
120
+    });
121
+  }
122
+
123
+  private static void executeUpdate(JdbcTemplate jdbcTemplate, String sql, Object[][] args) {
124
+    for (Object[] arg : args) {
125
+      jdbcTemplate.update(sql, arg);
126
+    }
127
+  }
128
+
129
+  private static Timestamp ts(int time) {
130
+    return new Timestamp(time);
131
+  }
132
+
123 133
 }

+ 3
- 1
dddsample/src/main/resources/context-persistence.xml Wyświetl plik

@@ -8,11 +8,13 @@
8 8
     <property name="location" value="classpath:jdbc.properties"/>
9 9
   </bean>
10 10
 
11
-  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
11
+  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
12 12
     <property name="url" value="${jdbc.url}"/>
13 13
     <property name="driverClassName" value="${jdbc.driverClassName}"/>
14 14
     <property name="username" value="${jdbc.username}"/>
15 15
     <property name="password" value="${jdbc.password}"/>
16
+    <property name="initialSize" value="4"/>
17
+    <property name="defaultAutoCommit" value="false"/>
16 18
   </bean>
17 19
 
18 20
   <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

+ 0
- 1
dddsample/src/main/resources/context-service.xml Wyświetl plik

@@ -15,7 +15,6 @@
15 15
 
16 16
   <bean id="cargoService" class="se.citerus.dddsample.service.CargoServiceImpl">
17 17
     <property name="cargoRepository" ref="cargoRepository"/>
18
-    <property name="handlingEventRepository" ref="handlingEventRepository"/>
19 18
   </bean>
20 19
 
21 20
   <bean id="handlingEventService" class="se.citerus.dddsample.service.HandlingEventServiceImpl">

+ 41
- 35
dddsample/src/test/java/se/citerus/dddsample/domain/CargoTest.java Wyświetl plik

@@ -9,48 +9,54 @@ import java.util.Date;
9 9
 
10 10
 public class CargoTest extends TestCase {
11 11
 
12
-  public void testCurrentLocationUnknownWhenNoEvents() throws Exception {
12
+  // TODO:
13
+  // it seems that events are not added to the system by cargo.deliveryHistory().addEvent(),
14
+  // but rather new HandlingEvents are stored and associated with its cargo. This test should
15
+  // work against the repositories or the service layer. The delivery history of a cargo should be
16
+  // read-only from the cargo end. // PeBa
17
+
18
+  public void testlastKnownLocationUnknownWhenNoEvents() throws Exception {
13 19
     Location destination = new Location("AUMEL");
14 20
     Location origin = new Location("SESTO");
15 21
     Cargo cargo = new Cargo(new TrackingId("XYZ"), origin, destination);
16 22
 
17
-//    assertEquals(Location.UNKNOWN, cargo.currentLocation());
23
+    assertEquals(Location.UNKNOWN, cargo.lastKnownLocation());
18 24
   }
19 25
   
20
-  public void testCurrentLocationReceived() throws Exception {
26
+  public void testlastKnownLocationReceived() throws Exception {
21 27
     Cargo cargo = populateCargoReceivedStockholm();
22 28
 
23
-//    assertEquals(new Location("SESTO"), cargo.currentLocation());
29
+    assertEquals(new Location("SESTO"), cargo.lastKnownLocation());
24 30
   }
25 31
 
26
-  public void testCurrentLocationClaimed() throws Exception {
32
+  public void testlastKnownLocationClaimed() throws Exception {
27 33
     Cargo cargo = populateCargoClaimedMelbourne();
28 34
 
29
-//    assertEquals(new Location("AUMEL"), cargo.currentLocation());
35
+    assertEquals(new Location("AUMEL"), cargo.lastKnownLocation());
30 36
   }
31 37
   
32
-  public void testCurrentLocationUnloaded() throws Exception {
38
+  public void testlastKnownLocationUnloaded() throws Exception {
33 39
     Cargo cargo = populateCargoOffHongKong();
34 40
 
35
-//    assertEquals(new Location("CNHGK"), cargo.currentLocation());
41
+    assertEquals(new Location("CNHGK"), cargo.lastKnownLocation());
36 42
   }
37 43
 
38
-  public void testCurrentLocationloaded() throws Exception {
44
+  public void testlastKnownLocationloaded() throws Exception {
39 45
     Cargo cargo = populateCargoOnHamburg();
40 46
 
41
-//    assertEquals(new Location("DEHAM"), cargo.currentLocation());
47
+    assertEquals(new Location("DEHAM"), cargo.lastKnownLocation());
42 48
   }
43 49
 
44 50
   public void testAtFinalLocation() throws Exception {
45 51
     Cargo cargo = populateCargoOffMelbourne();
46 52
 
47
-//    assertTrue(cargo.atFinalDestiation());
53
+    assertTrue(cargo.hasArrived());
48 54
   }
49 55
 
50 56
   public void testNotAtFinalLocationWhenNotUnloaded() throws Exception {
51 57
     Cargo cargo = populateCargoOnHongKong();
52 58
 
53
-//    assertFalse(cargo.atFinalDestiation());
59
+    assertFalse(cargo.hasArrived());
54 60
   }
55 61
   
56 62
   public void testEquality() throws Exception {
@@ -59,16 +65,17 @@ public class CargoTest extends TestCase {
59 65
     Cargo c3 = new Cargo(new TrackingId("ABC"), new Location("A"), new Location("X"));
60 66
     Cargo c4 = new Cargo(new TrackingId("ABC"), new Location("A"), new Location("C"));
61 67
 
62
-    assertTrue("TrackingID, origin and finalDestnation should be equal if Cargos are considered equal", c1.equals(c4));
68
+    assertTrue("Cargos should be equal when TrackingIDs are equal", c1.equals(c4));
69
+    assertTrue("Cargos should be equal when TrackingIDs are equal", c1.equals(c3));
70
+    assertTrue("Cargos should be equal when TrackingIDs are equal", c3.equals(c4));
63 71
     assertFalse("Cargos are not equal when TrackingID differ", c1.equals(c2));
64
-    assertFalse("Cargos are not equal when Locations differ", c2.equals(c3));
65 72
   }
66 73
 
67 74
   // TODO: Generate test data some better way
68 75
   private Cargo populateCargoReceivedStockholm() throws Exception {
69 76
     final Cargo cargo = new Cargo(new TrackingId("XYZ"), new Location("SESTO"), new Location("AUMEL"));
70 77
 
71
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.RECEIVE, null));
78
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.RECEIVE, new Location("SESTO")));
72 79
 
73 80
     return cargo;
74 81
   }
@@ -76,26 +83,25 @@ public class CargoTest extends TestCase {
76 83
   private Cargo populateCargoClaimedMelbourne() throws Exception {
77 84
     final Cargo cargo = populateCargoOffMelbourne();
78 85
 
79
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-09"), new Date(), HandlingEvent.Type.CLAIM, null));
86
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-09"), new Date(), HandlingEvent.Type.CLAIM, new Location("AUMEL")));
80 87
     
81 88
     return cargo;
82 89
   }
83 90
   
84
-  // TODO: Generate test data some better way
85 91
   private Cargo populateCargoOffHongKong() throws Exception {
86 92
     final Cargo cargo = new Cargo(new TrackingId("XYZ"), new Location("SESTO"), new Location("AUMEL"));
87 93
 
88 94
     final CarrierMovement stockholmToHamburg = new CarrierMovement(
89 95
             new CarrierMovementId("CAR_001"), new Location("SESTO"), new Location("DEHAM"));
90 96
 
91
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
92
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
97
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
98
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
93 99
 
94 100
     final CarrierMovement hamburgToHongKong = new CarrierMovement(
95 101
             new CarrierMovementId("CAR_001"), new Location("DEHAM"), new Location("CNHGK"));
96 102
 
97
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
98
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-04"), new Date(), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
103
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
104
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-04"), new Date(), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
99 105
 
100 106
     return cargo;
101 107
   }
@@ -106,13 +112,13 @@ public class CargoTest extends TestCase {
106 112
     final CarrierMovement stockholmToHamburg = new CarrierMovement(
107 113
             new CarrierMovementId("CAR_001"), new Location("SESTO"), new Location("DEHAM"));
108 114
 
109
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
110
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
115
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
116
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
111 117
 
112 118
     final CarrierMovement hamburgToHongKong = new CarrierMovement(
113 119
             new CarrierMovementId("CAR_001"), new Location("DEHAM"), new Location("CNHGK"));
114 120
 
115
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
121
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
116 122
 
117 123
     return cargo;
118 124
   }
@@ -123,20 +129,20 @@ public class CargoTest extends TestCase {
123 129
     final CarrierMovement stockholmToHamburg = new CarrierMovement(
124 130
             new CarrierMovementId("CAR_001"), new Location("SESTO"), new Location("DEHAM"));
125 131
 
126
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
127
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
132
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
133
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
128 134
 
129 135
     final CarrierMovement hamburgToHongKong = new CarrierMovement(
130 136
             new CarrierMovementId("CAR_001"), new Location("DEHAM"), new Location("CNHGK"));
131 137
 
132
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
133
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-04"), new Date(), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
138
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
139
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-04"), new Date(), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
134 140
 
135 141
     final CarrierMovement hongKongToMelbourne = new CarrierMovement(
136 142
             new CarrierMovementId("CAR_001"), new Location("CNHGK"), new Location("AUMEL"));
137 143
 
138
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-05"), new Date(), HandlingEvent.Type.LOAD, hongKongToMelbourne));
139
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-07"), new Date(), HandlingEvent.Type.UNLOAD, hongKongToMelbourne));
144
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-05"), new Date(), HandlingEvent.Type.LOAD, hongKongToMelbourne));
145
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-07"), new Date(), HandlingEvent.Type.UNLOAD, hongKongToMelbourne));
140 146
 
141 147
     return cargo;
142 148
   }
@@ -147,19 +153,19 @@ public class CargoTest extends TestCase {
147 153
     final CarrierMovement stockholmToHamburg = new CarrierMovement(
148 154
             new CarrierMovementId("CAR_001"), new Location("SESTO"), new Location("DEHAM"));
149 155
 
150
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
151
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
156
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-01"), new Date(), HandlingEvent.Type.LOAD, stockholmToHamburg));
157
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-02"), new Date(), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
152 158
 
153 159
     final CarrierMovement hamburgToHongKong = new CarrierMovement(
154 160
             new CarrierMovementId("CAR_001"), new Location("DEHAM"), new Location("CNHGK"));
155 161
 
156
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
157
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-04"), new Date(), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
162
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-03"), new Date(), HandlingEvent.Type.LOAD, hamburgToHongKong));
163
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-04"), new Date(), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
158 164
 
159 165
     final CarrierMovement hongKongToMelbourne = new CarrierMovement(
160 166
             new CarrierMovementId("CAR_001"), new Location("CNHGK"), new Location("AUMEL"));
161 167
 
162
-//    cargo.handle(new HandlingEvent(cargo, getDate("2007-12-05"), new Date(), HandlingEvent.Type.LOAD, hongKongToMelbourne));
168
+    cargo.deliveryHistory().addEvent(new HandlingEvent(cargo, getDate("2007-12-05"), new Date(), HandlingEvent.Type.LOAD, hongKongToMelbourne));
163 169
 
164 170
     return cargo;
165 171
   }

+ 2
- 2
dddsample/src/test/java/se/citerus/dddsample/domain/DeliveryHistoryTest.java Wyświetl plik

@@ -11,7 +11,7 @@ public class DeliveryHistoryTest extends TestCase {
11 11
 
12 12
   public void testEvensOrderedByTimeOccured() throws Exception {
13 13
     DeliveryHistory dh = new DeliveryHistory();
14
-    assertTrue(dh.eventsOrderedByTime().isEmpty());
14
+    assertTrue(dh.eventsOrderedByCompletionTime().isEmpty());
15 15
 
16 16
     DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
17 17
     CarrierMovement carrierMovement = new CarrierMovement(new CarrierMovementId("CAR_001"), new Location("FROM"), new Location("TO"));
@@ -21,7 +21,7 @@ public class DeliveryHistoryTest extends TestCase {
21 21
     HandlingEvent he4 = new HandlingEvent(null, df.parse("2010-01-02"), new Date(), HandlingEvent.Type.UNLOAD, carrierMovement);
22 22
     dh.addEvent(he1, he2, he3, he4);
23 23
 
24
-    List<HandlingEvent> orderEvents = dh.eventsOrderedByTime();
24
+    List<HandlingEvent> orderEvents = dh.eventsOrderedByCompletionTime();
25 25
     assertEquals(4, orderEvents.size());
26 26
     assertSame(he2, orderEvents.get(0));
27 27
     assertSame(he4, orderEvents.get(1));

+ 5
- 2
dddsample/src/test/java/se/citerus/dddsample/domain/HandlingEventTest.java Wyświetl plik

@@ -102,10 +102,13 @@ public class HandlingEventTest extends TestCase {
102 102
     HandlingEvent ev2 = new HandlingEvent(null, timeOccured, timeRegistered, LOAD, cm);
103 103
 
104 104
     // Two handling events are not equal() even if all non-uuid fields are identical
105
-    assertFalse(ev1.equals(ev2));
106
-    assertFalse(ev2.equals(ev1));
105
+    assertTrue(ev1.equals(ev2));
106
+    assertTrue(ev2.equals(ev1));
107 107
 
108 108
     assertTrue(ev1.equals(ev1));
109
+
110
+    assertFalse(ev2.equals(null));
111
+    assertFalse(ev2.equals(new Object()));
109 112
   }
110 113
 
111 114
 }

+ 1
- 1
dddsample/src/test/java/se/citerus/dddsample/domain/TrackingScenarioTest.java Wyświetl plik

@@ -16,7 +16,7 @@ public class TrackingScenarioTest extends TestCase {
16 16
 
17 17
     DeliveryHistory deliveryHistory = populateDeliveryHistory(cargo);
18 18
 
19
-    List<HandlingEvent> handlingEvents = deliveryHistory.eventsOrderedByTime();
19
+    List<HandlingEvent> handlingEvents = deliveryHistory.eventsOrderedByCompletionTime();
20 20
 
21 21
     assertEquals(4, handlingEvents.size());
22 22
     final HandlingEvent event = deliveryHistory.lastEvent();

+ 2
- 1
dddsample/src/test/java/se/citerus/dddsample/repository/AbstractRepositoryTest.java Wyświetl plik

@@ -4,6 +4,7 @@ import org.hibernate.SessionFactory;
4 4
 import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
5 5
 import org.springframework.orm.hibernate3.HibernateTransactionManager;
6 6
 import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
7
+import org.springframework.transaction.support.TransactionTemplate;
7 8
 import se.citerus.dddsample.util.SampleDataGenerator;
8 9
 
9 10
 public abstract class AbstractRepositoryTest extends AbstractTransactionalDataSourceSpringContextTests {
@@ -31,7 +32,7 @@ public abstract class AbstractRepositoryTest extends AbstractTransactionalDataSo
31 32
 
32 33
   @Override
33 34
   protected void onSetUpInTransaction() throws Exception {
34
-    SampleDataGenerator.loadSampleData(jdbcTemplate);
35
+    SampleDataGenerator.loadSampleData(jdbcTemplate, new TransactionTemplate(transactionManager));
35 36
     sjt = new SimpleJdbcTemplate(jdbcTemplate);
36 37
   }
37 38
 

+ 3
- 2
dddsample/src/test/java/se/citerus/dddsample/repository/CargoRepositoryTest.java Wyświetl plik

@@ -24,6 +24,7 @@ public class CargoRepositoryTest extends AbstractRepositoryTest {
24 24
     assertEquals(trackingId, cargo.trackingId());
25 25
     assertEquals(origin, cargo.origin());
26 26
     assertEquals(finalDestination, cargo.finalDestination());
27
+    // TODO: verify delivery history
27 28
   }
28 29
 
29 30
   public void testSave() {
@@ -39,9 +40,9 @@ public class CargoRepositoryTest extends AbstractRepositoryTest {
39 40
 
40 41
     flush();
41 42
 
42
-    Map<String, Object> map = jdbcTemplate.queryForMap("select * from Cargo where id = 'AAA'");
43
+    Map<String, Object> map = sjt.queryForMap("select * from Cargo where tracking_id = 'AAA'");
43 44
 
44
-    assertEquals("AAA", map.get("ID"));
45
+    assertEquals("AAA", map.get("TRACKING_ID"));
45 46
     // TODO: check origin/finalDestination ids
46 47
   }
47 48
 

+ 5
- 12
dddsample/src/test/java/se/citerus/dddsample/repository/HandlingEventRepositoryTest.java Wyświetl plik

@@ -1,6 +1,9 @@
1 1
 package se.citerus.dddsample.repository;
2 2
 
3
-import se.citerus.dddsample.domain.*;
3
+import se.citerus.dddsample.domain.Cargo;
4
+import se.citerus.dddsample.domain.HandlingEvent;
5
+import se.citerus.dddsample.domain.Location;
6
+import se.citerus.dddsample.domain.TrackingId;
4 7
 
5 8
 import java.util.Date;
6 9
 import java.util.Map;
@@ -33,21 +36,11 @@ public class HandlingEventRepositoryTest extends AbstractRepositoryTest {
33 36
     flush();
34 37
 
35 38
     Map<String,Object> result = sjt.queryForMap("select * from HandlingEvent where id = ?", event.id());
36
-    assertEquals("XYZ", result.get("CARGO_ID"));
39
+    assertEquals(1L, result.get("CARGO_ID"));
37 40
     assertEquals(new Date(10), result.get("COMPLETIONTIME"));
38 41
     assertEquals(new Date(20), result.get("REGISTRATIONTIME"));
39 42
     assertEquals("CLAIM", result.get("TYPE"));
40 43
     // TODO: the rest of the columns
41 44
   }
42 45
 
43
-  public void testFindDeliveryHistory() {
44
-    DeliveryHistory dh = handlingEventRepository.findDeliveryHistory(new TrackingId("XYZ"));
45
-
46
-    assertNotNull(dh);
47
-    assertEquals(12, dh.eventsOrderedByTime().size());
48
-    HandlingEvent lastEvent = dh.lastEvent();
49
-    assertNotNull(lastEvent);
50
-    assertEquals("AUMEL", lastEvent.location().unlocode());
51
-    // TODO: the rest of the properties, and maybe a longer list of events
52
-  }
53 46
 }

+ 8
- 16
dddsample/src/test/java/se/citerus/dddsample/service/CargoServiceTest.java Wyświetl plik

@@ -71,6 +71,13 @@ public class CargoServiceTest extends AbstractDependencyInjectionSpringContextTe
71 71
    */
72 72
   public void testCargoServiceFindByTrackingIdScenario() {
73 73
     final Cargo cargo = new Cargo(new TrackingId("XYZ"), new Location("ORIG"), new Location("DEST"));
74
+    HandlingEvent claimed = new HandlingEvent(cargo, new Date(10), new Date(20), HandlingEvent.Type.CLAIM, new Location("SESTO"));
75
+    CarrierMovement carrierMovement = new CarrierMovement(new CarrierMovementId("CAR_001"), new Location("SESTO"), new Location("MUGER"));
76
+    HandlingEvent loaded = new HandlingEvent(cargo, new Date(12), new Date(25), HandlingEvent.Type.LOAD, carrierMovement);
77
+    HandlingEvent unloaded = new HandlingEvent(cargo, new Date(100), new Date(110), HandlingEvent.Type.UNLOAD, carrierMovement);
78
+    // Add out of order to verify ordering in DTO
79
+    cargo.deliveryHistory().addEvent(loaded, unloaded, claimed);
80
+
74 81
     final IAnswer<Cargo> cargoAnswer = new TransactionVerifyingAnswer<Cargo>() {
75 82
       public Cargo answerWithinTransaction() throws Throwable {
76 83
         return cargo;
@@ -78,22 +85,7 @@ public class CargoServiceTest extends AbstractDependencyInjectionSpringContextTe
78 85
     };
79 86
     expect(cargoRepository.find(new TrackingId("XYZ"))).andAnswer(cargoAnswer);
80 87
 
81
-    final IAnswer<DeliveryHistory> deliveryHistoryAnswer = new TransactionVerifyingAnswer<DeliveryHistory>() {
82
-      protected DeliveryHistory answerWithinTransaction() throws Throwable {
83
-        DeliveryHistory dh = new DeliveryHistory();
84
-        HandlingEvent claimed = new HandlingEvent(cargo, new Date(10), new Date(20), HandlingEvent.Type.CLAIM, new Location("SESTO"));
85
-        CarrierMovement carrierMovement = new CarrierMovement(new CarrierMovementId("CAR_001"), new Location("SESTO"), new Location("MUGER"));
86
-        HandlingEvent loaded = new HandlingEvent(cargo, new Date(12), new Date(25), HandlingEvent.Type.LOAD, carrierMovement);
87
-        HandlingEvent unloaded = new HandlingEvent(cargo, new Date(100), new Date(110), HandlingEvent.Type.UNLOAD, carrierMovement);
88
-
89
-        // Add out of order to verify ordering in DTO
90
-        dh.addEvent(loaded, unloaded, claimed);
91
-        return dh;
92
-      }
93
-    };
94
-    expect(handlingEventRepository.findDeliveryHistory(new TrackingId("XYZ"))).andAnswer(deliveryHistoryAnswer);
95
-
96
-    replay(cargoRepository, handlingEventRepository);
88
+    replay(cargoRepository);
97 89
 
98 90
 
99 91
     // Tested call