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

Made all domain model classes inherit common pattern base classes, removing lots of boilerplate code.

Made all immutable fields final, setting to null in package local no-args ctor (Hibernate will stil be able to set fields in runtime).

Added javadoc on Cargo.

Removed "empty itinerary" null pattern object, since a cargo is not always supposed to have an itinerary. More work left here though.
peter_backlund 17 лет назад
Родитель
Сommit
6cdbca4e47
26 измененных файлов: 205 добавлений и 502 удалений
  1. 40
    36
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Cargo.java
  2. 13
    35
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Delivery.java
  3. 4
    33
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Itinerary.java
  4. 11
    45
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Leg.java
  5. 6
    32
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Projections.java
  6. 7
    4
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/RouteSpecification.java
  7. 2
    1
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/RoutingStatus.java
  8. 5
    23
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/TrackingId.java
  9. 1
    1
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/TransportStatus.java
  10. 4
    21
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/EventSequenceNumber.java
  11. 1
    2
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/HandlingEvent.java
  12. 0
    1
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/HandlingEventRepository.java
  13. 1
    1
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/HandlingHistory.java
  14. 19
    17
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/location/CustomsZone.java
  15. 14
    39
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/location/Location.java
  16. 4
    23
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/location/UnLocode.java
  17. 10
    37
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/shared/HandlingActivity.java
  18. 8
    40
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/CarrierMovement.java
  19. 4
    24
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/Schedule.java
  20. 9
    28
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/Voyage.java
  21. 5
    25
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/VoyageNumber.java
  22. 8
    1
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/shared/experimental/EntitySupport.java
  23. 0
    7
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/shared/experimental/ValueObject.java
  24. 3
    1
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/shared/experimental/ValueObjectSupport.java
  25. 26
    20
      dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/interfaces/booking/facade/DTOAssembler.java
  26. 0
    5
      dddsample/tracking/core/src/test/java/se/citerus/dddsample/tracking/core/domain/model/cargo/ItineraryTest.java

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

@@ -6,8 +6,7 @@ import se.citerus.dddsample.tracking.core.domain.model.location.CustomsZone;
6 6
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7 7
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
8 8
 import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
9
-import se.citerus.dddsample.tracking.core.domain.shared.DomainObjectUtils;
10
-import se.citerus.dddsample.tracking.core.domain.shared.Entity;
9
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.EntitySupport;
11 10
 
12 11
 import java.util.Date;
13 12
 
@@ -46,9 +45,9 @@ import java.util.Date;
46 45
  * or not a cargo is misdirected, what the current status of the cargo is (on board carrier,
47 46
  * in port etc), are captured in this aggregate.
48 47
  */
49
-public class Cargo implements Entity<Cargo> {
48
+public class Cargo extends EntitySupport<Cargo,TrackingId> {
50 49
 
51
-  private TrackingId trackingId;
50
+  private final TrackingId trackingId;
52 51
   private RouteSpecification routeSpecification;
53 52
   private Itinerary itinerary;
54 53
   private Delivery delivery;
@@ -64,6 +63,11 @@ public class Cargo implements Entity<Cargo> {
64 63
     this.projections = new Projections(delivery, itinerary, routeSpecification);
65 64
   }
66 65
 
66
+  @Override
67
+  public TrackingId identity() {
68
+    return trackingId;
69
+  }
70
+
67 71
   /**
68 72
    * The tracking id is the identity of this entity, and is unique.
69 73
    *
@@ -77,7 +81,7 @@ public class Cargo implements Entity<Cargo> {
77 81
    * @return The itinerary. Never null.
78 82
    */
79 83
   public Itinerary itinerary() {
80
-    return DomainObjectUtils.nullSafe(this.itinerary, Itinerary.EMPTY_ITINERARY);
84
+    return itinerary;
81 85
   }
82 86
 
83 87
   /**
@@ -87,30 +91,51 @@ public class Cargo implements Entity<Cargo> {
87 91
     return routeSpecification;
88 92
   }
89 93
 
94
+  /**
95
+   * @return Estimated time of arrival.
96
+   */
90 97
   public Date estimatedTimeOfArrival() {
91 98
     return projections.estimatedTimeOfArrival();
92 99
   }
93 100
 
101
+  /**
102
+   * @return Next expected activity.
103
+   */
94 104
   public HandlingActivity nextExpectedActivity() {
95 105
     return projections.nextExpectedActivity();
96 106
   }
97 107
 
108
+  /**
109
+   * @return True if cargo is misdirected.
110
+   */
98 111
   public boolean isMisdirected() {
99 112
     return delivery.isMisdirected(itinerary, routeSpecification);
100 113
   }
101 114
 
115
+  /**
116
+   * @return Transport status.
117
+   */
102 118
   public TransportStatus transportStatus() {
103 119
     return delivery.transportStatus();
104 120
   }
105 121
 
122
+  /**
123
+   * @return Routing status.
124
+   */
106 125
   public RoutingStatus routingStatus() {
107 126
     return delivery.routingStatus(itinerary, routeSpecification);
108 127
   }
109 128
 
129
+  /**
130
+   * @return Current voyage.
131
+   */
110 132
   public Voyage currentVoyage() {
111 133
     return delivery.currentVoyage();
112 134
   }
113 135
 
136
+  /**
137
+   * @return Last known location.
138
+   */
114 139
   public Location lastKnownLocation() {
115 140
     return delivery.lastKnownLocation();
116 141
   }
@@ -141,15 +166,24 @@ public class Cargo implements Entity<Cargo> {
141 166
     this.projections = new Projections(delivery, itinerary, routeSpecification);
142 167
   }
143 168
 
169
+  /**
170
+   * @return Customs zone.
171
+   */
144 172
   public CustomsZone customsZone() {
145 173
     return routeSpecification.destination().customsZone();
146 174
   }
147 175
 
148 176
 
177
+  /**
178
+   * @return Customs clearance point.
179
+   */
149 180
   public Location customsClearancePoint() {
150 181
     return customsZone().entryPoint(itinerary.locations());
151 182
   }
152 183
 
184
+  /**
185
+   * @return True if the cargo is ready to be claimed.
186
+   */
153 187
   public boolean isReadyToClaim() {
154 188
     return delivery.isUnloadedAtDestination(routeSpecification);
155 189
   }
@@ -178,43 +212,13 @@ public class Cargo implements Entity<Cargo> {
178 212
   }
179 213
 
180 214
   @Override
181
-  public boolean sameAs(final Cargo other) {
182
-    return other != null && trackingId().sameValueAs(other.trackingId());
183
-  }
184
-
185
-  /**
186
-   * @param object to compare
187
-   * @return True if they have the same identity
188
-   * @see #sameAs(Cargo)
189
-   */
190
-  @Override
191
-  public boolean equals(final Object object) {
192
-    if (this == object) return true;
193
-    if (object == null || getClass() != object.getClass()) return false;
194
-
195
-    final Cargo other = (Cargo) object;
196
-    return sameAs(other);
197
-  }
198
-
199
-  /**
200
-   * @return Hash code of tracking id.
201
-   */
202
-  @Override
203
-  public int hashCode() {
204
-    return trackingId.hashCode();
205
-  }
206
-
207
-  @Override
208 215
   public String toString() {
209 216
     return trackingId + " (" + routeSpecification + ")";
210 217
   }
211 218
 
212 219
   Cargo() {
213 220
     // Needed by Hibernate
221
+    trackingId = null;
214 222
   }
215 223
 
216
-  // Auto-generated surrogate key
217
-  @SuppressWarnings("UnusedDeclaration")
218
-  private Long id;
219
-
220 224
 }

+ 13
- 35
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Delivery.java Просмотреть файл

@@ -1,15 +1,13 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import org.apache.commons.lang.builder.EqualsBuilder;
5
-import org.apache.commons.lang.builder.HashCodeBuilder;
6 4
 import static se.citerus.dddsample.tracking.core.domain.model.cargo.RoutingStatus.*;
7 5
 import static se.citerus.dddsample.tracking.core.domain.model.cargo.TransportStatus.ONBOARD_CARRIER;
8 6
 import static se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent.Type.*;
9 7
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
10 8
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
11 9
 import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
12
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
10
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
13 11
 
14 12
 import java.util.Date;
15 13
 
@@ -17,10 +15,10 @@ import java.util.Date;
17 15
  * Everything about the delivery of the cargo, i.e. where the cargo is
18 16
  * right now, whether or not it's routed, misdirected and so on.
19 17
  */
20
-public class Delivery implements ValueObject<Delivery> {
18
+public class Delivery extends ValueObjectSupport<Delivery> {
21 19
 
22
-  private HandlingActivity mostRecentHandlingActivity;
23
-  private Date calculatedAt;
20
+  private final HandlingActivity mostRecentHandlingActivity;
21
+  private final Date calculatedAt;
24 22
 
25 23
   /**
26 24
    * Derives a new delivery when a cargo has been handled.
@@ -57,7 +55,7 @@ public class Delivery implements ValueObject<Delivery> {
57 55
    * @return Last known location of the cargo, or Location.UNKNOWN if the delivery history is empty.
58 56
    */
59 57
   Location lastKnownLocation() {
60
-    if (mostRecentHandlingActivity != null) {
58
+    if (isHandled()) {
61 59
       return mostRecentHandlingActivity.location();
62 60
     } else {
63 61
       return Location.UNKNOWN;
@@ -68,13 +66,17 @@ public class Delivery implements ValueObject<Delivery> {
68 66
    * @return Current voyage.
69 67
    */
70 68
   Voyage currentVoyage() {
71
-    if (mostRecentHandlingActivity != null && transportStatus().equals(ONBOARD_CARRIER)) {
69
+    if (isHandled() && transportStatus().equals(ONBOARD_CARRIER)) {
72 70
       return mostRecentHandlingActivity.voyage();
73 71
     } else {
74 72
       return Voyage.NONE;
75 73
     }
76 74
   }
77 75
 
76
+  private boolean isHandled() {
77
+    return mostRecentHandlingActivity != null;
78
+  }
79
+
78 80
   /**
79 81
    * Check if cargo is misdirected.
80 82
    * <p/>
@@ -105,7 +107,7 @@ public class Delivery implements ValueObject<Delivery> {
105 107
    * @param routeSpecification route specification
106 108
    */
107 109
   boolean isUnloadedAtDestination(final RouteSpecification routeSpecification) {
108
-    return mostRecentHandlingActivity != null &&
110
+    return isHandled() &&
109 111
           (CLAIM.sameValueAs(mostRecentHandlingActivity.type()) || UNLOAD.sameValueAs(mostRecentHandlingActivity.type()) &&
110 112
            routeSpecification.destination().sameAs(mostRecentHandlingActivity.location()));
111 113
   }
@@ -144,34 +146,10 @@ public class Delivery implements ValueObject<Delivery> {
144 146
            !isMisdirected(itinerary, routeSpecification);
145 147
   }
146 148
 
147
-  @Override
148
-  public boolean sameValueAs(final Delivery other) {
149
-    return other != null && new EqualsBuilder().
150
-      append(this.mostRecentHandlingActivity, other.mostRecentHandlingActivity).
151
-      append(this.calculatedAt, other.calculatedAt).
152
-      isEquals();
153
-  }
154
-
155
-  @Override
156
-  public boolean equals(final Object o) {
157
-    if (this == o) return true;
158
-    if (o == null || getClass() != o.getClass()) return false;
159
-
160
-    final Delivery other = (Delivery) o;
161
-
162
-    return sameValueAs(other);
163
-  }
164
-
165
-  @Override
166
-  public int hashCode() {
167
-    return new HashCodeBuilder().
168
-      append(mostRecentHandlingActivity).
169
-      append(calculatedAt).
170
-      toHashCode();
171
-  }
172
-
173 149
   Delivery() {
174 150
     // Needed by Hibernate
151
+    calculatedAt = null;
152
+    mostRecentHandlingActivity = null;
175 153
   }
176 154
 
177 155
 }

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

@@ -6,18 +6,16 @@ import se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent;
6 6
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7 7
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
8 8
 import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
9
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
9
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
10 10
 
11 11
 import java.util.*;
12 12
 
13 13
 /**
14 14
  * An itinerary.
15 15
  */
16
-public class Itinerary implements ValueObject<Itinerary> {
16
+public class Itinerary extends ValueObjectSupport<Itinerary> {
17 17
 
18
-  private List<Leg> legs = Collections.emptyList();
19
-
20
-  static final Itinerary EMPTY_ITINERARY = new Itinerary();
18
+  private final List<Leg> legs;
21 19
   private static final Date END_OF_DAYS = new Date(Long.MAX_VALUE);
22 20
 
23 21
   /**
@@ -210,31 +208,6 @@ public class Itinerary implements ValueObject<Itinerary> {
210 208
     return null;
211 209
   }
212 210
 
213
-
214
-  /**
215
-   * @param other itinerary to compare
216
-   * @return <code>true</code> if the legs in this and the other itinerary are all equal.
217
-   */
218
-  @Override
219
-  public boolean sameValueAs(final Itinerary other) {
220
-    return other != null && legs.equals(other.legs);
221
-  }
222
-
223
-  @Override
224
-  public boolean equals(final Object o) {
225
-    if (this == o) return true;
226
-    if (o == null || getClass() != o.getClass()) return false;
227
-
228
-    final Itinerary itinerary = (Itinerary) o;
229
-
230
-    return sameValueAs(itinerary);
231
-  }
232
-
233
-  @Override
234
-  public int hashCode() {
235
-    return legs.hashCode();
236
-  }
237
-
238 211
   @Override
239 212
   public String toString() {
240 213
     return StringUtils.join(legs, "\n");
@@ -242,9 +215,7 @@ public class Itinerary implements ValueObject<Itinerary> {
242 215
 
243 216
   Itinerary() {
244 217
     // Needed by Hibernate
218
+    legs = null;
245 219
   }
246 220
 
247
-  // Auto-generated surrogate key
248
-  @SuppressWarnings("UnusedDeclaration")
249
-  private Long id;
250 221
 }

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

@@ -1,26 +1,24 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import org.apache.commons.lang.builder.EqualsBuilder;
5
-import org.apache.commons.lang.builder.HashCodeBuilder;
6 4
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7 5
 import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
8
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
6
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
9 7
 
10 8
 import java.util.Date;
11 9
 
12 10
 /**
13 11
  * An itinerary consists of one or more legs.
14 12
  */
15
-public class Leg implements ValueObject<Leg> {
13
+public class Leg extends ValueObjectSupport<Leg> {
16 14
 
17
-  private Voyage voyage;
18
-  private Location loadLocation;
19
-  private Location unloadLocation;
20
-  private Date loadTime;
21
-  private Date unloadTime;
15
+  private final Voyage voyage;
16
+  private final Location loadLocation;
17
+  private final Location unloadLocation;
18
+  private final Date loadTime;
19
+  private final Date unloadTime;
22 20
 
23
-  // TODO hide this, use factory
21
+  // TODO hide this, use factory only
24 22
   public Leg(Voyage voyage, Location loadLocation, Location unloadLocation, Date loadTime, Date unloadTime) {
25 23
     Validate.notNull(voyage, "Voyage is required");
26 24
     Validate.notNull(loadLocation, "Load location is required");
@@ -86,38 +84,6 @@ public class Leg implements ValueObject<Leg> {
86 84
   }
87 85
 
88 86
   @Override
89
-  public boolean sameValueAs(final Leg other) {
90
-    return other != null && new EqualsBuilder().
91
-      append(this.voyage, other.voyage).
92
-      append(this.loadLocation, other.loadLocation).
93
-      append(this.unloadLocation, other.unloadLocation).
94
-      append(this.loadTime, other.loadTime).
95
-      append(this.unloadTime, other.unloadTime).
96
-      isEquals();
97
-  }
98
-
99
-  @Override
100
-  public boolean equals(final Object o) {
101
-    if (this == o) return true;
102
-    if (o == null || getClass() != o.getClass()) return false;
103
-
104
-    Leg leg = (Leg) o;
105
-
106
-    return sameValueAs(leg);
107
-  }
108
-
109
-  @Override
110
-  public int hashCode() {
111
-    return new HashCodeBuilder().
112
-      append(voyage).
113
-      append(loadLocation).
114
-      append(unloadLocation).
115
-      append(loadTime).
116
-      append(unloadTime).
117
-      toHashCode();
118
-  }
119
-
120
-  @Override
121 87
   public String toString() {
122 88
     return "Load in " + loadLocation + " at " + loadTime +
123 89
       " --- Unload in " + unloadLocation + " at " + unloadTime;
@@ -125,9 +91,9 @@ public class Leg implements ValueObject<Leg> {
125 91
 
126 92
   Leg() {
127 93
     // Needed by Hibernate
94
+    voyage = null;
95
+    loadLocation = unloadLocation = null;
96
+    loadTime = unloadTime = null;
128 97
   }
129 98
 
130
-  // Auto-generated surrogate key
131
-  private Long id;
132
-
133 99
 }

+ 6
- 32
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/Projections.java Просмотреть файл

@@ -1,11 +1,9 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3
-import org.apache.commons.lang.builder.EqualsBuilder;
4
-import org.apache.commons.lang.builder.HashCodeBuilder;
5 3
 import static se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent.Type.*;
6 4
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7 5
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
8
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
6
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
9 7
 
10 8
 import java.util.Date;
11 9
 import java.util.Iterator;
@@ -16,10 +14,10 @@ import java.util.Iterator;
16 14
  * <p/>
17 15
  * It is updated on routing changes as well as handling.
18 16
  */
19
-class Projections implements ValueObject<Projections> {
17
+class Projections extends ValueObjectSupport<Projections> {
20 18
 
21
-  private Date estimatedTimeOfArrival;
22
-  private HandlingActivity nextExpectedActivity;
19
+  private final Date estimatedTimeOfArrival;
20
+  private final HandlingActivity nextExpectedActivity;
23 21
 
24 22
   private static final Date ETA_UNKOWN = null;
25 23
   private static final HandlingActivity NO_ACTIVITY = null;
@@ -134,34 +132,10 @@ class Projections implements ValueObject<Projections> {
134 132
     return NO_ACTIVITY;
135 133
   }
136 134
 
137
-
138
-  @Override
139
-  public boolean sameValueAs(final Projections other) {
140
-    return other != null && new EqualsBuilder().
141
-      append(this.estimatedTimeOfArrival, other.estimatedTimeOfArrival).
142
-      append(this.nextExpectedActivity, other.nextExpectedActivity).
143
-      isEquals();
144
-  }
145
-
146
-  @Override
147
-  public boolean equals(final Object o) {
148
-    if (this == o) return true;
149
-    if (o == null || getClass() != o.getClass()) return false;
150
-
151
-    final Projections other = (Projections) o;
152
-    return sameValueAs(other);
153
-  }
154
-
155
-  @Override
156
-  public int hashCode() {
157
-    return new HashCodeBuilder().
158
-      append(estimatedTimeOfArrival).
159
-      append(nextExpectedActivity).
160
-      toHashCode();
161
-  }
162
-
163 135
   Projections() {
164 136
     // Needed by Hibernate
137
+    estimatedTimeOfArrival = null;
138
+    nextExpectedActivity = null;
165 139
   }
166 140
 
167 141
 }

+ 7
- 4
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/cargo/RouteSpecification.java Просмотреть файл

@@ -5,7 +5,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
5 5
 import org.apache.commons.lang.builder.HashCodeBuilder;
6 6
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7 7
 import se.citerus.dddsample.tracking.core.domain.shared.AbstractSpecification;
8
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
8
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObject;
9 9
 
10 10
 import java.util.Date;
11 11
 
@@ -13,11 +13,12 @@ import java.util.Date;
13 13
  * Route specification. Describes where a cargo orign and destination is,
14 14
  * and the arrival deadline.
15 15
  */
16
+// TODO use composition instead of inheritance
16 17
 public class RouteSpecification extends AbstractSpecification<Itinerary> implements ValueObject<RouteSpecification> {
17 18
 
18
-  private Location origin;
19
-  private Location destination;
20
-  private Date arrivalDeadline;
19
+  private final Location origin;
20
+  private final Location destination;
21
+  private final Date arrivalDeadline;
21 22
 
22 23
   /**
23 24
    * @param origin          origin location - can't be the same as the destination
@@ -123,6 +124,8 @@ public class RouteSpecification extends AbstractSpecification<Itinerary> impleme
123 124
 
124 125
   RouteSpecification() {
125 126
     // Needed by Hibernate
127
+    origin = destination = null;
128
+    arrivalDeadline = null;
126 129
   }
127 130
 
128 131
 }

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

@@ -1,6 +1,7 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
3
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObject;
4
+
4 5
 
5 6
 /**
6 7
  * The different routing statuses of a cargo.

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

@@ -2,16 +2,16 @@ package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3 3
 import org.apache.commons.lang.StringUtils;
4 4
 import org.apache.commons.lang.Validate;
5
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
5
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
6 6
 
7 7
 import java.io.Serializable;
8 8
 
9 9
 /**
10 10
  * Uniquely identifies a particular cargo. Automatically generated by the application.
11 11
  */
12
-public final class TrackingId implements ValueObject<TrackingId>, Serializable {
12
+public final class TrackingId extends ValueObjectSupport<TrackingId> implements Serializable {
13 13
 
14
-  private String id;
14
+  private final String id;
15 15
 
16 16
   /**
17 17
    * Constructor.
@@ -36,31 +36,13 @@ public final class TrackingId implements ValueObject<TrackingId>, Serializable {
36 36
   }
37 37
 
38 38
   @Override
39
-  public boolean equals(Object o) {
40
-    if (this == o) return true;
41
-    if (o == null || getClass() != o.getClass()) return false;
42
-
43
-    TrackingId other = (TrackingId) o;
44
-
45
-    return sameValueAs(other);
46
-  }
47
-
48
-  @Override
49
-  public int hashCode() {
50
-    return id.hashCode();
51
-  }
52
-
53
-  @Override
54
-  public boolean sameValueAs(TrackingId other) {
55
-    return other != null && this.id.equals(other.id);
56
-  }
57
-
58
-  @Override
59 39
   public String toString() {
60 40
     return id;
61 41
   }
62 42
 
63 43
   TrackingId() {
64 44
     // Needed by Hibernate
45
+    id = null;
65 46
   }
47
+  
66 48
 }

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

@@ -1,7 +1,7 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.cargo;
2 2
 
3 3
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
4
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
4
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObject;
5 5
 
6 6
 /**
7 7
  * Represents the different transport statuses for a cargo.

+ 4
- 21
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/EventSequenceNumber.java Просмотреть файл

@@ -1,12 +1,12 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.handling;
2 2
 
3
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
3
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
4 4
 
5 5
 import java.util.concurrent.atomic.AtomicLong;
6 6
 
7
-public class EventSequenceNumber implements ValueObject<EventSequenceNumber> {
7
+public class EventSequenceNumber extends ValueObjectSupport<EventSequenceNumber> {
8 8
 
9
-  private long value;
9
+  private final long value;
10 10
   private static final AtomicLong SEQUENCE = new AtomicLong(System.currentTimeMillis());
11 11
 
12 12
   private EventSequenceNumber(final long value) {
@@ -22,30 +22,13 @@ public class EventSequenceNumber implements ValueObject<EventSequenceNumber> {
22 22
   }
23 23
 
24 24
   @Override
25
-  public boolean sameValueAs(final EventSequenceNumber other) {
26
-    return false;
27
-  }
28
-
29
-  @Override
30
-  public boolean equals(Object o) {
31
-    if (this == o) return true;
32
-    if (o == null || getClass() != o.getClass()) return false;
33
-
34
-    return sameValueAs((EventSequenceNumber) o);
35
-  }
36
-
37
-  @Override
38
-  public int hashCode() {
39
-    return Long.valueOf(value).hashCode();
40
-  }
41
-
42
-  @Override
43 25
   public String toString() {
44 26
     return String.valueOf(value);
45 27
   }
46 28
 
47 29
   EventSequenceNumber() {
48 30
     // Needed by Hibernate
31
+    value = -1L;
49 32
   }
50 33
 
51 34
 }

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

@@ -5,12 +5,11 @@ import org.apache.commons.lang.builder.EqualsBuilder;
5 5
 import org.apache.commons.lang.builder.HashCodeBuilder;
6 6
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Cargo;
7 7
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
8
-import se.citerus.dddsample.tracking.core.domain.model.handling.EventSequenceNumber;
9 8
 import se.citerus.dddsample.tracking.core.domain.model.shared.HandlingActivity;
10 9
 import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
11 10
 import se.citerus.dddsample.tracking.core.domain.shared.DomainEvent;
12 11
 import se.citerus.dddsample.tracking.core.domain.shared.DomainObjectUtils;
13
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
12
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObject;
14 13
 
15 14
 import java.util.Date;
16 15
 

+ 0
- 1
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/HandlingEventRepository.java Просмотреть файл

@@ -1,7 +1,6 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.handling;
2 2
 
3 3
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Cargo;
4
-import se.citerus.dddsample.tracking.core.domain.model.handling.EventSequenceNumber;
5 4
 
6 5
 /**
7 6
  * Handling event repository.

+ 1
- 1
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/handling/HandlingHistory.java Просмотреть файл

@@ -2,7 +2,7 @@ package se.citerus.dddsample.tracking.core.domain.model.handling;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4 4
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Cargo;
5
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
5
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObject;
6 6
 
7 7
 import java.util.*;
8 8
 import static java.util.Collections.sort;

+ 19
- 17
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/location/CustomsZone.java Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.location;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import se.citerus.dddsample.tracking.core.domain.shared.Entity;
4
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.EntitySupport;
5 5
 
6 6
 import java.util.Arrays;
7 7
 import java.util.List;
@@ -10,10 +10,10 @@ import java.util.regex.Pattern;
10 10
 /**
11 11
  * A geographical zone within which there are no customs restrictions or checks.
12 12
  */
13
-public class CustomsZone implements Entity<CustomsZone> {
13
+public class CustomsZone extends EntitySupport<CustomsZone,String> {
14 14
 
15
-  private String code;
16
-  private String name;
15
+  private final String code;
16
+  private final String name;
17 17
 
18 18
   // TODO: Find out what the standards are for this, if any. For now:
19 19
   // For CustomsZone code, we are using the "country code" portion of the UnLocode,
@@ -36,6 +36,11 @@ public class CustomsZone implements Entity<CustomsZone> {
36 36
     this.name = name;
37 37
   }
38 38
 
39
+  @Override
40
+  public String identity() {
41
+    return code;
42
+  }
43
+
39 44
   /**
40 45
    * Where would a Cargo enter this CustomsZone if it were
41 46
    * following this route. Note that specific voyages, etc do not
@@ -44,9 +49,11 @@ public class CustomsZone implements Entity<CustomsZone> {
44 49
    * @param route
45 50
    * @return
46 51
    */
47
-  public Location entryPoint(List<Location> route) {
52
+  public Location entryPoint(final List<Location> route) {
48 53
     for (Location location : route) {
49
-      if (this.includes(location)) return location;
54
+      if (this.includes(location)) {
55
+        return location;
56
+      }
50 57
     }
51 58
     return null; //The route does not enter this CustomsZone
52 59
   }
@@ -58,7 +65,7 @@ public class CustomsZone implements Entity<CustomsZone> {
58 65
    * @param route
59 66
    * @return
60 67
    */
61
-  public Location entryPoint(Location... route) {
68
+  public Location entryPoint(final Location... route) {
62 69
     return entryPoint(Arrays.asList(route));
63 70
   }
64 71
 
@@ -102,23 +109,18 @@ public class CustomsZone implements Entity<CustomsZone> {
102 109
     return name;
103 110
   }
104 111
 
105
-  @Override
106
-  public String toString() {
107
-    return code + "[" + name + "]";
112
+  public boolean includes(final Location location) {
113
+    return this.sameAs(location.customsZone());
108 114
   }
109 115
 
110 116
   @Override
111
-  public boolean sameAs(CustomsZone other) {
112
-    return code.equals(other.code);
117
+  public String toString() {
118
+    return code + "[" + name + "]";
113 119
   }
114 120
 
115 121
   CustomsZone() {
116 122
     // Needed by Hibernate
123
+    code = name = null;
117 124
   }
118 125
 
119
-  public boolean includes(Location location) {
120
-    return this.sameAs(location.customsZone());
121
-  }
122
-
123
-
124 126
 }

+ 14
- 39
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/location/Location.java Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.location;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import se.citerus.dddsample.tracking.core.domain.shared.Entity;
4
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.EntitySupport;
5 5
 
6 6
 import java.util.TimeZone;
7 7
 
@@ -11,9 +11,9 @@ import java.util.TimeZone;
11 11
  * <p/>
12 12
  * It is uniquely identified by a UN Locode.
13 13
  */
14
-public final class Location implements Entity<Location> {
14
+public final class Location extends EntitySupport<Location, UnLocode> {
15 15
 
16
-  private UnLocode unLocode;
16
+  private final UnLocode unLocode;
17 17
   private String name;
18 18
   private TimeZone timeZone;
19 19
   private CustomsZone customsZone;
@@ -30,8 +30,8 @@ public final class Location implements Entity<Location> {
30 30
    *
31 31
    * @param unLocode    UN Locode
32 32
    * @param name        location name
33
-   * @param timeZone
34
-   * @param customsZone
33
+   * @param timeZone    time zone
34
+   * @param customsZone customs zone
35 35
    * @throws IllegalArgumentException if the UN Locode or name is null
36 36
    */
37 37
   Location(final UnLocode unLocode, final String name, final TimeZone timeZone, final CustomsZone customsZone) {
@@ -46,6 +46,11 @@ public final class Location implements Entity<Location> {
46 46
     this.customsZone = customsZone;
47 47
   }
48 48
 
49
+  @Override
50
+  public UnLocode identity() {
51
+    return unLocode;
52
+  }
53
+
49 54
   /**
50 55
    * @return UN Locode for this location.
51 56
    */
@@ -68,35 +73,10 @@ public final class Location implements Entity<Location> {
68 73
   }
69 74
 
70 75
   /**
71
-   * @param object to compare
72
-   * @return Since this is an entity this will be true iff UN locodes are equal.
73
-   */
74
-  @Override
75
-  public boolean equals(final Object object) {
76
-    if (object == null) {
77
-      return false;
78
-    }
79
-    if (this == object) {
80
-      return true;
81
-    }
82
-    if (!(object instanceof Location)) {
83
-      return false;
84
-    }
85
-    Location other = (Location) object;
86
-    return sameAs(other);
87
-  }
88
-
89
-  @Override
90
-  public boolean sameAs(final Location other) {
91
-    return this.unLocode.sameValueAs(other.unLocode);
92
-  }
93
-
94
-  /**
95
-   * @return Hash code of UN locode.
76
+   * @return Time zone of this location.
96 77
    */
97
-  @Override
98
-  public int hashCode() {
99
-    return unLocode.hashCode();
78
+  public TimeZone timeZone() {
79
+    return timeZone;
100 80
   }
101 81
 
102 82
   @Override
@@ -106,12 +86,7 @@ public final class Location implements Entity<Location> {
106 86
 
107 87
   Location() {
108 88
     // Needed by Hibernate
109
-  }
110
-
111
-  private Long id;
112
-
113
-  public TimeZone timeZone() {
114
-    return timeZone;
89
+    unLocode = null;
115 90
   }
116 91
 
117 92
 }

+ 4
- 23
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/location/UnLocode.java Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.location;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
4
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
5 5
 
6 6
 import java.util.regex.Pattern;
7 7
 
@@ -11,9 +11,9 @@ import java.util.regex.Pattern;
11 11
  * http://www.unece.org/cefact/locode/
12 12
  * http://www.unece.org/cefact/locode/DocColumnDescription.htm#LOCODE
13 13
  */
14
-public final class UnLocode implements ValueObject<UnLocode> {
14
+public final class UnLocode extends ValueObjectSupport<UnLocode> {
15 15
 
16
-  private String unlocode;
16
+  private final String unlocode;
17 17
 
18 18
   // Country code is exactly two letters.
19 19
   // Location code is usually three letters, but may contain the numbers 2-9 as well
@@ -40,32 +40,13 @@ public final class UnLocode implements ValueObject<UnLocode> {
40 40
   }
41 41
 
42 42
   @Override
43
-  public boolean equals(final Object o) {
44
-    if (this == o) return true;
45
-    if (o == null || getClass() != o.getClass()) return false;
46
-
47
-    UnLocode other = (UnLocode) o;
48
-
49
-    return sameValueAs(other);
50
-  }
51
-
52
-  @Override
53
-  public int hashCode() {
54
-    return unlocode.hashCode();
55
-  }
56
-
57
-  @Override
58
-  public boolean sameValueAs(UnLocode other) {
59
-    return other != null && this.unlocode.equals(other.unlocode);
60
-  }
61
-
62
-  @Override
63 43
   public String toString() {
64 44
     return stringValue();
65 45
   }
66 46
 
67 47
   UnLocode() {
68 48
     // Needed by Hibernate
49
+    unlocode = null;
69 50
   }
70 51
 
71 52
 }

+ 10
- 37
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/shared/HandlingActivity.java Просмотреть файл

@@ -1,27 +1,25 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.shared;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import org.apache.commons.lang.builder.EqualsBuilder;
5
-import org.apache.commons.lang.builder.HashCodeBuilder;
6 4
 import se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent;
7 5
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
8 6
 import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
9
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
7
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
10 8
 
11 9
 /**
12 10
  * A handling activity represents how and where a cargo can be handled,
13 11
  * and can be used to express predictions about what is expected to
14 12
  * happen to a cargo in the future.
15 13
  */
16
-public class HandlingActivity implements ValueObject<HandlingActivity> {
14
+public class HandlingActivity extends ValueObjectSupport<HandlingActivity> {
17 15
 
18 16
   // TODO introduce something like this (?):
19 17
   // HandlingActivity.loadOnto(voyage).in(location)
20 18
   // HandlingActivity.claimIn(location)
21 19
 
22
-  private HandlingEvent.Type type;
23
-  private Location location;
24
-  private Voyage voyage;
20
+  private final HandlingEvent.Type type;
21
+  private final Location location;
22
+  private final Voyage voyage;
25 23
 
26 24
   public HandlingActivity(final HandlingEvent.Type type, final Location location) {
27 25
     Validate.notNull(type, "Handling event type is required");
@@ -29,12 +27,13 @@ public class HandlingActivity implements ValueObject<HandlingActivity> {
29 27
 
30 28
     this.type = type;
31 29
     this.location = location;
30
+    this.voyage = null;
32 31
   }
33 32
 
34 33
   public HandlingActivity(final HandlingEvent.Type type, final Location location, final Voyage voyage) {
35 34
     Validate.notNull(type, "Handling event type is required");
36 35
     Validate.notNull(location, "Location is required");
37
-    Validate.notNull(location, "Voyage is required");
36
+    Validate.notNull(voyage, "Voyage is required");
38 37
 
39 38
     this.type = type;
40 39
     this.location = location;
@@ -54,41 +53,15 @@ public class HandlingActivity implements ValueObject<HandlingActivity> {
54 53
   }
55 54
 
56 55
   @Override
57
-  public boolean sameValueAs(final HandlingActivity other) {
58
-    return other != null && new EqualsBuilder().
59
-      append(this.type, other.type).
60
-      append(this.location, other.location).
61
-      append(this.voyage, other.voyage).
62
-      isEquals();
63
-  }
64
-
65
-  @Override
66
-  public int hashCode() {
67
-    return new HashCodeBuilder().
68
-      append(this.type).
69
-      append(this.location).
70
-      append(this.voyage).
71
-      toHashCode();
72
-  }
73
-
74
-  @Override
75
-  public boolean equals(final Object obj) {
76
-    if (obj == this) return true;
77
-    if (obj == null) return false;
78
-    if (obj.getClass() != this.getClass()) return false;
79
-
80
-    HandlingActivity other = (HandlingActivity) obj;
81
-
82
-    return sameValueAs(other);
83
-  }
84
-
85
-  @Override
86 56
   public String toString() {
87 57
     return type + " in " + location + (voyage != null ? ", " + voyage : "");
88 58
   }
89 59
 
90 60
   HandlingActivity() {
91 61
     // Needed by Hibernate
62
+    type = null;
63
+    location = null;
64
+    voyage = null;
92 65
   }
93 66
 
94 67
 }

+ 8
- 40
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/CarrierMovement.java Просмотреть файл

@@ -1,10 +1,8 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.voyage;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import org.apache.commons.lang.builder.EqualsBuilder;
5
-import org.apache.commons.lang.builder.HashCodeBuilder;
6 4
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
7
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
5
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
8 6
 
9 7
 import java.util.Date;
10 8
 
@@ -12,12 +10,12 @@ import java.util.Date;
12 10
 /**
13 11
  * A carrier movement is a vessel voyage from one location to another.
14 12
  */
15
-public final class CarrierMovement implements ValueObject<CarrierMovement> {
13
+public final class CarrierMovement extends ValueObjectSupport<CarrierMovement> {
16 14
 
17
-  private Location departureLocation;
18
-  private Location arrivalLocation;
19
-  private Date departureTime;
20
-  private Date arrivalTime;
15
+  private final Location departureLocation;
16
+  private final Location arrivalLocation;
17
+  private final Date departureTime;
18
+  private final Date arrivalTime;
21 19
 
22 20
   // Null object pattern 
23 21
   public static final CarrierMovement NONE = new CarrierMovement(
@@ -86,40 +84,10 @@ public final class CarrierMovement implements ValueObject<CarrierMovement> {
86 84
     );
87 85
   }
88 86
 
89
-  @Override
90
-  public boolean equals(final Object o) {
91
-    if (this == o) return true;
92
-    if (o == null || getClass() != o.getClass()) return false;
93
-
94
-    final CarrierMovement that = (CarrierMovement) o;
95
-
96
-    return sameValueAs(that);
97
-  }
98
-
99
-  @Override
100
-  public int hashCode() {
101
-    return new HashCodeBuilder().
102
-      append(this.departureLocation).
103
-      append(this.departureTime).
104
-      append(this.arrivalLocation).
105
-      append(this.arrivalTime).
106
-      toHashCode();
107
-  }
108
-
109
-  @Override
110
-  public boolean sameValueAs(CarrierMovement other) {
111
-    return other != null && new EqualsBuilder().
112
-      append(this.departureLocation, other.departureLocation).
113
-      append(this.departureTime, other.departureTime).
114
-      append(this.arrivalLocation, other.arrivalLocation).
115
-      append(this.arrivalTime, other.arrivalTime).
116
-      isEquals();
117
-  }
118
-
119 87
   CarrierMovement() {
120 88
     // Needed by Hibernate
89
+    arrivalLocation = departureLocation = null;
90
+    arrivalTime = departureTime = null;
121 91
   }
122 92
 
123
-  // Auto-generated surrogate key
124
-  private Long id;
125 93
 }

+ 4
- 24
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/Schedule.java Просмотреть файл

@@ -1,9 +1,8 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.voyage;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import org.apache.commons.lang.builder.HashCodeBuilder;
5 4
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
6
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
5
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
7 6
 
8 7
 import java.util.Collections;
9 8
 import java.util.Date;
@@ -12,9 +11,9 @@ import java.util.List;
12 11
 /**
13 12
  * A voyage schedule.
14 13
  */
15
-public class Schedule implements ValueObject<Schedule> {
14
+public class Schedule extends ValueObjectSupport<Schedule> {
16 15
 
17
-  private List<CarrierMovement> carrierMovements;
16
+  private final List<CarrierMovement> carrierMovements;
18 17
 
19 18
   public static final Schedule EMPTY = new Schedule();
20 19
 
@@ -59,27 +58,8 @@ public class Schedule implements ValueObject<Schedule> {
59 58
     return null;
60 59
   }
61 60
 
62
-  @Override
63
-  public boolean sameValueAs(final Schedule other) {
64
-    return other != null && this.carrierMovements.equals(other.carrierMovements);
65
-  }
66
-
67
-  @Override
68
-  public boolean equals(final Object o) {
69
-    if (this == o) return true;
70
-    if (o == null || getClass() != o.getClass()) return false;
71
-
72
-    final Schedule that = (Schedule) o;
73
-
74
-    return sameValueAs(that);
75
-  }
76
-
77
-  @Override
78
-  public int hashCode() {
79
-    return new HashCodeBuilder().append(this.carrierMovements).toHashCode();
80
-  }
81
-
82 61
   Schedule() {
83 62
     // Needed by Hibernate
63
+    carrierMovements = null;
84 64
   }
85 65
 }

+ 9
- 28
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/Voyage.java Просмотреть файл

@@ -2,7 +2,7 @@ package se.citerus.dddsample.tracking.core.domain.model.voyage;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4 4
 import se.citerus.dddsample.tracking.core.domain.model.location.Location;
5
-import se.citerus.dddsample.tracking.core.domain.shared.Entity;
5
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.EntitySupport;
6 6
 
7 7
 import java.util.ArrayList;
8 8
 import java.util.Date;
@@ -11,9 +11,9 @@ import java.util.List;
11 11
 /**
12 12
  * A Voyage.
13 13
  */
14
-public class Voyage implements Entity<Voyage> {
14
+public class Voyage extends EntitySupport<Voyage,VoyageNumber> {
15 15
 
16
-  private VoyageNumber voyageNumber;
16
+  private final VoyageNumber voyageNumber;
17 17
   private Schedule schedule;
18 18
 
19 19
   // Null object pattern
@@ -29,6 +29,11 @@ public class Voyage implements Entity<Voyage> {
29 29
     this.schedule = schedule;
30 30
   }
31 31
 
32
+  @Override
33
+  public VoyageNumber identity() {
34
+    return voyageNumber;
35
+  }
36
+  
32 37
   /**
33 38
    * @return Voyage number.
34 39
    */
@@ -65,39 +70,15 @@ public class Voyage implements Entity<Voyage> {
65 70
   }
66 71
 
67 72
   @Override
68
-  public int hashCode() {
69
-    return voyageNumber.hashCode();
70
-  }
71
-
72
-  @Override
73
-  public boolean equals(Object o) {
74
-    if (this == o) return true;
75
-    if (o == null) return false;
76
-    if (!(o instanceof Voyage)) return false;
77
-
78
-    final Voyage that = (Voyage) o;
79
-
80
-    return sameAs(that);
81
-  }
82
-
83
-  @Override
84
-  public boolean sameAs(Voyage other) {
85
-    return other != null && this.voyageNumber().sameValueAs(other.voyageNumber());
86
-  }
87
-
88
-  @Override
89 73
   public String toString() {
90 74
     return "Voyage " + voyageNumber;
91 75
   }
92 76
 
93 77
   Voyage() {
94 78
     // Needed by Hibernate
79
+    voyageNumber = null;
95 80
   }
96 81
 
97
-  // Needed by Hibernate
98
-  private Long id;
99
-
100
-
101 82
   /**
102 83
    * Builder pattern is used for incremental construction
103 84
    * of a Voyage aggregate. This serves as an aggregate factory.

+ 5
- 25
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/model/voyage/VoyageNumber.java Просмотреть файл

@@ -1,43 +1,22 @@
1 1
 package se.citerus.dddsample.tracking.core.domain.model.voyage;
2 2
 
3 3
 import org.apache.commons.lang.Validate;
4
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
4
+import se.citerus.dddsample.tracking.core.domain.shared.experimental.ValueObjectSupport;
5 5
 
6 6
 /**
7 7
  * Identifies a voyage.
8 8
  */
9
-public class VoyageNumber implements ValueObject<VoyageNumber> {
9
+public class VoyageNumber extends ValueObjectSupport<VoyageNumber> {
10 10
 
11
-  private String number;
11
+  private final String number;
12 12
 
13
-  public VoyageNumber(String number) {
13
+  public VoyageNumber(final String number) {
14 14
     Validate.notNull(number);
15 15
 
16 16
     this.number = number;
17 17
   }
18 18
 
19 19
   @Override
20
-  public boolean equals(Object o) {
21
-    if (this == o) return true;
22
-    if (o == null) return false;
23
-    if (!(o instanceof VoyageNumber)) return false;
24
-
25
-    final VoyageNumber other = (VoyageNumber) o;
26
-
27
-    return sameValueAs(other);
28
-  }
29
-
30
-  @Override
31
-  public int hashCode() {
32
-    return number.hashCode();
33
-  }
34
-
35
-  @Override
36
-  public boolean sameValueAs(VoyageNumber other) {
37
-    return other != null && this.number.equals(other.number);
38
-  }
39
-
40
-  @Override
41 20
   public String toString() {
42 21
     return number;
43 22
   }
@@ -48,6 +27,7 @@ public class VoyageNumber implements ValueObject<VoyageNumber> {
48 27
 
49 28
   VoyageNumber() {
50 29
     // Needed by Hibernate
30
+    number = null;
51 31
   }
52 32
 
53 33
 }

+ 8
- 1
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/shared/experimental/EntitySupport.java Просмотреть файл

@@ -18,12 +18,19 @@ public abstract class EntitySupport<T extends Entity, ID> implements Entity<T, I
18 18
     return identity().hashCode();
19 19
   }
20 20
 
21
+  @SuppressWarnings({"SimplifiableIfStatement", "unchecked"})
21 22
   @Override
22 23
   public final boolean equals(final Object o) {
23 24
     if (this == o) return true;
24
-    if (o == null || getClass() != o.getClass()) return false;
25
+    // TODO class comparision is too strict for ORM proxies
26
+    if (o == null || !(o instanceof EntitySupport)) return false;
27
+    //if (o == null || getClass() != o.getClass()) return false;
25 28
 
26 29
     return sameAs((T) o);
27 30
   }
28 31
 
32
+  @SuppressWarnings("UnusedDeclaration")
33
+  // Surrogate primary key
34
+  private Long id;
35
+
29 36
 }

+ 0
- 7
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/shared/experimental/ValueObject.java Просмотреть файл

@@ -13,11 +13,4 @@ public interface ValueObject<T> {
13 13
    */
14 14
   boolean sameValueAs(T other);
15 15
 
16
-  /**
17
-   * Value objects can be freely copied.
18
-   *
19
-   * @return A safe, deep copy of this value object.
20
-   */
21
-  T copy();
22
-
23 16
 }

+ 3
- 1
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/domain/shared/experimental/ValueObjectSupport.java Просмотреть файл

@@ -2,7 +2,6 @@ package se.citerus.dddsample.tracking.core.domain.shared.experimental;
2 2
 
3 3
 import org.apache.commons.lang.builder.EqualsBuilder;
4 4
 import org.apache.commons.lang.builder.HashCodeBuilder;
5
-import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
6 5
 
7 6
 /**
8 7
  * Base class for value objects.
@@ -12,6 +11,8 @@ import se.citerus.dddsample.tracking.core.domain.shared.ValueObject;
12 11
 public abstract class ValueObjectSupport<T extends ValueObject> implements ValueObject<T> {
13 12
 
14 13
   private transient int cachedHashCode = 0;
14
+  @SuppressWarnings("UnusedDeclaration")
15
+  private final Long id = null;
15 16
 
16 17
   /**
17 18
    * @param other The other value object.
@@ -49,6 +50,7 @@ public abstract class ValueObjectSupport<T extends ValueObject> implements Value
49 50
    * @param o other object
50 51
    * @return True if other object has the same value as this value object.
51 52
    */
53
+  @SuppressWarnings({"SimplifiableIfStatement", "unchecked"})
52 54
   @Override
53 55
   public final boolean equals(final Object o) {
54 56
     if (this == o) return true;

+ 26
- 20
dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/interfaces/booking/facade/DTOAssembler.java Просмотреть файл

@@ -1,22 +1,23 @@
1 1
 package se.citerus.dddsample.tracking.core.interfaces.booking.facade;
2 2
 
3
+import se.citerus.dddsample.tracking.booking.api.CargoRoutingDTO;
4
+import se.citerus.dddsample.tracking.booking.api.LegDTO;
5
+import se.citerus.dddsample.tracking.booking.api.LocationDTO;
6
+import se.citerus.dddsample.tracking.booking.api.RouteCandidateDTO;
3 7
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Cargo;
8
+import se.citerus.dddsample.tracking.core.domain.model.cargo.Itinerary;
4 9
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Leg;
5 10
 import se.citerus.dddsample.tracking.core.domain.model.cargo.RoutingStatus;
6
-import se.citerus.dddsample.tracking.core.domain.model.cargo.Itinerary;
11
+import se.citerus.dddsample.tracking.core.domain.model.location.Location;
12
+import se.citerus.dddsample.tracking.core.domain.model.location.LocationRepository;
13
+import se.citerus.dddsample.tracking.core.domain.model.location.UnLocode;
14
+import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
7 15
 import se.citerus.dddsample.tracking.core.domain.model.voyage.VoyageNumber;
8 16
 import se.citerus.dddsample.tracking.core.domain.model.voyage.VoyageRepository;
9
-import se.citerus.dddsample.tracking.core.domain.model.voyage.Voyage;
10
-import se.citerus.dddsample.tracking.core.domain.model.location.UnLocode;
11
-import se.citerus.dddsample.tracking.core.domain.model.location.LocationRepository;
12
-import se.citerus.dddsample.tracking.core.domain.model.location.Location;
13
-import se.citerus.dddsample.tracking.booking.api.CargoRoutingDTO;
14
-import se.citerus.dddsample.tracking.booking.api.LegDTO;
15
-import se.citerus.dddsample.tracking.booking.api.RouteCandidateDTO;
16
-import se.citerus.dddsample.tracking.booking.api.*;
17 17
 
18
-import java.util.List;
19 18
 import java.util.ArrayList;
19
+import java.util.Collections;
20
+import java.util.List;
20 21
 
21 22
 final class DTOAssembler {
22 23
 
@@ -25,17 +26,22 @@ final class DTOAssembler {
25 26
    * @return A cargo routing DTO
26 27
    */
27 28
   static CargoRoutingDTO toDTO(final Cargo cargo) {
28
-    final List<Leg> legs = cargo.itinerary().legs();
29
+    final Itinerary itinerary = cargo.itinerary();
30
+
31
+    List<LegDTO> legDTOList = Collections.emptyList();
32
+    if (itinerary != null) {
33
+      final List<Leg> legs = itinerary.legs();
29 34
 
30
-    final List<LegDTO> legDTOList = new ArrayList<LegDTO>(legs.size());
31
-    for (Leg leg : legs) {
32
-      final LegDTO legDTO = new LegDTO(
33
-        leg.voyage().voyageNumber().stringValue(),
34
-        leg.loadLocation().unLocode().stringValue(),
35
-        leg.unloadLocation().unLocode().stringValue(),
36
-        leg.loadTime(),
37
-        leg.unloadTime());
38
-      legDTOList.add(legDTO);
35
+      legDTOList = new ArrayList<LegDTO>(legs.size());
36
+      for (Leg leg : legs) {
37
+        final LegDTO legDTO = new LegDTO(
38
+          leg.voyage().voyageNumber().stringValue(),
39
+          leg.loadLocation().unLocode().stringValue(),
40
+          leg.unloadLocation().unLocode().stringValue(),
41
+          leg.loadTime(),
42
+          leg.unloadTime());
43
+        legDTOList.add(legDTO);
44
+      }
39 45
     }
40 46
 
41 47
     return new CargoRoutingDTO(

+ 0
- 5
dddsample/tracking/core/src/test/java/se/citerus/dddsample/tracking/core/domain/model/cargo/ItineraryTest.java Просмотреть файл

@@ -89,11 +89,6 @@ public class ItineraryTest extends TestCase {
89 89
 
90 90
     HandlingActivity claimRotterdam = new HandlingActivity(CLAIM, ROTTERDAM);
91 91
     assertFalse(itinerary.isExpected(claimRotterdam));
92
-
93
-    //Unrouted Cargo shouldn't go anywhere or do anything
94
-    assertFalse(Itinerary.EMPTY_ITINERARY.isExpected(receiveShanghai));
95
-    assertFalse(Itinerary.EMPTY_ITINERARY.isExpected(loadShanghai));
96
-
97 92
   }
98 93
 
99 94
   public void testCreateItinerary() throws Exception {