citerus / dddsample-core Goto Github PK
View Code? Open in Web Editor NEWThis is the new home of the original DDD Sample app (previously hosted at sf.net)..
License: MIT License
This is the new home of the original DDD Sample app (previously hosted at sf.net)..
License: MIT License
Hi there,
I have to apologise first for this issue for the reason below:
I am a
PHP
developer that has minimalJava
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?
Hi, Is there any document outlining the requirements to arrive at the bounded contexts. Where can I get the domain information about cargo tracking?
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
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?
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.
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?
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.
mvn spring-boot:run
Error: org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
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?
We currently have an entire generated website for the project at DDD Sample Application - Introduction using files located in src/site/. Redirect sourceforge page to GH Pages page. Add description of project.
(Not exactly an issue for the GitHub project, but adding it anyway for tracking)
in class SampleLocations, "HANGZOU" is not correcttly spelled, pls change it to "HANGZHOU"
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:
<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>
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
Steps to reproduce: Build project
Expected: Project gives no errors about obsolete JDBCTemplates
Actual: Project gives errors about obsolete JDBCTemplates
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:
I can get the application to error when booking cargo:
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)
Why does the Cargo.java hold a direct reference to the Location.java class, isn't the whole idea aggregate roots to avoid references outside of the aggregate root ?
Add a CODEOWNERS file to the repo in order to automatically add default reviewers to PRs.
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.
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."
When importing the project code into Eclipse Mars, I have 1 error that says "@webservice annotation contains an endpointInterface attribute. No parameters annotated with @WebParam allowed in implementation class".
This error appears in the HandlingReportServiceImpl class.
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.
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.
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?
Is there any thoughts about updating this project to Spring Boot 3? It would be very interesting for the community.
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.
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.
none
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.
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.