├── .github ├── FUNDING.yml └── workflows │ ├── build_standard.yml │ ├── release.yml │ └── build_master.yml ├── settings.gradle ├── src ├── test │ ├── resources │ │ └── test │ │ │ ├── docker │ │ │ └── compose │ │ │ │ ├── no-services-2 │ │ │ │ └── docker-compose.yml │ │ │ │ └── no-services-1 │ │ │ │ └── docker-compose.yml │ │ │ ├── microservice │ │ │ └── spring-boot │ │ │ │ └── docker-compose.yml │ │ │ └── oas-tests │ │ │ ├── operation-without-id-1.yml │ │ │ ├── oas-with-error.yml │ │ │ ├── operation-without-id-2.yml │ │ │ ├── sample-object-as-parameter-1.yml │ │ │ ├── sample-object-as-parameter-2.yml │ │ │ └── sample-contract.yml │ └── java │ │ ├── test │ │ ├── annotated │ │ │ └── type │ │ │ │ ├── BoundedContextTestAnnotation.java │ │ │ │ └── TestBoundedContext.java │ │ ├── application │ │ │ └── spring │ │ │ │ └── boot │ │ │ │ ├── model │ │ │ │ ├── CustomerId.java │ │ │ │ ├── Address.java │ │ │ │ └── Customer.java │ │ │ │ ├── TestSpringBootApplication.java │ │ │ │ └── interfaces │ │ │ │ ├── IgnoredResource.java │ │ │ │ └── CustomerInformationHolder.java │ │ ├── duplicate │ │ │ ├── domainobject │ │ │ │ └── name │ │ │ │ │ ├── model │ │ │ │ │ ├── CustomerId.java │ │ │ │ │ ├── duplicate1 │ │ │ │ │ │ └── CustomerId.java │ │ │ │ │ ├── duplicate2 │ │ │ │ │ │ └── CustomerId.java │ │ │ │ │ ├── Address.java │ │ │ │ │ └── Customer.java │ │ │ │ │ ├── TestSpringBootApplication.java │ │ │ │ │ └── interfaces │ │ │ │ │ └── CustomerInformationHolder.java │ │ │ └── aggregate │ │ │ │ └── name │ │ │ │ ├── TestSpringBootApplication.java │ │ │ │ └── interfaces │ │ │ │ ├── TestInformationHolder.java │ │ │ │ ├── TestInformationHolder2.java │ │ │ │ └── TestInformationHolder3.java │ │ └── microservice │ │ │ └── spring │ │ │ └── boot │ │ │ ├── service1 │ │ │ ├── Microservice1.java │ │ │ └── interfaces │ │ │ │ └── CustomerInformationHolder.java │ │ │ └── service2 │ │ │ └── Microservice2.java │ │ └── org │ │ └── contextmapper │ │ └── discovery │ │ ├── model │ │ ├── ParameterTest.java │ │ ├── MethodTest.java │ │ ├── BoundedContextTest.java │ │ ├── ServiceTest.java │ │ ├── ContextMapTest.java │ │ ├── AggregateTest.java │ │ ├── RelationshipTest.java │ │ ├── TypeTest.java │ │ └── DomainObjectTest.java │ │ ├── cml │ │ └── CMLPrimitiveTypeMapperTest.java │ │ ├── strategies │ │ ├── boundedcontexts │ │ │ └── AnnotatedTypeBoundedContextDiscoveryStrategyTest.java │ │ ├── names │ │ │ └── SeparatorToCamelCaseBoundedContextNameMappingStrategyTest.java │ │ └── relationships │ │ │ └── DockerComposeRelationshipDiscoveryStrategyTest.java │ │ ├── ContextMapDiscovererTest.java │ │ └── ContextMapSerializerTest.java └── main │ └── java │ └── org │ └── contextmapper │ └── discovery │ ├── model │ ├── DomainObjectType.java │ ├── TypeKind.java │ ├── Parameter.java │ ├── Attribute.java │ ├── ContextMap.java │ ├── Service.java │ ├── BoundedContext.java │ ├── Method.java │ ├── Relationship.java │ ├── Aggregate.java │ ├── DomainObject.java │ └── Type.java │ ├── strategies │ ├── names │ │ ├── DefaultBoundedContextNameMappingStrategy.java │ │ ├── BoundedContextNameMappingStrategy.java │ │ └── SeparatorToCamelCaseBoundedContextNameMappingStrategy.java │ ├── relationships │ │ ├── AbstractRelationshipDiscoveryStrategy.java │ │ ├── RelationshipDiscoveryStrategy.java │ │ └── DockerComposeRelationshipDiscoveryStrategy.java │ ├── boundedcontexts │ │ ├── AbstractBoundedContextDiscoveryStrategy.java │ │ ├── BoundedContextDiscoveryStrategy.java │ │ ├── AnnotatedTypeBoundedContextDiscoveryStrategy.java │ │ ├── SpringBootBoundedContextDiscoveryStrategy.java │ │ └── OASBoundedContextDiscoveryStrategy.java │ └── helper │ │ ├── ReflectionHelpers.java │ │ └── AnnotationScanner.java │ ├── cml │ └── CMLPrimitiveTypeMapper.java │ ├── ContextMapSerializer.java │ └── ContextMapDiscoverer.java ├── Examples ├── LakesideMutual │ ├── settings.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── build.gradle │ ├── gradlew.bat │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── org │ │ │ └── contextmapper │ │ │ └── lakesidemutual │ │ │ └── example │ │ │ └── LakesideMutualContextMapDiscoverer.java │ ├── README.md │ └── gradlew └── README.md ├── codecov.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── .gitignore ├── gradlew.bat └── gradlew /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: stefan-ka 2 | 3 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'context-map-discovery' 2 | 3 | -------------------------------------------------------------------------------- /src/test/resources/test/docker/compose/no-services-2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'lakesidemutual-example' 2 | 3 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: on 4 | patch: off 5 | precision: 1 6 | 7 | -------------------------------------------------------------------------------- /src/test/resources/test/docker/compose/no-services-1/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/gradle.properties: -------------------------------------------------------------------------------- 1 | # dependency versions 2 | discoveryLibVersion=1.4.0 3 | lakesideMutualVersion=0.0.1-SNAPSHOT 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-map-discovery/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/test/java/test/annotated/type/BoundedContextTestAnnotation.java: -------------------------------------------------------------------------------- 1 | package test.annotated.type; 2 | 3 | public @interface BoundedContextTestAnnotation { 4 | } 5 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-map-discovery/HEAD/Examples/LakesideMutual/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Examples/README.md: -------------------------------------------------------------------------------- 1 | # Example Projects 2 | This folder contains example microservice projects to which we applied our Context Map discovery library. 3 | 4 | * [Lakeside Mutual](./LakesideMutual/) 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Oct 25 16:08:31 CEST 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Oct 27 08:42:13 CET 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /src/test/resources/test/microservice/spring-boot/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | microservice1: 4 | build: microservice1 5 | image: test/microservice1 6 | ports: 7 | - "8080:8080" 8 | microservice2: 9 | build: microservice2 10 | image: test/microservice2 11 | depends_on: 12 | - microservice1 13 | ports: 14 | - "8090:8090" 15 | -------------------------------------------------------------------------------- /src/test/resources/test/oas-tests/operation-without-id-1.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: ReferenceManagementServiceAPI 4 | version: "1.0" 5 | paths: 6 | /TestEndpoint1: 7 | get: 8 | operationId: operation1 9 | responses: 10 | "200": 11 | description: response message payload (success case) 12 | delete: 13 | responses: 14 | "200": 15 | description: response message payload (success case) 16 | -------------------------------------------------------------------------------- /src/test/resources/test/oas-tests/oas-with-error.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: ReferenceManagementServiceAPI 4 | version: "1.0" 5 | paths: 6 | /ErrorTest: 7 | get: 8 | operationId: operation1 9 | responses: 10 | "200": 11 | description: response message payload (success case) 12 | get: 13 | operationId: operation1 14 | responses: 15 | "200": 16 | description: response message payload (success case) 17 | -------------------------------------------------------------------------------- /src/test/resources/test/oas-tests/operation-without-id-2.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: ReferenceManagementServiceAPI 4 | version: "1.0" 5 | paths: 6 | /TestEndpoint1: 7 | get: 8 | operationId: operation1 9 | responses: 10 | "200": 11 | description: response message payload (success case) 12 | delete: 13 | operationId: "" 14 | responses: 15 | "200": 16 | description: response message payload (success case) 17 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Publication repos 2 | ossSnapshotRepository=https://oss.sonatype.org/content/repositories/snapshots/ 3 | ossReleaseStagingRepository=https://oss.sonatype.org/service/local/staging/deploy/maven2/ 4 | 5 | # dependency versions 6 | jUnitVersion=5.11.0 7 | cmlVersion=6.11.0 8 | reflectionsVersion=0.10.2 9 | springBootVersion=2.6.4 10 | springWebVersion=5.3.16 11 | commonsLangVersion=3.9 12 | commonsIOVersion=2.6 13 | snakeYMLVersion=1.25 14 | swaggerParserVersion=2.0.20 15 | logbackVersion=1.2.6 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | out/ 4 | 5 | # IntelliJ 6 | .idea/ 7 | 8 | # Eclipse 9 | .classpath 10 | .project 11 | .settings/ 12 | bin 13 | 14 | # Generated test models 15 | src-gen/ 16 | 17 | # Gradle 18 | .gradle/ 19 | build/ 20 | 21 | # Log file 22 | *.log 23 | 24 | # BlueJ files 25 | *.ctxt 26 | 27 | # Mobile Tools for Java (J2ME) 28 | .mtj.tmp/ 29 | 30 | # Package Files # 31 | *.jar 32 | *.war 33 | *.nar 34 | *.ear 35 | *.zip 36 | *.tar.gz 37 | *.rar 38 | 39 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 40 | hs_err_pid* 41 | -------------------------------------------------------------------------------- /src/test/java/test/annotated/type/TestBoundedContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.annotated.type; 17 | 18 | @BoundedContextTestAnnotation 19 | public class TestBoundedContext { 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/test/application/spring/boot/model/CustomerId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.application.spring.boot.model; 17 | 18 | public class CustomerId { 19 | 20 | private String id; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/model/CustomerId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name.model; 17 | 18 | public class CustomerId { 19 | 20 | private String id; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/model/duplicate1/CustomerId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name.model.duplicate1; 17 | 18 | public class CustomerId { 19 | 20 | private String id; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/model/duplicate2/CustomerId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name.model.duplicate2; 17 | 18 | public class CustomerId { 19 | 20 | private String id; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/application/spring/boot/TestSpringBootApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.application.spring.boot; 17 | 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | 20 | @SpringBootApplication 21 | public class TestSpringBootApplication { 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/microservice/spring/boot/service1/Microservice1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.microservice.spring.boot.service1; 17 | 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | 20 | @SpringBootApplication 21 | public class Microservice1 { 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/microservice/spring/boot/service2/Microservice2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.microservice.spring.boot.service2; 17 | 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | 20 | @SpringBootApplication 21 | public class Microservice2 { 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/aggregate/name/TestSpringBootApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.aggregate.name; 17 | 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | 20 | @SpringBootApplication 21 | public class TestSpringBootApplication { 22 | } 23 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'org.contextmapper' 6 | version '1.0-SNAPSHOT' 7 | 8 | sourceCompatibility = 11 9 | 10 | repositories { 11 | mavenCentral() 12 | mavenLocal() 13 | } 14 | 15 | dependencies { 16 | implementation "org.contextmapper:context-map-discovery:${discoveryLibVersion}" 17 | 18 | // lakeside mutual dependencies (local Maven repo) 19 | implementation "com.lakesidemutual:customer-core:${lakesideMutualVersion}" 20 | implementation "com.lakesidemutual:customer-management-backend:${lakesideMutualVersion}" 21 | implementation "com.lakesidemutual:customer-self-service-backend:${lakesideMutualVersion}" 22 | implementation "com.lakesidemutual:policy-management-backend:${lakesideMutualVersion}" 23 | implementation "com.lakesidemutual:spring-boot-admin:${lakesideMutualVersion}" 24 | 25 | implementation('org.jvnet.mimepull:mimepull:1.9.10') 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/TestSpringBootApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name; 17 | 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | 20 | @SpringBootApplication 21 | public class TestSpringBootApplication { 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/DomainObjectType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | /** 19 | * Represents the type of a discovered domain object. 20 | * 21 | * @author Stefan Kapferer 22 | */ 23 | public enum DomainObjectType { 24 | 25 | ENTITY, VALUE_OBJECT 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/TypeKind.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | /** 19 | * Used to classify the kind of a type. Can either by a primitive type or a domain object type. 20 | * 21 | * @author Stefan Kapferer 22 | */ 23 | public enum TypeKind { 24 | 25 | PRIMITIVE, DOMAIN_OBJECT 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/aggregate/name/interfaces/TestInformationHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.aggregate.name.interfaces; 17 | 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | @RestController 22 | @RequestMapping({"/test"}) 23 | public class TestInformationHolder { 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/aggregate/name/interfaces/TestInformationHolder2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.aggregate.name.interfaces; 17 | 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | @RestController 22 | @RequestMapping({"/test"}) 23 | public class TestInformationHolder2 { 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/aggregate/name/interfaces/TestInformationHolder3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.aggregate.name.interfaces; 17 | 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | @RestController 22 | @RequestMapping({"/test"}) 23 | public class TestInformationHolder3 { 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/test/microservice/spring/boot/service1/interfaces/CustomerInformationHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.microservice.spring.boot.service1.interfaces; 17 | 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | @RestController 22 | @RequestMapping({"/customers"}) 23 | public class CustomerInformationHolder { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/build_standard.yml: -------------------------------------------------------------------------------- 1 | name: Build (standard) 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | - name: Set up JDK 11 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 11 21 | - name: Gradle caches 22 | uses: actions/cache@v2 23 | with: 24 | path: | 25 | ~/.gradle/caches 26 | ~/.gradle/wrapper 27 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 28 | restore-keys: | 29 | ${{ runner.os }}-gradle- 30 | - name: Grant execute permission for gradlew 31 | run: chmod +x gradlew 32 | - name: Build with Gradle 33 | run: ./gradlew clean build snapshot 34 | - name: Upload coverage to Codecov 35 | uses: codecov/codecov-action@v4 36 | with: 37 | token: ${{ secrets.CODECOV_TOKEN }} 38 | 39 | -------------------------------------------------------------------------------- /src/test/java/test/application/spring/boot/model/Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.application.spring.boot.model; 17 | 18 | public class Address { 19 | 20 | private String street; 21 | private String city; 22 | private int plz; 23 | private String[] arrayTest; 24 | 25 | public int getPlz() { 26 | return plz; 27 | } 28 | 29 | public String getCity() { 30 | return city; 31 | } 32 | 33 | public String getStreet() { 34 | return street; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/model/Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name.model; 17 | 18 | public class Address { 19 | 20 | private String street; 21 | private String city; 22 | private int plz; 23 | private String[] arrayTest; 24 | 25 | public int getPlz() { 26 | return plz; 27 | } 28 | 29 | public String getCity() { 30 | return city; 31 | } 32 | 33 | public String getStreet() { 34 | return street; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/names/DefaultBoundedContextNameMappingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.names; 17 | 18 | /** 19 | * Default name mapping strategy. Just take the same name as given... 20 | * 21 | * @author Stefan Kapferer 22 | */ 23 | public class DefaultBoundedContextNameMappingStrategy implements BoundedContextNameMappingStrategy { 24 | 25 | @Override 26 | public String mapBoundedContextName(String name) { 27 | return name; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/relationships/AbstractRelationshipDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.relationships; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | 20 | public abstract class AbstractRelationshipDiscoveryStrategy implements RelationshipDiscoveryStrategy { 21 | 22 | protected ContextMapDiscoverer discoverer; 23 | 24 | @Override 25 | public void setContextMapDiscoverer(ContextMapDiscoverer discoverer) { 26 | this.discoverer = discoverer; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/boundedcontexts/AbstractBoundedContextDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.boundedcontexts; 17 | 18 | import org.contextmapper.discovery.model.BoundedContext; 19 | 20 | public abstract class AbstractBoundedContextDiscoveryStrategy implements BoundedContextDiscoveryStrategy { 21 | 22 | protected BoundedContext createBoundedContext(String name, String technology) { 23 | BoundedContext bc = new BoundedContext(name); 24 | bc.setTechnology(technology); 25 | return bc; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/test/application/spring/boot/interfaces/IgnoredResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.application.spring.boot.interfaces; 17 | 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.web.bind.annotation.PutMapping; 20 | import org.springframework.web.bind.annotation.RequestMapping; 21 | import org.springframework.web.bind.annotation.RestController; 22 | 23 | @RestController 24 | @RequestMapping 25 | public class IgnoredResource { 26 | 27 | // this resource will be ignored, since the @RequestMapping annotation contains no value 28 | 29 | @PutMapping 30 | public ResponseEntity ignoredOperation() { 31 | return null; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/boundedcontexts/BoundedContextDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.boundedcontexts; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | import org.contextmapper.discovery.model.BoundedContext; 20 | 21 | import java.util.Set; 22 | 23 | /** 24 | * Interface for all Bounded Context discovery strategies. 25 | * 26 | * @author Stefan Kapferer 27 | */ 28 | public interface BoundedContextDiscoveryStrategy { 29 | 30 | /** 31 | * Discovers Bounded Contexts 32 | * 33 | * @return a set of discovered Bounded Contexts 34 | */ 35 | Set discoverBoundedContexts(); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/ParameterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | 22 | public class ParameterTest { 23 | 24 | @Test 25 | public void canCreateParameter() { 26 | // given 27 | Type type = new Type(new DomainObject(DomainObjectType.VALUE_OBJECT, "TestType")); 28 | 29 | // when 30 | Parameter parameter = new Parameter("testParameter", type); 31 | 32 | // then 33 | assertEquals("testParameter", parameter.getName()); 34 | assertEquals("TestType", parameter.getType().getName()); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/test/application/spring/boot/model/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.application.spring.boot.model; 17 | 18 | import java.util.Collection; 19 | import java.util.List; 20 | import java.util.Set; 21 | 22 | public class Customer { 23 | 24 | private CustomerId id; 25 | private List
addressList; 26 | private Set
addressSet; 27 | private Collection
addressCollection; 28 | 29 | public CustomerId getId() { 30 | return id; 31 | } 32 | 33 | public List
getAddressList() { 34 | return addressList; 35 | } 36 | 37 | public Collection
getAddressCollection() { 38 | return addressCollection; 39 | } 40 | 41 | public Set
getAddressSet() { 42 | return addressSet; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/model/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name.model; 17 | 18 | import java.util.Collection; 19 | import java.util.List; 20 | import java.util.Set; 21 | 22 | public class Customer { 23 | 24 | private CustomerId id; 25 | private List
addressList; 26 | private Set
addressSet; 27 | private Collection
addressCollection; 28 | 29 | public CustomerId getId() { 30 | return id; 31 | } 32 | 33 | public List
getAddressList() { 34 | return addressList; 35 | } 36 | 37 | public Collection
getAddressCollection() { 38 | return addressCollection; 39 | } 40 | 41 | public Set
getAddressSet() { 42 | return addressSet; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Parameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | /** 19 | * Represents a parameter of a domain object method. 20 | * 21 | * @author Stefan Kapferer 22 | */ 23 | public class Parameter { 24 | 25 | private String name; 26 | private Type type; 27 | 28 | public Parameter(String name, Type type) { 29 | this.name = name; 30 | this.type = type; 31 | } 32 | 33 | /** 34 | * Gets the name of the parameter. 35 | * 36 | * @return the name of the parameter 37 | */ 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | /** 43 | * Gets the type of the parameter. 44 | * 45 | * @return the type of the parameter 46 | */ 47 | public Type getType() { 48 | return type; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/names/BoundedContextNameMappingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.names; 17 | 18 | /** 19 | * Interface for name mapping strategies. Used in {@link org.contextmapper.discovery.ContextMapDiscoverer} to provide 20 | * different approaches to lookup discovered Bounded Contexts (relationship discovering strategies may search for 21 | * Bounded Contexts with different namings). 22 | * 23 | * @author Stefan Kapferer 24 | */ 25 | public interface BoundedContextNameMappingStrategy { 26 | 27 | /** 28 | * Maps a Bounded Context name to another one identifying the same context. 29 | * 30 | * @param name the given Bounded Context name 31 | * @return the other Bounded Context name used for the same context 32 | */ 33 | String mapBoundedContextName(String name); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/resources/test/oas-tests/sample-object-as-parameter-1.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: ReferenceManagementServiceAPI 4 | version: "1.0" 5 | tags: 6 | - name: PaperArchiveFacade 7 | description: general data-oriented endpoint 8 | externalDocs: 9 | description: INFORMATION_HOLDER_RESOURCE 10 | url: https://microservice-api-patterns.org/patterns/responsibility/ 11 | paths: 12 | /PaperArchiveFacade: 13 | summary: general data-oriented endpoint 14 | description: 'MAP link: INFORMATION_HOLDER_RESOURCE available at [the MAP website](https://microservice-api-patterns.org/)' 15 | get: 16 | tags: 17 | - PaperArchiveFacade 18 | summary: read only 19 | description: This operation realizes the Retrieval Operation pattern, described 20 | [on the MAP website](https://microservice-api-patterns.org/patterns/responsibility/operationResponsibilities/RetrievalOperation.html). 21 | operationId: lookupPapersFromAuthor 22 | parameters: 23 | - name: Parameter1 24 | in: query 25 | description: unspecified 26 | required: true 27 | schema: 28 | type: object 29 | properties: 30 | attr1: 31 | type: string 32 | attr2: 33 | type: integer 34 | attr3: 35 | type: object 36 | properties: 37 | subattr1: 38 | type: string 39 | subattr2: 40 | type: string 41 | responses: 42 | "200": 43 | description: response message payload (success case) 44 | -------------------------------------------------------------------------------- /src/test/resources/test/oas-tests/sample-object-as-parameter-2.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: ReferenceManagementServiceAPI 4 | version: "1.0" 5 | tags: 6 | - name: PaperArchiveFacade 7 | description: general data-oriented endpoint 8 | externalDocs: 9 | description: INFORMATION_HOLDER_RESOURCE 10 | url: https://microservice-api-patterns.org/patterns/responsibility/ 11 | paths: 12 | /PaperArchiveFacade: 13 | summary: general data-oriented endpoint 14 | description: 'MAP link: INFORMATION_HOLDER_RESOURCE available at [the MAP website](https://microservice-api-patterns.org/)' 15 | get: 16 | tags: 17 | - PaperArchiveFacade 18 | summary: read only 19 | description: This operation realizes the Retrieval Operation pattern, described 20 | [on the MAP website](https://microservice-api-patterns.org/patterns/responsibility/operationResponsibilities/RetrievalOperation.html). 21 | operationId: lookupPapersFromAuthor 22 | parameters: 23 | - name: Parameter1 24 | in: query 25 | description: unspecified 26 | required: true 27 | schema: 28 | $ref: '#/components/schemas/Parameter1Type' 29 | responses: 30 | "200": 31 | description: response message payload (success case) 32 | 33 | components: 34 | schemas: 35 | Parameter1Type: 36 | type: object 37 | properties: 38 | attr1: 39 | type: string 40 | attr2: 41 | type: integer 42 | attr3: 43 | type: object 44 | properties: 45 | subattr1: 46 | type: string 47 | subattr2: 48 | type: string 49 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/cml/CMLPrimitiveTypeMapperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.cml; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.*; 21 | 22 | public class CMLPrimitiveTypeMapperTest { 23 | 24 | @Test 25 | public void canMapPrimitiveType() { 26 | // given 27 | CMLPrimitiveTypeMapper mapper = new CMLPrimitiveTypeMapper(); 28 | 29 | // when 30 | String type1 = mapper.mapType("string"); 31 | String type2 = mapper.mapType("String"); 32 | 33 | // then 34 | assertEquals("String", type1); 35 | assertEquals("String", type2); 36 | } 37 | 38 | @Test 39 | public void canReturnInputIfNotMappable() { 40 | // given 41 | CMLPrimitiveTypeMapper mapper = new CMLPrimitiveTypeMapper(); 42 | 43 | // when 44 | String type = mapper.mapType("MySuperImaginativeType"); 45 | 46 | // then 47 | assertEquals("MySuperImaginativeType", type); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/relationships/RelationshipDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.relationships; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | import org.contextmapper.discovery.model.Relationship; 20 | 21 | import java.util.Set; 22 | 23 | /** 24 | * Interface for all relationship discovery strategies. 25 | * 26 | * @author Stefan Kapferer 27 | */ 28 | public interface RelationshipDiscoveryStrategy { 29 | 30 | /** 31 | * Discovers relationships between Bounded Contexts. 32 | * 33 | * @return a set of discovered relationships 34 | */ 35 | Set discoverRelationships(); 36 | 37 | /** 38 | * Sets the reference to the parent discoverer. Must be set before discovering starts, so 39 | * that relationship discoverer can lookup Bounded Contexts. 40 | * 41 | * @param discoverer the {@link ContextMapDiscoverer} which uses the discovery strategy 42 | */ 43 | void setContextMapDiscoverer(ContextMapDiscoverer discoverer); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Context Mapper Discovery Library 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Gradle caches 21 | uses: actions/cache@v2 22 | with: 23 | path: | 24 | ~/.gradle/caches 25 | ~/.gradle/wrapper 26 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 27 | restore-keys: | 28 | ${{ runner.os }}-gradle- 29 | - name: Configure GPG Key 30 | run: | 31 | mkdir -p ~/.gnupg/ 32 | printf "$GPG_SIGNING_KEY" | base64 --decode > ~/.gnupg/private.key 33 | gpg --import --batch ~/.gnupg/private.key 34 | env: 35 | GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} 36 | - name: Grant execute permission for gradlew 37 | run: chmod +x gradlew 38 | - name: Release with Gradle 39 | run: ./gradlew clean build publish -Prelease.useLastTag=true -Psigning.keyId=${GPG_KEY_ID} -Psigning.password=${GPG_KEY_PASSPHRASE} -Psigning.secretKeyRingFile=/home/runner/.gnupg/private.key 40 | env: 41 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} 42 | GPG_KEY_PASSPHRASE: ${{ secrets.GPG_KEY_PASSPHRASE }} 43 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 44 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 45 | - name: Upload coverage to Codecov 46 | uses: codecov/codecov-action@v4 47 | with: 48 | token: ${{ secrets.CODECOV_TOKEN }} 49 | 50 | -------------------------------------------------------------------------------- /.github/workflows/build_master.yml: -------------------------------------------------------------------------------- 1 | name: Build (master) 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags-ignore: 8 | - '**' 9 | 10 | jobs: 11 | build_and_publish_snapshot: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | - name: Set up JDK 11 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: 11 22 | - name: Gradle caches 23 | uses: actions/cache@v2 24 | with: 25 | path: | 26 | ~/.gradle/caches 27 | ~/.gradle/wrapper 28 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 29 | restore-keys: | 30 | ${{ runner.os }}-gradle- 31 | - name: Configure GPG Key 32 | run: | 33 | mkdir -p ~/.gnupg/ 34 | printf "$GPG_SIGNING_KEY" | base64 --decode > ~/.gnupg/private.key 35 | gpg --import --batch ~/.gnupg/private.key 36 | env: 37 | GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} 38 | - name: Grant execute permission for gradlew 39 | run: chmod +x gradlew 40 | - name: Build with Gradle 41 | run: ./gradlew clean build snapshot publish -Psigning.keyId=${GPG_KEY_ID} -Psigning.password=${GPG_KEY_PASSPHRASE} -Psigning.secretKeyRingFile=/home/runner/.gnupg/private.key 42 | env: 43 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} 44 | GPG_KEY_PASSPHRASE: ${{ secrets.GPG_KEY_PASSPHRASE }} 45 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 46 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 47 | - name: Upload coverage to Codecov 48 | uses: codecov/codecov-action@v4 49 | with: 50 | token: ${{ secrets.CODECOV_TOKEN }} 51 | 52 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/names/SeparatorToCamelCaseBoundedContextNameMappingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.names; 17 | 18 | /** 19 | * Maps Bounded Context name using a separator to Camel-Case notation. 20 | *

21 | * For example: 22 | * - 'example-context' to 'ExampleContext' 23 | * - 'example_context' to 'ExampleContext' 24 | * - etc. 25 | * 26 | * @author Stefan Kapferer 27 | */ 28 | public class SeparatorToCamelCaseBoundedContextNameMappingStrategy implements BoundedContextNameMappingStrategy { 29 | 30 | private String separator; 31 | 32 | public SeparatorToCamelCaseBoundedContextNameMappingStrategy(String separator) { 33 | this.separator = separator; 34 | } 35 | 36 | @Override 37 | public String mapBoundedContextName(String name) { 38 | String[] parts = name.split(separator); 39 | StringBuilder sb = new StringBuilder(); 40 | for (String part : parts) { 41 | if (!"".equals(part)) 42 | sb.append(part.substring(0, 1).toUpperCase()).append(part.substring(1, part.length())); 43 | } 44 | return sb.toString(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/cml/CMLPrimitiveTypeMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.cml; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | /** 22 | * Maps types to CML primitive types, if possible. 23 | * 24 | * @author Stefan Kapferer 25 | */ 26 | public class CMLPrimitiveTypeMapper { 27 | 28 | private static final String[] PRIMITIVE_CML_TYPES = {"String", "int", "Integer", "Long", "Boolean", "Date", 29 | "DateTime", "Timestamp", "BigDecimal", "BigInteger", "Double", "Float", "Key", "PagingParameter", 30 | "PagedResult", "Blob", "Clob", "Object[]"}; 31 | 32 | private Map typeMap; 33 | 34 | public CMLPrimitiveTypeMapper() { 35 | this.typeMap = new HashMap<>(); 36 | for (String primitiveType : PRIMITIVE_CML_TYPES) { 37 | typeMap.put(primitiveType.toLowerCase(), primitiveType); 38 | } 39 | } 40 | 41 | /** 42 | * Maps the input type to a primitive type supported by the CML language; if possible. 43 | * 44 | * @param type the type that shall be mapped 45 | * @return the mapped type; or the input type in case it could not be mapped 46 | */ 47 | public String mapType(String type) { 48 | if (typeMap.containsKey(type.toLowerCase())) 49 | return typeMap.get(type.toLowerCase()); 50 | return type; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/strategies/boundedcontexts/AnnotatedTypeBoundedContextDiscoveryStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.boundedcontexts; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | import org.contextmapper.discovery.model.BoundedContext; 20 | import org.contextmapper.discovery.strategies.boundedcontexts.AnnotatedTypeBoundedContextDiscoveryStrategy; 21 | import org.junit.jupiter.api.Test; 22 | import test.annotated.type.BoundedContextTestAnnotation; 23 | 24 | import java.util.Set; 25 | 26 | import static org.junit.jupiter.api.Assertions.assertEquals; 27 | 28 | public class AnnotatedTypeBoundedContextDiscoveryStrategyTest { 29 | 30 | @Test 31 | public void canFindBoundedContextByAnnotatedType() { 32 | // given 33 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 34 | .usingBoundedContextDiscoveryStrategies( 35 | new AnnotatedTypeBoundedContextDiscoveryStrategy("test.annotated.type", BoundedContextTestAnnotation.class, "Java") 36 | ); 37 | 38 | // when 39 | Set bcs = discoverer.discoverContextMap().getBoundedContexts(); 40 | 41 | // then 42 | assertEquals(1, bcs.size()); 43 | BoundedContext bc = bcs.iterator().next(); 44 | assertEquals("TestBoundedContext", bc.getName()); 45 | assertEquals("Java", bc.getTechnology()); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/test/duplicate/domainobject/name/interfaces/CustomerInformationHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.duplicate.domainobject.name.interfaces; 17 | 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.web.bind.annotation.*; 20 | import test.duplicate.domainobject.name.model.Address; 21 | import test.duplicate.domainobject.name.model.Customer; 22 | import test.duplicate.domainobject.name.model.duplicate1.CustomerId; 23 | 24 | @RestController 25 | @RequestMapping({"customers", "second-ignored-mapping"}) 26 | public class CustomerInformationHolder { 27 | 28 | @PutMapping({"/{customerId}/address"}) 29 | public ResponseEntity

changeAddress(@PathVariable CustomerId customerId, @RequestBody Address requestDto) { 30 | // method will never be called; this is just for our reflection (scanning) tests; 31 | return null; 32 | } 33 | 34 | @PutMapping({"/{customerId}/address"}) 35 | public ResponseEntity
changeAddress(@PathVariable test.duplicate.domainobject.name.model.CustomerId customerId, @RequestBody Address requestDto) { 36 | // method will never be called; this is just for our reflection (scanning) tests; 37 | return null; 38 | } 39 | 40 | @GetMapping({"/{customerId}/"}) 41 | public ResponseEntity getCustomer(@PathVariable test.duplicate.domainobject.name.model.duplicate2.CustomerId customerId) { 42 | // method will never be called; this is just for our reflection (scanning) tests; 43 | return null; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/MethodTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | 22 | public class MethodTest { 23 | 24 | @Test 25 | public void canCreateMethod() { 26 | // when 27 | Method method = new Method("testMethod"); 28 | 29 | // then 30 | assertEquals("testMethod", method.getName()); 31 | } 32 | 33 | @Test 34 | public void canSetReturnType() { 35 | // given 36 | Method method = new Method("testMethod"); 37 | 38 | // then 39 | Type returnType = new Type(new DomainObject(DomainObjectType.VALUE_OBJECT, "ReturnType")); 40 | method.setReturnType(returnType); 41 | 42 | // then 43 | assertEquals("ReturnType", method.getReturnType().getName()); 44 | } 45 | 46 | @Test 47 | public void canAddParameter() { 48 | // given 49 | Method method = new Method("TestMethod"); 50 | 51 | // when 52 | Type parameterType = new Type(new DomainObject(DomainObjectType.VALUE_OBJECT, "ParameterType")); 53 | Parameter parameter = new Parameter("testParam", parameterType); 54 | method.addParameter(parameter); 55 | 56 | // then 57 | Parameter resultParam = method.getParameters().iterator().next(); 58 | assertEquals("testParam", resultParam.getName()); 59 | assertEquals("ParameterType", resultParam.getType().getName()); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/boundedcontexts/AnnotatedTypeBoundedContextDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.boundedcontexts; 17 | 18 | import org.contextmapper.discovery.model.BoundedContext; 19 | import org.contextmapper.discovery.strategies.helper.AnnotationScanner; 20 | import org.reflections.Reflections; 21 | import org.reflections.scanners.SubTypesScanner; 22 | import org.reflections.scanners.TypeAnnotationsScanner; 23 | 24 | import java.lang.annotation.Annotation; 25 | import java.util.HashSet; 26 | import java.util.Set; 27 | 28 | /** 29 | * Find Bounded Contexts by annotated Java types. 30 | * 31 | * @author Stefan Kapferer 32 | */ 33 | public class AnnotatedTypeBoundedContextDiscoveryStrategy extends AbstractBoundedContextDiscoveryStrategy implements BoundedContextDiscoveryStrategy { 34 | 35 | private String packageName; 36 | private Class annotation; 37 | private String technology; 38 | 39 | public AnnotatedTypeBoundedContextDiscoveryStrategy(String packageName, Class annotation, String technology) { 40 | this.packageName = packageName; 41 | this.annotation = annotation; 42 | this.technology = technology; 43 | } 44 | 45 | @Override 46 | public Set discoverBoundedContexts() { 47 | Set set = new HashSet<>(); 48 | for (Class type : new AnnotationScanner().scanForAnnotatedType(packageName, annotation)) { 49 | set.add(createBoundedContext(type.getSimpleName(), technology)); 50 | } 51 | return set; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/test/application/spring/boot/interfaces/CustomerInformationHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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 test.application.spring.boot.interfaces; 17 | 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.web.bind.annotation.*; 20 | import test.application.spring.boot.model.Address; 21 | import test.application.spring.boot.model.Customer; 22 | import test.application.spring.boot.model.CustomerId; 23 | 24 | import java.util.List; 25 | 26 | @RestController 27 | @RequestMapping({"/customers"}) 28 | public class CustomerInformationHolder { 29 | 30 | @PutMapping({"/{customerId}/address"}) 31 | public ResponseEntity
changeAddress(@PathVariable CustomerId customerId, @RequestBody Address requestDto) { 32 | // method will never be called; this is just for our reflection (scanning) tests; 33 | return null; 34 | } 35 | 36 | @GetMapping({"/{customerId}/"}) 37 | public ResponseEntity getCustomer(@PathVariable CustomerId customerId) { 38 | // method will never be called; this is just for our reflection (scanning) tests; 39 | return null; 40 | } 41 | 42 | @GetMapping({"/{customerIds}/"}) 43 | public ResponseEntity> getCustomers(@PathVariable List customerIds) { 44 | // method will never be called; this is just for our reflection (scanning) tests; 45 | return null; 46 | } 47 | 48 | @DeleteMapping(value = "/{customerId}/") 49 | public ResponseEntity deleteCustomer(@PathVariable CustomerId customerId) { 50 | // method will never be called; this is just for our reflection (scanning) tests; 51 | return null; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/ContextMapSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery; 17 | 18 | import org.apache.commons.io.FilenameUtils; 19 | import org.contextmapper.discovery.cml.ContextMapToCMLConverter; 20 | import org.contextmapper.discovery.model.ContextMap; 21 | import org.contextmapper.dsl.ContextMappingDSLStandaloneSetup; 22 | import org.contextmapper.dsl.contextMappingDSL.ContextMappingModel; 23 | import org.eclipse.emf.common.util.URI; 24 | import org.eclipse.emf.ecore.resource.Resource; 25 | import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; 26 | import org.eclipse.xtext.resource.SaveOptions; 27 | 28 | import java.io.File; 29 | import java.io.IOException; 30 | 31 | /** 32 | * Serializes discovered {@link org.contextmapper.discovery.model.ContextMap} to Context Mapper DSL (CML) code. 33 | * 34 | * @author Stefan Kapferer 35 | */ 36 | public class ContextMapSerializer { 37 | 38 | public void serializeContextMap(ContextMap contextMap, File cmlFile) throws IOException { 39 | if (!FilenameUtils.getExtension(cmlFile.toString()).equals("cml")) 40 | throw new IllegalArgumentException("The CML file must end with the file extension '*.cml'!"); 41 | if (contextMap.getBoundedContexts().size() <= 0) 42 | throw new IllegalArgumentException("The Context Map must at least contain one Bounded Context to be serialized!"); 43 | 44 | ContextMappingDSLStandaloneSetup.doSetup(); 45 | Resource resource = new ResourceSetImpl().createResource(URI.createURI(cmlFile.toURI().toString())); 46 | ContextMappingModel model = new ContextMapToCMLConverter().convert(contextMap); 47 | resource.getContents().add(model); 48 | resource.save(SaveOptions.defaultOptions().toOptionsMap()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/boundedcontexts/SpringBootBoundedContextDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.boundedcontexts; 17 | 18 | import org.contextmapper.discovery.strategies.helper.AnnotationScanner; 19 | import org.springframework.boot.autoconfigure.SpringBootApplication; 20 | import org.springframework.web.bind.annotation.*; 21 | 22 | import java.lang.reflect.Method; 23 | import java.util.Set; 24 | 25 | public class SpringBootBoundedContextDiscoveryStrategy extends AbstractRESTResourceBasedBoundedContextDiscoveryStrategy implements BoundedContextDiscoveryStrategy { 26 | 27 | private String packageName; 28 | 29 | public SpringBootBoundedContextDiscoveryStrategy(String packageName) { 30 | this.packageName = packageName; 31 | } 32 | 33 | @Override 34 | protected Set> findBoundedContextTypes() { 35 | return new AnnotationScanner().scanForAnnotatedType(packageName, SpringBootApplication.class); 36 | } 37 | 38 | @Override 39 | protected String findBoundedContextTechnology(Class boundedContextType) { 40 | return "Spring Boot"; 41 | } 42 | 43 | @Override 44 | protected Set> findResourceTypes(String packageName) { 45 | return new AnnotationScanner().scanForAnnotatedType(packageName, RequestMapping.class); 46 | } 47 | 48 | @Override 49 | protected String findResourcePath(Class resourceType) { 50 | RequestMapping requestMapping = resourceType.getAnnotation(RequestMapping.class); 51 | if (requestMapping.value().length > 0) 52 | return requestMapping.value()[0]; 53 | return ""; 54 | } 55 | 56 | @Override 57 | protected Set findResourceMethods(Class resourceType) { 58 | return new AnnotationScanner().scanForAnnotatedMethods(resourceType, RequestMapping.class, PutMapping.class, 59 | GetMapping.class, PostMapping.class, PatchMapping.class, DeleteMapping.class); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/BoundedContextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.*; 22 | 23 | public class BoundedContextTest { 24 | 25 | @Test 26 | public void cannotCreateBoundedContextWithNullName() { 27 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 28 | new BoundedContext(null); 29 | }); 30 | } 31 | 32 | @Test 33 | public void cannotCreateBoundedContextWithEmptyName() { 34 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 35 | new BoundedContext(""); 36 | }); 37 | } 38 | 39 | @Test 40 | public void canCreateBoundedContextWithName() { 41 | // given 42 | BoundedContext boundedContext; 43 | 44 | // when 45 | boundedContext = new BoundedContext("TestContext"); 46 | 47 | // then 48 | assertEquals("TestContext", boundedContext.getName()); 49 | } 50 | 51 | @Test 52 | public void canSetTechnology() { 53 | // given 54 | BoundedContext boundedContext = new BoundedContext("TestContext"); 55 | 56 | // when 57 | boundedContext.setTechnology("Java"); 58 | 59 | // then 60 | assertEquals("Java", boundedContext.getTechnology()); 61 | } 62 | 63 | @Test 64 | public void boundedContextsWithSameNameAreEqual() { 65 | // given 66 | BoundedContext bc1 = new BoundedContext("TestContext"); 67 | BoundedContext bc2 = new BoundedContext("TestContext"); 68 | 69 | // when 70 | boolean equals = bc1.equals(bc2); 71 | 72 | // then 73 | assertTrue(equals); 74 | } 75 | 76 | @Test 77 | public void otherObjectsAreNotEqual() { 78 | // given 79 | BoundedContext bc = new BoundedContext("TestContext"); 80 | 81 | // when 82 | boolean equals = bc.equals(new Object()); 83 | 84 | // then 85 | assertFalse(equals); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/src/main/java/org/contextmapper/lakesidemutual/example/LakesideMutualContextMapDiscoverer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.lakesidemutual.example; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | import org.contextmapper.discovery.ContextMapSerializer; 20 | import org.contextmapper.discovery.model.ContextMap; 21 | import org.contextmapper.discovery.strategies.boundedcontexts.SpringBootBoundedContextDiscoveryStrategy; 22 | import org.contextmapper.discovery.strategies.names.SeparatorToCamelCaseBoundedContextNameMappingStrategy; 23 | import org.contextmapper.discovery.strategies.relationships.DockerComposeRelationshipDiscoveryStrategy; 24 | 25 | import java.io.File; 26 | import java.io.IOException; 27 | 28 | public class LakesideMutualContextMapDiscoverer { 29 | 30 | public static void main(String[] args) throws IOException { 31 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 32 | .usingBoundedContextDiscoveryStrategies( 33 | new SpringBootBoundedContextDiscoveryStrategy("com.lakesidemutual")) 34 | .usingRelationshipDiscoveryStrategies( 35 | new DockerComposeRelationshipDiscoveryStrategy(new File(System.getProperty("user.home") + "/source/LakesideMutual/"))) 36 | .usingBoundedContextNameMappingStrategies( 37 | new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-") { 38 | @Override 39 | public String mapBoundedContextName(String s) { 40 | // remove the "Backend" part of the Docker service names to map correctly... 41 | String name = super.mapBoundedContextName(s); 42 | return name.endsWith("Backend") ? name.substring(0, name.length() - 7) : name; 43 | } 44 | }); 45 | 46 | ContextMap contextmap = discoverer.discoverContextMap(); 47 | new ContextMapSerializer().serializeContextMap(contextmap, new File("./src-gen/lakesidemutual.cml")); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Attribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | /** 22 | * Represents an entity attribute. 23 | * 24 | * @author Stefan Kapferer 25 | */ 26 | public class Attribute { 27 | 28 | private DomainObject parent; 29 | private String name; 30 | private Type type; 31 | 32 | public Attribute(Type type, String name) { 33 | this.type = type; 34 | this.name = name; 35 | } 36 | 37 | /** 38 | * Gets the name of the attribute. 39 | * 40 | * @return the name of the attribute 41 | */ 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | /** 47 | * Gets the type of the attribute. 48 | * 49 | * @return the type of the attribute 50 | */ 51 | public Type getType() { 52 | return type; 53 | } 54 | 55 | /** 56 | * Gets the parent domain object containing this attribute. 57 | * 58 | * @return the parent domain object containing this attribute 59 | */ 60 | public DomainObject getParent() { 61 | return parent; 62 | } 63 | 64 | /** 65 | * Sets the parent domain object containing this attribute. 66 | * 67 | * @param parent the parent domain object containing this attribute 68 | */ 69 | public void setParent(DomainObject parent) { 70 | this.parent = parent; 71 | } 72 | 73 | @Override 74 | public boolean equals(Object object) { 75 | if (!(object instanceof Attribute)) 76 | return false; 77 | 78 | Attribute attribute = (Attribute) object; 79 | 80 | return new EqualsBuilder() 81 | .append(parent, attribute.parent) 82 | .append(name, attribute.name) 83 | .append(type, attribute.type) 84 | .isEquals(); 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | return new HashCodeBuilder() 90 | .append(parent) 91 | .append(name) 92 | .append(type) 93 | .hashCode(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/helper/ReflectionHelpers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.helper; 17 | 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.Modifier; 20 | import java.lang.reflect.ParameterizedType; 21 | import java.lang.reflect.Type; 22 | import java.util.*; 23 | import java.util.stream.Collectors; 24 | 25 | /** 26 | * Some helper methods for scanning entities etc. 27 | * 28 | * @author Stefan Kapferer 29 | */ 30 | public class ReflectionHelpers { 31 | 32 | /** 33 | * Gets the actual types of a parameterized type. 34 | * 35 | * @param parameterizedType the parameterized type 36 | * @return the actual types 37 | */ 38 | public Set> getActualTypesOfParameterizedType(ParameterizedType parameterizedType) { 39 | Set> actualTypes = new HashSet<>(); 40 | for (Type actualType : parameterizedType.getActualTypeArguments()) { 41 | if (!(actualType instanceof Class)) 42 | continue; 43 | actualTypes.add((Class) actualType); 44 | } 45 | return actualTypes; 46 | } 47 | 48 | /** 49 | * Gets all fields of a type. 50 | * 51 | * @param type the type for which the fields shall be returned 52 | * @return the list of fields of the given type 53 | */ 54 | public List getAllFieldsOfType(Class type) { 55 | if (type == null) { 56 | return Collections.emptyList(); 57 | } 58 | 59 | List result = new ArrayList<>(getAllFieldsOfType(type.getSuperclass())); 60 | result.addAll(Arrays.asList(type.getDeclaredFields()).stream().filter(f -> !f.getName().startsWith("$")).collect(Collectors.toSet())); 61 | return result; 62 | } 63 | 64 | /** 65 | * Checks whether a type is a collection, set, or list. 66 | * 67 | * @param type the type to be checked for collection types 68 | * @return true, if the given type is a set, list, or collection. false otherwise. 69 | */ 70 | public boolean isCollectionType(Class type) { 71 | if (type.equals(List.class)) 72 | return true; 73 | else if (type.equals(Set.class)) 74 | return true; 75 | else if (type.equals(Collection.class)) 76 | return true; 77 | return false; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/ServiceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.*; 22 | 23 | public class ServiceTest { 24 | 25 | @Test 26 | public void cannotCreateServiceWithNullName() { 27 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 28 | new Service(null); 29 | }); 30 | } 31 | 32 | @Test 33 | public void cannotCreateServiceWithEmptyName() { 34 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 35 | new Service(""); 36 | }); 37 | } 38 | 39 | @Test 40 | public void canCreateServiceWithName() { 41 | // given 42 | Service service; 43 | 44 | // when 45 | service = new Service("TestService"); 46 | 47 | // then 48 | assertEquals("TestService", service.getName()); 49 | } 50 | 51 | @Test 52 | public void canAddOperation() { 53 | // given 54 | Service service = new Service("TestService"); 55 | 56 | // when 57 | service.addOperation(new Method("createEntity")); 58 | 59 | // then 60 | assertEquals(1, service.getOperations().size()); 61 | assertEquals("createEntity", service.getOperations().iterator().next().getName()); 62 | } 63 | 64 | @Test 65 | public void servicesWithSameNameAreEqual() { 66 | // given 67 | Service service1 = new Service("TestService"); 68 | Service service2 = new Service("TestService"); 69 | 70 | // when 71 | boolean equals = service1.equals(service2); 72 | 73 | // then 74 | assertTrue(equals); 75 | } 76 | 77 | @Test 78 | public void otherObjectsAreNotEqual() { 79 | // given 80 | Service service = new Service("TestService"); 81 | 82 | // when 83 | boolean equals = service.equals(new Object()); 84 | 85 | // then 86 | assertFalse(equals); 87 | } 88 | 89 | @Test 90 | public void canAddComment() { 91 | // given 92 | Service service = new Service("TestService"); 93 | String comment = "Test comment"; 94 | 95 | // when 96 | service.setDiscoveryComment(comment); 97 | 98 | // then 99 | assertEquals(comment, service.getDiscoveryComment()); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/helper/AnnotationScanner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.helper; 17 | 18 | import org.reflections.Reflections; 19 | import org.reflections.util.ClasspathHelper; 20 | import org.reflections.util.ConfigurationBuilder; 21 | import org.reflections.util.FilterBuilder; 22 | 23 | import java.lang.annotation.Annotation; 24 | import java.lang.reflect.Method; 25 | import java.util.HashSet; 26 | import java.util.Set; 27 | import java.util.stream.Collectors; 28 | 29 | import static org.reflections.scanners.Scanners.*; 30 | 31 | /** 32 | * Provides methods for annotation scanning. 33 | * 34 | * @author Stefan Kapferer 35 | */ 36 | public class AnnotationScanner { 37 | 38 | /** 39 | * Finds all types within a package annotated with a given annotation. 40 | * 41 | * @param packageName the package within which to search for the types 42 | * @param annotation the annotation with which the types must be annotated 43 | * @return the set of types within the given package which are annotated with the given annotation 44 | */ 45 | public Set> scanForAnnotatedType(String packageName, Class annotation) { 46 | Reflections reflections = new Reflections(packageName); 47 | return reflections.getTypesAnnotatedWith(annotation); 48 | } 49 | 50 | /** 51 | * Finds all methods of a type which are annotated with a given annotation. 52 | * 53 | * @param type the type within which you want to search for methods 54 | * @param annotations the annotations with which the methods must be annotated (at least one of the given annotations) 55 | * @return the set of methods within the given type which are annotated with the given annotation 56 | */ 57 | public Set scanForAnnotatedMethods(Class type, Class... annotations) { 58 | Set methods = new HashSet<>(); 59 | Reflections reflections = new Reflections(new ConfigurationBuilder() 60 | .setUrls(ClasspathHelper.forClass(type)) 61 | .setScanners(TypesAnnotated, MethodsAnnotated, MethodsReturn) 62 | .filterInputsBy(new FilterBuilder().includePackage(type.getPackageName())) 63 | ); 64 | for (Class annotation : annotations) { 65 | methods.addAll(reflections.getMethodsAnnotatedWith(annotation)); 66 | } 67 | return methods.stream().filter(m -> m.getDeclaringClass().equals(type)).collect(Collectors.toSet()); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/strategies/names/SeparatorToCamelCaseBoundedContextNameMappingStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.names; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | import org.contextmapper.discovery.model.BoundedContext; 20 | import org.contextmapper.discovery.strategies.boundedcontexts.SpringBootBoundedContextDiscoveryStrategy; 21 | import org.junit.jupiter.api.Test; 22 | import org.junit.jupiter.params.ParameterizedTest; 23 | import org.junit.jupiter.params.provider.Arguments; 24 | import org.junit.jupiter.params.provider.MethodSource; 25 | 26 | import java.util.stream.Stream; 27 | 28 | import static org.junit.jupiter.api.Assertions.assertEquals; 29 | import static org.junit.jupiter.api.Assertions.assertNotNull; 30 | 31 | public class SeparatorToCamelCaseBoundedContextNameMappingStrategyTest { 32 | 33 | @ParameterizedTest 34 | @MethodSource("createMappingTestParameters") 35 | public void canMapBoundedContextName(String inputName, String expectedName) { 36 | // given 37 | SeparatorToCamelCaseBoundedContextNameMappingStrategy strategy = new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-"); 38 | 39 | // when 40 | String boundedContextName = strategy.mapBoundedContextName(inputName); 41 | 42 | // then 43 | assertEquals(expectedName, boundedContextName); 44 | } 45 | 46 | private static Stream createMappingTestParameters() { 47 | return Stream.of(Arguments.of("", ""), 48 | Arguments.of("a", "A"), 49 | Arguments.of("a-b", "AB"), 50 | Arguments.of("example-context", "ExampleContext"), 51 | Arguments.of("a-example-context", "AExampleContext"), 52 | Arguments.of("example", "Example")); 53 | } 54 | 55 | @Test 56 | public void canMapBoundedContextsInDiscoverer() { 57 | // given 58 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 59 | .usingBoundedContextDiscoveryStrategies( 60 | new SpringBootBoundedContextDiscoveryStrategy("test.application.spring.boot") 61 | ) 62 | .usingBoundedContextNameMappingStrategies( 63 | new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-") 64 | ); 65 | 66 | // when 67 | discoverer.discoverContextMap(); 68 | BoundedContext bc = discoverer.lookupBoundedContext("test-spring-boot"); 69 | 70 | // then 71 | assertNotNull(bc); 72 | assertEquals("TestSpringBoot", bc.getName()); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/ContextMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | /** 22 | * Context Map with discovered Bounded Contexts and relationships 23 | * 24 | * @author Stefan Kapferer 25 | */ 26 | public class ContextMap { 27 | 28 | private Set boundedContexts = new HashSet<>(); 29 | private Set relationships = new HashSet<>(); 30 | 31 | /** 32 | * Adds a Bounded Context to the Context Map 33 | * 34 | * @param boundedContext the Bounded Context to be added to the Context Map 35 | */ 36 | public void addBoundedContext(BoundedContext boundedContext) { 37 | this.boundedContexts.add(boundedContext); 38 | } 39 | 40 | /** 41 | * Adds all Bounded Contexts in the given set to the Context Map 42 | * 43 | * @param boundedContexts the set of Bounded Contexts to be added to the Context Map 44 | */ 45 | public void addAllBoundedContexts(Set boundedContexts) { 46 | this.boundedContexts.addAll(boundedContexts); 47 | } 48 | 49 | /** 50 | * Adds a relationship to the Context Map 51 | * 52 | * @param relationship the relationship to be added to the Context Map 53 | */ 54 | public void addRelationship(Relationship relationship) { 55 | if (!boundedContexts.contains(relationship.getUpstream())) 56 | throw new IllegalArgumentException("The upstream Bounded Context of this relationship is not part of the Context Map."); 57 | if (!boundedContexts.contains(relationship.getDownstream())) 58 | throw new IllegalArgumentException("The downstream Bounded Context of this relationship is not part of the Context Map."); 59 | this.relationships.add(relationship); 60 | } 61 | 62 | /** 63 | * Adds all relationships in the give set to the Context Map 64 | * 65 | * @param relationships the set of relationships to be added to the Context Map 66 | */ 67 | public void addAllRelationships(Set relationships) { 68 | for (Relationship relationship : relationships) { 69 | addRelationship(relationship); 70 | } 71 | } 72 | 73 | /** 74 | * Gets the Bounded Contexts of the Context Map 75 | * 76 | * @return a set of Bounded Contexts 77 | */ 78 | public Set getBoundedContexts() { 79 | return new HashSet<>(boundedContexts); 80 | } 81 | 82 | /** 83 | * Gets the relationships between Bounded Contexts of this Context Map 84 | * 85 | * @return a set of relationship between Bounded Contexts 86 | */ 87 | public Set getRelationships() { 88 | return new HashSet<>(relationships); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/ContextMapTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | public class ContextMapTest { 24 | 25 | @Test 26 | public void canAddBoundedContext() { 27 | // given 28 | ContextMap contextMap = new ContextMap(); 29 | BoundedContext context = new BoundedContext("TestContext"); 30 | 31 | // when 32 | contextMap.addBoundedContext(context); 33 | 34 | // then 35 | assertEquals(1, contextMap.getBoundedContexts().size()); 36 | assertEquals("TestContext", contextMap.getBoundedContexts().iterator().next().getName()); 37 | } 38 | 39 | @Test 40 | public void canAddRelationship() { 41 | // given 42 | ContextMap contextMap = new ContextMap(); 43 | BoundedContext upstream = new BoundedContext("Upstream"); 44 | BoundedContext downstream = new BoundedContext("Downstream"); 45 | contextMap.addBoundedContext(upstream); 46 | contextMap.addBoundedContext(downstream); 47 | Relationship relationship = new Relationship(upstream, downstream); 48 | 49 | // when 50 | contextMap.addRelationship(relationship); 51 | 52 | // then 53 | assertEquals(1, contextMap.getRelationships().size()); 54 | Relationship testRel = contextMap.getRelationships().iterator().next(); 55 | assertEquals("Upstream", testRel.getUpstream().getName()); 56 | assertEquals("Downstream", testRel.getDownstream().getName()); 57 | } 58 | 59 | @Test 60 | public void cannotAddRelationshipWithMissingUpstream() { 61 | // given 62 | ContextMap contextMap = new ContextMap(); 63 | BoundedContext downstream = new BoundedContext("Downstream"); 64 | Relationship relationship = new Relationship(new BoundedContext("Upstream"), downstream); 65 | contextMap.addBoundedContext(downstream); 66 | 67 | // when, then 68 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 69 | contextMap.addRelationship(relationship); 70 | }); 71 | } 72 | 73 | @Test 74 | public void cannotAddRelationshipWithMissingDownstream() { 75 | // given 76 | ContextMap contextMap = new ContextMap(); 77 | BoundedContext upstream = new BoundedContext("Upstream"); 78 | Relationship relationship = new Relationship(upstream, new BoundedContext("Downstream")); 79 | contextMap.addBoundedContext(upstream); 80 | 81 | // when, then 82 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 83 | contextMap.addRelationship(relationship); 84 | }); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Service.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** 25 | * Represents a discovered Service. 26 | * 27 | * @author Stefan Kapferer 28 | */ 29 | public class Service { 30 | 31 | private String name; 32 | private String discoveryComment; 33 | private Set operations; 34 | 35 | public Service(String name) { 36 | setName(name); 37 | this.operations = new HashSet<>(); 38 | } 39 | 40 | /** 41 | * Sets the name of this Service. 42 | * 43 | * @param name the name of the Service. 44 | */ 45 | public void setName(String name) { 46 | if (name == null || "".equals(name)) 47 | throw new IllegalArgumentException("The name of a Service must not be null or empty."); 48 | this.name = name; 49 | } 50 | 51 | /** 52 | * Gets the name of this Service. 53 | * 54 | * @return the name of the Service as String 55 | */ 56 | public String getName() { 57 | return name; 58 | } 59 | 60 | /** 61 | * Adds an operation to the service. 62 | * 63 | * @param operation the operation that shall be added to the service 64 | */ 65 | public void addOperation(Method operation) { 66 | this.operations.add(operation); 67 | } 68 | 69 | /** 70 | * Returns all operations of the service. 71 | * 72 | * @return all operations of the service. 73 | */ 74 | public Set getOperations() { 75 | return new HashSet<>(operations); 76 | } 77 | 78 | /** 79 | * Sets a comment regarding how the Service has been discovered. 80 | * 81 | * @param discoveryComment the comment regarding how the Service has been discovered 82 | */ 83 | public void setDiscoveryComment(String discoveryComment) { 84 | this.discoveryComment = discoveryComment; 85 | } 86 | 87 | /** 88 | * Gets a comment regarding how the Service has been discovered. 89 | * 90 | * @return a comment regarding how the Service has been discovered. 91 | */ 92 | public String getDiscoveryComment() { 93 | return discoveryComment; 94 | } 95 | 96 | @Override 97 | public boolean equals(Object object) { 98 | if (!(object instanceof Service)) 99 | return false; 100 | 101 | Service bc = (Service) object; 102 | 103 | return new EqualsBuilder() 104 | .append(name, bc.name) 105 | .isEquals(); 106 | } 107 | 108 | @Override 109 | public int hashCode() { 110 | return new HashCodeBuilder() 111 | .append(name) 112 | .hashCode(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/test/resources/test/oas-tests/sample-contract.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: ReferenceManagementServiceAPI 4 | version: "1.0" 5 | tags: 6 | - name: PaperArchiveFacade 7 | description: general data-oriented endpoint 8 | externalDocs: 9 | description: INFORMATION_HOLDER_RESOURCE 10 | url: https://microservice-api-patterns.org/patterns/responsibility/ 11 | paths: 12 | /PaperArchiveFacade: 13 | summary: general data-oriented endpoint 14 | description: 'MAP link: INFORMATION_HOLDER_RESOURCE available at [the MAP website](https://microservice-api-patterns.org/)' 15 | get: 16 | tags: 17 | - PaperArchiveFacade 18 | summary: read only 19 | description: This operation realizes the Retrieval Operation pattern, described 20 | [on the MAP website](https://microservice-api-patterns.org/patterns/responsibility/operationResponsibilities/RetrievalOperation.html). 21 | operationId: lookupPapersFromAuthor 22 | parameters: 23 | - name: Parameter1 24 | in: query 25 | description: unspecified 26 | required: true 27 | schema: 28 | type: string 29 | responses: 30 | "200": 31 | description: response message payload (success case) 32 | content: 33 | application/json: 34 | schema: 35 | type: array 36 | items: 37 | $ref: '#/components/schemas/PaperItemDTO' 38 | put: 39 | tags: 40 | - PaperArchiveFacade 41 | summary: write only 42 | description: This operation realizes the State Creation Operation pattern, described 43 | [on the MAP website](https://microservice-api-patterns.org/patterns/responsibility/operationResponsibilities/StateCreationOperation.html). 44 | operationId: createPaperItem 45 | requestBody: 46 | content: 47 | application/json: 48 | schema: 49 | $ref: '#/components/schemas/createPaperItemParameter' 50 | responses: 51 | "200": 52 | description: response message payload (success case) 53 | content: 54 | application/json: 55 | schema: 56 | $ref: '#/components/schemas/PaperItemDTO' 57 | post: 58 | tags: 59 | - PaperArchiveFacade 60 | description: unspecified operation responsibility 61 | operationId: convertToMarkdownForWebsite 62 | requestBody: 63 | content: 64 | application/json: 65 | schema: 66 | $ref: '#/components/schemas/PaperItemKey' 67 | responses: 68 | "200": 69 | description: response message payload (success case) 70 | content: 71 | application/json: 72 | schema: 73 | type: object 74 | properties: 75 | anonymous1: 76 | type: string 77 | components: 78 | schemas: 79 | PaperItemDTO: 80 | type: object 81 | properties: 82 | title: 83 | type: string 84 | authors: 85 | type: string 86 | venue: 87 | type: string 88 | paperItemId: 89 | $ref: '#/components/schemas/PaperItemKey' 90 | PaperItemKey: 91 | type: object 92 | properties: 93 | doi: 94 | type: string 95 | createPaperItemParameter: 96 | type: object 97 | properties: 98 | who: 99 | type: string 100 | what: 101 | type: string 102 | where: 103 | type: string -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/AggregateTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | public class AggregateTest { 27 | 28 | @Test 29 | public void cannotCreateAggregateWithNullName() { 30 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 31 | new Aggregate(null); 32 | }); 33 | } 34 | 35 | @Test 36 | public void cannotCreateAggregateWithEmptyName() { 37 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 38 | new Aggregate(""); 39 | }); 40 | } 41 | 42 | @Test 43 | public void canCreateAggregateWithName() { 44 | // given 45 | Aggregate aggregate; 46 | 47 | // when 48 | aggregate = new Aggregate("TestAggregate"); 49 | 50 | // then 51 | assertEquals("TestAggregate", aggregate.getName()); 52 | } 53 | 54 | @Test 55 | public void canAddDomainObject() { 56 | // given 57 | Aggregate aggregate = new Aggregate("TestAggregate"); 58 | 59 | // when 60 | aggregate.addDomainObject(new DomainObject(DomainObjectType.ENTITY, "Entity", "test.Entity")); 61 | 62 | // then 63 | assertEquals(1, aggregate.getDomainObjects().size()); 64 | assertEquals(new DomainObject(DomainObjectType.ENTITY, "Entity", "test.Entity"), aggregate.getDomainObjects().iterator().next()); 65 | } 66 | 67 | @Test 68 | public void canAddServices() { 69 | // given 70 | Aggregate aggregate = new Aggregate("TestAggregate"); 71 | 72 | // when 73 | Set services = new HashSet<>(); 74 | services.add(new Service("TestService1")); 75 | services.add(new Service("TestService2")); 76 | aggregate.addServices(services); 77 | 78 | // then 79 | assertEquals(2, aggregate.getServices().size()); 80 | } 81 | 82 | @Test 83 | public void aggregatesWithSameNameAreEqual() { 84 | // given 85 | Aggregate aggregate1 = new Aggregate("TestAggregate"); 86 | Aggregate aggregate2 = new Aggregate("TestAggregate"); 87 | 88 | // when 89 | boolean equals = aggregate1.equals(aggregate2); 90 | 91 | // then 92 | assertTrue(equals); 93 | } 94 | 95 | @Test 96 | public void otherObjectsAreNotEqual() { 97 | // given 98 | Aggregate aggregate = new Aggregate("TestAggregate"); 99 | 100 | // when 101 | boolean equals = aggregate.equals(new Object()); 102 | 103 | // then 104 | assertFalse(equals); 105 | } 106 | 107 | @Test 108 | public void canAddComment() { 109 | // given 110 | Aggregate aggregate = new Aggregate("TestAggregate"); 111 | String comment = "This aggregate has been created on the basis of the REST controller test.TestAggregate"; 112 | 113 | // when 114 | aggregate.setDiscoveryComment(comment); 115 | 116 | // then 117 | assertEquals(comment, aggregate.getDiscoveryComment()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/BoundedContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** 25 | * Represents a discovered Bounded Context. 26 | * 27 | * @author Stefan Kapferer 28 | */ 29 | public class BoundedContext { 30 | 31 | private String name; 32 | private String technology; 33 | private Set aggregates; 34 | 35 | public BoundedContext(String name) { 36 | setName(name); 37 | this.aggregates = new HashSet<>(); 38 | } 39 | 40 | /** 41 | * Sets the name of this Bounded Context. 42 | * 43 | * @param name the name of the Bounded Context. 44 | */ 45 | public void setName(String name) { 46 | if (name == null || "".equals(name)) 47 | throw new IllegalArgumentException("The name of a Bounded Context must not be null or empty."); 48 | this.name = name; 49 | } 50 | 51 | /** 52 | * Gets the name of this Bounded Context. 53 | * 54 | * @return the name of the Bounded Context as String 55 | */ 56 | public String getName() { 57 | return name; 58 | } 59 | 60 | /** 61 | * Sets the implementation technology of this Bounded Context. 62 | * 63 | * @param technology the implementation technology of this Bounded Context as a String 64 | */ 65 | public void setTechnology(String technology) { 66 | this.technology = technology; 67 | } 68 | 69 | /** 70 | * Gets the implementation technology of this Bounded Context. 71 | * 72 | * @return the implementation technology of this Bounded Context as a String 73 | */ 74 | public String getTechnology() { 75 | return technology; 76 | } 77 | 78 | /** 79 | * Adds Aggregates to the Bounded Context. 80 | * 81 | * @param aggregates the set of Aggregates to be added 82 | */ 83 | public void addAggregates(Set aggregates) { 84 | this.aggregates.addAll(aggregates); 85 | } 86 | 87 | /** 88 | * Adds an Aggregate to the Bounded Context. 89 | * 90 | * @param aggregate the Aggregate to be added to the Bounded Context 91 | */ 92 | public void addAggregate(Aggregate aggregate) { 93 | this.aggregates.add(aggregate); 94 | } 95 | 96 | /** 97 | * Gets the Aggregates of the Bounded Context. 98 | * 99 | * @return the set of Aggregates of the Bounded Context 100 | */ 101 | public Set getAggregates() { 102 | return new HashSet<>(aggregates); 103 | } 104 | 105 | @Override 106 | public boolean equals(Object object) { 107 | if (!(object instanceof BoundedContext)) 108 | return false; 109 | 110 | BoundedContext bc = (BoundedContext) object; 111 | 112 | return new EqualsBuilder() 113 | .append(name, bc.name) 114 | .isEquals(); 115 | } 116 | 117 | @Override 118 | public int hashCode() { 119 | return new HashCodeBuilder() 120 | .append(name) 121 | .hashCode(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Method.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** 25 | * Represents a method in a domain object. 26 | * 27 | * @author Stefan Kapferer 28 | */ 29 | public class Method { 30 | 31 | private DomainObject parent; 32 | private String name; 33 | private Type returnType; 34 | private Set parameters; 35 | 36 | public Method(String name) { 37 | this.name = name; 38 | this.parameters = new HashSet<>(); 39 | } 40 | 41 | /** 42 | * Gets the name of the method. 43 | * 44 | * @return the name of the method 45 | */ 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | /** 51 | * Sets the return type of the method. 52 | * 53 | * @param returnType the return type of the method 54 | */ 55 | public void setReturnType(Type returnType) { 56 | this.returnType = returnType; 57 | } 58 | 59 | /** 60 | * Gets the return type of the method. 61 | * 62 | * @return the return type of the method 63 | */ 64 | public Type getReturnType() { 65 | return returnType; 66 | } 67 | 68 | /** 69 | * Adds a new parameter to the method. 70 | * 71 | * @param parameter the parameter to be added to the method 72 | */ 73 | public void addParameter(Parameter parameter) { 74 | this.parameters.add(parameter); 75 | } 76 | 77 | /** 78 | * Adds a set of new parameters to the method. 79 | * 80 | * @param parameters the set of parameters to be added to the method 81 | */ 82 | public void addParameters(Set parameters) { 83 | this.parameters.addAll(parameters); 84 | } 85 | 86 | /** 87 | * Gets the parameters of the method. 88 | * 89 | * @return the set of parameters of the method 90 | */ 91 | public Set getParameters() { 92 | return new HashSet<>(parameters); 93 | } 94 | 95 | /** 96 | * Gets the parent domain object containing this attribute. 97 | * 98 | * @return the parent domain object containing this attribute 99 | */ 100 | public DomainObject getParent() { 101 | return parent; 102 | } 103 | 104 | /** 105 | * Sets the parent domain object containing this attribute. 106 | * 107 | * @param parent the parent domain object containing this attribute 108 | */ 109 | public void setParent(DomainObject parent) { 110 | this.parent = parent; 111 | } 112 | 113 | @Override 114 | public boolean equals(Object object) { 115 | if (!(object instanceof Method)) 116 | return false; 117 | 118 | Method method = (Method) object; 119 | 120 | return new EqualsBuilder() 121 | .append(parent, method.parent) 122 | .append(name, method.name) 123 | .isEquals(); 124 | } 125 | 126 | @Override 127 | public int hashCode() { 128 | return new HashCodeBuilder() 129 | .append(parent) 130 | .append(name) 131 | .hashCode(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/RelationshipTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.*; 22 | 23 | public class RelationshipTest { 24 | 25 | @Test 26 | public void canCreateRelationship() { 27 | // given 28 | BoundedContext bc1 = new BoundedContext("TestContext1"); 29 | BoundedContext bc2 = new BoundedContext("TestContext2"); 30 | 31 | // when 32 | Relationship relationship = new Relationship(bc1, bc2); 33 | 34 | // then 35 | assertEquals("TestContext1", relationship.getUpstream().getName()); 36 | assertEquals("TestContext2", relationship.getDownstream().getName()); 37 | } 38 | 39 | @Test 40 | public void relationshipsWithSameContextsAreEqual() { 41 | // given 42 | Relationship relationship1 = new Relationship(new BoundedContext("TestContext1"), new BoundedContext("TestContext1")); 43 | Relationship relationship2 = new Relationship(new BoundedContext("TestContext1"), new BoundedContext("TestContext1")); 44 | 45 | // when 46 | boolean equals = relationship1.equals(relationship2); 47 | 48 | // then 49 | assertTrue(equals); 50 | } 51 | 52 | @Test 53 | public void otherObjectsAreNotEqual() { 54 | // given 55 | Relationship relationship = new Relationship(new BoundedContext("TestContext1"), new BoundedContext("TestContext1")); 56 | 57 | // when 58 | boolean equals = relationship.equals(new Object()); 59 | 60 | // then 61 | assertFalse(equals); 62 | } 63 | 64 | @Test 65 | public void canAddExposedAggregates() { 66 | // given 67 | BoundedContext upstream = new BoundedContext("UpstreamContext"); 68 | Aggregate aggregate = new Aggregate("ExposedAggregate"); 69 | upstream.addAggregate(aggregate); 70 | BoundedContext downstream = new BoundedContext("DownstreamContext"); 71 | 72 | // when 73 | Relationship relationship = new Relationship(upstream, downstream); 74 | relationship.addExposedAggregate(aggregate); 75 | 76 | // then 77 | assertEquals(1, relationship.getExposedAggregates().size()); 78 | assertEquals(aggregate, relationship.getExposedAggregates().iterator().next()); 79 | } 80 | 81 | @Test 82 | public void cannotAddExposedAggregateWhichIsNotPartOfUpstreamContext() { 83 | // given 84 | BoundedContext upstream = new BoundedContext("UpstreamContext"); 85 | Aggregate aggregate = new Aggregate("ExposedAggregate"); 86 | BoundedContext downstream = new BoundedContext("DownstreamContext"); 87 | Relationship relationship = new Relationship(upstream, downstream); 88 | 89 | // when, then 90 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 91 | relationship.addExposedAggregate(aggregate); 92 | }); 93 | } 94 | 95 | @Test 96 | public void canSetExposedAggregateDiscoveryComment() { 97 | // given 98 | Relationship relationship = new Relationship(new BoundedContext("UpstreamContext"), new BoundedContext("DownstreamContext")); 99 | 100 | // when 101 | relationship.setExposedAggregatesComment("testcomment"); 102 | 103 | // then 104 | assertEquals("testcomment", relationship.getExposedAggregatesComment()); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Relationship.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** 25 | * Represents an upstream-downstream relationship between two Bounded Contexts. 26 | * 27 | * @author Stefan Kapferer 28 | */ 29 | public class Relationship { 30 | 31 | private BoundedContext upstream; 32 | private BoundedContext downstream; 33 | private Set exposedAggregates; 34 | private String exposedAggregatesComment; 35 | 36 | public Relationship(BoundedContext upstream, BoundedContext downstream) { 37 | this.upstream = upstream; 38 | this.downstream = downstream; 39 | this.exposedAggregates = new HashSet<>(); 40 | } 41 | 42 | /** 43 | * Gets the upstream Bounded Context. 44 | * 45 | * @return the upstream Bounded Context 46 | */ 47 | public BoundedContext getUpstream() { 48 | return upstream; 49 | } 50 | 51 | /** 52 | * Gets the downstream Bounded Context. 53 | * 54 | * @return the downstream Bounded Context 55 | */ 56 | public BoundedContext getDownstream() { 57 | return downstream; 58 | } 59 | 60 | /** 61 | * Gets the exposed Aggregates up the upstream within this relationship. 62 | * 63 | * @return the set of exposed Aggregates by the upstream context 64 | */ 65 | public Set getExposedAggregates() { 66 | return new HashSet<>(exposedAggregates); 67 | } 68 | 69 | /** 70 | * Adds a set of Aggregates to the exposed Aggregates of the relationship. 71 | * 72 | * @param exposedAggregates the set of Aggregates which are exposed 73 | */ 74 | public void addExposedAggregates(Set exposedAggregates) { 75 | for (Aggregate aggregate : exposedAggregates) { 76 | addExposedAggregate(aggregate); 77 | } 78 | } 79 | 80 | /** 81 | * Sets a comment regarding how the exposed Aggregates have been discovered. 82 | * 83 | * @param exposedAggregatesComment the comment explaining how the exposed Aggregates have been discovered 84 | */ 85 | public void setExposedAggregatesComment(String exposedAggregatesComment) { 86 | this.exposedAggregatesComment = exposedAggregatesComment; 87 | } 88 | 89 | /** 90 | * Gets a comment regarding how the exposed Aggregates have been discovered. 91 | * 92 | * @return the comment explaining how the exposed Aggregates have been discovered 93 | */ 94 | public String getExposedAggregatesComment() { 95 | return exposedAggregatesComment; 96 | } 97 | 98 | /** 99 | * Adds an Aggregate to the exposed Aggregates of the relationship. 100 | * 101 | * @param aggregate the Aggregate which is exposed 102 | */ 103 | public void addExposedAggregate(Aggregate aggregate) { 104 | if (!this.upstream.getAggregates().contains(aggregate)) 105 | throw new IllegalArgumentException("The exposed Aggregates must be part of the upstream Bounded Context! " + 106 | "('" + aggregate.getName() + "' is not part of '" + upstream.getName() + "')"); 107 | this.exposedAggregates.add(aggregate); 108 | } 109 | 110 | @Override 111 | public boolean equals(Object object) { 112 | if (!(object instanceof Relationship)) 113 | return false; 114 | 115 | Relationship relationship = (Relationship) object; 116 | 117 | return new EqualsBuilder() 118 | .append(upstream, relationship.upstream) 119 | .append(downstream, relationship.downstream) 120 | .isEquals(); 121 | } 122 | 123 | @Override 124 | public int hashCode() { 125 | return new HashCodeBuilder() 126 | .append(upstream) 127 | .append(downstream) 128 | .hashCode(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/TypeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.*; 21 | 22 | public class TypeTest { 23 | 24 | @Test 25 | public void cannotCreateNullDomainObjectType() { 26 | assertThrows(RuntimeException.class, () -> { 27 | new Type((DomainObject) null); 28 | }); 29 | } 30 | 31 | @Test 32 | public void cannotCreateNullPrimitiveType() { 33 | assertThrows(RuntimeException.class, () -> { 34 | new Type((String) null); 35 | }); 36 | } 37 | 38 | @Test 39 | public void cannotCreateEmptyPrimitiveType() { 40 | assertThrows(RuntimeException.class, () -> { 41 | new Type(""); 42 | }); 43 | } 44 | 45 | @Test 46 | public void canCreateDomainObjectType() { 47 | // given 48 | DomainObject object = new DomainObject(DomainObjectType.ENTITY, "Customer"); 49 | 50 | // when 51 | Type type = new Type(object); 52 | 53 | // then 54 | assertEquals(TypeKind.DOMAIN_OBJECT, type.getKind()); 55 | assertTrue(type.isDomainObjectType()); 56 | assertEquals("Customer", type.getDomainObjectType().getName()); 57 | } 58 | 59 | @Test 60 | public void canCreatePrimitiveType() { 61 | // given 62 | String primitiveType = "String"; 63 | 64 | // when 65 | Type type = new Type(primitiveType); 66 | 67 | // then 68 | assertEquals(TypeKind.PRIMITIVE, type.getKind()); 69 | assertTrue(type.isPrimitiveType()); 70 | assertEquals(primitiveType, type.getPrimitiveType()); 71 | } 72 | 73 | @Test 74 | public void cannotGetPrimitiveType4DomainObjectType() { 75 | // given 76 | Type type = new Type(new DomainObject(DomainObjectType.ENTITY, "Customer")); 77 | 78 | // when, then 79 | assertThrows(RuntimeException.class, () -> { 80 | type.getPrimitiveType(); 81 | }); 82 | } 83 | 84 | @Test 85 | public void cannotGetDomainObjectType4PrimitiveType() { 86 | // given 87 | Type type = new Type("String"); 88 | 89 | // when, then 90 | assertThrows(RuntimeException.class, () -> { 91 | type.getDomainObjectType(); 92 | }); 93 | } 94 | 95 | @Test 96 | public void otherObjectsAreNotEqual() { 97 | // given 98 | Type type = new Type("String"); 99 | 100 | // when 101 | boolean equals = type.equals(new Object()); 102 | 103 | // then 104 | assertFalse(equals); 105 | } 106 | 107 | @Test 108 | public void domainObjectTypesOfSameObjectAreEqual() { 109 | // given 110 | Type type1 = new Type(new DomainObject(DomainObjectType.ENTITY, "Customer")); 111 | Type type2 = new Type(new DomainObject(DomainObjectType.ENTITY, "Customer")); 112 | 113 | // when 114 | boolean equals = type1.equals(type2); 115 | 116 | // then 117 | assertTrue(equals); 118 | } 119 | 120 | @Test 121 | public void primitiveTypeOfSameTypeAreEqual() { 122 | // given 123 | Type type1 = new Type("String"); 124 | Type type2 = new Type("String"); 125 | 126 | // when 127 | boolean equals = type1.equals(type2); 128 | 129 | // then 130 | assertTrue(equals); 131 | } 132 | 133 | @Test 134 | public void canSetCollectionType() { 135 | // given 136 | Type type = new Type("String"); 137 | 138 | // when 139 | type.setCollectionType("List"); 140 | 141 | // then 142 | assertEquals("List", type.getCollectionType()); 143 | } 144 | 145 | @Test 146 | public void cannotGetCollectionTypeIfItsNotCollection() { 147 | // given 148 | Type type = new Type("String"); 149 | 150 | // when, then 151 | assertThrows(RuntimeException.class, () -> { 152 | type.getCollectionType(); 153 | }); 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Aggregate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** 25 | * Represents a discovered Aggregate. 26 | * 27 | * @author Stefan Kapferer 28 | */ 29 | public class Aggregate { 30 | 31 | private String name; 32 | private Set domainObjects; 33 | private Set services; 34 | private String discoveryComment; 35 | 36 | public Aggregate(String name) { 37 | setName(name); 38 | this.domainObjects = new HashSet<>(); 39 | this.services = new HashSet<>(); 40 | } 41 | 42 | /** 43 | * Sets the name of this Aggregate. 44 | * 45 | * @param name the name of the Aggregate. 46 | */ 47 | public void setName(String name) { 48 | if (name == null || "".equals(name)) 49 | throw new IllegalArgumentException("The name of an Aggregate must not be null or empty."); 50 | this.name = name; 51 | } 52 | 53 | /** 54 | * Gets the name of this Aggregate. 55 | * 56 | * @return the name of the Aggregate as String 57 | */ 58 | public String getName() { 59 | return name; 60 | } 61 | 62 | /** 63 | * Adds a domain object to the Aggregate. 64 | * 65 | * @param domainObject the domain object to be added to the Aggregate 66 | */ 67 | public void addDomainObject(DomainObject domainObject) { 68 | this.domainObjects.add(domainObject); 69 | domainObject.setParent(this); 70 | } 71 | 72 | /** 73 | * Adds all domain objects in the given set to the Aggregate. 74 | * 75 | * @param domainObjects the set of domain objects to be added to the Aggregate 76 | */ 77 | public void addDomainObjects(Set domainObjects) { 78 | for (DomainObject domainObject : domainObjects) { 79 | this.addDomainObject(domainObject); 80 | } 81 | } 82 | 83 | /** 84 | * Adds a service to the Aggregate. 85 | * 86 | * @param service the service to be added to the Aggregate 87 | */ 88 | public void addService(Service service) { 89 | this.services.add(service); 90 | } 91 | 92 | /** 93 | * Adds all services in the given set to the Aggregate. 94 | * 95 | * @param services the set of services to be added to the Aggregate 96 | */ 97 | public void addServices(Set services) { 98 | for (Service service : services) { 99 | this.addService(service); 100 | } 101 | } 102 | 103 | /** 104 | * Gets the set of domain objects within the Aggregate. 105 | * 106 | * @return the set of domain objects which are part of the Aggregate 107 | */ 108 | public Set getDomainObjects() { 109 | return new HashSet<>(domainObjects); 110 | } 111 | 112 | /** 113 | * Gets the set of services within the Aggregate. 114 | * 115 | * @return the set of services which are part of the Aggregate 116 | */ 117 | public Set getServices() { 118 | return new HashSet<>(services); 119 | } 120 | 121 | /** 122 | * Sets a comment regarding how the Aggregate has been discovered. 123 | * 124 | * @param discoveryComment the comment regarding how the Aggregate has been discovered 125 | */ 126 | public void setDiscoveryComment(String discoveryComment) { 127 | this.discoveryComment = discoveryComment; 128 | } 129 | 130 | /** 131 | * Gets a comment regarding how the Aggregate has been discovered. 132 | * 133 | * @return a comment regarding how the Aggregate has been discovered. 134 | */ 135 | public String getDiscoveryComment() { 136 | return discoveryComment; 137 | } 138 | 139 | @Override 140 | public boolean equals(Object object) { 141 | if (!(object instanceof Aggregate)) 142 | return false; 143 | 144 | Aggregate bc = (Aggregate) object; 145 | 146 | return new EqualsBuilder() 147 | .append(name, bc.name) 148 | .isEquals(); 149 | } 150 | 151 | @Override 152 | public int hashCode() { 153 | return new HashCodeBuilder() 154 | .append(name) 155 | .hashCode(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/relationships/DockerComposeRelationshipDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.relationships; 17 | 18 | import org.apache.commons.io.FileUtils; 19 | import org.apache.commons.io.filefilter.NameFileFilter; 20 | import org.apache.commons.io.filefilter.TrueFileFilter; 21 | import org.contextmapper.discovery.model.BoundedContext; 22 | import org.contextmapper.discovery.model.Relationship; 23 | import org.yaml.snakeyaml.Yaml; 24 | 25 | import java.io.File; 26 | import java.io.FileInputStream; 27 | import java.io.FileNotFoundException; 28 | import java.util.*; 29 | 30 | public class DockerComposeRelationshipDiscoveryStrategy extends AbstractRelationshipDiscoveryStrategy implements RelationshipDiscoveryStrategy { 31 | 32 | private File sourcePath; 33 | 34 | public DockerComposeRelationshipDiscoveryStrategy(File sourcePath) { 35 | this.sourcePath = sourcePath; 36 | } 37 | 38 | @Override 39 | public Set discoverRelationships() { 40 | Set relationships = new HashSet<>(); 41 | for (File dockerComposeFile : findDockerComposeFiles()) { 42 | relationships.addAll(discoverRelationships(dockerComposeFile)); 43 | } 44 | return relationships; 45 | } 46 | 47 | private Set discoverRelationships(File dockerComposeFile) { 48 | Set relationships = new HashSet<>(); 49 | for (ServiceDependency dependency : parseDependencies(dockerComposeFile)) { 50 | BoundedContext upstreamContext = discoverer.lookupBoundedContext(dependency.dependsOn); 51 | BoundedContext downstreamContext = discoverer.lookupBoundedContext(dependency.service); 52 | if (upstreamContext != null && downstreamContext != null) { 53 | Relationship relationship = new Relationship(upstreamContext, downstreamContext); 54 | // We cannot discover 'exposed aggregates' with this Docker strategy. Therefore, we 55 | // just add all discovered Aggregates to the 'exposed aggregates'. 56 | relationship.addExposedAggregates(upstreamContext.getAggregates()); 57 | relationship.setExposedAggregatesComment("The list of exposed Aggregates may contain Aggregates which are not used by the downstream (discovery strategy simply added all Aggregates)."); 58 | relationships.add(relationship); 59 | } 60 | } 61 | return relationships; 62 | } 63 | 64 | protected List parseDependencies(File dockerComposeFile) { 65 | List result = new ArrayList<>(); 66 | try { 67 | Yaml yaml = new Yaml(); 68 | Map composeObjectMap = yaml.load(new FileInputStream(dockerComposeFile)); 69 | if (!composeObjectMap.containsKey("services")) 70 | return result; 71 | Map services = (Map) composeObjectMap.get("services"); 72 | if (services == null) 73 | return result; 74 | for (String service : services.keySet()) { 75 | if (((Map) services.get(service)).containsKey("depends_on")) 76 | result.addAll(createServiceDependencies4Service(service, (List) ((Map) services.get(service)).get("depends_on"))); 77 | } 78 | } catch (FileNotFoundException e) { 79 | throw new IllegalArgumentException("The file '" + dockerComposeFile.toString() + "' does not exist!", e); 80 | } 81 | return result; 82 | } 83 | 84 | private List createServiceDependencies4Service(String service, List dependencies) { 85 | List resultList = new ArrayList<>(); 86 | for (String dependency : dependencies) { 87 | resultList.add(new ServiceDependency(service, dependency)); 88 | } 89 | return resultList; 90 | } 91 | 92 | private Collection findDockerComposeFiles() { 93 | return FileUtils.listFiles(sourcePath, new NameFileFilter("docker-compose.yml"), TrueFileFilter.INSTANCE); 94 | } 95 | 96 | protected class ServiceDependency { 97 | private String service; 98 | private String dependsOn; 99 | 100 | ServiceDependency(String service, String dependsOn) { 101 | this.service = service; 102 | this.dependsOn = dependsOn; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/ContextMapDiscovererTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery; 17 | 18 | import org.contextmapper.discovery.model.BoundedContext; 19 | import org.contextmapper.discovery.model.ContextMap; 20 | import org.contextmapper.discovery.model.Relationship; 21 | import org.contextmapper.discovery.strategies.boundedcontexts.AbstractBoundedContextDiscoveryStrategy; 22 | import org.contextmapper.discovery.strategies.boundedcontexts.BoundedContextDiscoveryStrategy; 23 | import org.contextmapper.discovery.strategies.relationships.AbstractRelationshipDiscoveryStrategy; 24 | import org.contextmapper.discovery.strategies.relationships.RelationshipDiscoveryStrategy; 25 | import org.junit.jupiter.api.Test; 26 | 27 | import java.util.HashSet; 28 | import java.util.Set; 29 | 30 | import static org.junit.jupiter.api.Assertions.*; 31 | 32 | public class ContextMapDiscovererTest { 33 | 34 | @Test 35 | public void canDiscoverBoundedContexts() { 36 | // given 37 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 38 | .usingBoundedContextDiscoveryStrategies( 39 | new DummyDiscoveryStrategy() 40 | ); 41 | 42 | // when 43 | ContextMap contextMap = discoverer.discoverContextMap(); 44 | 45 | // then 46 | assertEquals(2, contextMap.getBoundedContexts().size()); 47 | assertTrue(contextMap.getBoundedContexts().contains(new BoundedContext("DummyUpstreamContext"))); 48 | assertTrue(contextMap.getBoundedContexts().contains(new BoundedContext("DummyDownstreamContext"))); 49 | } 50 | 51 | @Test 52 | public void canDiscoverRelationship() { 53 | // given 54 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 55 | .usingBoundedContextDiscoveryStrategies( 56 | new DummyDiscoveryStrategy()) 57 | .usingRelationshipDiscoveryStrategies( 58 | new DummyRelationshipStrategy() 59 | ); 60 | 61 | // when 62 | ContextMap contextMap = discoverer.discoverContextMap(); 63 | 64 | // then 65 | assertEquals(2, contextMap.getBoundedContexts().size()); 66 | assertEquals(1, contextMap.getRelationships().size()); 67 | Relationship relationship = contextMap.getRelationships().iterator().next(); 68 | assertEquals("DummyUpstreamContext", relationship.getUpstream().getName()); 69 | assertEquals("DummyDownstreamContext", relationship.getDownstream().getName()); 70 | } 71 | 72 | @Test 73 | public void canLookupDiscoveredBoundedContextByName() { 74 | // given 75 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 76 | .usingBoundedContextDiscoveryStrategies( 77 | new DummyDiscoveryStrategy() 78 | ); 79 | 80 | // when 81 | discoverer.discoverContextMap(); 82 | 83 | // then 84 | assertNotNull(discoverer.lookupBoundedContext("DummyUpstreamContext")); 85 | } 86 | 87 | @Test 88 | public void nameLookupReturnsNullIfBCNotFound() { 89 | // given 90 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 91 | .usingBoundedContextDiscoveryStrategies( 92 | new DummyDiscoveryStrategy() 93 | ); 94 | 95 | // when 96 | discoverer.discoverContextMap(); 97 | 98 | // then 99 | assertNull(discoverer.lookupBoundedContext("NotExistingContext")); 100 | } 101 | 102 | private class DummyDiscoveryStrategy extends AbstractBoundedContextDiscoveryStrategy implements BoundedContextDiscoveryStrategy { 103 | @Override 104 | public Set discoverBoundedContexts() { 105 | // just discover a dummy Bounded Context: 106 | Set bcs = new HashSet<>(); 107 | bcs.add(new BoundedContext("DummyUpstreamContext")); 108 | bcs.add(new BoundedContext("DummyDownstreamContext")); 109 | return bcs; 110 | } 111 | } 112 | 113 | private class DummyRelationshipStrategy extends AbstractRelationshipDiscoveryStrategy implements RelationshipDiscoveryStrategy { 114 | @Override 115 | public Set discoverRelationships() { 116 | Set relationships = new HashSet<>(); 117 | relationships.add(new Relationship(new BoundedContext("DummyUpstreamContext"), new BoundedContext("DummyDownstreamContext"))); 118 | return relationships; 119 | } 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/ContextMapDiscoverer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery; 17 | 18 | import org.contextmapper.discovery.model.BoundedContext; 19 | import org.contextmapper.discovery.model.ContextMap; 20 | import org.contextmapper.discovery.strategies.boundedcontexts.BoundedContextDiscoveryStrategy; 21 | import org.contextmapper.discovery.strategies.names.BoundedContextNameMappingStrategy; 22 | import org.contextmapper.discovery.strategies.names.DefaultBoundedContextNameMappingStrategy; 23 | import org.contextmapper.discovery.strategies.relationships.RelationshipDiscoveryStrategy; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Arrays; 27 | import java.util.List; 28 | 29 | /** 30 | * Discovers Bounded Contexts and relationships between them with given strategies. 31 | * 32 | * @author Stefan Kapferer 33 | */ 34 | public class ContextMapDiscoverer { 35 | 36 | private ContextMap contextMap; 37 | private List boundedContextDiscoveryStrategies = new ArrayList<>(); 38 | private List relationshipDiscoveryStrategies = new ArrayList<>(); 39 | private List boundedContextNameMappingStrategies = new ArrayList<>(); 40 | 41 | public ContextMapDiscoverer() { 42 | this.contextMap = new ContextMap(); 43 | this.boundedContextNameMappingStrategies.add(new DefaultBoundedContextNameMappingStrategy()); 44 | } 45 | 46 | /** 47 | * Registers the Bounded Context discovery strategies to be used. 48 | * 49 | * @param boundedContextDiscoveryStrategies the Bounded Context discovery strategies 50 | */ 51 | public ContextMapDiscoverer usingBoundedContextDiscoveryStrategies(BoundedContextDiscoveryStrategy... boundedContextDiscoveryStrategies) { 52 | this.boundedContextDiscoveryStrategies.addAll(Arrays.asList(boundedContextDiscoveryStrategies)); 53 | return this; 54 | } 55 | 56 | /** 57 | * Registers the relationship discovery strategies to be used. 58 | * 59 | * @param relationshipDiscoveryStrategies the relationship discovery strategies 60 | */ 61 | public ContextMapDiscoverer usingRelationshipDiscoveryStrategies(RelationshipDiscoveryStrategy... relationshipDiscoveryStrategies) { 62 | for (RelationshipDiscoveryStrategy strategy : relationshipDiscoveryStrategies) { 63 | strategy.setContextMapDiscoverer(this); 64 | } 65 | this.relationshipDiscoveryStrategies.addAll(Arrays.asList(relationshipDiscoveryStrategies)); 66 | return this; 67 | } 68 | 69 | /** 70 | * Registers Bounded Context name mapping strategies to find Bounded Context in 71 | * {@link #lookupBoundedContext(String) lookupBoundedContext} with different input names. 72 | * 73 | * @param boundedContextNameMappingStrategies the Bounded Context name mapping strategies 74 | */ 75 | public ContextMapDiscoverer usingBoundedContextNameMappingStrategies(BoundedContextNameMappingStrategy... boundedContextNameMappingStrategies) { 76 | this.boundedContextNameMappingStrategies.addAll(Arrays.asList(boundedContextNameMappingStrategies)); 77 | return this; 78 | } 79 | 80 | /** 81 | * Discovers the Bounded Contexts and relationships. 82 | * 83 | * @return the Context Map with the discovered Bounded Contexts and relationships 84 | */ 85 | public ContextMap discoverContextMap() { 86 | for (BoundedContextDiscoveryStrategy strategy : boundedContextDiscoveryStrategies) { 87 | contextMap.addAllBoundedContexts(strategy.discoverBoundedContexts()); 88 | } 89 | for (RelationshipDiscoveryStrategy strategy : relationshipDiscoveryStrategies) { 90 | contextMap.addAllRelationships(strategy.discoverRelationships()); 91 | } 92 | return contextMap; 93 | } 94 | 95 | /** 96 | * Finds discovered Bounded Context by name, using lookup strategy if configured. 97 | * 98 | * @param name the Bounded Context name to be looked up 99 | * @return the corresponding Bounded Context or null, if the name was not found 100 | */ 101 | public BoundedContext lookupBoundedContext(String name) { 102 | for (BoundedContextNameMappingStrategy strategy : boundedContextNameMappingStrategies) { 103 | BoundedContext bc = getBoundedContextByName(strategy.mapBoundedContextName(name)); 104 | if (bc != null) 105 | return bc; 106 | } 107 | return null; 108 | } 109 | 110 | private BoundedContext getBoundedContextByName(String name) { 111 | return this.contextMap.getBoundedContexts().stream().filter(bc -> bc.getName().equals(name)).findFirst().orElse(null); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/README.md: -------------------------------------------------------------------------------- 1 | # Lakeside Mutual Example 2 | The [Lakeside Mutual](https://github.com/Microservice-API-Patterns/LakesideMutual/) project is a fictitious insurance company which serves as a sample application to demonstrate microservices and Domain-driven Design (DDD). 3 | 4 | We use the project here to illustrate how the Context Mapper discovery library can be used to reverse engineer a Context Mapping DSL (CML) model from existing source code. The project's backend services are based on [Spring Boot](https://spring.io/projects/spring-boot) and it provides a [Docker Compose](https://docs.docker.com/compose/) configuration to start all microservices. Thus, our [discovery strategies](https://github.com/ContextMapper/context-map-discovery#existing-strategies) support to reverse engineer a Context Map for the [Lakeside Mutual](https://github.com/Microservice-API-Patterns/LakesideMutual/) project. 5 | 6 | ## Lakeside Mutual Context Map Discovery 7 | The class [src/main/java/org/contextmapper/lakesidemutual/example/LakesideMutualContextMapDiscoverer.java](./src/main/java/org/contextmapper/lakesidemutual/example/LakesideMutualContextMapDiscoverer.java) contains the code needed to discover the Context Map for the Lakeside Mutual project: 8 | 9 | ```java 10 | public class LakesideMutualContextMapDiscoverer { 11 | 12 | public static void main(String[] args) throws IOException { 13 | // configure the discoverer 14 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 15 | .usingBoundedContextDiscoveryStrategies( 16 | new SpringBootBoundedContextDiscoveryStrategy("com.lakesidemutual")) 17 | .usingRelationshipDiscoveryStrategies( 18 | new DockerComposeRelationshipDiscoveryStrategy(new File(System.getProperty("user.home") + "/source/LakesideMutual/"))) 19 | .usingBoundedContextNameMappingStrategies( 20 | new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-") { 21 | @Override 22 | public String mapBoundedContextName(String s) { 23 | // remove the "Backend" part of the Docker service names to map correctly... 24 | String name = super.mapBoundedContextName(s); 25 | return name.endsWith("Backend") ? name.substring(0, name.length() - 7) : name; 26 | } 27 | }); 28 | 29 | // run the discovery process to get the Context Map 30 | ContextMap contextmap = discoverer.discoverContextMap(); 31 | 32 | // serialize the Context Map to CML 33 | new ContextMapSerializer().serializeContextMap(contextmap, new File("./src-gen/lakesidemutual.cml")); 34 | } 35 | 36 | } 37 | 38 | ``` 39 | 40 | **Spring Boot Bounded Context Discovery Strategy**: 41 | The Spring Boot Context Map discovery strategy simply needs to know the package in which it shall search for the `@SpringBootApplication` annotation. For this example, we scan `com.lakesidemutual`. 42 | 43 | **Docker Compose Relationship Discovery Strategy**: 44 | The Docker Compose strategy needs to know the root directory of the cloned Lakeside Mutual project. Within this directory it will search for docker-compose.yml files to analyze the relationships (dependencies). 45 | 46 | **Bounded Context Name Mapping Strategy**: 47 | In our example illustrated above we use an adjusted [SeparatorToCamelCaseBoundedContextNameMappingStrategy](https://github.com/ContextMapper/context-map-discovery#bounded-context-name-mapping-strategies) strategy, since the services in the docker-compose.yml files are named in the format _customer-core_ while the Spring Boot discovery strategy will use the application class name in the format _CustomerCore_. The adjusted name mapping strategy illustrated above further removes the "Backend" strings at the end, since the Spring Boot discovery strategy will detect the Bounded Contexts without this ending. 48 | 49 | **Resulting Model**: 50 | 51 | The example code above finally stores the discovered Context Map under [src-gen/lakesidemutual.cml](./src-gen/lakesidemutual.cml). 52 | 53 | ## Procedure to Run this Example 54 | 1. Clone the [Lakeside Mutual](https://github.com/Microservice-API-Patterns/LakesideMutual) project. 55 | 2. Build all backend (Java) projects with the provided Maven build and publish them to your local Maven repository: 56 | 57 | `mvn clean install` 58 | 59 | **Note:** Spring Boot works with it's own special class loader and the JAR's produced by the given Maven Builds are not scannable for the [reflections library](https://github.com/ronmamo/reflections) (classes located within BOOT-INF). In order to build real JAR archives, you first have to disable the _spring-boot-maven-plugin_ in all these backend projects (one solution is to simply comment the section out in the pom.xml files). 60 | 61 | 3. Clone this example project and import it within your favorite IDE (import Gradle project). 62 | 4. Adjust the source root path in the [LakesideMutualContextMapDiscoverer](./src/main/java/org/contextmapper/lakesidemutual/example/LakesideMutualContextMapDiscoverer.java) class to the location where you cloned the Lakeside Mutual project (DockerComposeRelationshipDiscoveryStrategy). 63 | 5. Run the [LakesideMutualContextMapDiscoverer](./src/main/java/org/contextmapper/lakesidemutual/example/LakesideMutualContextMapDiscoverer.java) main method to generate the Context Map. 64 | 65 | **Note:** Of course there are other ways how to run the example main method. You just have to ensure that your classpath contains our discovery library (find Maven or Gradle include snippets [here](https://github.com/ContextMapper/context-map-discovery#example)) and all Lakeside Mutual microservices you want to discover (for the Spring Boot discovery strategy). We added all the projects to the classpath with Gradle here (see [build.gradle](./build.gradle)). 66 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/DomainObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** 25 | * Represents a discovered domain object (part of an Aggregate). 26 | * 27 | * @author Stefan Kapferer 28 | */ 29 | public class DomainObject { 30 | 31 | private String name; 32 | private String originalType; 33 | private Set attributes; 34 | private Set methods; 35 | private String discoveryComment; 36 | private DomainObjectType type; 37 | private Aggregate parent; 38 | 39 | public DomainObject(DomainObjectType type, String name) { 40 | if (name == null || "".equals(name)) 41 | throw new IllegalArgumentException("The name of a domain object must not be null or empty."); 42 | if (type == null) 43 | throw new IllegalArgumentException("The type of a domain object must not be null."); 44 | 45 | this.type = type; 46 | this.name = name; 47 | this.attributes = new HashSet<>(); 48 | this.methods = new HashSet<>(); 49 | } 50 | 51 | public DomainObject(DomainObjectType type, String name, String originalType) { 52 | this(type, name); 53 | this.originalType = originalType; 54 | } 55 | 56 | /** 57 | * Gets the name of the domain object. 58 | * 59 | * @return the name of the domain object 60 | */ 61 | public String getName() { 62 | return name; 63 | } 64 | 65 | /** 66 | * Gets the original type of the domain object. 67 | * 68 | * @return the original type of the domain object 69 | */ 70 | public String getOriginalType() { 71 | return originalType; 72 | } 73 | 74 | /** 75 | * Gets the type of the domain object. 76 | * 77 | * @return the type of the domain object 78 | */ 79 | public DomainObjectType getType() { 80 | return type; 81 | } 82 | 83 | /** 84 | * Sets the type of the domain object. 85 | * 86 | * @param type the type of the domain object 87 | */ 88 | public void setType(DomainObjectType type) { 89 | this.type = type; 90 | } 91 | 92 | /** 93 | * Adds a new attribute to the domain object. 94 | * 95 | * @param attribute the attribute to be added to the domain object 96 | */ 97 | public void addAttribute(Attribute attribute) { 98 | attribute.setParent(this); 99 | this.attributes.add(attribute); 100 | } 101 | 102 | /** 103 | * Gets the set of attributes of the domain object. 104 | * 105 | * @return the set of attributes of the domain object 106 | */ 107 | public Set getAttributes() { 108 | return new HashSet<>(attributes); 109 | } 110 | 111 | /** 112 | * Adds a new method to the domain object. 113 | * 114 | * @param method the method to be added to the domain object 115 | */ 116 | public void addMethod(Method method) { 117 | method.setParent(this); 118 | this.methods.add(method); 119 | } 120 | 121 | /** 122 | * Gets the set of methods of the domain object. 123 | * 124 | * @return the set of methods of the domain object 125 | */ 126 | public Set getMethods() { 127 | return new HashSet<>(methods); 128 | } 129 | 130 | /** 131 | * Sets a comment describing how the domain object has been discovered. 132 | * 133 | * @param discoveryComment the comment describing how the domain object has been discovered 134 | */ 135 | public void setDiscoveryComment(String discoveryComment) { 136 | this.discoveryComment = discoveryComment; 137 | } 138 | 139 | /** 140 | * Gets a comment describing how the domain object has been discovered. 141 | * 142 | * @return the comment describing how the domain object has been discovered 143 | */ 144 | public String getDiscoveryComment() { 145 | return discoveryComment; 146 | } 147 | 148 | /** 149 | * Gets the parent Aggregate of which the domain object is part of. 150 | * 151 | * @return the parent Aggregate 152 | */ 153 | public Aggregate getParent() { 154 | return parent; 155 | } 156 | 157 | /** 158 | * Sets the parent Aggregate of which the domain object is part of. 159 | * 160 | * @param parent the parent Aggregate 161 | */ 162 | public void setParent(Aggregate parent) { 163 | this.parent = parent; 164 | } 165 | 166 | @Override 167 | public boolean equals(Object object) { 168 | if (!(object instanceof DomainObject)) 169 | return false; 170 | 171 | DomainObject domainObject = (DomainObject) object; 172 | 173 | return new EqualsBuilder() 174 | .append(type, domainObject.type) 175 | .append(name, domainObject.name) 176 | .isEquals(); 177 | } 178 | 179 | @Override 180 | public int hashCode() { 181 | return new HashCodeBuilder() 182 | .append(type) 183 | .append(name) 184 | .hashCode(); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /Examples/LakesideMutual/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/ContextMapSerializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery; 17 | 18 | import org.contextmapper.discovery.model.ContextMap; 19 | import org.contextmapper.discovery.strategies.boundedcontexts.OASBoundedContextDiscoveryStrategy; 20 | import org.contextmapper.discovery.strategies.boundedcontexts.SpringBootBoundedContextDiscoveryStrategy; 21 | import org.contextmapper.discovery.strategies.names.SeparatorToCamelCaseBoundedContextNameMappingStrategy; 22 | import org.contextmapper.discovery.strategies.relationships.DockerComposeRelationshipDiscoveryStrategy; 23 | import org.junit.jupiter.api.*; 24 | 25 | import java.io.File; 26 | import java.io.IOException; 27 | 28 | import static org.contextmapper.discovery.strategies.boundedcontexts.OASBoundedContextDiscoveryStrategyTest.SAMPLE_CONTRACT_LOCATION; 29 | import static org.junit.jupiter.api.Assertions.assertFalse; 30 | import static org.junit.jupiter.api.Assertions.assertTrue; 31 | 32 | public class ContextMapSerializerTest { 33 | 34 | private final static String SRC_GEN_FOLDER = "./src-gen"; 35 | private final static String TEST_CML_FILE = SRC_GEN_FOLDER + "/microservice-test.cml"; 36 | private final static String TEST_DOMAIN_MODEL_CML_FILE = SRC_GEN_FOLDER + "/domain-model-test.cml"; 37 | private final static String TEST_OAS_CML_FILE = SRC_GEN_FOLDER + "/domain-model-test.cml"; 38 | 39 | @BeforeEach 40 | void prepare() { 41 | File srcGen = new File(SRC_GEN_FOLDER); 42 | File testCMLFile = new File(TEST_CML_FILE); 43 | File testDomainModelCMLFile = new File(TEST_DOMAIN_MODEL_CML_FILE); 44 | File oasCMLFile = new File(TEST_OAS_CML_FILE); 45 | 46 | if (!srcGen.exists()) 47 | srcGen.mkdir(); 48 | 49 | if (testCMLFile.exists()) 50 | testCMLFile.delete(); 51 | 52 | if (testDomainModelCMLFile.exists()) 53 | testDomainModelCMLFile.delete(); 54 | 55 | if (oasCMLFile.exists()) 56 | oasCMLFile.delete(); 57 | 58 | assertFalse(testCMLFile.exists()); 59 | assertFalse(testDomainModelCMLFile.exists()); 60 | assertFalse(oasCMLFile.exists()); 61 | } 62 | 63 | @Test 64 | public void canSaveDiscoveredModelAsCMLFile() throws IOException { 65 | // given 66 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 67 | .usingBoundedContextDiscoveryStrategies( 68 | new SpringBootBoundedContextDiscoveryStrategy("test.microservice.spring.boot")) 69 | .usingRelationshipDiscoveryStrategies( 70 | new DockerComposeRelationshipDiscoveryStrategy(new File("./src/test/resources/test/microservice/spring-boot"))) 71 | .usingBoundedContextNameMappingStrategies( 72 | new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-") 73 | ); 74 | 75 | // when 76 | ContextMap contextmap = discoverer.discoverContextMap(); 77 | ContextMapSerializer serializer = new ContextMapSerializer(); 78 | serializer.serializeContextMap(contextmap, new File(TEST_CML_FILE)); 79 | 80 | // then 81 | assertTrue(new File(TEST_CML_FILE).exists()); 82 | } 83 | 84 | @Test 85 | public void canSaveDiscoveredBoundedContextDomainModels() throws IOException { 86 | // given 87 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 88 | .usingBoundedContextDiscoveryStrategies( 89 | new SpringBootBoundedContextDiscoveryStrategy("test.application.spring.boot")); 90 | 91 | // when 92 | ContextMap contextmap = discoverer.discoverContextMap(); 93 | ContextMapSerializer serializer = new ContextMapSerializer(); 94 | serializer.serializeContextMap(contextmap, new File(TEST_DOMAIN_MODEL_CML_FILE)); 95 | 96 | // then 97 | assertTrue(new File(TEST_DOMAIN_MODEL_CML_FILE).exists()); 98 | } 99 | 100 | @Test 101 | public void canSerializeDiscoveredBoundedContextFromOAS() throws IOException { 102 | // given 103 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 104 | .usingBoundedContextDiscoveryStrategies(new OASBoundedContextDiscoveryStrategy(SAMPLE_CONTRACT_LOCATION)); 105 | 106 | // when 107 | ContextMap contextmap = discoverer.discoverContextMap(); 108 | ContextMapSerializer serializer = new ContextMapSerializer(); 109 | serializer.serializeContextMap(contextmap, new File(TEST_OAS_CML_FILE)); 110 | 111 | // then 112 | assertTrue(new File(TEST_OAS_CML_FILE).exists()); 113 | } 114 | 115 | @Test 116 | public void cannotSerializeOtherThanCMLFile() { 117 | // given 118 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 119 | .usingBoundedContextDiscoveryStrategies( 120 | new SpringBootBoundedContextDiscoveryStrategy("test.microservice.spring.boot")); 121 | 122 | // when, then 123 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 124 | new ContextMapSerializer().serializeContextMap(discoverer.discoverContextMap(), new File("test.ext")); 125 | }); 126 | } 127 | 128 | @Test 129 | public void cannotSerializeEmptyContextMap() { 130 | // given 131 | ContextMap contextMap = new ContextMap(); 132 | 133 | // when, then 134 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 135 | new ContextMapSerializer().serializeContextMap(contextMap, new File("test.cml")); 136 | }); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/model/DomainObjectTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.contextmapper.discovery.model.DomainObjectType.ENTITY; 22 | import static org.contextmapper.discovery.model.DomainObjectType.VALUE_OBJECT; 23 | import static org.junit.jupiter.api.Assertions.*; 24 | 25 | public class DomainObjectTest { 26 | 27 | @Test 28 | public void canCreateEntity() { 29 | // given 30 | DomainObject domainObject; 31 | 32 | // when 33 | domainObject = new DomainObject(ENTITY, "Customer", "test.Customer"); 34 | 35 | // then 36 | assertEquals("test.Customer", domainObject.getOriginalType()); 37 | assertEquals("Customer", domainObject.getName()); 38 | } 39 | 40 | @Test 41 | public void canAddAttribute() { 42 | // given 43 | DomainObject domainObject = new DomainObject(ENTITY, "Name", "Type"); 44 | 45 | // when 46 | Attribute attribute = new Attribute(new Type("String"), "attr1"); 47 | domainObject.addAttribute(attribute); 48 | 49 | // then 50 | assertEquals(1, domainObject.getAttributes().size()); 51 | Attribute attribute1 = domainObject.getAttributes().iterator().next(); 52 | assertEquals(attribute, attribute1); 53 | assertEquals(domainObject, attribute1.getParent()); 54 | assertEquals("String", attribute1.getType().getPrimitiveType()); 55 | assertEquals("attr1", attribute1.getName()); 56 | assertFalse(attribute1.equals(new Object())); 57 | } 58 | 59 | @Test 60 | public void canAddReference() { 61 | // given 62 | DomainObject domainObject = new DomainObject(ENTITY, "Name", "test.Entity"); 63 | DomainObject referencedDomainObject = new DomainObject(ENTITY, "ReferencedType", "test.ReferencedType"); 64 | 65 | // when 66 | Attribute reference = new Attribute(new Type(referencedDomainObject), "reference"); 67 | domainObject.addAttribute(reference); 68 | 69 | // then 70 | assertEquals(1, domainObject.getAttributes().size()); 71 | Attribute reference1 = domainObject.getAttributes().iterator().next(); 72 | assertEquals(reference, reference1); 73 | assertEquals(domainObject, reference1.getParent()); 74 | assertEquals(referencedDomainObject, reference1.getType().getDomainObjectType()); 75 | assertEquals("reference", reference1.getName()); 76 | assertFalse(reference1.equals(new Object())); 77 | } 78 | 79 | @Test 80 | public void canAddMethod() { 81 | // given 82 | DomainObject domainObject = new DomainObject(ENTITY, "Name", "test.Entity"); 83 | Method method = new Method("testMethod"); 84 | 85 | // when 86 | domainObject.addMethod(method); 87 | 88 | // then 89 | assertEquals(1, domainObject.getMethods().size()); 90 | Method resultMethod = domainObject.getMethods().iterator().next(); 91 | assertEquals("testMethod", resultMethod.getName()); 92 | assertEquals(domainObject, resultMethod.getParent()); 93 | assertEquals(resultMethod, method); 94 | assertFalse(resultMethod.equals(new Object())); 95 | } 96 | 97 | @Test 98 | public void cannotCreateEntityWithNullName() { 99 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 100 | new DomainObject(ENTITY, null, "Type"); 101 | }); 102 | } 103 | 104 | @Test 105 | public void cannotCreateEntityWithEmptyName() { 106 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 107 | new DomainObject(ENTITY, "", "Type"); 108 | }); 109 | } 110 | 111 | @Test 112 | public void cannotCreateEntityWithNullType() { 113 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 114 | new DomainObject(null, "Name"); 115 | }); 116 | } 117 | 118 | @Test 119 | public void entitiesWithSameTypeAndNameAreEqual() { 120 | // given 121 | DomainObject domainObject1 = new DomainObject(ENTITY, "Name", "Type"); 122 | DomainObject domainObject2 = new DomainObject(ENTITY, "Name", "Type"); 123 | 124 | // when 125 | boolean equals = domainObject1.equals(domainObject1); 126 | 127 | // then 128 | assertTrue(equals); 129 | } 130 | 131 | @Test 132 | public void otherObjectsAreNotEqual() { 133 | // given 134 | DomainObject domainObject = new DomainObject(ENTITY, "Name", "Type"); 135 | 136 | // when 137 | boolean equals = domainObject.equals(new Object()); 138 | 139 | // then 140 | assertFalse(equals); 141 | } 142 | 143 | @Test 144 | public void canAddDiscoveryComment() { 145 | // given 146 | DomainObject domainObject = new DomainObject(ENTITY, "Type", "test.Type"); 147 | String discoveryComment = "This entity has been derived from the class test.Type."; 148 | 149 | // when 150 | domainObject.setDiscoveryComment(discoveryComment); 151 | 152 | // then 153 | assertEquals(discoveryComment, domainObject.getDiscoveryComment()); 154 | } 155 | 156 | @Test 157 | public void canSetType() { 158 | // given 159 | DomainObject domainObject = new DomainObject(VALUE_OBJECT, "TestType", "org.contextmapper.TestType"); 160 | 161 | // when 162 | domainObject.setType(ENTITY); 163 | 164 | // then 165 | assertEquals(ENTITY, domainObject.getType()); 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/model/Type.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.model; 17 | 18 | import org.apache.commons.lang3.builder.EqualsBuilder; 19 | import org.apache.commons.lang3.builder.HashCodeBuilder; 20 | 21 | /** 22 | * Represents a discovered type. Can occur in: operation return and parameter types 23 | * 24 | * @author Stefan Kapferer 25 | */ 26 | public class Type { 27 | 28 | private TypeKind kind; 29 | private String primitiveType; 30 | private DomainObject domainObjectType; 31 | private String collectionType; 32 | 33 | /** 34 | * Creates a primitive type. 35 | * 36 | * @param primitiveType the name of the primitive (or unknown; no domain object available for reference) type. 37 | */ 38 | public Type(String primitiveType) { 39 | if (primitiveType == null || "".equals(primitiveType)) 40 | throw new RuntimeException("Primitive type cannot be null or empty String!"); 41 | 42 | this.kind = TypeKind.PRIMITIVE; 43 | this.primitiveType = primitiveType; 44 | this.collectionType = ""; 45 | } 46 | 47 | /** 48 | * Creates a domain object type. 49 | * 50 | * @param domainObjectType the domain object that represents the type. 51 | */ 52 | public Type(DomainObject domainObjectType) { 53 | if (domainObjectType == null) 54 | throw new RuntimeException("The domain object of a domain object type cannot be null!"); 55 | 56 | this.kind = TypeKind.DOMAIN_OBJECT; 57 | this.domainObjectType = domainObjectType; 58 | this.collectionType = ""; 59 | } 60 | 61 | /** 62 | * Returns the kind of the type. Primitive or domain object. 63 | * 64 | * @return the kind of the type. 65 | */ 66 | public TypeKind getKind() { 67 | return kind; 68 | } 69 | 70 | /** 71 | * Returns the name of the type as a String. 72 | * 73 | * @return the name of the type. 74 | */ 75 | public String getName() { 76 | if (kind == TypeKind.DOMAIN_OBJECT) 77 | return domainObjectType.getName(); 78 | else 79 | return primitiveType; 80 | } 81 | 82 | /** 83 | * Returns the domain object; in case it is a domain object type. 84 | * 85 | * @return the domain object that represents the domain object type. 86 | */ 87 | public DomainObject getDomainObjectType() { 88 | if (this.kind != TypeKind.DOMAIN_OBJECT) 89 | throw new RuntimeException("This is not a domain object type!"); 90 | return domainObjectType; 91 | } 92 | 93 | /** 94 | * Returns the name of the primitive (or unknown) type; in case it is a primitive type. 95 | * 96 | * @return the name of the primitive type. 97 | */ 98 | public String getPrimitiveType() { 99 | if (this.kind != TypeKind.PRIMITIVE) 100 | throw new RuntimeException("This is not a primitive type"); 101 | return primitiveType; 102 | } 103 | 104 | /** 105 | * Indicates whether a type is a primitive (or unknown) type or not. 106 | * 107 | * @return true, in case it is a primitive type, false otherwise. 108 | */ 109 | public boolean isPrimitiveType() { 110 | return kind == TypeKind.PRIMITIVE; 111 | } 112 | 113 | /** 114 | * Indicates whether a type is a domain object type or not. 115 | * 116 | * @return true, in case is is a domain object type, false otherwise. 117 | */ 118 | public boolean isDomainObjectType() { 119 | return kind == TypeKind.DOMAIN_OBJECT; 120 | } 121 | 122 | /** 123 | * Indicates whether a type is a collection type or not. 124 | * 125 | * @return true, if a type is a collection type, false otherwise. 126 | */ 127 | public boolean isCollectionType() { 128 | return collectionType != null && !"".equals(collectionType); 129 | } 130 | 131 | /** 132 | * Sets the collection type (optional). 133 | * 134 | * @param collectionType the collection type to be set. 135 | */ 136 | public void setCollectionType(String collectionType) { 137 | this.collectionType = collectionType; 138 | } 139 | 140 | /** 141 | * Returns the collection type; in case the type is a collection type. 142 | * 143 | * @return the collection type. 144 | */ 145 | public String getCollectionType() { 146 | if (!isCollectionType()) 147 | throw new RuntimeException("This type is not a collection type"); 148 | return collectionType; 149 | } 150 | 151 | @Override 152 | public boolean equals(Object object) { 153 | if (!(object instanceof Type)) 154 | return false; 155 | 156 | Type type = (Type) object; 157 | 158 | if (kind == TypeKind.DOMAIN_OBJECT) 159 | return new EqualsBuilder() 160 | .append(domainObjectType, type.domainObjectType) 161 | .append(collectionType, type.collectionType) 162 | .isEquals(); 163 | else 164 | return new EqualsBuilder() 165 | .append(primitiveType, type.primitiveType) 166 | .append(collectionType, type.collectionType) 167 | .isEquals(); 168 | } 169 | 170 | @Override 171 | public int hashCode() { 172 | if (kind == TypeKind.DOMAIN_OBJECT) 173 | return new HashCodeBuilder() 174 | .append(domainObjectType) 175 | .append(kind) 176 | .append(collectionType) 177 | .hashCode(); 178 | else 179 | return new HashCodeBuilder() 180 | .append(primitiveType) 181 | .append(kind) 182 | .append(collectionType) 183 | .hashCode(); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/test/java/org/contextmapper/discovery/strategies/relationships/DockerComposeRelationshipDiscoveryStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.relationships; 17 | 18 | import org.contextmapper.discovery.ContextMapDiscoverer; 19 | import org.contextmapper.discovery.model.ContextMap; 20 | import org.contextmapper.discovery.model.Relationship; 21 | import org.contextmapper.discovery.strategies.boundedcontexts.SpringBootBoundedContextDiscoveryStrategy; 22 | import org.contextmapper.discovery.strategies.names.SeparatorToCamelCaseBoundedContextNameMappingStrategy; 23 | import org.junit.jupiter.api.Assertions; 24 | import org.junit.jupiter.api.Test; 25 | import org.junit.jupiter.params.ParameterizedTest; 26 | import org.junit.jupiter.params.provider.Arguments; 27 | import org.junit.jupiter.params.provider.MethodSource; 28 | 29 | import java.io.File; 30 | import java.util.List; 31 | import java.util.stream.Stream; 32 | 33 | import static org.junit.jupiter.api.Assertions.assertEquals; 34 | 35 | public class DockerComposeRelationshipDiscoveryStrategyTest { 36 | 37 | @Test 38 | public void canDiscoverRelationship() { 39 | // given 40 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 41 | .usingBoundedContextDiscoveryStrategies( 42 | new SpringBootBoundedContextDiscoveryStrategy("test.microservice.spring.boot")) 43 | .usingRelationshipDiscoveryStrategies( 44 | new DockerComposeRelationshipDiscoveryStrategy(new File("./src/test/resources/test/microservice/spring-boot"))) 45 | .usingBoundedContextNameMappingStrategies( 46 | new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-") 47 | ); 48 | 49 | // when 50 | ContextMap contextmap = discoverer.discoverContextMap(); 51 | 52 | // then 53 | assertEquals(1, contextmap.getRelationships().size()); 54 | Relationship relationship = contextmap.getRelationships().iterator().next(); 55 | assertEquals("Microservice1", relationship.getUpstream().getName()); 56 | assertEquals("Microservice2", relationship.getDownstream().getName()); 57 | } 58 | 59 | @Test 60 | public void canAddAllDiscoveredAggregatesToExposedAggregates() { 61 | // given 62 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 63 | .usingBoundedContextDiscoveryStrategies( 64 | new SpringBootBoundedContextDiscoveryStrategy("test.microservice.spring.boot")) 65 | .usingRelationshipDiscoveryStrategies( 66 | new DockerComposeRelationshipDiscoveryStrategy(new File("./src/test/resources/test/microservice/spring-boot"))) 67 | .usingBoundedContextNameMappingStrategies( 68 | new SeparatorToCamelCaseBoundedContextNameMappingStrategy("-") 69 | ); 70 | 71 | // when 72 | ContextMap contextmap = discoverer.discoverContextMap(); 73 | 74 | // then 75 | assertEquals(1, contextmap.getRelationships().size()); 76 | Relationship relationship = contextmap.getRelationships().iterator().next(); 77 | assertEquals("Microservice1", relationship.getUpstream().getName()); 78 | assertEquals("Microservice2", relationship.getDownstream().getName()); 79 | assertEquals(1, relationship.getExposedAggregates().size()); 80 | assertEquals("customers", relationship.getExposedAggregates().iterator().next().getName()); 81 | assertEquals("The list of exposed Aggregates may contain Aggregates which are not used by the downstream " + 82 | "(discovery strategy simply added all Aggregates).", relationship.getExposedAggregatesComment()); 83 | } 84 | 85 | @ParameterizedTest 86 | @MethodSource("noServicesDockerComposeFiles") 87 | public void emptyResultIfDockerComposeFileDoesNotContainServices(String sourcePath) { 88 | // given 89 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 90 | .usingBoundedContextDiscoveryStrategies( 91 | new SpringBootBoundedContextDiscoveryStrategy("test.microservice.spring.boot")) 92 | .usingRelationshipDiscoveryStrategies( 93 | new DockerComposeRelationshipDiscoveryStrategy(new File(sourcePath)) 94 | ); 95 | 96 | // when 97 | ContextMap contextmap = discoverer.discoverContextMap(); 98 | 99 | // then 100 | assertEquals(0, contextmap.getRelationships().size()); 101 | } 102 | 103 | private static Stream noServicesDockerComposeFiles() { 104 | return Stream.of(Arguments.of("./src/test/resources/test/docker/compose/no-services-1"), 105 | Arguments.of("./src/test/resources/test/docker/compose/no-services-2")); 106 | } 107 | 108 | @Test 109 | public void throwExceptionIfFileDoesNotExist() { 110 | // given 111 | ContextMapDiscoverer discoverer = new ContextMapDiscoverer() 112 | .usingBoundedContextDiscoveryStrategies( 113 | new SpringBootBoundedContextDiscoveryStrategy("test.microservice.spring.boot")) 114 | .usingRelationshipDiscoveryStrategies( 115 | new TestDockerComposeStrategy(new File("./src/test/resources/test/microservice/spring-boot")) 116 | ); 117 | 118 | // when, then 119 | Assertions.assertThrows(IllegalArgumentException.class, () -> { 120 | discoverer.discoverContextMap(); 121 | }); 122 | } 123 | 124 | private class TestDockerComposeStrategy extends DockerComposeRelationshipDiscoveryStrategy { 125 | public TestDockerComposeStrategy(File sourcePath) { 126 | super(sourcePath); 127 | } 128 | 129 | @Override 130 | protected List parseDependencies(File dockerComposeFile) { 131 | return super.parseDependencies(new File("this-docker-compose-file-does-not-exist.yml")); 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/contextmapper/discovery/strategies/boundedcontexts/OASBoundedContextDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Context Mapper Project Team 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 | * http://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.contextmapper.discovery.strategies.boundedcontexts; 17 | 18 | import com.google.common.collect.Sets; 19 | import io.swagger.v3.oas.models.OpenAPI; 20 | import io.swagger.v3.oas.models.Operation; 21 | import io.swagger.v3.oas.models.PathItem; 22 | import io.swagger.v3.oas.models.media.ArraySchema; 23 | import io.swagger.v3.oas.models.media.Content; 24 | import io.swagger.v3.oas.models.media.Schema; 25 | import io.swagger.v3.oas.models.responses.ApiResponse; 26 | import io.swagger.v3.parser.OpenAPIV3Parser; 27 | import io.swagger.v3.parser.core.models.ParseOptions; 28 | import io.swagger.v3.parser.models.RefType; 29 | import org.contextmapper.discovery.cml.CMLPrimitiveTypeMapper; 30 | import org.contextmapper.discovery.model.*; 31 | import org.slf4j.Logger; 32 | import org.slf4j.LoggerFactory; 33 | 34 | import java.util.HashMap; 35 | import java.util.Map; 36 | import java.util.Set; 37 | 38 | /** 39 | * Discovers Bounded Contexts with OpenAPI specifications as input. 40 | * 41 | * @author Stefan Kapferer 42 | */ 43 | public class OASBoundedContextDiscoveryStrategy implements BoundedContextDiscoveryStrategy { 44 | 45 | private static Logger LOG = LoggerFactory.getLogger(OASBoundedContextDiscoveryStrategy.class); 46 | 47 | private static final String JSON_MEDIA_TYPE = "application/json"; 48 | 49 | private Set oasLocations; 50 | private CMLPrimitiveTypeMapper typeMapper; 51 | private Map> domainObjectMap; 52 | private OpenAPI currentOAS; 53 | 54 | public OASBoundedContextDiscoveryStrategy(String... oasLocations) { 55 | this.oasLocations = Sets.newHashSet(oasLocations); 56 | this.typeMapper = new CMLPrimitiveTypeMapper(); 57 | this.domainObjectMap = new HashMap<>(); 58 | } 59 | 60 | @Override 61 | public Set discoverBoundedContexts() { 62 | var boundedContexts = Sets.newHashSet(); 63 | for (String location : this.oasLocations) { 64 | var parseResult = new OpenAPIV3Parser().readLocation(location, null, new ParseOptions()); 65 | if (!parseResult.getMessages().isEmpty()) 66 | LOG.error("Parsing the OAS '" + location + "' resulted in validation errors: " + String.join(", ", parseResult.getMessages())); 67 | currentOAS = parseResult.getOpenAPI(); 68 | if (currentOAS == null) 69 | throw new RuntimeException("Could not successfully parse OAS!"); 70 | boundedContexts.add(discoverBoundedContext(currentOAS)); 71 | } 72 | return boundedContexts; 73 | } 74 | 75 | private BoundedContext discoverBoundedContext(OpenAPI oas) { 76 | var bc = new BoundedContext(oas.getInfo().getTitle()); 77 | for (Map.Entry entry : oas.getPaths().entrySet()) { 78 | bc.addAggregate(discoverAggregate(entry.getKey(), entry.getValue())); 79 | } 80 | return bc; 81 | } 82 | 83 | private Aggregate discoverAggregate(String pathItemKey, PathItem pathItem) { 84 | var aggregateName = pathItemKey.substring(1).replace("/", "_"); // path key must start with '/'! 85 | var aggregate = new Aggregate(aggregateName); 86 | aggregate.setDiscoveryComment(pathItem.getSummary()); 87 | 88 | var service = new Service(aggregateName + "Service"); 89 | service.setDiscoveryComment("This service contains all operations of the following endpoint: " + pathItemKey); 90 | aggregate.addService(service); 91 | 92 | addOperationToService(service, discoverOperation(aggregate, pathItem.getGet())); 93 | addOperationToService(service, discoverOperation(aggregate, pathItem.getPut())); 94 | addOperationToService(service, discoverOperation(aggregate, pathItem.getPost())); 95 | addOperationToService(service, discoverOperation(aggregate, pathItem.getDelete())); 96 | addOperationToService(service, discoverOperation(aggregate, pathItem.getOptions())); 97 | addOperationToService(service, discoverOperation(aggregate, pathItem.getHead())); 98 | addOperationToService(service, discoverOperation(aggregate, pathItem.getPatch())); 99 | addOperationToService(service, discoverOperation(aggregate, pathItem.getTrace())); 100 | 101 | return aggregate; 102 | } 103 | 104 | private void addOperationToService(Service service, Method operation) { 105 | if (operation != null) 106 | service.addOperation(operation); 107 | } 108 | 109 | private Method discoverOperation(Aggregate aggregate, Operation oasOperation) { 110 | if (oasOperation == null || oasOperation.getOperationId() == null || "".equals(oasOperation.getOperationId())) 111 | return null; 112 | 113 | var operation = new Method(oasOperation.getOperationId()); 114 | 115 | // parameters 116 | if (oasOperation.getParameters() != null) { 117 | for (io.swagger.v3.oas.models.parameters.Parameter parameter : oasOperation.getParameters()) { 118 | operation.addParameter(discoverParameter(aggregate, parameter)); 119 | } 120 | } 121 | 122 | // request body 123 | if (oasOperation.getRequestBody() != null && oasOperation.getRequestBody().getContent() != null && 124 | oasOperation.getRequestBody().getContent().containsKey(JSON_MEDIA_TYPE)) { 125 | operation.addParameter(new Parameter("input", 126 | createType4JSONContent(oasOperation.getRequestBody().getContent(), aggregate, 127 | formatTypeName(oasOperation.getOperationId() + "ParameterType")))); 128 | } 129 | 130 | // return type (currently an endpoint can only have one response, otherwise we do not discover) 131 | if (oasOperation.getResponses() != null && oasOperation.getResponses().size() == 1) { 132 | String responseKey = oasOperation.getResponses().keySet().iterator().next(); 133 | ApiResponse response = oasOperation.getResponses().get(responseKey); 134 | // we currently only support json; TODO: implement more generic solution 135 | if (response.getContent() != null && response.getContent().containsKey(JSON_MEDIA_TYPE)) 136 | operation.setReturnType(createType4JSONContent(response.getContent(), aggregate, oasOperation.getOperationId() + "ReturnType")); 137 | } 138 | 139 | return operation; 140 | } 141 | 142 | private Parameter discoverParameter(Aggregate aggregate, io.swagger.v3.oas.models.parameters.Parameter oasParameter) { 143 | var schema = oasParameter.getSchema(); 144 | if (isRefSchema(schema)) 145 | schema = resolveSchemaByRef(schema.get$ref()); 146 | return new Parameter(oasParameter.getName(), createType4Schema(aggregate, schema, oasParameter.getName() + "Type")); 147 | } 148 | 149 | private Type createType4JSONContent(Content content, Aggregate aggregate, String inputTypeName) { 150 | Schema schema = content.get(JSON_MEDIA_TYPE).getSchema(); 151 | var typeName = inputTypeName; 152 | if (isRefSchema(schema)) { 153 | typeName = getTypeNameFromSchemaRef(schema.get$ref()); 154 | schema = resolveSchemaByRef(schema.get$ref()); 155 | } 156 | return createType4Schema(aggregate, schema, typeName); 157 | } 158 | 159 | private Type createType4Schema(Aggregate aggregate, Schema inputSchema, String inputTypeName) { 160 | var schema = inputSchema; 161 | var typeName = inputTypeName; 162 | if (isRefSchema(schema)) { 163 | typeName = getTypeNameFromSchemaRef(schema.get$ref()); 164 | schema = resolveSchemaByRef(schema.get$ref()); 165 | } 166 | 167 | switch (schema.getType()) { 168 | case "object": 169 | DomainObject object = createEntity4Schema(aggregate, formatTypeName(typeName), schema); 170 | return new Type(object); 171 | case "array": 172 | ArraySchema arraySchema = (ArraySchema) schema; 173 | Type type = createType4Schema(aggregate, arraySchema.getItems(), typeName); 174 | type.setCollectionType("List"); 175 | return type; 176 | default: 177 | return new Type(typeMapper.mapType(schema.getType())); 178 | } 179 | } 180 | 181 | private DomainObject createEntity4Schema(Aggregate aggregate, String objectName, Schema objectSchema) { 182 | if (!domainObjectMap.containsKey(aggregate)) 183 | domainObjectMap.put(aggregate, new HashMap<>()); 184 | 185 | // don't create a new object, if an entity with that name already exists 186 | if (domainObjectMap.get(aggregate).containsKey(objectName)) 187 | return domainObjectMap.get(aggregate).get(objectName); 188 | 189 | // create entity 190 | var domainObject = new DomainObject(DomainObjectType.ENTITY, objectName); 191 | for (String propertyKey : (Set) objectSchema.getProperties().keySet()) { 192 | var property = (Schema) objectSchema.getProperties().get(propertyKey); 193 | if (isRefSchema(property)) 194 | property = resolveSchemaByRef(property.get$ref()); 195 | Type type = null; 196 | switch (property.getType()) { 197 | case "object": 198 | type = new Type(createEntity4Schema(aggregate, formatTypeName(propertyKey + "Type"), property)); 199 | break; 200 | default: 201 | type = new Type(typeMapper.mapType(property.getType())); 202 | } 203 | domainObject.addAttribute(new Attribute(type, propertyKey)); 204 | } 205 | 206 | aggregate.addDomainObject(domainObject); 207 | domainObjectMap.get(aggregate).put(objectName, domainObject); 208 | return domainObject; 209 | } 210 | 211 | private String formatTypeName(String typeName) { 212 | return typeName.substring(0, 1).toUpperCase() + (typeName.length() > 1 ? typeName.substring(1) : ""); 213 | } 214 | 215 | private boolean isRefSchema(Schema schema) { 216 | return schema.get$ref() != null && !"".equals(schema.get$ref()); 217 | } 218 | 219 | private Schema resolveSchemaByRef(String ref) { 220 | return currentOAS.getComponents().getSchemas().get(getTypeNameFromSchemaRef(ref)); 221 | } 222 | 223 | private String getTypeNameFromSchemaRef(String ref) { 224 | return ref.replace(RefType.SCHEMAS.getInternalPrefix(), ""); 225 | } 226 | 227 | } 228 | --------------------------------------------------------------------------------