Bladeren bron

Improved report submission and reporting service. Core now deploys correctly.

peter_backlund 16 jaren geleden
bovenliggende
commit
7d52039c4d

+ 6
- 0
dddsample/external/reporting-api/pom.xml Bestand weergeven

@@ -12,4 +12,10 @@
12 12
   <name>External: Reporting API</name>
13 13
   <version>${project.parent.version}</version>
14 14
   <description>Reporting API</description>
15
+  <dependencies>
16
+    <dependency>
17
+      <groupId>javax.ws.rs</groupId>
18
+      <artifactId>jsr311-api</artifactId>
19
+    </dependency>
20
+  </dependencies>
15 21
 </project>

+ 10
- 2
dddsample/external/reporting-api/src/main/java/se/citerus/dddsample/reporting/api/ReportSubmission.java Bestand weergeven

@@ -1,9 +1,17 @@
1 1
 package se.citerus.dddsample.reporting.api;
2 2
 
3
+import javax.ws.rs.*;
4
+
5
+@Consumes({"application/json", "application/xml"})
6
+@Path("/")
3 7
 public interface ReportSubmission {
4 8
 
5
-  void reportCargo(CargoDetails cargoDetails);
9
+  @PUT
10
+  @Path("/cargo")
11
+  void submitCargoDetails(CargoDetails cargoDetails);
6 12
 
7
-  void reportHandling(String trackingId, Handling handling);
13
+  @POST
14
+  @Path("/cargo/{trackingId}/handled")
15
+  void submitHandling(@PathParam("trackingId") String trackingId, Handling handling);
8 16
 
9 17
 }

+ 8
- 67
dddsample/external/reporting/src/main/java/com/reporting/ReportingService.java Bestand weergeven

@@ -1,80 +1,21 @@
1 1
 package com.reporting;
2 2
 
3
-import com.reporting.db.ReportDAO;
4
-import com.reporting.reports.CargoReport;
5
-import com.reporting.reports.VoyageReport;
6
-import org.apache.commons.logging.Log;
7
-import org.apache.commons.logging.LogFactory;
8
-import org.springframework.transaction.annotation.Transactional;
9
-import se.citerus.dddsample.reporting.api.CargoDetails;
10
-import se.citerus.dddsample.reporting.api.Handling;
11
-import se.citerus.dddsample.reporting.api.ReportSubmission;
12
-
13
-import javax.ws.rs.*;
3
+import javax.ws.rs.GET;
4
+import javax.ws.rs.Path;
5
+import javax.ws.rs.PathParam;
6
+import javax.ws.rs.Produces;
14 7
 import javax.ws.rs.core.Response;
15
-import java.text.ParseException;
16
-
17
-import static com.reporting.Constants.US_DATETIME;
18
-import static javax.ws.rs.core.Response.ok;
19
-import static javax.ws.rs.core.Response.status;
20 8
 
21
-@Produces({"application/json", "application/pdf"})
22
-@Consumes({"application/json", "application/xml"})
9
+@Produces({"application/json", "application/pdf", "application/xml"})
23 10
 @Path("/")
24
-public class ReportingService implements ReportSubmission {
25
-
26
-  private ReportDAO reportDAO;
27
-  private static final Log LOG = LogFactory.getLog(ReportingService.class);
28
-
29
-  public ReportingService(ReportDAO reportDAO) {
30
-    this.reportDAO = reportDAO;
31
-  }
11
+public interface ReportingService {
32 12
 
33 13
   @GET
34 14
   @Path("/cargo/{trackingId}.{format}")
35
-  public Response getCargoReport(@PathParam("trackingId") String trackingId, @PathParam("format") String format) throws ParseException {
36
-    CargoReport cargoReport = reportDAO.loadCargoReport(trackingId);
37
-    if (cargoReport == null) return status(404).build();
38
-
39
-    return ok(cargoReport).
40
-      type("application/" + format).
41
-      lastModified(US_DATETIME.parse(cargoReport.getCargo().getLastUpdatedOn())).
42
-      build();
43
-  }
15
+  public Response getCargoReport(@PathParam("trackingId") String trackingId, @PathParam("format") String format);
44 16
 
45 17
   @GET
46 18
   @Path("/voyage/{voyageNumber}.{format}")
47
-  public Response getVoyageReport(@PathParam("voyageNumber") String voyageNumber, @PathParam("format") String format) throws ParseException {
48
-    VoyageReport voyageReport = reportDAO.loadVoyageReport(voyageNumber);
49
-    if (voyageReport == null) return status(404).build();
50
-
51
-    return ok(voyageReport).
52
-      type("application/" + format).
53
-      lastModified(US_DATETIME.parse(voyageReport.getVoyage().getLastUpdatedOn())).
54
-      build();
55
-  }
56
-
57
-  @Override
58
-  @PUT
59
-  @Path("/cargo")
60
-  @Transactional
61
-  public void reportCargo(CargoDetails cargoDetails) {
62
-    reportDAO.storeCargoDetals(cargoDetails);
63
-    LOG.info("Stored cargo: " + cargoDetails);
64
-  }
65
-
66
-  @Override
67
-  @POST
68
-  @Path("/cargo/{trackingId}/handled")
69
-  @Transactional
70
-  public void reportHandling(@PathParam("trackingId") String trackingId, Handling handling) {
71
-    reportDAO.storeHandling(trackingId, handling);
72
-    LOG.info("Stored handling of cargo " + trackingId + ": " + handling);
73
-  }
74
-
75
-  @SuppressWarnings({"UnusedDeclaration"})
76
-  ReportingService() {
77
-    // Needed by CGLIB
78
-  }
19
+  public Response getVoyageReport(@PathParam("voyageNumber") String voyageNumber, @PathParam("format") String format);
79 20
 
80 21
 }

+ 80
- 0
dddsample/external/reporting/src/main/java/com/reporting/ReportingServiceImpl.java Bestand weergeven

@@ -0,0 +1,80 @@
1
+package com.reporting;
2
+
3
+import com.reporting.db.ReportDAO;
4
+import com.reporting.reports.CargoReport;
5
+import com.reporting.reports.VoyageReport;
6
+import org.apache.commons.logging.Log;
7
+import org.apache.commons.logging.LogFactory;
8
+import org.springframework.transaction.annotation.Transactional;
9
+import se.citerus.dddsample.reporting.api.CargoDetails;
10
+import se.citerus.dddsample.reporting.api.Handling;
11
+import se.citerus.dddsample.reporting.api.ReportSubmission;
12
+
13
+import javax.ws.rs.core.Response;
14
+import java.text.ParseException;
15
+import java.util.Date;
16
+
17
+import static com.reporting.Constants.US_DATETIME;
18
+import static javax.ws.rs.core.Response.ok;
19
+import static javax.ws.rs.core.Response.status;
20
+
21
+public class ReportingServiceImpl implements ReportSubmission, ReportingService {
22
+
23
+  private ReportDAO reportDAO;
24
+  private static final Log LOG = LogFactory.getLog(ReportingServiceImpl.class);
25
+
26
+  public ReportingServiceImpl(ReportDAO reportDAO) {
27
+    this.reportDAO = reportDAO;
28
+  }
29
+
30
+  @Override
31
+  public Response getCargoReport(String trackingId, String format) {
32
+    CargoReport cargoReport = reportDAO.loadCargoReport(trackingId);
33
+    if (cargoReport == null) return status(404).build();
34
+
35
+    Date date = parseDate(cargoReport.getCargo().getLastUpdatedOn());
36
+    return ok(cargoReport).
37
+      type("application/" + format).
38
+      lastModified(date).
39
+      build();
40
+  }
41
+
42
+  @Override
43
+  public Response getVoyageReport(String voyageNumber, String format) {
44
+    VoyageReport voyageReport = reportDAO.loadVoyageReport(voyageNumber);
45
+    if (voyageReport == null) return status(404).build();
46
+
47
+    return ok(voyageReport).
48
+      type("application/" + format).
49
+      lastModified(parseDate(voyageReport.getVoyage().getLastUpdatedOn())).
50
+      build();
51
+  }
52
+
53
+  @Override
54
+  @Transactional
55
+  public void submitCargoDetails(CargoDetails cargoDetails) {
56
+    reportDAO.storeCargoDetals(cargoDetails);
57
+    LOG.info("Stored cargo: " + cargoDetails);
58
+  }
59
+
60
+  @Override
61
+  @Transactional
62
+  public void submitHandling(String trackingId, Handling handling) {
63
+    reportDAO.storeHandling(trackingId, handling);
64
+    LOG.info("Stored handling of cargo " + trackingId + ": " + handling);
65
+  }
66
+
67
+  private Date parseDate(String lastUpdatedOn) {
68
+    try {
69
+      return US_DATETIME.parse(lastUpdatedOn);
70
+    } catch (ParseException e) {
71
+      throw new RuntimeException(e);
72
+    }
73
+  }
74
+
75
+  @SuppressWarnings({"UnusedDeclaration"})
76
+  ReportingServiceImpl() {
77
+    // Needed by CGLIB
78
+  }
79
+
80
+}

+ 1
- 1
dddsample/external/reporting/src/main/resources/context.xml Bestand weergeven

@@ -19,7 +19,7 @@
19 19
     <constructor-arg ref="dataSource"/>
20 20
   </bean>
21 21
 
22
-  <bean id="reportingService" class="com.reporting.ReportingService">
22
+  <bean id="reportingService" class="com.reporting.ReportingServiceImpl">
23 23
     <constructor-arg ref="reportDAO"/>
24 24
   </bean>
25 25
 

dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/infrastructure/reporting/ReportsUpdater.java → dddsample/tracking/core/src/main/java/se/citerus/dddsample/tracking/core/infrastructure/reporting/ReportPusher.java Bestand weergeven

@@ -1,11 +1,9 @@
1 1
 package se.citerus.dddsample.tracking.core.infrastructure.reporting;
2 2
 
3
-import org.apache.cxf.jaxrs.client.WebClient;
4
-import org.springframework.beans.factory.annotation.Autowired;
5
-import org.springframework.stereotype.Service;
6 3
 import org.springframework.transaction.annotation.Transactional;
7 4
 import se.citerus.dddsample.reporting.api.CargoDetails;
8 5
 import se.citerus.dddsample.reporting.api.Handling;
6
+import se.citerus.dddsample.reporting.api.ReportSubmission;
9 7
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Cargo;
10 8
 import se.citerus.dddsample.tracking.core.domain.model.cargo.CargoRepository;
11 9
 import se.citerus.dddsample.tracking.core.domain.model.cargo.TrackingId;
@@ -13,43 +11,38 @@ import se.citerus.dddsample.tracking.core.domain.model.handling.EventSequenceNum
13 11
 import se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEvent;
14 12
 import se.citerus.dddsample.tracking.core.domain.model.handling.HandlingEventRepository;
15 13
 
16
-@Service
17
-public class ReportsUpdater {
14
+public class ReportPusher {
18 15
 
19
-  private WebClient webClient;
20 16
   private CargoRepository cargoRepository;
21 17
   private HandlingEventRepository handlingEventRepository;
22
-  private String handlingPath;
23
-  private String cargoDetailsPath;
18
+  private ReportSubmission reportSubmission;
24 19
 
25
-  @Autowired
26
-  public ReportsUpdater(final WebClient webClient,
27
-                        final CargoRepository cargoRepository,
28
-                        final HandlingEventRepository handlingEventRepository,
29
-                        final String handlingPath,
30
-                        final String cargoDetailsPath) {
31
-    this.webClient = webClient;
20
+  public ReportPusher(final ReportSubmission reportSubmission,
21
+                      final CargoRepository cargoRepository,
22
+                      final HandlingEventRepository handlingEventRepository) {
23
+    this.reportSubmission = reportSubmission;
32 24
     this.cargoRepository = cargoRepository;
33 25
     this.handlingEventRepository = handlingEventRepository;
34
-    this.handlingPath = handlingPath;
35
-    this.cargoDetailsPath = cargoDetailsPath;
36 26
   }
37 27
 
38 28
   @Transactional
39 29
   public void reportHandlingEvent(final EventSequenceNumber sequenceNumber) {
40 30
     HandlingEvent handlingEvent = handlingEventRepository.find(sequenceNumber);
41
-    Handling handling = toHandling(handlingEvent);
42
-    webClient.path(handlingPath).post(handling);
31
+    Handling handling = assembleFrom(handlingEvent);
32
+    String trackingIdString = handlingEvent.cargo().trackingId().stringValue();
33
+
34
+    reportSubmission.submitHandling(trackingIdString, handling);
43 35
   }
44 36
 
45 37
   @Transactional
46 38
   public void reportCargoUpdate(final TrackingId trackingId) {
47 39
     Cargo cargo = cargoRepository.find(trackingId);
48
-    CargoDetails cargoDetails = toCargoDetails(cargo);
49
-    webClient.path(cargoDetailsPath).post(cargoDetails);
40
+    CargoDetails cargoDetails = assembleFrom(cargo);
41
+
42
+    reportSubmission.submitCargoDetails(cargoDetails);
50 43
   }
51 44
 
52
-  private Handling toHandling(HandlingEvent handlingEvent) {
45
+  private Handling assembleFrom(HandlingEvent handlingEvent) {
53 46
     Handling handling = new Handling();
54 47
     handling.setLocation(handlingEvent.location().name());
55 48
     handling.setType(handlingEvent.activity().type().name());
@@ -57,7 +50,7 @@ public class ReportsUpdater {
57 50
     return handling;
58 51
   }
59 52
 
60
-  private CargoDetails toCargoDetails(Cargo cargo) {
53
+  private CargoDetails assembleFrom(Cargo cargo) {
61 54
     CargoDetails cargoDetails = new CargoDetails();
62 55
     cargoDetails.setTrackingId(cargo.trackingId().stringValue());
63 56
     cargoDetails.setFinalDestination(cargo.routeSpecification().destination().name());
@@ -66,4 +59,8 @@ public class ReportsUpdater {
66 59
     return cargoDetails;
67 60
   }
68 61
 
62
+  ReportPusher() {
63
+    // Needed by CGLIB
64
+  }
65
+
69 66
 }

+ 12
- 0
dddsample/tracking/core/src/main/resources/contexts/context-infrastructure-messaging.xml Bestand weergeven

@@ -27,8 +27,20 @@
27 27
     <jms:listener destination="CargoUpdateTopic" ref="misdirectedNotifierListener"/>
28 28
     <jms:listener destination="CargoUpdateTopic" ref="readyToClaimNotfierListener"/>
29 29
     <jms:listener destination="CargoHandledTopic" ref="cargoUpdaterListener"/>
30
+    <jms:listener destination="CargoHandledTopic" ref="reportHandlingListener"/>
31
+    <jms:listener destination="CargoUpdateTopic" ref="reportCargoUpdateListener"/>
30 32
   </jms:listener-container>
31 33
 
34
+  <bean id="reportHandlingListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
35
+    <property name="delegate" ref="reportPusher"/>
36
+    <property name="defaultListenerMethod" value="reportHandlingEvent"/>
37
+  </bean>
38
+
39
+  <bean id="reportCargoUpdateListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
40
+    <property name="delegate" ref="reportPusher"/>
41
+    <property name="defaultListenerMethod" value="reportCargoUpdate"/>
42
+  </bean>
43
+
32 44
   <bean id="misdirectedNotifierListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
33 45
     <property name="delegate" ref="misdirectedNotifier"/>
34 46
     <property name="defaultListenerMethod" value="alertIfMisdirected"/>

+ 23
- 0
dddsample/tracking/core/src/main/resources/contexts/context-infrastructure-reporting.xml Bestand weergeven

@@ -0,0 +1,23 @@
1
+<?xml version="1.0"?>
2
+
3
+<beans xmlns="http://www.springframework.org/schema/beans"
4
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
+       xmlns:context="http://www.springframework.org/schema/context"
6
+       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
7
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
8
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
9
+                           http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
10
+
11
+  <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/>
12
+
13
+  <jaxrs:client id="reportSubmission"
14
+                serviceClass="se.citerus.dddsample.reporting.api.ReportSubmission"
15
+                address="http://localhost:8080/reporting/rest"/>
16
+
17
+  <bean id="reportPusher" class="se.citerus.dddsample.tracking.core.infrastructure.reporting.ReportPusher">
18
+    <constructor-arg ref="reportSubmission"/>
19
+    <constructor-arg ref="cargoRepositoryHibernate"/>
20
+    <constructor-arg ref="handlingEventRepositoryHibernate"/>
21
+  </bean>
22
+
23
+</beans>

+ 1
- 0
dddsample/tracking/core/src/main/resources/contexts/context-infrastructure.xml Bestand weergeven

@@ -7,5 +7,6 @@
7 7
   <import resource="context-infrastructure-persistence.xml"/>
8 8
   <import resource="context-infrastructure-messaging.xml"/>
9 9
   <import resource="context-infrastructure-routing.xml"/>
10
+  <import resource="context-infrastructure-reporting.xml"/>
10 11
 
11 12
 </beans>

+ 17
- 18
dddsample/tracking/core/src/test/java/se/citerus/dddsample/tracking/core/infrastructure/reporting/ReportsUpdaterTest.java Bestand weergeven

@@ -1,34 +1,36 @@
1 1
 package se.citerus.dddsample.tracking.core.infrastructure.reporting;
2 2
 
3
-import org.apache.cxf.jaxrs.client.WebClient;
4 3
 import org.junit.Before;
5 4
 import org.junit.Test;
6
-import static org.mockito.Matchers.eq;
7
-import static org.mockito.Mockito.*;
8 5
 import se.citerus.dddsample.reporting.api.CargoDetails;
9 6
 import se.citerus.dddsample.reporting.api.Handling;
10
-import static se.citerus.dddsample.tracking.core.application.util.DateTestUtil.toDate;
7
+import se.citerus.dddsample.reporting.api.ReportSubmission;
11 8
 import se.citerus.dddsample.tracking.core.domain.model.cargo.Cargo;
12 9
 import se.citerus.dddsample.tracking.core.domain.model.cargo.CargoRepository;
13 10
 import se.citerus.dddsample.tracking.core.domain.model.cargo.RouteSpecification;
14 11
 import se.citerus.dddsample.tracking.core.domain.model.cargo.TrackingId;
15 12
 import se.citerus.dddsample.tracking.core.domain.model.handling.*;
16
-import static se.citerus.dddsample.tracking.core.domain.model.location.SampleLocations.HONGKONG;
17
-import static se.citerus.dddsample.tracking.core.domain.model.location.SampleLocations.ROTTERDAM;
18 13
 import se.citerus.dddsample.tracking.core.infrastructure.persistence.inmemory.CargoRepositoryInMem;
19 14
 import se.citerus.dddsample.tracking.core.infrastructure.persistence.inmemory.HandlingEventRepositoryInMem;
20 15
 import se.citerus.dddsample.tracking.core.infrastructure.persistence.inmemory.LocationRepositoryInMem;
21 16
 import se.citerus.dddsample.tracking.core.infrastructure.persistence.inmemory.VoyageRepositoryInMem;
22 17
 
18
+import static org.mockito.Matchers.eq;
19
+import static org.mockito.Mockito.mock;
20
+import static org.mockito.Mockito.verify;
21
+import static se.citerus.dddsample.tracking.core.application.util.DateTestUtil.toDate;
22
+import static se.citerus.dddsample.tracking.core.domain.model.location.SampleLocations.HONGKONG;
23
+import static se.citerus.dddsample.tracking.core.domain.model.location.SampleLocations.ROTTERDAM;
24
+
23 25
 public class ReportsUpdaterTest {
24 26
 
25
-  ReportsUpdater reportsUpdater;
26
-  WebClient client;
27
+  ReportPusher reportPusher;
28
+  ReportSubmission reportSubmission;
27 29
   EventSequenceNumber eventSequenceNumber;
28 30
 
29 31
   @Before
30 32
   public void setUp() {
31
-    client = mock(WebClient.class);
33
+    reportSubmission = mock(ReportSubmission.class);
32 34
     CargoRepository cargoRepository = new CargoRepositoryInMem();
33 35
     HandlingEventRepository handlingEventRepository = new HandlingEventRepositoryInMem();
34 36
     HandlingEventFactory handlingEventFactory = new HandlingEventFactory(cargoRepository, new VoyageRepositoryInMem(), new LocationRepositoryInMem());
@@ -45,15 +47,13 @@ public class ReportsUpdaterTest {
45 47
 
46 48
     cargo.handled(handlingEvent.activity());
47 49
 
48
-    reportsUpdater = new ReportsUpdater(client, cargoRepository, handlingEventRepository, "/handling", "/cargo");
50
+    reportPusher = new ReportPusher(reportSubmission, cargoRepository, handlingEventRepository);
49 51
     eventSequenceNumber = handlingEvent.sequenceNumber();
50 52
   }
51 53
 
52 54
   @Test
53 55
   public void reportCargoUpdate() {
54
-    when(client.path("/cargo")).thenReturn(client);
55
-
56
-    reportsUpdater.reportCargoUpdate(new TrackingId("ABC"));
56
+    reportPusher.reportCargoUpdate(new TrackingId("ABC"));
57 57
 
58 58
     CargoDetails expected = new CargoDetails();
59 59
     expected.setTrackingId("ABC");
@@ -61,20 +61,19 @@ public class ReportsUpdaterTest {
61 61
     expected.setFinalDestination("Rotterdam");
62 62
     expected.setCurrentStatus("IN_PORT");
63 63
 
64
-    verify(client).post(eq(expected));
64
+    verify(reportSubmission).submitCargoDetails(eq(expected));
65 65
   }
66 66
 
67 67
   @Test
68 68
   public void reportHandling() {
69
-    when(client.path("/handling")).thenReturn(client);
70
-
71
-    reportsUpdater.reportHandlingEvent(eventSequenceNumber);
69
+    reportPusher.reportHandlingEvent(eventSequenceNumber);
72 70
     
73 71
     Handling expected = new Handling();
74 72
     expected.setLocation("Hongkong");
75 73
     expected.setType("RECEIVE");
76 74
     expected.setVoyage("");
77
-    verify(client).post(eq(expected));
75
+
76
+    verify(reportSubmission).submitHandling(eq("ABC"), eq(expected));
78 77
   }
79 78
 
80 79
 }