Giter VIP home page Giter VIP logo

dddsample-core's Introduction

DDDSample

Java CI with Maven

This is the new home of the original DDD Sample app hosted at SourceForge.

Our intention is to move everything from SourceForge to GitHub in due time while starting upgrading both the technical aspects as well as the DDD aspects of the DDD Sample.

This project is a joint effort by Eric Evans' company Domain Language and the Swedish software consulting company Citerus.

The application uses Spring Boot. To start it go to the root directory and type mvn spring-boot:run or run the main method of the Application class from your IDE.
Then open http://localhost:8080/dddsample in your browser (and make sure that no firewall is blocking the communication and that Javascript for localhost is not blocked).

Discussion group: https://groups.google.com/forum/#!forum/dddsample

Development blog: https://citerus.github.io/dddsample-core/

Trello board: https://trello.com/b/PTDFRyxd

How to build

Using Maven (we recommend using the included Maven wrapper), run this command to compile and run all the tests:

./mvnw verify

If you want to compile without running the tests, run the following command:

./mvnw compile

For Windows users, use the included mvnw.cmd file instead, without the ./ but using the same arguments.

How to run

To start the app using the included application server and in-process HSQL database, run this command:

./mvnw spring-boot:run

For Windows users, use the included mvnw.cmd file instead, without the ./ but using the same arguments.

Entity relationships

The diagram was created with diagrams.net (formerly draw.io).

Using the HandlingReport REST API

The HandlingReport API has one endpoint that takes a JSON request body:

POST /dddsample/handlingReport

You can use cURL to send the request using an JSON file for the body:

curl --data-binary "@/path/to/project/src/test/resources/sampleHandlingReport.json" \
-H 'Content-Type: application/json;charset=UTF-8' \
http://localhost:8080/dddsample/handlingReport

See the api-docs.yaml file for a complete API definition.

dddsample-core's People

Contributors

cyberkni avatar daneidmark avatar dependabot[bot] avatar ericevans0 avatar ikardovskiy avatar jeham avatar jorgenfalk avatar jostly avatar jrende avatar kevinojt avatar kingsleylong avatar llissery avatar mackapappa avatar mdeinum avatar mikelhamer avatar orende avatar patrikfr avatar peterbacklund avatar ralmeidaa avatar rickardsundin avatar swissspidy avatar tmtron avatar yashtef avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dddsample-core's Issues

Why getters from domain classes should not be prefixed with “get” in DDD?

The DDDSample project seems to be a reference about how to design a DDD project.

I noticed all the getters in the domain classes are not prefixed by get. Ex: Cargo#delivery

Richard C. Martin, in his book Clean Code, sates:

Accessors, mutators, and predicates should be named for their value and prefixed with get, set, and is according to the javabean standard.

So, should we avoid to follow his advice in this context? If so, why would it be more important than consistency?

Copied from my question on SO.

Update to Spring Boot 3

Is there any thoughts about updating this project to Spring Boot 3? It would be very interesting for the community.

Requirements

Hi, Is there any document outlining the requirements to arrive at the bounded contexts. Where can I get the domain information about cargo tracking?

Class under the domain/model path is "Anemia model"?

Like:
class Cargo { public TrackingId trackingId() { return trackingId; } public Location origin() { return origin; } public Delivery delivery() { return delivery; } public RouteSpecification routeSpecification() { return routeSpecification; } }

Additional, I‘m newer, and I found Entity interface, why no Aggregate interface?

Isn't it a problem that you add entities to an aggregate from a different aggregate?

https://github.com/citerus/dddsample-core/blob/master/src/main/java/se/citerus/dddsample/application/impl/BookingServiceImpl.java#L38

    final TrackingId trackingId = cargoRepository.nextTrackingId();
    final Location origin = locationRepository.find(originUnLocode);
    final Location destination = locationRepository.find(destinationUnLocode);
    final RouteSpecification routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);

    final Cargo cargo = new Cargo(trackingId, routeSpecification);

    cargoRepository.store(cargo);

Here the Location is an entity, actually it looks like an aggregate root. Still you pass it as a parameter to the RouteSpecification. Afaik. aggregates cannot access each other directly. You should have added only a verified LocationId to the RouteSpecification, which is not necessarily the UnLocode you use for finding it. But correct me if I am wrong.

Error creating bean with name 'rmiGraphTraversalService'

When start with default setting in IntelliJ IDEA as a web app for tomcat, it fails with:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rmiGraphTraversalService' defined in class path resource [com/pathfinder/internal/applicationContext.xml]: Invocation of init method failed; nested exception is java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 

Error sending handling event SOAP message

When using SOAP to send a register handling event to the service, the SOAP API returns an OK response, but the application logs show that the handling of the event fails with an exception.

Steps to reproduce:

  1. Send a soap message to the service with the following body:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.handling.interfaces.dddsample.citerus.se/">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:submitReport>
         <!--Optional:-->
         <arg0>
            <completionTime>2022-01-01T00:00:00</completionTime>
            <!--1 or more repetitions:-->
            <trackingIds>2</trackingIds>
            <type>LOAD</type>
            <unLocode>AA234</unLocode>
            <!--Optional:-->
            <voyageNumber>5</voyageNumber>
         </arg0>
      </ws:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
  1. Look at the application logs

Expected behavior:
Handles handling event without errors.

Actual behavior:
Following logs shown:

2022-10-01 11:54:29.343  INFO 54823 --- [nio-8080-exec-1] s.c.d.i.m.jms.JmsApplicationEventsImpl   : Received handling event registration attempt se.citerus.dddsample.interfaces.handling.HandlingEventRegistrationAttempt@7ad887e3[
  registrationTime=Sat Oct 01 11:54:29 CEST 2022
  completionTime=Sat Jan 01 00:00:00 CET 2022
  trackingId=2
  voyageNumber=5
  type=LOAD
  unLocode=AA234
]
2022-10-01 11:54:29.379 ERROR 54823 --- [erContainer#1-1] HandlingEventRegistrationAttemptConsumer : javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Forbidden class se.citerus.dddsample.interfaces.handling.HandlingEventRegistrationAttempt! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to configure trusted classes.

javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Forbidden class se.citerus.dddsample.interfaces.handling.HandlingEventRegistrationAttempt! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to configure trusted classes.
	at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36) ~[activemq-client-5.15.3.jar:5.15.3]
	at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:213) ~[activemq-client-5.15.3.jar:5.15.3]
	at se.citerus.dddsample.infrastructure.messaging.jms.HandlingEventRegistrationAttemptConsumer.onMessage(HandlingEventRegistrationAttemptConsumer.java:26) ~[classes/:na]
	at org.springframework.jms.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:211) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_252]
Caused by: java.lang.ClassNotFoundException: Forbidden class se.citerus.dddsample.interfaces.handling.HandlingEventRegistrationAttempt! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to configure trusted classes.
	at org.apache.activemq.util.ClassLoadingAwareObjectInputStream.checkSecurity(ClassLoadingAwareObjectInputStream.java:112) ~[activemq-client-5.15.3.jar:5.15.3]
	at org.apache.activemq.util.ClassLoadingAwareObjectInputStream.resolveClass(ClassLoadingAwareObjectInputStream.java:57) ~[activemq-client-5.15.3.jar:5.15.3]
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1925) ~[na:1.8.0_252]
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1808) ~[na:1.8.0_252]
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2099) ~[na:1.8.0_252]
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1625) ~[na:1.8.0_252]
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:465) ~[na:1.8.0_252]
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:423) ~[na:1.8.0_252]
	at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:211) ~[activemq-client-5.15.3.jar:5.15.3]
	... 11 common frames omitted

Java 9/10 Support

To run the project using Java 9 or 10, I had to add the following configuration;

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <jvmArguments>--add-modules java.xml.bind,java.xml.ws</jvmArguments>
                </configuration>
            </plugin>

Unfortunately, this will break Java 8 support.

Http Status 404 - Not Found

Hi there,

I have to apologise first for this issue for the reason below:

I am a PHP developer that has minimal Java experience. I have always read about most Java Technologies and Tools and so the knowledge I have is barely theoretical even.

I have manually built a Tomcat Servelet Container that is sitting on Ubuntu 16.4 distribution. The server works as expected and well. I played around with few of the examples in there.

My problem is that when I cloned this project and built it myself everything looked promising as all 96 test cases passed during the built process.

I noticed that the packaging strategy uses a *.jar for deployment. Knowing that the Servelet Container allows *.war files for deployment I added the following dependencies within my pom file as shown by git dIff:

diff --git a/pom.xml b/pom.xml
index 80df796..69dd8c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,6 +5,7 @@
     <artifactId>dddsample</artifactId>
     <name>DDDSample</name>
     <version>2.0-SNAPSHOT</version>
+    <packaging>war</packaging>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
@@ -166,6 +167,11 @@
             <artifactId>selenium-java</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>

     <reporting>

My assumption was that the context path would be what Tomcat gives back if not dddsample, that is, http:localhost:8080/dddsample would have pointed me to the index page of the application.

It really is not easy to have a working deployment of the application and I suspect perhaps Tomcat is not a good enough server to recognise Spring Framework application. I am also sceptical on Glassfish as it never proved me better before.

Anything I am doing wrong here?

Set up a version running in the cloud

Note:
We probably want to fix the security alerts before we do this. One easy way to do that would be to enable Dependabot to automatically open PRs in the project and then work through them until we reach an acceptable level.

Coupling to ORM

Hello, its more question/suggestion:

Even now you have tickets in trello to fix storing itinerary, also if this was not finalized model but a live one, it would greatly benefit from separation of models and orm. Isn't it?
Also such questions are rised in blog, but not fully explained.
There are many ways, memento/mapstruct... But pros and cons are not always obvious.
It would be cool to have a full example ☺️

Wrong Beans init order

Spring initializes Beans in declared order.

In DDDSampleApplicationContext.java

“graphTraversalService” should be initialized before "routingService" because "routingService" requires "graphTraversalService"

"handlingEventFactory" should be initialized before "handlingEventRepository" because "handlingEventRepository" requires "handlingEventFactory"

Or they will just get null pointers.

Clearer and more isolated aggregates

Currently the aggregates have direct references to eachothers roots; replace this with identity references.

Note from @orende
"I recommend doing this after the JPA migration. It's not a trivial change given the considerable complexity of JPA annotations, but should be possible with enough study of the documentation."

Some spell fault

in class SampleLocations, "HANGZOU" is not correcttly spelled, pls change it to "HANGZHOU"

Package by feature, not layer

After doing some research, I got confirmation that folder-by-feature is superior to folder-by-layer in the majority of cases. To get some arguments we can read among others, this article, this one, or even this answer.

I think that the code of DDDSample should be refactored to follow this approach, or even using modules.

What do you think?

How to build and run this in IntelliJ Idea

This is almost certainly a user error. I haven't used Java that much (never used or even knew about Java EE before looking at this). I have tried for the past few hours to get this to work correctly with no luck. Can you guys please point me in some directions for how to do this please? Thanks.

Add scenario/integration test

This is more a feature request, but: Add scenario test using SUIT/Test-DSL. What needs to be done to be able to use SUIT/Test-DSL?

Which scenario tests exists today?

Date parsing failure when assigning cargo to route

I can get the application to error when booking cargo:

  1. Go to http://localhost:8080/dddsample/admin/list
  2. Click on book new cargo http://localhost:8080/dddsample/admin/registration
  3. Origin JNTKO Destination AUMEL, Select arrival deadline a couple of months out "03/06/2023" (not US-locale, it uses Europe Locale)
  4. Click book http://localhost:8080/dddsample/admin/show?trackingId=7FEB8AEE
  5. Says Not routed - so click "Route this cargo" - http://localhost:8080/dddsample/admin/selectItinerary?trackingId=7FEB8AEE
  6. Click first button, "assign cargo to this route"

See page with exception:

Sun Apr 23 14:13:04 PDT 2023
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='routeAssignmentCommand'. Error count: 10

The logs show:

Field error in object 'routeAssignmentCommand' on field 'legs[1].toDate': rejected value [2023-04-29 07:05]; codes [typeMismatch.routeAssignmentCommand.legs[1].toDate,typeMismatch.routeAssignmentCommand.legs.toDate,typeMismatch.legs[1].toDate,typeMismatch.legs.toDate,typeMismatch.toDate,typeMismatch.java.time.Instant,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [routeAssignmentCommand.legs[1].toDate,legs[1].toDate]; arguments []; default message [legs[1].toDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.Instant' for property 'legs[1].toDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.Instant] for value '2023-04-29 07:05'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2023-04-29 07:05]]

Running on Ubuntu 18, JDK 11

❱ java -version                 
Picked up JAVA_TOOL_OPTIONS: -XX:-UseBiasedLocking -Djdk.nio.maxCachedBufferSize=262144 -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints
openjdk version "11.0.14.1" 2022-02-08 LTS
OpenJDK Runtime Environment Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS, mixed mode)

Infrastructure layer depending on domain layer and interface declarations

Hi! I have some questions similar about the title and I hope that I can learn with you 😄, I am doing my own cargo-api and i have some interpretations different from yours.

  1. Why, your Infrastructure layer is making reference to the models of the domain on repositories? Should the Infrastructure never points upwards on the layered architecture? For exempla here your LocationRepositoryJPA know the types of the domain importing than, when I ready the book Eric makes clear you lower layers shouldn't have to point to the upper layers, so i thought that the infrastructure layer would have his own model declaration and in the domain layer we would translate that model with factories to the domain model, makes sense to you? Or I am caring too much about it, and it's ok to repositories knows the domain models?

  2. Why you are defining the interfaces where your domain depends on the domain layer? It's ok you define the interface of something (repository or a request to third party API) in the infrastructure layer and your domain depends on the interface declared on the infra and not the domain layer?

Thanks to make this repository public, I enjoyed a lot of reading and learning about your implementation.

Document project history

In the source forge repository, the landing page included this historical item

This project is a joint effort by Eric Evans' company Domain Language and the Swedish software consulting company Citerus.

This language appears to be missing from this github repository.

It's useful, when providing references to this repository, to be able to point to the documentation of its lineage, which lends some additional weight to this project as an "authority" of how DDD was imagined in the past.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.