Skip to content

Commit 1d349d3

Browse files
StephanPirnbaumodrotbohm
authored andcommitted
GH-18 - Abstractions to express CQRS concepts.
We no provide annotations to express CQRS concepts like commands, command handlers, dispatchers and query models in application code. See the Javadoc of the introduced annotations for details. Also @domainevent was extended to carry new, optional attributes for symmetry with what's available for commands.
1 parent a19fdaf commit 1d349d3

9 files changed

Lines changed: 374 additions & 1 deletion

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<artifactId>jmolecules-architecture</artifactId>
9+
<groupId>org.jmolecules</groupId>
10+
<version>1.1.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>jmolecules-cqrs-architecture</artifactId>
14+
15+
<name>jMolecules - CQRS Architecture</name>
16+
<description>Concepts of the cqrs architecture style.</description>
17+
18+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jmolecules.architecture.cqrs.annotation;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Identifies a command in the context of CQRS, i.e. a request to the system for the change of data. Commands are always
26+
* in imperative tense and thus, unlike an event, do not state that something has already happened, but something is
27+
* requested to happen. With that, the {@link CommandHandler} which is processing the command has the option reject the
28+
* command.
29+
*
30+
* @author Christian Stettler
31+
* @author Henning Schwentner
32+
* @author Stephan Pirnbaum
33+
* @author Martin Schimak
34+
* @author Oliver Drotbohm
35+
* @since 1.1
36+
* @see <a href="http://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young - Commands</a>
37+
*/
38+
@Documented
39+
@Retention(RetentionPolicy.RUNTIME)
40+
@Target(ElementType.TYPE)
41+
public @interface Command {
42+
43+
/**
44+
* An identifier for the namespace of the command to group multiple commands and let clients express their interest in
45+
* all commands of a specific namespace. If not set, external tooling may default this to the fully-qualified package
46+
* name of the annotated type.
47+
*/
48+
String namespace() default "";
49+
50+
/**
51+
* An identifier for the name of the command used to abstract away from the type system and to guard against
52+
* refactorings. If not set, external tooling may default this to the simple class name of the annotated type.
53+
*/
54+
String name() default "";
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jmolecules.architecture.cqrs.annotation;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Identifies a command dispatcher in the context of CQRS, i.e. logic to dispatch a {@link Command}.
26+
*
27+
* @author Christian Stettler
28+
* @author Henning Schwentner
29+
* @author Stephan Pirnbaum
30+
* @author Martin Schimak
31+
* @author Oliver Drotbohm
32+
* @since 1.1
33+
* @see <a href="http://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young - Commands</a>
34+
*/
35+
@Documented
36+
@Retention(RetentionPolicy.RUNTIME)
37+
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
38+
public @interface CommandDispatcher {
39+
40+
/**
41+
* Optional identification of the command dispatched by this dispatcher. This information may be used for easier
42+
* linkage between command and dispatcher by external tools and refers to the combination of
43+
* {@link Command#namespace()} and {@link Command#name()}, separated by '.' (dot).
44+
*/
45+
String dispatches() default "";
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jmolecules.architecture.cqrs.annotation;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Identifies a command handler in the context of CQRS, i.e. logic to process a {@link Command}. The command handler may
26+
* or may not reject the command. In case of processing, the handler takes care of orchestrating the business logic
27+
* related to the command.
28+
*
29+
* @author Christian Stettler
30+
* @author Henning Schwentner
31+
* @author Stephan Pirnbaum
32+
* @author Martin Schimak
33+
* @author Oliver Drotbohm
34+
* @since 1.1
35+
* @see <a href="http://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young - Commands</a>
36+
*/
37+
@Documented
38+
@Retention(RetentionPolicy.RUNTIME)
39+
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
40+
public @interface CommandHandler {
41+
42+
/**
43+
* Optional identification of the namespace of the command handled by this handler. This information may be used for
44+
* easier linkage between command and handler by external tools and refers to {@link Command#namespace()}. When
45+
* leaving the default value, it is assumed that the method signature makes clear what command is consumed. If the
46+
* handler takes care of all commands of a specific namespace, the value of this field needs to be set to the
47+
* respective namespace and the {@link CommandHandler#name()} ()} needs to be set accordingly. If the handler doesn't
48+
* care about the namespace, the value may be set to the '*' (asterisk) placeholder.
49+
*/
50+
String namespace() default "";
51+
52+
/**
53+
* Optional identification of the name of the command handled by this handler. This information may be used for easier
54+
* linkage between command and handler by external tools and refers to {@link Command#name()}. When leaving the
55+
* default value, it is assumed that the method signature makes clear what command is consumed. If the handler takes
56+
* care of all commands of a specific namespace, the value of this field needs to be set to the '*' (asterisk)
57+
* placeholder.
58+
*/
59+
String name() default "";
60+
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jmolecules.architecture.cqrs.annotation;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Identifies a query model element in the context of CQRS, i.e. a (persistent) object optimized for read-access and
26+
* only only on the Q(uery) part of the architecture. The query model represents the current state or rather
27+
* materialized view after replaying the events published by the application.
28+
*
29+
* @author Christian Stettler
30+
* @author Henning Schwentner
31+
* @author Stephan Pirnbaum
32+
* @author Martin Schimak
33+
* @author Oliver Drotbohm
34+
* @since 1.1
35+
* @see <a href="http://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young</a>
36+
*/
37+
@Documented
38+
@Retention(RetentionPolicy.RUNTIME)
39+
@Target(ElementType.TYPE)
40+
public @interface QueryModel {}

jmolecules-architecture/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<description>Architectural Styles in Java</description>
1717

1818
<modules>
19+
<module>jmolecules-cqrs-architecture</module>
1920
<module>jmolecules-layered-architecture</module>
2021
<module>jmolecules-onion-architecture</module>
2122
</modules>

jmolecules-events/src/main/java/org/jmolecules/event/annotation/DomainEvent.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,12 @@
1515
*/
1616
package org.jmolecules.event.annotation;
1717

18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
1824
/**
1925
* A domain event is a full-fledged part of the domain model, a representation of something that happened in the domain.
2026
* It allows making the events that the domain experts want to track or be notified of explicit, or which are associated
@@ -28,5 +34,25 @@
2834
* @see <a href="https://domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf">Domain-Driven Design
2935
* Reference (Evans) - Domain Events</a>
3036
*/
37+
@Retention(RetentionPolicy.RUNTIME)
38+
@Target(ElementType.TYPE)
39+
@Documented
3140
public @interface DomainEvent {
41+
42+
/**
43+
* An identifier for the namespace of the event to group multiple events and let clients express their interest in all
44+
* events of a specific namespace. If not set, external tooling may default this to the fully-qualified package name
45+
* of the annotated type.
46+
*
47+
* @since 1.1
48+
*/
49+
String namespace() default "";
50+
51+
/**
52+
* An identifier for the name of the event used to abstract away from the type system and to guard against
53+
* refactorings. If not set, external tooling may default this to the simple class name of the annotated type.
54+
*
55+
* @since 1.1
56+
*/
57+
String name() default "";
3258
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jmolecules.event.annotation;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Identifies a domain event handler, i.e. logic to process a {@link DomainEvent}.
26+
*
27+
* @author Christian Stettler
28+
* @author Henning Schwentner
29+
* @author Stephan Pirnbaum
30+
* @author Martin Schimak
31+
* @author Oliver Drotbohm
32+
* @since 1.1
33+
*/
34+
@Documented
35+
@Retention(RetentionPolicy.RUNTIME)
36+
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
37+
public @interface DomainEventHandler {
38+
39+
/**
40+
* Optional identification of the namespace of the domain event handled by this handler. This information may be used
41+
* for easier linkage between event and handler by external tools and refers to {@link DomainEvent#namespace()}. When
42+
* leaving the default value, it is assumed that the method signature makes clear what event is consumed. If the
43+
* handler takes care of all events of a specific namespace, the value of this field needs to be set to the respective
44+
* namespace and the {@link DomainEventHandler#name()} needs to be set accordingly. If the handler doesn't care about
45+
* the namespace, the value may be set to the '*' (asterisk) placeholder.
46+
*/
47+
String namespace() default "";
48+
49+
/**
50+
* Optional identification of the name of the domain event handled by this handler. This information may be used for
51+
* easier linkage between event and handler by external tools and refers to {@link DomainEvent#name()}. When leaving
52+
* the default value, it is assumed that the method signature makes clear what event is consumed. If the handler takes
53+
* care of all events of a specific namespace, the value of this field needs to be set to the '*' asterisk
54+
* placeholder.
55+
*/
56+
String name() default "";
57+
}

0 commit comments

Comments
 (0)