瀏覽代碼

Changed persistence layer to point to the InMem repositories

Added test-context-persistence.xml to still be able to test hibernate repositories
Added HandlingEventService (first lab version...)
Added HandlingEvent- and Carrier-Repository.
Modified some equality operators to fit better with HandlingEventRepository (Maybe unneccessary after all, but it's working...)
jorgen_falk 18 年之前
父節點
當前提交
7ec3437e26
共有 21 個文件被更改,包括 622 次插入64 次删除
  1. 29
    0
      dddsample/src/main/java/se/citerus/dddsample/domain/Cargo.java
  2. 26
    1
      dddsample/src/main/java/se/citerus/dddsample/domain/HandlingEvent.java
  3. 1
    1
      dddsample/src/main/java/se/citerus/dddsample/domain/Location.java
  4. 1
    0
      dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepository.java
  5. 4
    0
      dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepositoryHibernate.java
  6. 18
    58
      dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepositoryInMem.java
  7. 9
    0
      dddsample/src/main/java/se/citerus/dddsample/repository/CarrierRepository.java
  8. 36
    0
      dddsample/src/main/java/se/citerus/dddsample/repository/CarrierRepositoryInMem.java
  9. 12
    0
      dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepository.java
  10. 142
    0
      dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepositoryInMem.java
  11. 20
    0
      dddsample/src/main/java/se/citerus/dddsample/service/HandlingEventService.java
  12. 74
    0
      dddsample/src/main/java/se/citerus/dddsample/service/HandlingEventServiceImpl.java
  13. 12
    2
      dddsample/src/main/resources/context-persistence.xml
  14. 5
    0
      dddsample/src/main/resources/context-service.xml
  15. 8
    0
      dddsample/src/main/webapp/style.css
  16. 1
    1
      dddsample/src/test/java/se/citerus/dddsample/domain/CargoRepositoryTest.java
  17. 11
    0
      dddsample/src/test/java/se/citerus/dddsample/domain/CargoTest.java
  18. 57
    0
      dddsample/src/test/java/se/citerus/dddsample/domain/HandlingEventTest.java
  19. 102
    0
      dddsample/src/test/java/se/citerus/dddsample/service/HandlingEventServiceTest.java
  20. 6
    1
      dddsample/src/test/resources/mock-context-persistence.xml
  21. 48
    0
      dddsample/src/test/resources/test-context-persistence.xml

+ 29
- 0
dddsample/src/main/java/se/citerus/dddsample/domain/Cargo.java 查看文件

@@ -1,5 +1,7 @@
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;
3 5
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
4 6
 import org.apache.commons.lang.builder.ToStringStyle;
5 7
 
@@ -88,4 +90,31 @@ public class Cargo {
88 90
   public String toString() {
89 91
     return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
90 92
   }
93
+
94
+  @Override
95
+  public boolean equals(Object obj) {
96
+    if (obj instanceof Cargo == false) {
97
+      return false;
98
+    }
99
+    if (this == obj) {
100
+      return true;
101
+    }
102
+    Cargo rhs = (Cargo) obj;
103
+    return new EqualsBuilder()
104
+      .append(trackingId, rhs.trackingId)
105
+      .append(origin, rhs.origin)
106
+      .append(finalDestination, rhs.finalDestination)
107
+      .isEquals();
108
+  }
109
+
110
+  @Override
111
+  public int hashCode() {
112
+    return new HashCodeBuilder(7, 39)
113
+    .append(trackingId)
114
+    .append(origin)
115
+    .append(finalDestination)
116
+    .toHashCode();
117
+  }
118
+  
119
+  
91 120
 }

+ 26
- 1
dddsample/src/main/java/se/citerus/dddsample/domain/HandlingEvent.java 查看文件

@@ -5,6 +5,8 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
5 5
 
6 6
 import javax.persistence.*;
7 7
 import java.util.Date;
8
+import java.util.HashSet;
9
+import java.util.Set;
8 10
 
9 11
 /**
10 12
  * HandlingEvent links the type of handling with a CarrierMovement.
@@ -32,6 +34,9 @@ public class HandlingEvent implements Comparable<HandlingEvent> {
32 34
   @Column(name = "time")
33 35
   private Date time;
34 36
 
37
+  @Transient /*TODO: Change to many-to-many if we decide on that approach*/
38
+  private Set<Cargo> cargos;
39
+  
35 40
   public enum Type {
36 41
     LOAD, UNLOAD, RECEIVE, CLAIM
37 42
   }
@@ -46,6 +51,7 @@ public class HandlingEvent implements Comparable<HandlingEvent> {
46 51
     this.time = time;
47 52
     this.type = type;
48 53
     this.carrierMovement = carrierMovement;
54
+    this.cargos = new HashSet<Cargo>();
49 55
   }
50 56
 
51 57
   public Type getType() {
@@ -92,6 +98,20 @@ public class HandlingEvent implements Comparable<HandlingEvent> {
92 98
     
93 99
     return location;
94 100
   }
101
+
102
+
103
+  /**
104
+   * Register a set of Cargos
105
+   * 
106
+   * @param cargos
107
+   */
108
+  public void register(Set<Cargo> cargosToRegister) {
109
+    this.cargos.addAll(cargosToRegister);
110
+  }
111
+  
112
+  public Set<Cargo> getRegisterdCargos(){
113
+    return cargos;
114
+  }
95 115
   
96 116
   
97 117
   @Override
@@ -101,10 +121,15 @@ public class HandlingEvent implements Comparable<HandlingEvent> {
101 121
 
102 122
   @Override
103 123
   public int hashCode() {
104
-    return HashCodeBuilder.reflectionHashCode(this, excludedFields);
124
+    return HashCodeBuilder.reflectionHashCode(this);
105 125
   }
106 126
 
107 127
   public int compareTo(HandlingEvent o) {
108 128
     return time.compareTo(o.getTime());
109 129
   }
130
+
131
+  public static Type parseType(String type) {
132
+    return Type.valueOf(type);
133
+  }
134
+
110 135
 }

+ 1
- 1
dddsample/src/main/java/se/citerus/dddsample/domain/Location.java 查看文件

@@ -14,7 +14,7 @@ public class Location {
14 14
   /**
15 15
    * The NULL Location object
16 16
    */
17
-  public static final Location NULL = new Location(Location.class.getName() + ".NULL");
17
+  public static final Location NULL = new Location("Unknown");
18 18
 
19 19
   @Id
20 20
   private Long id;

+ 1
- 0
dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepository.java 查看文件

@@ -5,4 +5,5 @@ import se.citerus.dddsample.domain.TrackingId;
5 5
 
6 6
 public interface CargoRepository {
7 7
   Cargo find(TrackingId trackingId);
8
+  void save(Cargo cargo);
8 9
 }

+ 4
- 0
dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepositoryHibernate.java 查看文件

@@ -18,4 +18,8 @@ public class CargoRepositoryHibernate implements CargoRepository {
18 18
     return (Cargo) sessionFactory.getCurrentSession().
19 19
             get(Cargo.class, trackingId);
20 20
   }
21
+
22
+  public void save(Cargo cargo) {
23
+    sessionFactory.getCurrentSession().saveOrUpdate(cargo);
24
+  }
21 25
 }

+ 18
- 58
dddsample/src/main/java/se/citerus/dddsample/repository/CargoRepositoryInMem.java 查看文件

@@ -1,16 +1,11 @@
1 1
 package se.citerus.dddsample.repository;
2 2
 
3
-import java.text.DateFormat;
4
-import java.text.ParseException;
5
-import java.text.SimpleDateFormat;
6
-import java.util.Date;
7 3
 import java.util.HashMap;
8 4
 import java.util.Map;
9 5
 
10 6
 import org.springframework.dao.DataRetrievalFailureException;
11 7
 
12 8
 import se.citerus.dddsample.domain.Cargo;
13
-import se.citerus.dddsample.domain.CarrierMovement;
14 9
 import se.citerus.dddsample.domain.HandlingEvent;
15 10
 import se.citerus.dddsample.domain.Location;
16 11
 import se.citerus.dddsample.domain.TrackingId;
@@ -27,10 +22,10 @@ import se.citerus.dddsample.domain.TrackingId;
27 22
  */
28 23
 public class CargoRepositoryInMem implements CargoRepository {
29 24
   private Map<String, Cargo> cargoDb;
25
+  private HandlingEventRepository handlingEventRepository;
30 26
 
31 27
   public CargoRepositoryInMem() throws Exception {
32 28
     cargoDb = new HashMap<String, Cargo>();
33
-    setup();
34 29
   }
35 30
 
36 31
   public Cargo find(TrackingId trackingId) {
@@ -40,75 +35,40 @@ public class CargoRepositoryInMem implements CargoRepository {
40 35
     
41 36
     return cargoDb.get(trackingId.getId());
42 37
   }
38
+  
39
+  public void save(Cargo cargo) {
40
+    //No need to save anything with InMem
41
+  }
43 42
 
44
-  private void setup() throws Exception {
43
+  /**
44
+   * 
45
+   * @throws Exception
46
+   */
47
+  public void init() throws Exception {
45 48
     String trackIdXYZ = "XYZ";
46 49
     final Cargo cargoXYZ = new Cargo(new TrackingId(trackIdXYZ), new Location("SESTO"), new Location("AUMEL"));
47
-    
48
-    cargoXYZ.handle(new HandlingEvent(getDate("2007-11-30"), HandlingEvent.Type.RECEIVE, null));
49
-
50
-    final CarrierMovement stockholmToHamburg = new CarrierMovement(new Location("SESTO"), new Location("DEHAM"));
51
-
52
-    cargoXYZ.handle(new HandlingEvent(getDate("2007-12-01"), HandlingEvent.Type.LOAD, stockholmToHamburg));
53
-    cargoXYZ.handle(new HandlingEvent(getDate("2007-12-02"), HandlingEvent.Type.UNLOAD, stockholmToHamburg));
54
-
55
-    final CarrierMovement hamburgToHongKong = new CarrierMovement(new Location("DEHAM"), new Location("CNHKG"));
56
-
57
-    cargoXYZ.handle(new HandlingEvent(getDate("2007-12-03"), HandlingEvent.Type.LOAD, hamburgToHongKong));
58
-    cargoXYZ.handle(new HandlingEvent(getDate("2007-12-05"), HandlingEvent.Type.UNLOAD, hamburgToHongKong));
59
-
60 50
     cargoDb.put(trackIdXYZ, cargoXYZ);
61 51
     
62
-    
63 52
     String trackIdZYX = "ZYX";
64 53
     final Cargo cargoZYX = new Cargo(new TrackingId(trackIdZYX), new Location("AUMEL"), new Location("SESTO"));
65
-    
66
-    cargoZYX.handle(new HandlingEvent(getDate("2007-12-09"), HandlingEvent.Type.RECEIVE, null));
67
-    
68
-    final CarrierMovement melbourneToTokyo = new CarrierMovement(new Location("AUMEL"), new Location("JPTOK"));
69
-
70
-    cargoZYX.handle(new HandlingEvent(getDate("2007-12-10"), HandlingEvent.Type.LOAD, melbourneToTokyo));
71
-    cargoZYX.handle(new HandlingEvent(getDate("2007-12-12"), HandlingEvent.Type.UNLOAD, melbourneToTokyo));
72
-
73
-    final CarrierMovement tokyoToLosAngeles = new CarrierMovement(new Location("JPTOK"), new Location("USLA"));
74
-
75
-    cargoZYX.handle(new HandlingEvent(getDate("2007-12-13"), HandlingEvent.Type.LOAD, tokyoToLosAngeles));
76
-
77 54
     cargoDb.put(trackIdZYX, cargoZYX);
78 55
     
79 56
     String trackIdABC = "ABC";
80 57
     final Cargo cargoABC = new Cargo(new TrackingId(trackIdABC), new Location("SESTO"), new Location("FIHEL"));
81
-    
82
-    cargoABC.handle(new HandlingEvent(getDate("2008-01-01"), HandlingEvent.Type.RECEIVE, null));
83
-
84
-    final CarrierMovement stockholmToHelsinki = new CarrierMovement(new Location("SESTO"), new Location("FIHEL"));
85
-
86
-    cargoABC.handle(new HandlingEvent(getDate("2008-01-02"), HandlingEvent.Type.LOAD, stockholmToHelsinki));
87
-    cargoABC.handle(new HandlingEvent(getDate("2008-01-03"), HandlingEvent.Type.UNLOAD, stockholmToHelsinki));
88
-    cargoABC.handle(new HandlingEvent(getDate("2008-01-05"), HandlingEvent.Type.CLAIM, null));
89
-    
90 58
     cargoDb.put(trackIdABC, cargoABC);
91 59
     
92 60
     String trackIdCBA = "CBA";
93 61
     final Cargo cargoCBA = new Cargo(new TrackingId(trackIdCBA), new Location("FIHEL"), new Location("SESTO"));
94
-    
95
-    cargoCBA.handle(new HandlingEvent(getDate("2008-01-10"), HandlingEvent.Type.RECEIVE, null));
96
-
97
-    
98 62
     cargoDb.put(trackIdCBA, cargoCBA);
63
+    
64
+    for (Cargo cargo : cargoDb.values()) {
65
+      for (HandlingEvent event : handlingEventRepository.findByTrackingId(cargo.trackingId())) {
66
+        cargo.handle(event);
67
+      }   
68
+    }
99 69
   }
100 70
 
101
-  /**
102
-   * Parse an ISO 8601 (YYYY-MM-DD) String to Date
103
-   * 
104
-   * @param isoFormat
105
-   *            String to parse.
106
-   * @return Created date instance.
107
-   * @throws ParseException
108
-   *             Thrown if parsing fails.
109
-   */
110
-  private Date getDate(String isoFormat) throws ParseException {
111
-    final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
112
-    return dateFormat.parse(isoFormat);
71
+  public void setHandlingEventRepository(HandlingEventRepository handlingEventRepository) {
72
+    this.handlingEventRepository = handlingEventRepository;
113 73
   }
114 74
 }

+ 9
- 0
dddsample/src/main/java/se/citerus/dddsample/repository/CarrierRepository.java 查看文件

@@ -0,0 +1,9 @@
1
+package se.citerus.dddsample.repository;
2
+
3
+import se.citerus.dddsample.domain.CarrierMovement;
4
+
5
+public interface CarrierRepository {
6
+
7
+  CarrierMovement find(String carrierId);
8
+
9
+}

+ 36
- 0
dddsample/src/main/java/se/citerus/dddsample/repository/CarrierRepositoryInMem.java 查看文件

@@ -0,0 +1,36 @@
1
+package se.citerus.dddsample.repository;
2
+
3
+import java.util.HashMap;
4
+
5
+import se.citerus.dddsample.domain.CarrierMovement;
6
+import se.citerus.dddsample.domain.Location;
7
+
8
+public class CarrierRepositoryInMem implements CarrierRepository {
9
+  private HashMap<String, CarrierMovement> carriers;
10
+
11
+  public CarrierRepositoryInMem() {
12
+    carriers = new HashMap<String, CarrierMovement>();
13
+    setup();
14
+  }
15
+
16
+  private void setup() {
17
+    final CarrierMovement stockholmToHamburg = new CarrierMovement(new Location("SESTO"), new Location("DEHAM"));
18
+    final CarrierMovement hamburgToHongKong = new CarrierMovement(new Location("DEHAM"), new Location("CNHKG"));
19
+    final CarrierMovement melbourneToTokyo = new CarrierMovement(new Location("AUMEL"), new Location("JPTOK"));
20
+    final CarrierMovement tokyoToLosAngeles = new CarrierMovement(new Location("JPTOK"), new Location("USLA"));
21
+    final CarrierMovement stockholmToHelsinki = new CarrierMovement(new Location("SESTO"), new Location("FIHEL"));
22
+    
23
+    carriers.put("SESTO_DEHAM", stockholmToHamburg);
24
+    carriers.put("DEHAM_CNHKG", hamburgToHongKong);
25
+    carriers.put("AUMEL_JPTOK", melbourneToTokyo);
26
+    carriers.put("JPTOK_USLA", tokyoToLosAngeles);
27
+    carriers.put("SESTO_FIHEL", stockholmToHelsinki);
28
+  }
29
+
30
+  public CarrierMovement find(String carrierId) {
31
+    return carriers.get(carrierId);
32
+  }
33
+  
34
+  
35
+
36
+}

+ 12
- 0
dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepository.java 查看文件

@@ -0,0 +1,12 @@
1
+package se.citerus.dddsample.repository;
2
+
3
+import java.util.Set;
4
+
5
+import se.citerus.dddsample.domain.HandlingEvent;
6
+import se.citerus.dddsample.domain.TrackingId;
7
+
8
+public interface HandlingEventRepository {
9
+  HandlingEvent find(String handlingEventId);
10
+  void save(HandlingEvent event);
11
+  Set<HandlingEvent> findByTrackingId(final TrackingId trackingId);
12
+}

+ 142
- 0
dddsample/src/main/java/se/citerus/dddsample/repository/HandlingEventRepositoryInMem.java 查看文件

@@ -0,0 +1,142 @@
1
+package se.citerus.dddsample.repository;
2
+
3
+import java.text.DateFormat;
4
+import java.text.ParseException;
5
+import java.text.SimpleDateFormat;
6
+import java.util.Date;
7
+import java.util.HashMap;
8
+import java.util.HashSet;
9
+import java.util.Set;
10
+
11
+import org.apache.commons.logging.Log;
12
+import org.apache.commons.logging.LogFactory;
13
+
14
+import se.citerus.dddsample.domain.Cargo;
15
+import se.citerus.dddsample.domain.CarrierMovement;
16
+import se.citerus.dddsample.domain.HandlingEvent;
17
+import se.citerus.dddsample.domain.Location;
18
+import se.citerus.dddsample.domain.TrackingId;
19
+import se.citerus.dddsample.domain.HandlingEvent.Type;
20
+
21
+public class HandlingEventRepositoryInMem implements HandlingEventRepository{
22
+  private HashMap<String, HandlingEvent> eventDB;
23
+  private CarrierRepository carrierRepository;
24
+  
25
+  private final Log logger = LogFactory.getLog(getClass());
26
+
27
+  public HandlingEventRepositoryInMem() throws ParseException {
28
+    eventDB = new HashMap<String, HandlingEvent>();
29
+  }
30
+
31
+  /**
32
+   * Initilaze the in mem repository.
33
+   * 
34
+   * SpringIoC will call this init-method after the bean has bean created and properties has been set.
35
+   * 
36
+   * @throws ParseException
37
+   */
38
+  public void init() throws ParseException {
39
+    
40
+    // CargoXYZ
41
+    final Cargo cargoXYZ = new Cargo(new TrackingId("XYZ"), new Location("SESTO"), new Location("AUMEL"));
42
+    registerEvent(cargoXYZ, "2007-11-30", HandlingEvent.Type.RECEIVE, null);
43
+
44
+    final CarrierMovement stockholmToHamburg = carrierRepository.find("SESTO_DEHAM");
45
+    registerEvent(cargoXYZ, "2007-12-01", HandlingEvent.Type.LOAD, stockholmToHamburg);
46
+    registerEvent(cargoXYZ, "2007-12-02", HandlingEvent.Type.UNLOAD, stockholmToHamburg);
47
+    
48
+    final CarrierMovement hamburgToHongKong = carrierRepository.find("DEHAM_CNHKG");
49
+    registerEvent(cargoXYZ, "2007-12-03", HandlingEvent.Type.LOAD, hamburgToHongKong);
50
+    registerEvent(cargoXYZ, "2007-12-05", HandlingEvent.Type.UNLOAD, hamburgToHongKong);
51
+    
52
+    //CargoZYX
53
+    final Cargo cargoZYX = new Cargo(new TrackingId("ZYX"), new Location("AUMEL"), new Location("SESTO"));
54
+    registerEvent(cargoZYX, "2007-12-09", HandlingEvent.Type.RECEIVE, null);
55
+    
56
+    final CarrierMovement melbourneToTokyo = carrierRepository.find("AUMEL_JPTOK");
57
+    registerEvent(cargoZYX, "2007-12-10", HandlingEvent.Type.LOAD, melbourneToTokyo);
58
+    registerEvent(cargoZYX, "2007-12-12", HandlingEvent.Type.UNLOAD, melbourneToTokyo);
59
+    
60
+    final CarrierMovement tokyoToLosAngeles = carrierRepository.find("JPTOK_USLA");
61
+    registerEvent(cargoZYX, "2007-12-13", HandlingEvent.Type.LOAD, tokyoToLosAngeles);
62
+ 
63
+    //CargoABC
64
+    final Cargo cargoABC = new Cargo(new TrackingId("ABC"), new Location("SESTO"), new Location("FIHEL"));
65
+    registerEvent(cargoABC, "2008-01-01", HandlingEvent.Type.RECEIVE, null);
66
+    
67
+    final CarrierMovement stockholmToHelsinki = new CarrierMovement(new Location("SESTO"), new Location("FIHEL"));
68
+    registerEvent(cargoABC, "2008-01-02", HandlingEvent.Type.LOAD, stockholmToHelsinki);
69
+    registerEvent(cargoABC, "2008-01-03", HandlingEvent.Type.UNLOAD, stockholmToHelsinki);
70
+    registerEvent(cargoABC, "2008-01-05", HandlingEvent.Type.CLAIM, null);
71
+
72
+    //CargoCBA
73
+    final Cargo cargoCBA = new Cargo(new TrackingId("CBA"), new Location("FIHEL"), new Location("SESTO"));
74
+    registerEvent(cargoCBA, "2008-01-10", HandlingEvent.Type.RECEIVE, null);
75
+  }
76
+
77
+  
78
+  private void registerEvent(Cargo cargo, String date, Type type, CarrierMovement carrierMovement) throws ParseException{
79
+    HandlingEvent ev= new HandlingEvent(getDate(date), type, carrierMovement);
80
+    ev.register(toSet(cargo));
81
+    String id = cargo.trackingId() + "_" + type + "_" + date;
82
+    
83
+    logger.debug("Adding event " + id + "(" + ev + ")");
84
+    eventDB.put(id, ev);
85
+  }
86
+  
87
+  
88
+  private Set<Cargo> toSet(Cargo... cargoArgs) {
89
+    Set<Cargo> cargos = new HashSet<Cargo>();
90
+    for (Cargo cargo : cargoArgs) {
91
+      cargos.add(cargo);
92
+    }
93
+    
94
+    return cargos;
95
+  }
96
+
97
+  /**
98
+   * Parse an ISO 8601 (YYYY-MM-DD) String to Date
99
+   * 
100
+   * @param isoFormat
101
+   *            String to parse.
102
+   * @return Created date instance.
103
+   * @throws ParseException
104
+   *             Thrown if parsing fails.
105
+   */
106
+  private Date getDate(String isoFormat) throws ParseException {
107
+    final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
108
+    return dateFormat.parse(isoFormat);
109
+  }
110
+  
111
+  public HandlingEvent find(String handlingEventId){
112
+    return eventDB.get(handlingEventId);
113
+  }
114
+
115
+  public void save(HandlingEvent event) {
116
+    // Mimmick saving to database
117
+    for (Cargo cargo : event.getRegisterdCargos()) {
118
+      cargo.handle(event);
119
+    }
120
+  }
121
+
122
+  @SuppressWarnings("unchecked")
123
+  public Set<HandlingEvent> findByTrackingId(final TrackingId trackingId) {
124
+    Set<HandlingEvent> events = new HashSet<HandlingEvent>();
125
+    for (HandlingEvent event : eventDB.values()) {
126
+      for (Cargo cargo : event.getRegisterdCargos()) {
127
+        if (cargo.trackingId().equals(trackingId)) {
128
+          events.add(event);
129
+          break;
130
+        }
131
+      }   
132
+    }
133
+    
134
+    logger.debug("findByTrackingId " + trackingId + " finds " + events);
135
+    
136
+    return events;
137
+  }
138
+
139
+  public void setCarrierRepository(CarrierRepository carrierRepository) {
140
+    this.carrierRepository = carrierRepository;
141
+  }
142
+}

+ 20
- 0
dddsample/src/main/java/se/citerus/dddsample/service/HandlingEventService.java 查看文件

@@ -0,0 +1,20 @@
1
+package se.citerus.dddsample.service;
2
+
3
+import java.util.Date;
4
+
5
+
6
+public interface HandlingEventService {
7
+
8
+  /**
9
+   * Regster an event with the EventHandling service
10
+   * 
11
+   * TODO: Fix javadoc when we know more about the relation between Cargo and HandlingEvent...
12
+   * 
13
+   * @param date
14
+   * @param type
15
+   * @param carrierId
16
+   * @param trackIds
17
+   */
18
+  public abstract void register(Date date, String type, String carrierId, String[] trackIds);
19
+
20
+}

+ 74
- 0
dddsample/src/main/java/se/citerus/dddsample/service/HandlingEventServiceImpl.java 查看文件

@@ -0,0 +1,74 @@
1
+package se.citerus.dddsample.service;
2
+
3
+import java.util.Date;
4
+import java.util.HashSet;
5
+import java.util.Set;
6
+
7
+import org.apache.commons.lang.Validate;
8
+
9
+import se.citerus.dddsample.domain.Cargo;
10
+import se.citerus.dddsample.domain.CarrierMovement;
11
+import se.citerus.dddsample.domain.HandlingEvent;
12
+import se.citerus.dddsample.domain.TrackingId;
13
+import se.citerus.dddsample.repository.CargoRepository;
14
+import se.citerus.dddsample.repository.CarrierRepository;
15
+import se.citerus.dddsample.repository.HandlingEventRepository;
16
+
17
+public class HandlingEventServiceImpl implements HandlingEventService {
18
+  private CargoRepository cargoRepository;
19
+  private CarrierRepository carrierRepository;
20
+  private HandlingEventRepository handlingEventRepository;
21
+
22
+
23
+  public void register(Date date, String type, String carrierId, String[] trackingIds) {
24
+    HandlingEvent event = new HandlingEvent(date, HandlingEvent.parseType(type), findCarrier(carrierId));
25
+    Set<Cargo> cargos = findCargos(trackingIds);
26
+    event.register(cargos);
27
+    
28
+    handlingEventRepository.save(event);
29
+  }
30
+
31
+
32
+  private Set<Cargo> findCargos(String[] trackingIds) {
33
+    Set<Cargo> cargos = new HashSet<Cargo>();
34
+    
35
+    for (String trackingId : trackingIds) {
36
+      cargos.add(findCargo(trackingId));
37
+    }
38
+    
39
+    return cargos;
40
+  }
41
+
42
+
43
+  private Cargo findCargo(String trackingId) {
44
+    Cargo cargo = cargoRepository.find(new TrackingId(trackingId));
45
+    Validate.notNull(cargo, "Cargo is not found. Tracking ID=" + trackingId);
46
+    
47
+    return cargo;
48
+  }
49
+
50
+  private CarrierMovement findCarrier(String carrierId) {
51
+    if (carrierId == null){
52
+      return null;
53
+    }
54
+    CarrierMovement carrier = carrierRepository.find(carrierId);
55
+    Validate.notNull(carrier, "Carrier is not found: Carrier ID=" + carrierId);
56
+    
57
+    return carrier;
58
+  }
59
+
60
+  public void setCargoRepository(CargoRepository cargoRepository) {
61
+    this.cargoRepository = cargoRepository;
62
+  }
63
+
64
+  public void setCarrierRepository(CarrierRepository carrierRepository) {
65
+    this.carrierRepository = carrierRepository;
66
+  }
67
+
68
+  public void setHandlingEventRepository(HandlingEventRepository handlingEventRepository) {
69
+    this.handlingEventRepository = handlingEventRepository;
70
+  }
71
+
72
+
73
+
74
+}

+ 12
- 2
dddsample/src/main/resources/context-persistence.xml 查看文件

@@ -39,8 +39,18 @@
39 39
     <property name="sessionFactory" ref="sessionFactory"/>
40 40
   </bean>
41 41
 
42
-  <bean id="cargoRepository" class="se.citerus.dddsample.repository.CargoRepositoryHibernate">
43
-    <property name="sessionFactory" ref="sessionFactory"/>
42
+  <bean id="cargoRepository" class="se.citerus.dddsample.repository.CargoRepositoryInMem" init-method="init">
43
+    <property name="handlingEventRepository" ref="handlingEventRepository"/>
44
+  </bean>
45
+  
46
+  <bean id="handlingEventRepository" class="se.citerus.dddsample.repository.HandlingEventRepositoryInMem" init-method="init">
47
+    <property name="carrierRepository" ref="carrierRepository"/>
44 48
   </bean>
49
+  
50
+  <bean id="carrierRepository" class="se.citerus.dddsample.repository.CarrierRepositoryInMem" />
51
+  
52
+  <!--bean id="cargoRepository" class="se.citerus.dddsample.repository.CargoRepositoryHibernate">
53
+    <property name="sessionFactory" ref="sessionFactory"/>
54
+  </bean-->
45 55
 
46 56
 </beans>

+ 5
- 0
dddsample/src/main/resources/context-service.xml 查看文件

@@ -13,4 +13,9 @@
13 13
     <property name="cargoRepository" ref="cargoRepository"/>
14 14
   </bean>
15 15
 
16
+  <bean id="handlingEventService" class="se.citerus.dddsample.service.HandlingEventServiceImpl">
17
+    <property name="cargoRepository" ref="cargoRepository"/>
18
+    <property name="handlingEventRepository" ref="handlingEventRepository"/>
19
+    <property name="carrierRepository" ref="carrierRepository"/>
20
+  </bean>
16 21
 </beans>

+ 8
- 0
dddsample/src/main/webapp/style.css 查看文件

@@ -187,6 +187,14 @@ input.radio {
187 187
 /**************************************************************
188 188
    Custom div and span
189 189
  **************************************************************/
190
+#apptitle h1{
191
+  font-size: 1.6em;
192
+  margin-left: 200px;
193
+  margin-bottom: 10px;
194
+  border-bottom: 0px
195
+  
196
+}
197
+
190 198
 #container {
191 199
   text-align: left;
192 200
   width: 500px;

+ 1
- 1
dddsample/src/test/java/se/citerus/dddsample/domain/CargoRepositoryTest.java 查看文件

@@ -12,7 +12,7 @@ public class CargoRepositoryTest extends AbstractTransactionalDataSourceSpringCo
12 12
   }
13 13
 
14 14
   protected String[] getConfigLocations() {
15
-    return new String[]{"context-persistence.xml"};
15
+    return new String[]{"test-context-persistence.xml"};
16 16
   }
17 17
 
18 18
   protected void onSetUpInTransaction() throws Exception {

+ 11
- 0
dddsample/src/test/java/se/citerus/dddsample/domain/CargoTest.java 查看文件

@@ -52,6 +52,17 @@ public class CargoTest extends TestCase {
52 52
 
53 53
     assertFalse(cargo.atFinalDestiation());
54 54
   }
55
+  
56
+  public void testEquality() throws Exception {
57
+    Cargo c1 = new Cargo(new TrackingId("ABC"), new Location("A"), new Location("C"));
58
+    Cargo c2 = new Cargo(new TrackingId("CBA"), new Location("A"), new Location("C"));
59
+    Cargo c3 = new Cargo(new TrackingId("ABC"), new Location("A"), new Location("X"));
60
+    Cargo c4 = new Cargo(new TrackingId("ABC"), new Location("A"), new Location("C"));
61
+
62
+    assertTrue("TrackingID, origin and finalDestnation should be equal if Cargos are considered equal", c1.equals(c4));
63
+    assertFalse("Cargos are not equal when TrackingID differ", c1.equals(c2));
64
+    assertFalse("Cargos are not equal when Locations differ", c2.equals(c3));
65
+  }
55 66
 
56 67
   // TODO: Generate test data some better way
57 68
   private Cargo populateCargoReceivedStockholm() throws Exception {

+ 57
- 0
dddsample/src/test/java/se/citerus/dddsample/domain/HandlingEventTest.java 查看文件

@@ -1,5 +1,11 @@
1 1
 package se.citerus.dddsample.domain;
2 2
 
3
+import java.util.Calendar;
4
+import java.util.Date;
5
+import java.util.HashSet;
6
+import java.util.Set;
7
+
8
+import se.citerus.dddsample.domain.HandlingEvent.Type;
3 9
 import junit.framework.TestCase;
4 10
 
5 11
 public class HandlingEventTest extends TestCase {
@@ -33,4 +39,55 @@ public class HandlingEventTest extends TestCase {
33 39
 
34 40
     assertEquals(Location.NULL, ev.getLocation());
35 41
   }
42
+  
43
+  public void testParseType() throws Exception {
44
+    assertEquals(Type.CLAIM, HandlingEvent.parseType("CLAIM"));
45
+    assertEquals(Type.LOAD, HandlingEvent.parseType("LOAD"));
46
+    assertEquals(Type.UNLOAD, HandlingEvent.parseType("UNLOAD"));
47
+    assertEquals(Type.RECEIVE, HandlingEvent.parseType("RECEIVE"));
48
+  }
49
+  
50
+  public void testParseTypeIllegal() throws Exception {
51
+    try {
52
+      HandlingEvent.parseType("NOT_A_HANDLING_EVENT_TYPE");
53
+      assertTrue("Expected IllegaArgumentException to be thrown", false);
54
+    } catch (IllegalArgumentException e) {
55
+      // All's well
56
+    }
57
+  }
58
+  
59
+  public void testEquality() throws Exception {
60
+    Date date = Calendar.getInstance().getTime();
61
+    Location locationAAA = new Location("AAA");
62
+    Location locationBBB = new Location("BBB");
63
+    CarrierMovement cm = new CarrierMovement(locationAAA, locationBBB);
64
+    
65
+    Cargo cargo1 = new Cargo(new TrackingId("ABC"), new Location("A"), new Location("C"));
66
+    Cargo cargo2 = new Cargo(new TrackingId("CBA"), new Location("C"), new Location("A"));
67
+    Cargo cargo3 = new Cargo(new TrackingId("CBA"), new Location("C"), new Location("A")); //Identical to cargo2
68
+    
69
+    Set<Cargo> cargos1 = new HashSet<Cargo>();
70
+    cargos1.add(cargo1);
71
+    
72
+    Set<Cargo> cargos2 = new HashSet<Cargo>();
73
+    cargos2.add(cargo1);
74
+    cargos2.add(cargo2);
75
+    
76
+    Set<Cargo> cargos3 = new HashSet<Cargo>();
77
+    cargos3.add(cargo1);
78
+    cargos3.add(cargo3);
79
+    
80
+    
81
+    HandlingEvent ev1 = new HandlingEvent(date, HandlingEvent.Type.LOAD, cm);
82
+    ev1.register(cargos1);
83
+    
84
+    HandlingEvent ev2 = new HandlingEvent(date, HandlingEvent.Type.LOAD, cm);
85
+    ev2.register(cargos2);
86
+    
87
+    HandlingEvent ev3 = new HandlingEvent(date, HandlingEvent.Type.LOAD, cm);
88
+    ev3.register(cargos2);  
89
+    
90
+    assertFalse("HandlingEvents should not be considered equal if the Set of Cargo is not equal", ev1.equals(ev2));
91
+    assertTrue("HandlingEvents should be considered equal if the Set of Cargo is equal", ev2.equals(ev3));
92
+  }
36 93
 }

+ 102
- 0
dddsample/src/test/java/se/citerus/dddsample/service/HandlingEventServiceTest.java 查看文件

@@ -0,0 +1,102 @@
1
+package se.citerus.dddsample.service;
2
+
3
+import java.util.Calendar;
4
+import java.util.Date;
5
+import java.util.HashSet;
6
+import java.util.Set;
7
+
8
+import junit.framework.TestCase;
9
+import se.citerus.dddsample.domain.Cargo;
10
+import se.citerus.dddsample.domain.CarrierMovement;
11
+import se.citerus.dddsample.domain.HandlingEvent;
12
+import se.citerus.dddsample.domain.Location;
13
+import se.citerus.dddsample.domain.TrackingId;
14
+import se.citerus.dddsample.repository.CargoRepository;
15
+import se.citerus.dddsample.repository.CarrierRepository;
16
+import se.citerus.dddsample.repository.HandlingEventRepository;
17
+import static org.easymock.EasyMock.*;
18
+
19
+public class HandlingEventServiceTest extends TestCase {
20
+  private HandlingEventServiceImpl service;
21
+  private CargoRepository cargoRepository;
22
+  private CarrierRepository carrierRepository;
23
+  private HandlingEventRepository handlingEventRepository;
24
+  
25
+  private final Cargo cargoABC = new Cargo(new TrackingId("ABC"), new Location("ABCFROM"), new Location("ABCTO"));
26
+  private final Cargo cargoXYZ = new Cargo(new TrackingId("XYZ"), new Location("XYZFROM"), new Location("XYZTO"));
27
+  private final CarrierMovement cmAAA_BBB = new CarrierMovement(new Location("AAA"), new Location("BBB"));
28
+
29
+  protected void setUp() throws Exception{
30
+    service = new HandlingEventServiceImpl();
31
+    cargoRepository = createMock(CargoRepository.class);
32
+    carrierRepository = createMock(CarrierRepository.class);
33
+    handlingEventRepository = createMock(HandlingEventRepository.class);
34
+    
35
+    service.setCargoRepository(cargoRepository);
36
+    service.setCarrierRepository(carrierRepository);
37
+    service.setHandlingEventRepository(handlingEventRepository);
38
+  }
39
+
40
+  public void testRegisterEvent() throws Exception {
41
+    String carrierId = "AAA_BBB";
42
+    final String[] trackIds = { "ABC", "XYZ" };
43
+    Date date = Calendar.getInstance().getTime();
44
+    String type = "UNLOAD";
45
+    
46
+    expect(cargoRepository.find(new TrackingId("ABC"))).andReturn(cargoABC);
47
+    expect(cargoRepository.find(new TrackingId("XYZ"))).andReturn(cargoXYZ);
48
+    expect(carrierRepository.find("AAA_BBB")).andReturn(cmAAA_BBB);
49
+    
50
+    HandlingEvent event = new HandlingEvent(date, HandlingEvent.parseType(type), cmAAA_BBB);
51
+    Set<Cargo> cargos = new HashSet<Cargo>();
52
+    cargos.add(cargoABC);
53
+    cargos.add(cargoXYZ);
54
+    event.register(cargos);
55
+    
56
+    handlingEventRepository.save(event);
57
+    
58
+    replay(cargoRepository, carrierRepository, handlingEventRepository);
59
+    
60
+    service.register(date, type, carrierId, trackIds);
61
+    
62
+    verify(cargoRepository, carrierRepository, handlingEventRepository);
63
+  }
64
+  
65
+  public void testRegisterEventInvalidCarrier() throws Exception {
66
+    final String[] trackIds = { "ABC", "XYZ" };
67
+    Date date = Calendar.getInstance().getTime();
68
+    String type = "UNLOAD";
69
+    
70
+    expect(cargoRepository.find(new TrackingId("ABC"))).andReturn(cargoABC);
71
+    expect(cargoRepository.find(new TrackingId("XYZ"))).andReturn(cargoXYZ);
72
+    expect(carrierRepository.find("AAA_BBB")).andReturn(null);
73
+    
74
+    replay(cargoRepository, carrierRepository, handlingEventRepository);
75
+    
76
+    try {
77
+      service.register(date, type, "AAA_BBB", trackIds);
78
+      assertFalse(true);
79
+    } catch (IllegalArgumentException e) {
80
+      // Expected IllegalArgumentExecption
81
+    }
82
+  }
83
+  
84
+  public void testRegisterEventInvalidCargo() throws Exception {
85
+    final String[] trackIds = { "ABC", "XYZ" };
86
+    Date date = Calendar.getInstance().getTime();
87
+    String type = "UNLOAD";
88
+    
89
+    expect(cargoRepository.find(new TrackingId("ABC"))).andReturn(cargoABC);
90
+    expect(cargoRepository.find(new TrackingId("XYZ"))).andReturn(null);
91
+    expect(carrierRepository.find("AAA_BBB")).andReturn(cmAAA_BBB);
92
+    
93
+    replay(cargoRepository, carrierRepository, handlingEventRepository);
94
+    
95
+    try {
96
+      service.register(date, type, "AAA_BBB", trackIds);
97
+      assertFalse(true);
98
+    } catch (IllegalArgumentException e) {
99
+      // Expected IllegalArgumentExecption
100
+    }
101
+  }
102
+}

+ 6
- 1
dddsample/src/test/resources/mock-context-persistence.xml 查看文件

@@ -11,5 +11,10 @@
11 11
   <bean id="cargoRepository" class="org.easymock.EasyMock" factory-method="createMock">
12 12
     <constructor-arg value="se.citerus.dddsample.repository.CargoRepository"/>
13 13
   </bean>
14
-
14
+  
15
+  <bean id="handlingEventRepository" class="se.citerus.dddsample.repository.HandlingEventRepositoryInMem" init-method="init">
16
+    <property name="carrierRepository" ref="carrierRepository"/>
17
+  </bean>
18
+  
19
+  <bean id="carrierRepository" class="se.citerus.dddsample.repository.CarrierRepositoryInMem" />
15 20
 </beans>

+ 48
- 0
dddsample/src/test/resources/test-context-persistence.xml 查看文件

@@ -0,0 +1,48 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+
3
+<beans  xmlns="http://www.springframework.org/schema/beans"
4
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
+        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
6
+
7
+  <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
8
+    <property name="location" value="classpath:jdbc.properties"/>
9
+  </bean>
10
+
11
+  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
12
+    <property name="url" value="${jdbc.url}"/>
13
+    <property name="driverClassName" value="${jdbc.driverClassName}"/>
14
+    <property name="username" value="${jdbc.username}"/>
15
+    <property name="password" value="${jdbc.password}"/>
16
+  </bean>
17
+
18
+  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
19
+    <property name="dataSource" ref="dataSource"/>
20
+    <property name="annotatedClasses">
21
+      <list>
22
+        <value>se.citerus.dddsample.domain.Cargo</value>
23
+        <value>se.citerus.dddsample.domain.Location</value>
24
+        <value>se.citerus.dddsample.domain.DeliveryHistory</value>
25
+        <value>se.citerus.dddsample.domain.HandlingEvent</value>
26
+        <value>se.citerus.dddsample.domain.CarrierMovement</value>
27
+      </list>
28
+    </property>
29
+    <property name="hibernateProperties">
30
+      <props>
31
+        <!-- These are properties that are common for test and production -->
32
+        <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
33
+        <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
34
+      </props>
35
+    </property>
36
+  </bean>
37
+
38
+  <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
39
+    <property name="sessionFactory" ref="sessionFactory"/>
40
+  </bean>
41
+
42
+  <!--  bean id="cargoRepository" class="se.citerus.dddsample.repository.CargoRepositoryInMem" / -->
43
+
44
+  <bean id="cargoRepository" class="se.citerus.dddsample.repository.CargoRepositoryHibernate">
45
+    <property name="sessionFactory" ref="sessionFactory"/>
46
+  </bean>
47
+
48
+</beans>