├── .gitignore
├── Dockerfile
├── azure-pipelines.yml
├── github
├── images
│ ├── consul-after-registration.png
│ ├── eureka-after-registration.png
│ ├── use-case-overview.png
│ ├── use-case-role-system.png
│ └── use-case-role-user.png
├── resources
│ └── Technolords.xml
└── uml
│ ├── use-case-overview.uxf
│ ├── use-case-role-system.uxf
│ └── use-case-role-user.uxf
├── license.md
├── pom.xml
├── readme.md
└── src
├── main
├── java
│ └── net
│ │ └── technolords
│ │ └── micro
│ │ ├── camel
│ │ ├── MockMain.java
│ │ ├── lifecycle
│ │ │ └── MainLifecycleStrategy.java
│ │ ├── listener
│ │ │ └── MockMainListener.java
│ │ ├── processor
│ │ │ ├── EurekaRenewalProcessor.java
│ │ │ └── ResponseProcessor.java
│ │ └── route
│ │ │ ├── EurekaRenewalRoute.java
│ │ │ └── MockRoute.java
│ │ ├── command
│ │ ├── Command.java
│ │ ├── CommandManager.java
│ │ ├── ConfigCommand.java
│ │ ├── LogCommand.java
│ │ ├── ReloadCommand.java
│ │ ├── ResetCommand.java
│ │ ├── StatsCommand.java
│ │ └── StopCommand.java
│ │ ├── config
│ │ ├── ConfigurationManager.java
│ │ └── PropertiesManager.java
│ │ ├── filter
│ │ └── InfoFilter.java
│ │ ├── input
│ │ ├── ConfigurationSelector.java
│ │ ├── json
│ │ │ └── JsonPathEvaluator.java
│ │ └── xml
│ │ │ ├── ConfigurationToNamespaceContext.java
│ │ │ ├── DefaultNamespaceContext.java
│ │ │ └── XpathEvaluator.java
│ │ ├── log
│ │ └── LogManager.java
│ │ ├── model
│ │ ├── ResponseContext.java
│ │ └── jaxb
│ │ │ ├── Configuration.java
│ │ │ ├── Configurations.java
│ │ │ ├── namespace
│ │ │ ├── NamespaceConfig.java
│ │ │ └── NamespaceList.java
│ │ │ ├── package-info.java
│ │ │ ├── query
│ │ │ ├── QueryGroup.java
│ │ │ ├── QueryGroups.java
│ │ │ └── QueryParameter.java
│ │ │ ├── registration
│ │ │ ├── HealthCheck.java
│ │ │ ├── Registration.java
│ │ │ ├── Service.java
│ │ │ └── ServiceRegistration.java
│ │ │ └── resource
│ │ │ ├── JsonpathConfig.java
│ │ │ ├── ResourceGroup.java
│ │ │ ├── ResourceGroups.java
│ │ │ ├── SimpleResource.java
│ │ │ └── XpathConfig.java
│ │ ├── output
│ │ └── ResponseContextGenerator.java
│ │ └── registry
│ │ ├── MockRegistry.java
│ │ ├── ServiceRegistrationManager.java
│ │ ├── consul
│ │ ├── ConsulPayloadFactory.java
│ │ └── ConsulRequestFactory.java
│ │ ├── eureka
│ │ ├── EurekaPayloadFactory.java
│ │ └── EurekaRequestFactory.java
│ │ └── util
│ │ └── MetadataHelper.java
└── resources
│ ├── build-meta-data.txt
│ ├── log4j2.xml
│ ├── mock
│ ├── local-traxis-structure-service.json
│ ├── remote-traxis-structure-service.json
│ ├── sample-get-complex.json
│ ├── sample-get-default.json
│ ├── sample-get.json
│ ├── sample-post1.json
│ ├── sample-post2.json
│ └── sample-post4.txt
│ ├── xml
│ └── default-configuration.xml
│ └── xsd
│ └── configurations.xsd
└── test
├── java
└── net
│ └── technolords
│ └── micro
│ ├── RouteTestSupport.java
│ ├── camel
│ ├── listener
│ │ └── MockTestListener.java
│ └── processor
│ │ └── ResponseProcessorTest.java
│ ├── command
│ ├── CommandManagerTest.java
│ ├── ConfigCommandTest.java
│ ├── StatsCommandTest.java
│ └── StopCommandTest.java
│ ├── config
│ ├── ConfigurationManagerTest.java
│ └── ConfigurationsTest.java
│ ├── input
│ └── ConfigurationSelectorTest.java
│ ├── log
│ └── LogManagerTest.java
│ ├── registry
│ ├── consul
│ │ └── ConsulPayloadFactoryTest.java
│ ├── eureka
│ │ ├── EurekaPayloadFactoryTest.java
│ │ └── EurekaRequestFactoryTest.java
│ └── util
│ │ └── MetadataHelperTest.java
│ ├── test
│ ├── PathSupport.java
│ ├── PathSupportTest.java
│ └── factory
│ │ ├── ConfigurationsFactory.java
│ │ └── ServiceFactory.java
│ └── util
│ └── WhitespaceFilter.java
└── resources
├── config
├── log
│ └── config-for-LogManagerTest.xml
├── mock
│ ├── config-1-for-ConfigCommandTest.xml
│ ├── config-2-for-ConfigCommandTest.xml
│ ├── config-for-AllOperationsTest.xml
│ ├── config-for-CommandManagerTest.xml
│ ├── config-for-ConfigSelectorTest.xml
│ ├── config-for-ConfigurationManagerTest.xml
│ ├── config-for-ResponseProcessorTest.xml
│ └── test-configuration-with-queryParams.xml
└── registration
│ └── config-for-registrations.xml
├── data
├── request
│ └── post-1-for-ResponseProcessorTest.xml
└── response
│ ├── get-1-for-ConfigurationManagerTest.txt
│ ├── get-1-for-ResponseProcessorTest.txt
│ ├── get-2-for-ConfigurationManagerTest.txt
│ ├── get-3-for-ConfigurationManagerTest.json
│ ├── post-1-for-ResponseProcessorTest.txt
│ ├── post-2-for-ResponseProcessorTest.txt
│ ├── sample-get-122333.json
│ ├── sample-get-complex.json
│ └── sample-get-default.json
└── json
├── consul-payload-register.json
└── eureka-payload-register.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | target/
3 | *.iml
4 | dependency-reduced-pom.xml
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8
2 |
3 | ARG MOCK_VERSION
4 | ARG JAR_FILE
5 |
6 | LABEL mock.version=${MOCK_VERSION}
7 |
8 | RUN mkdir -p /etc/mock
9 |
10 | ADD target/${JAR_FILE} /etc/mock/mock.jar
11 |
12 | EXPOSE 9090
13 |
14 | VOLUME ["/var/mock"]
15 |
16 | WORKDIR "/etc/mock/"
17 |
18 | ENTRYPOINT ["sh","-c", "java ${JAVA_OPTS} -jar /etc/mock/mock.jar"]
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Starter pipeline
2 | # Start with a minimal pipeline that you can customize to build and deploy your code.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - master
8 |
9 | pool:
10 | vmImage: ubuntu-latest
11 |
12 | steps:
13 | - script: echo Hello, world!
14 | displayName: 'Run a one-line script'
15 |
16 | - script: |
17 | echo Add other tasks to build, test, and deploy your project.
18 | echo See https://aka.ms/yaml
19 | displayName: 'Run a multi-line script'
20 |
--------------------------------------------------------------------------------
/github/images/consul-after-registration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Technolords/microservice-mock/86bf8a30b606b3ddfbf803d0fd3e81bdc2f31ce0/github/images/consul-after-registration.png
--------------------------------------------------------------------------------
/github/images/eureka-after-registration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Technolords/microservice-mock/86bf8a30b606b3ddfbf803d0fd3e81bdc2f31ce0/github/images/eureka-after-registration.png
--------------------------------------------------------------------------------
/github/images/use-case-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Technolords/microservice-mock/86bf8a30b606b3ddfbf803d0fd3e81bdc2f31ce0/github/images/use-case-overview.png
--------------------------------------------------------------------------------
/github/images/use-case-role-system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Technolords/microservice-mock/86bf8a30b606b3ddfbf803d0fd3e81bdc2f31ce0/github/images/use-case-role-system.png
--------------------------------------------------------------------------------
/github/images/use-case-role-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Technolords/microservice-mock/86bf8a30b606b3ddfbf803d0fd3e81bdc2f31ce0/github/images/use-case-role-user.png
--------------------------------------------------------------------------------
/github/resources/Technolords.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/github/uml/use-case-overview.uxf:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10
4 |
5 | UMLGeneric
6 |
7 | 430
8 | 60
9 | 600
10 | 580
11 |
12 | halign=left
13 | Mock
14 |
15 |
16 |
17 | UMLActor
18 |
19 | 250
20 | 440
21 | 80
22 | 110
23 |
24 | System
25 |
26 |
27 |
28 | UMLActor
29 |
30 | 260
31 | 170
32 | 60
33 | 110
34 |
35 | User
36 |
37 |
38 |
39 | UMLPackage
40 |
41 | 1110
42 | 450
43 | 140
44 | 70
45 |
46 | bg=gray
47 | File
48 | --
49 | response
50 |
51 |
52 |
53 |
54 | UMLPackage
55 |
56 | 1110
57 | 180
58 | 140
59 | 70
60 |
61 | bg=gray
62 | File
63 | --
64 | configuration
65 |
66 |
67 |
68 |
69 | UMLUseCase
70 |
71 | 540
72 | 190
73 | 130
74 | 60
75 |
76 | Execute
77 | command
78 |
79 |
80 |
81 | UMLUseCase
82 |
83 | 540
84 | 460
85 | 130
86 | 60
87 |
88 | Generate
89 | response
90 |
91 |
92 |
93 | Relation
94 |
95 | 300
96 | 200
97 | 260
98 | 40
99 |
100 |
101 | 10.0;20.0;240.0;20.0
102 |
103 |
104 | Relation
105 |
106 | 300
107 | 470
108 | 260
109 | 40
110 |
111 |
112 | 10.0;20.0;240.0;20.0
113 |
114 |
115 | Relation
116 |
117 | 660
118 | 470
119 | 160
120 | 40
121 |
122 | lt=.>
123 | <<includes>>
124 | 140.0;20.0;10.0;20.0
125 |
126 |
127 | UMLUseCase
128 |
129 | 800
130 | 460
131 | 130
132 | 60
133 |
134 | Read
135 | resource
136 |
137 |
138 |
139 | Relation
140 |
141 | 920
142 | 470
143 | 210
144 | 40
145 |
146 |
147 | 10.0;20.0;190.0;20.0
148 |
149 |
150 | UMLUseCase
151 |
152 | 800
153 | 190
154 | 130
155 | 60
156 |
157 | Read
158 | configuration
159 |
160 |
161 |
162 | Relation
163 |
164 | 620
165 | 230
166 | 220
167 | 250
168 |
169 | lt=.>
170 | <<includes>>
171 | 200.0;10.0;10.0;230.0
172 |
173 |
174 | Relation
175 |
176 | 920
177 | 200
178 | 210
179 | 40
180 |
181 |
182 | 10.0;20.0;190.0;20.0
183 |
184 |
185 |
--------------------------------------------------------------------------------
/github/uml/use-case-role-system.uxf:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10
4 |
5 | UMLActor
6 |
7 | 150
8 | 290
9 | 80
10 | 110
11 |
12 | System
13 |
14 |
15 |
16 | UMLGeneric
17 |
18 | 260
19 | 40
20 | 690
21 | 590
22 |
23 | halign=left
24 | Mock
25 |
26 |
27 |
28 | UMLUseCase
29 |
30 | 310
31 | 310
32 | 130
33 | 60
34 |
35 | Handle
36 | request
37 |
38 |
39 |
40 | Relation
41 |
42 | 200
43 | 320
44 | 130
45 | 40
46 |
47 |
48 | 10.0;20.0;110.0;20.0
49 |
50 |
51 | Relation
52 |
53 | 610
54 | 210
55 | 150
56 | 80
57 |
58 | lt=.>
59 | <<includes>>
60 | 130.0;60.0;10.0;10.0
61 |
62 |
63 | UMLUseCase
64 |
65 | 740
66 | 250
67 | 130
68 | 60
69 |
70 | Read
71 | resource
72 |
73 |
74 |
75 | UMLUseCase
76 |
77 | 510
78 | 170
79 | 130
80 | 60
81 |
82 | Read
83 | configuration
84 |
85 |
86 |
87 | Relation
88 |
89 | 420
90 | 220
91 | 140
92 | 120
93 |
94 | lt=.>
95 | <<includes>>
96 | 120.0;10.0;10.0;100.0
97 |
98 |
99 | UMLUseCase
100 |
101 | 740
102 | 90
103 | 130
104 | 60
105 |
106 | Find matching
107 | API
108 |
109 |
110 |
111 | Relation
112 |
113 | 610
114 | 120
115 | 150
116 | 80
117 |
118 | lt=.>
119 | <<includes>>
120 | 130.0;10.0;10.0;60.0
121 |
122 |
123 | UMLUseCase
124 |
125 | 740
126 | 520
127 | 130
128 | 60
129 |
130 | Delay
131 | response
132 |
133 |
134 |
135 | Relation
136 |
137 | 410
138 | 350
139 | 140
140 | 110
141 |
142 | lt=.>
143 | <<extends>>
144 | 10.0;10.0;120.0;90.0
145 |
146 |
147 | UMLUseCase
148 |
149 | 520
150 | 430
151 | 130
152 | 60
153 |
154 | Generate
155 | response
156 |
157 |
158 |
159 | Relation
160 |
161 | 620
162 | 470
163 | 150
164 | 80
165 |
166 | lt=.>
167 | <<includes>>
168 | 130.0;60.0;10.0;10.0
169 |
170 |
171 | UMLUseCase
172 |
173 | 740
174 | 350
175 | 130
176 | 60
177 |
178 | Status
179 | code
180 |
181 |
182 |
183 | Relation
184 |
185 | 620
186 | 380
187 | 140
188 | 80
189 |
190 | lt=.>
191 | <<includes>>
192 | 120.0;10.0;10.0;60.0
193 |
194 |
195 | UMLPackage
196 |
197 | 1030
198 | 240
199 | 140
200 | 70
201 |
202 | bg=gray
203 | File
204 | --
205 | response
206 |
207 |
208 |
209 |
210 | Relation
211 |
212 | 860
213 | 260
214 | 190
215 | 40
216 |
217 |
218 | 10.0;20.0;170.0;20.0
219 |
220 |
221 | UMLPackage
222 |
223 | 1030
224 | 150
225 | 140
226 | 70
227 |
228 | bg=gray
229 | File
230 | --
231 | configuration
232 |
233 |
234 |
235 |
236 | Relation
237 |
238 | 630
239 | 170
240 | 420
241 | 40
242 |
243 |
244 | 10.0;20.0;400.0;20.0
245 |
246 |
247 |
--------------------------------------------------------------------------------
/github/uml/use-case-role-user.uxf:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10
4 |
5 | UMLActor
6 |
7 | 120
8 | 310
9 | 60
10 | 110
11 |
12 | User
13 |
14 |
15 |
16 | UMLGeneric
17 |
18 | 280
19 | 110
20 | 770
21 | 510
22 |
23 | halign=left
24 | Mock
25 |
26 |
27 |
28 | UMLUseCase
29 |
30 | 400
31 | 320
32 | 130
33 | 60
34 |
35 | Execute
36 | command
37 |
38 |
39 |
40 | Relation
41 |
42 | 160
43 | 330
44 | 260
45 | 40
46 |
47 |
48 | 10.0;20.0;240.0;20.0
49 |
50 |
51 | UMLUseCase
52 |
53 | 630
54 | 210
55 | 130
56 | 60
57 |
58 | Manage
59 | log level
60 |
61 |
62 |
63 | Relation
64 |
65 | 510
66 | 250
67 | 160
68 | 100
69 |
70 | lt=.>
71 | <<includes>>
72 | 140.0;10.0;10.0;80.0
73 |
74 |
75 | UMLUseCase
76 |
77 | 410
78 | 150
79 | 130
80 | 60
81 |
82 | Terminate
83 | JVM
84 |
85 |
86 |
87 | Relation
88 |
89 | 460
90 | 200
91 | 100
92 | 140
93 |
94 | lt=.>
95 | <<includes>>
96 | 10.0;10.0;10.0;120.0
97 |
98 |
99 | UMLUseCase
100 |
101 | 630
102 | 410
103 | 130
104 | 60
105 |
106 | Query
107 | stats
108 |
109 |
110 |
111 | UMLUseCase
112 |
113 | 410
114 | 520
115 | 130
116 | 60
117 |
118 | Replace
119 | configuration
120 |
121 |
122 |
123 | Relation
124 |
125 | 460
126 | 370
127 | 100
128 | 170
129 |
130 | lt=.>
131 | <<includes>>
132 | 10.0;150.0;10.0;10.0
133 |
134 |
135 | Relation
136 |
137 | 510
138 | 360
139 | 150
140 | 80
141 |
142 | lt=.>
143 | <<includes>>
144 | 130.0;60.0;10.0;10.0
145 |
146 |
147 | UMLUseCase
148 |
149 | 860
150 | 410
151 | 130
152 | 60
153 |
154 | Reset
155 | stats
156 |
157 |
158 |
159 | Relation
160 |
161 | 750
162 | 420
163 | 130
164 | 40
165 |
166 | lt=.>
167 | <<extends>>
168 | 10.0;20.0;110.0;20.0
169 |
170 |
171 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Technolords (Mike Ahlers)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Microservice mock
2 |
3 | [](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22net.technolords.micro.service%22%20mock)
4 | [](https://hub.docker.com/r/technolords/mock/)
5 | [](https://technolords.slack.com/messages/CA2A4FSEN/)
6 |
7 | ## Introduction
8 |
9 | This micro service represents a configurable webservice that can mock any other web service by means of configuration.
10 | When a request is made to the mock service, it checks the configuration for a matching URI. When a match is found,
11 | the associated response from the configuration is returned.
12 |
13 | ## References
14 |
15 | The table below provides some reference, sorted by alphabet:
16 |
17 | Reference | Remarks
18 | ----------|--------
19 | [Configurations](https://github.com/Technolords/microservice-mock/wiki/Configurations) | How to configure the micro service
20 | [Installations](https://github.com/Technolords/microservice-mock/wiki/Installations) | How to install and/or deploy the micro service
21 | [Logging](https://github.com/Technolords/microservice-mock/wiki/Logging) | How to configure logging
22 | [Roadmap](https://github.com/Technolords/microservice-mock/projects/1) | The roadmap
23 | [Runtime commands](https://github.com/Technolords/microservice-mock/wiki/Runtime-commands) | How to tweak the running instance
24 | [Service discovery](https://github.com/Technolords/microservice-mock/wiki/Service-discovery) | How to register the micro service with a service discovery
25 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/camel/MockMain.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.xml.bind.JAXBException;
6 |
7 | import org.apache.camel.main.Main;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.xml.sax.SAXException;
11 |
12 | import net.technolords.micro.camel.listener.MockMainListener;
13 | import net.technolords.micro.camel.route.EurekaRenewalRoute;
14 | import net.technolords.micro.camel.route.MockRoute;
15 | import net.technolords.micro.registry.MockRegistry;
16 |
17 | public class MockMain extends Main {
18 | private static final Logger LOGGER = LoggerFactory.getLogger(MockMain.class);
19 |
20 | /**
21 | * Default constructor which registers the start up properties.
22 | */
23 | public MockMain() {
24 | MockRegistry.registerPropertiesInRegistry(this);
25 | }
26 |
27 | /**
28 | * This method is invoked before the service is started, and performs some initialization steps. These
29 | * steps include:
30 | *
31 | * - Creation of beans, as well as adding these to the registry.
32 | * - Creation of the Camel routes, as well as adding these to the CamelContext.
33 | *
34 | * @throws JAXBException
35 | * When creation the configuration bean fails.
36 | * @throws IOException
37 | * When creation the configuration bean fails.
38 | * @throws SAXException
39 | * When creation the configuration bean fails.
40 | */
41 | @Override
42 | public void beforeStart() throws JAXBException, IOException, SAXException {
43 | LOGGER.debug("Before start called...");
44 | MockRegistry.registerBeansInRegistryBeforeStart();
45 | super.addMainListener(new MockMainListener());
46 | super.addRouteBuilder(new MockRoute());
47 | if (MockRegistry.findRegistrationManager().renewalRequired()) {
48 | LOGGER.info("Adding renewal route...");
49 | super.addRouteBuilder(new EurekaRenewalRoute());
50 | }
51 | }
52 |
53 | /**
54 | * This method is invoked after the service is started, and logs a confirmation message.
55 | */
56 | @Override
57 | public void afterStart() {
58 | LOGGER.debug("After start called...");
59 | MockRegistry.registerBeansInRegistryAfterStart();
60 | LOGGER.info("Mock service started ({}), use CTRL-C to terminate JVM", MockRegistry.findBuildMetaData());
61 | }
62 |
63 | /**
64 | * Auxiliary method to start the micro service.
65 | *
66 | * @throws Exception
67 | * When the micro service fails.
68 | */
69 | public void startService() throws Exception {
70 | super.run();
71 | }
72 |
73 | /**
74 | * The main executable.
75 | *
76 | * @param args
77 | * The arguments.
78 | *
79 | * @throws Exception
80 | * When the program fails.
81 | */
82 | public static void main(String[] args) throws Exception {
83 | LOGGER.info("About to start the Mock service...");
84 | MockMain mockedRestService = new MockMain();
85 | mockedRestService.startService();
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/camel/lifecycle/MainLifecycleStrategy.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.lifecycle;
2 |
3 | import org.apache.camel.CamelContext;
4 | import org.apache.camel.VetoCamelContextStartException;
5 | import org.apache.camel.management.DefaultManagementLifecycleStrategy;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import net.technolords.micro.registry.MockRegistry;
10 |
11 | public class MainLifecycleStrategy extends DefaultManagementLifecycleStrategy {
12 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
13 |
14 | public MainLifecycleStrategy(CamelContext camelContext) {
15 | super(camelContext);
16 | }
17 |
18 | @Override
19 | public void onContextStart(CamelContext camelContext) throws VetoCamelContextStartException {
20 | LOGGER.debug("onContextStart called...");
21 | MockRegistry.findRegistrationManager().registerService();
22 | super.onContextStart(camelContext);
23 | }
24 |
25 | @Override
26 | public void onContextStop(CamelContext context) {
27 | LOGGER.debug("onContextStop called...");
28 | MockRegistry.findRegistrationManager().deregisterService();
29 | super.onContextStop(getCamelContext());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/camel/listener/MockMainListener.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.listener;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import org.apache.camel.CamelContext;
6 | import org.apache.camel.main.MainListenerSupport;
7 | import org.apache.camel.spi.ShutdownStrategy;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import net.technolords.micro.camel.lifecycle.MainLifecycleStrategy;
12 |
13 | public class MockMainListener extends MainListenerSupport {
14 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
15 |
16 | @Override
17 | public void configure(CamelContext camelContext) {
18 | LOGGER.debug("Configure called...");
19 | this.updateShutdownStrategy(camelContext);
20 | camelContext.addLifecycleStrategy(new MainLifecycleStrategy(camelContext));
21 | }
22 |
23 | /**
24 | * Auxiliary method to configure the shutdown strategy associated with the CamelContext. As result
25 | * it will not wait longer than 1 second for any in-flight messages to complete execution.
26 | *
27 | * @param camelContext
28 | * The Camel context associated with the shutdown strategy.
29 | */
30 | private void updateShutdownStrategy(CamelContext camelContext) {
31 | LOGGER.debug("Updating shutdown strategy for camel context: {}", camelContext.getName());
32 | ShutdownStrategy shutdownStrategy = camelContext.getShutdownStrategy();
33 | shutdownStrategy.setTimeUnit(TimeUnit.SECONDS);
34 | shutdownStrategy.setTimeout(1L);
35 | shutdownStrategy.setShutdownNowOnTimeout(true);
36 | shutdownStrategy.setSuppressLoggingOnTimeout(true);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/camel/processor/EurekaRenewalProcessor.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.processor;
2 |
3 | import org.apache.camel.Exchange;
4 | import org.apache.camel.Processor;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import net.technolords.micro.registry.MockRegistry;
9 | import net.technolords.micro.registry.ServiceRegistrationManager;
10 |
11 | public class EurekaRenewalProcessor implements Processor {
12 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
13 | private ServiceRegistrationManager serviceRegistrationManager;
14 |
15 | @Override
16 | public void process(Exchange exchange) throws Exception {
17 | if (this.serviceRegistrationManager == null) {
18 | this.serviceRegistrationManager = MockRegistry.findRegistrationManager();
19 | }
20 | LOGGER.info("About to renew with {}", this.serviceRegistrationManager);
21 | this.serviceRegistrationManager.registerForAllEureka();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/camel/route/EurekaRenewalRoute.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.route;
2 |
3 | import org.apache.camel.LoggingLevel;
4 | import org.apache.camel.Processor;
5 | import org.apache.camel.builder.RouteBuilder;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import net.technolords.micro.registry.MockRegistry;
10 |
11 | public class EurekaRenewalRoute extends RouteBuilder {
12 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
13 | private static final String ROUTE_ID_RENEWAL = "RouteRenewal";
14 | private Processor renewalProcessor = null;
15 |
16 | public EurekaRenewalRoute() {
17 | this.renewalProcessor = MockRegistry.findEurekaRenewalProcessor();
18 | }
19 |
20 | @Override
21 | public void configure() throws Exception {
22 |
23 | from(this.generateTimedEndpoint())
24 | .routeId(ROUTE_ID_RENEWAL)
25 | .id(ROUTE_ID_RENEWAL)
26 | .log(LoggingLevel.TRACE, LOGGER, "Got timed event...")
27 | .process(this.renewalProcessor);
28 | }
29 |
30 | /**
31 | * Note the fixed 30s rate. This is required. See also:
32 | *
33 | * https://github.com/spring-cloud/spring-cloud-netflix/issues/373
34 | *
35 | * @return
36 | */
37 | protected String generateTimedEndpoint() {
38 | StringBuilder buffer = new StringBuilder();
39 | buffer.append("timer");
40 | buffer.append("://");
41 | buffer.append(ROUTE_ID_RENEWAL);
42 | buffer.append("?fixedRate=true");
43 | buffer.append("&delay=1000");
44 | buffer.append("&period=30s");
45 | return buffer.toString();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/camel/route/MockRoute.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.route;
2 |
3 | import org.apache.camel.Exchange;
4 | import org.apache.camel.ExchangePattern;
5 | import org.apache.camel.LoggingLevel;
6 | import org.apache.camel.Processor;
7 | import org.apache.camel.builder.RouteBuilder;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import net.technolords.micro.registry.MockRegistry;
12 |
13 | public class MockRoute extends RouteBuilder {
14 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
15 | public static final String ROUTE_ID_JETTY = "RouteJetty";
16 | public static final String ROUTE_ID_MAIN = "RouteMain";
17 | private static final String DIRECT_MAIN = "direct:main";
18 | private static final String JETTY_MAIN = "jetty:http://";
19 | private static final String JETTY_BINDING_ADDRESS = "0.0.0.0";
20 | private static final String JETTY_BINDING_PATH = "/";
21 | private static final String QUESTION_SIGN = "?";
22 | private static final String AND_SIGN = "&";
23 | private static final String EQUAL_SIGN = "=";
24 | private static final String TRUE_VALUE = "true";
25 | private String port = null;
26 | private Processor responseProcessor = null;
27 |
28 | public MockRoute() {
29 | this.port = MockRegistry.findConfiguredPort();
30 | this.responseProcessor = MockRegistry.findResponseProcessor();
31 | LOGGER.info("Using port: " + this.port);
32 | }
33 |
34 | /**
35 | * Generates a Camel route, that listens from any HTTP request made (GET or POST) regardless
36 | * of the path. The response resolution is delegated towards the response processor.
37 | */
38 | @Override
39 | public void configure() throws Exception {
40 |
41 | onException(Exception.class)
42 | .handled(true)
43 | .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(500))
44 | .transform(simple("An error occurred: ${exception.message}"));
45 |
46 | from(generateJettyEndpoint())
47 | .routeId(ROUTE_ID_JETTY)
48 | .id(ROUTE_ID_JETTY)
49 | .log(LoggingLevel.DEBUG, LOGGER, "Received request...")
50 | .setExchangePattern(ExchangePattern.InOut)
51 | .to(DIRECT_MAIN);
52 |
53 | from(DIRECT_MAIN)
54 | .routeId(ROUTE_ID_MAIN)
55 | .id(ROUTE_ID_MAIN)
56 | .log(LoggingLevel.DEBUG, LOGGER, "Current headers: ${headers}")
57 | .process(this.responseProcessor);
58 | }
59 |
60 | /**
61 | * Generates a Camel Jetty endpoint. Note that there is a (servlet) filter wired, but not by Camel. It seems
62 | * to be conflicting in the order of execution (as Camel itself also binds on /* as the filter does). As result
63 | * the filter is NOT the last one in the chain. For documentation purposes, the old way:
64 | *
65 | * jetty:http://0.0.0.0:9090/?matchOnUriPrefix=true&enableJmx=true&handlers=metrics&filtersRef=infoFilter
66 | * and the associated code snippet:
67 | * buffer.append(AND_SIGN).append("filtersRef").append(EQUAL_SIGN).append(InfoFilter.FILTER_ID);
68 | *
69 | * @return
70 | * A Camel Jetty endpoint
71 | */
72 | protected String generateJettyEndpoint() {
73 | StringBuilder buffer = new StringBuilder();
74 | // jetty:http://0.0.0.0:9090/?matchOnUriPrefix=true&enableJmx=true&handlers=metrics
75 | buffer.append(JETTY_MAIN).append(JETTY_BINDING_ADDRESS).append(":").append(this.port);
76 | buffer.append(JETTY_BINDING_PATH);
77 | buffer.append(QUESTION_SIGN).append("matchOnUriPrefix").append(EQUAL_SIGN).append(TRUE_VALUE);
78 | buffer.append(AND_SIGN).append("enableJmx").append(EQUAL_SIGN).append(TRUE_VALUE);
79 | buffer.append(AND_SIGN).append("handlers").append(EQUAL_SIGN).append("metrics");
80 | return buffer.toString();
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/Command.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import org.apache.camel.Exchange;
4 |
5 | import net.technolords.micro.model.ResponseContext;
6 |
7 | public interface Command {
8 | String CONFIG = "config";
9 | String LOG = "log";
10 | String RESET = "reset";
11 | String STATS = "stats";
12 | String STOP = "stop";
13 | String RELOAD = "reload";
14 |
15 | String getId();
16 | ResponseContext executeCommand(Exchange exchange);
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/CommandManager.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.net.HttpURLConnection;
4 | import java.util.Arrays;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import org.apache.camel.Exchange;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import net.technolords.micro.model.ResponseContext;
13 |
14 | public class CommandManager {
15 | private static final Logger LOGGER = LoggerFactory.getLogger(CommandManager.class);
16 |
17 | private static List supportedCommands = Arrays.asList(
18 | new ConfigCommand(),
19 | new LogCommand(),
20 | new ResetCommand(),
21 | new StatsCommand(),
22 | new StopCommand(),
23 | new ReloadCommand()
24 | );
25 |
26 | /**
27 | * Auxiliary method that executes a command by delegation (provided the command is supported).
28 | *
29 | * @param exchange
30 | * The exchange associated with the command.
31 | *
32 | * @return
33 | * The result of the command execution.
34 | */
35 | public static ResponseContext executeCommand(Exchange exchange) {
36 | Map commands = exchange.getIn().getHeaders();
37 | for (String key : commands.keySet()) {
38 | LOGGER.debug("Key: {} -> value: {}", key, commands.get(key));
39 | }
40 | ResponseContext responseContext = supportedCommands
41 | .stream()
42 | .filter(command -> commands.containsKey(command.getId()))
43 | .map(command -> command.executeCommand(exchange))
44 | .findAny()
45 | .orElse(createUnsupportedResponse());
46 | return responseContext;
47 | }
48 |
49 | /**
50 | * Auxiliary method that generates the result of an unsupported command.
51 | *
52 | * @return
53 | * The result of an unsupported command.
54 | */
55 | private static ResponseContext createUnsupportedResponse() {
56 | ResponseContext responseContext = new ResponseContext();
57 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
58 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_NOT_IMPLEMENTED));
59 | responseContext.setResponse("Currently not supported");
60 | return responseContext;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/ConfigCommand.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.io.StringWriter;
4 | import java.net.HttpURLConnection;
5 |
6 | import javax.xml.bind.JAXBContext;
7 | import javax.xml.bind.JAXBException;
8 | import javax.xml.bind.Marshaller;
9 |
10 | import org.apache.camel.Exchange;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import net.technolords.micro.config.ConfigurationManager;
15 | import net.technolords.micro.model.ResponseContext;
16 | import net.technolords.micro.model.jaxb.Configurations;
17 | import net.technolords.micro.registry.MockRegistry;
18 |
19 | public class ConfigCommand implements Command {
20 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
21 |
22 | /**
23 | * Auxiliary method to get the id associated with this command.
24 | *
25 | * @return
26 | * The id associated with the command.
27 | */
28 | @Override
29 | public String getId() {
30 | return Command.CONFIG;
31 | }
32 |
33 | /**
34 | * Auxiliary method that executes the config command.
35 | *
36 | * @param exchange
37 | * The Camel Exchange associated with the config command.
38 | *
39 | * @return
40 | * The result of the config command.
41 | */
42 | @Override
43 | public ResponseContext executeCommand(Exchange exchange) {
44 | LOGGER.debug("Config command called");
45 | ConfigurationManager configurationManager = MockRegistry.findConfigurationManager();
46 | ResponseContext responseContext = new ResponseContext();
47 | try {
48 | responseContext.setContentType(ResponseContext.XML_CONTENT_TYPE);
49 | responseContext.setResponse(marshallToXML(configurationManager.getConfigurations()));
50 | } catch (JAXBException e) {
51 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
52 | responseContext.setResponse(e.getMessage());
53 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_INTERNAL_ERROR));
54 | }
55 | return responseContext;
56 | }
57 |
58 | private static String marshallToXML(Configurations configurations) throws JAXBException {
59 | StringWriter stringWriter = new StringWriter();
60 | Marshaller marshaller = JAXBContext.newInstance(Configurations.class).createMarshaller();
61 | marshaller.marshal(configurations, stringWriter);
62 | return stringWriter.toString();
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/LogCommand.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.util.Map;
4 |
5 | import org.apache.camel.Exchange;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import net.technolords.micro.log.LogManager;
10 | import net.technolords.micro.model.ResponseContext;
11 |
12 | public class LogCommand implements Command {
13 | private static final Logger LOGGER = LoggerFactory.getLogger(LogCommand.class);
14 |
15 | /**
16 | * Auxiliary method to get the id associated with this command.
17 | *
18 | * @return
19 | * The id associated with the command.
20 | */
21 | @Override
22 | public String getId() {
23 | return Command.LOG;
24 | }
25 |
26 | /**
27 | * Auxiliary method that executes the log command. For consistency this class is kept, but in reality it
28 | * is delegated to the LogManager which consolidates all logic (as well as the required classes) with the
29 | * underlying logging framework (other than the logging facade, i.e. SLF4J).
30 | *
31 | * @param exchange
32 | * The Camel Exchange associated with the log command.
33 | *
34 | * @return
35 | * The result of the log command.
36 | */
37 | @Override
38 | public ResponseContext executeCommand(Exchange exchange) {
39 | Map commands = exchange.getIn().getHeaders();
40 | String logLevel = (String) commands.get(Command.LOG);
41 | LOGGER.debug("Log command called, with log level {}", logLevel);
42 | return LogManager.changeLogLevel(logLevel);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/ReloadCommand.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import net.technolords.micro.config.ConfigurationManager;
4 | import net.technolords.micro.model.ResponseContext;
5 | import net.technolords.micro.registry.MockRegistry;
6 | import org.apache.camel.Exchange;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.xml.sax.SAXException;
10 |
11 | import javax.xml.bind.JAXBException;
12 | import java.io.IOException;
13 | import java.net.HttpURLConnection;
14 |
15 | public class ReloadCommand implements Command {
16 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
17 |
18 | @Override
19 | public String getId() {
20 | return Command.RELOAD;
21 | }
22 |
23 | @Override
24 | public ResponseContext executeCommand(Exchange exchange) {
25 | LOGGER.info("Called...");
26 | ResponseContext responseContext = new ResponseContext();
27 | try {
28 | ConfigurationManager configurationManager = MockRegistry.findConfigurationManager();
29 | configurationManager.reloadConfiguration();
30 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
31 | responseContext.setResponse("Reloaded...");
32 | } catch (IOException | SAXException | JAXBException e) {
33 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
34 | responseContext.setResponse(e.getMessage());
35 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_INTERNAL_ERROR));
36 | }
37 | return responseContext;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/ResetCommand.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.net.HttpURLConnection;
4 |
5 | import org.apache.camel.Exchange;
6 | import org.eclipse.jetty.server.handler.StatisticsHandler;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import net.technolords.micro.model.ResponseContext;
11 | import net.technolords.micro.registry.MockRegistry;
12 |
13 | public class ResetCommand implements Command {
14 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
15 |
16 | /**
17 | * Auxiliary method to get the id associated with this command.
18 | *
19 | * @return
20 | * The id associated with the command.
21 | */
22 | @Override
23 | public String getId() {
24 | return Command.RESET;
25 | }
26 |
27 | /**
28 | * Auxiliary method that resets the statistics. Note that the StatisticsHandler is fetched from the Registry, which
29 | * is in fact a Jetty component.
30 | *
31 | * @return
32 | * The result of the reset command.
33 | */
34 | @Override
35 | public ResponseContext executeCommand(Exchange exchange) {
36 | LOGGER.debug("Reset command called...");
37 | ResponseContext responseContext = new ResponseContext();
38 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
39 | StatisticsHandler statisticsHandler = MockRegistry.findStatisticsHandler();
40 | if (statisticsHandler != null) {
41 | statisticsHandler.statsReset();
42 | responseContext.setResponse("Statistics has been reset");
43 | } else {
44 | responseContext.setResponse("Unable to retrieve statistics (no handler configured)");
45 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_NOT_FOUND));
46 | }
47 | return responseContext;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/StatsCommand.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.net.HttpURLConnection;
4 | import java.util.Map;
5 |
6 | import org.apache.camel.Exchange;
7 | import org.eclipse.jetty.server.handler.StatisticsHandler;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import net.technolords.micro.model.ResponseContext;
12 | import net.technolords.micro.registry.MockRegistry;
13 |
14 | public class StatsCommand implements Command {
15 | private static final Logger LOGGER = LoggerFactory.getLogger(StatsCommand.class);
16 |
17 | /**
18 | * Auxiliary method to get the id associated with this command.
19 | *
20 | * @return
21 | * The id associated with the command.
22 | */
23 | @Override
24 | public String getId() {
25 | return Command.STATS;
26 | }
27 |
28 | /**
29 | * Auxiliary method that reports the statistics. Note that the StatisticsHandler is fetched from the Registry,
30 | * which is in fact a Jetty component.
31 | *
32 | * @param exchange
33 | * The Camel Exchange associated with the report/stats. When the type is 'html' the report is generated in HTML
34 | * format, otherwise a custom String is returned.
35 | *
36 | * @return
37 | * The result of the stats command.
38 | */
39 | @Override
40 | public ResponseContext executeCommand(Exchange exchange) {
41 | LOGGER.debug("Stats command called...");
42 | Map commands = exchange.getIn().getHeaders();
43 | String type = (String) commands.get(STATS);
44 | ResponseContext responseContext = new ResponseContext();
45 | StatisticsHandler statisticsHandler = MockRegistry.findStatisticsHandler();
46 | if (statisticsHandler != null) {
47 | switch (type.toUpperCase()) {
48 | case "HTML":
49 | responseContext.setResponse(statisticsHandler.toStatsHTML());
50 | responseContext.setContentType(ResponseContext.HTML_CONTENT_TYPE);
51 | break;
52 | default:
53 | responseContext.setResponse(statisticsAsString(statisticsHandler));
54 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
55 | break;
56 | }
57 | } else {
58 | responseContext.setResponse("Unable to retrieve statistics (no handler configured)");
59 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_NOT_FOUND));
60 | }
61 | return responseContext;
62 | }
63 |
64 | private static String statisticsAsString(StatisticsHandler statisticsHandler) {
65 | StringBuilder buffer = new StringBuilder();
66 | buffer.append("Total requests: ").append(statisticsHandler.getDispatched());
67 | buffer.append(", total request time: ").append(statisticsHandler.getRequestTimeTotal());
68 | buffer.append(", mean time: ").append(statisticsHandler.getRequestTimeMean());
69 | buffer.append(", max time: ").append(statisticsHandler.getRequestTimeMax());
70 | buffer.append(", std dev: ").append(statisticsHandler.getRequestTimeStdDev());
71 | buffer.append(", last reset/start: ").append(statisticsHandler.getStatsOnMs()).append(" ms ago");
72 | return buffer.toString();
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/command/StopCommand.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.net.HttpURLConnection;
4 |
5 | import org.apache.camel.Exchange;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import net.technolords.micro.model.ResponseContext;
10 |
11 | public class StopCommand implements Command {
12 | private static final Logger LOGGER = LoggerFactory.getLogger(StopCommand.class);
13 |
14 | /**
15 | * Auxiliary method to get the id associated with this command.
16 | *
17 | * @return
18 | * The id associated with the command.
19 | */
20 | @Override
21 | public String getId() {
22 | return Command.STOP;
23 | }
24 |
25 | /**
26 | * Auxiliary method that stops the Main execution. This is achieved by calling stop on the CamelContext
27 | * which is associated with the Main.
28 | *
29 | * @param exchange
30 | * The exchange associated with the stop command.
31 | *
32 | * @return
33 | * The result of the stop command (unlikely to be received, as the execution is terminating).
34 | */
35 | @Override
36 | public ResponseContext executeCommand(Exchange exchange) {
37 | LOGGER.debug("Stop command called...");
38 | ResponseContext responseContext = new ResponseContext();
39 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
40 | try {
41 | exchange.getContext().stop();
42 | responseContext.setResponse("Stopping the mock..");
43 | } catch (Exception e) {
44 | responseContext.setResponse(e.getMessage());
45 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_INTERNAL_ERROR));
46 | }
47 | return responseContext;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/config/PropertiesManager.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.config;
2 |
3 | import static java.nio.file.StandardOpenOption.READ;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.nio.file.FileSystems;
8 | import java.nio.file.Files;
9 | import java.nio.file.Path;
10 | import java.util.Properties;
11 |
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import net.technolords.micro.log.LogManager;
16 |
17 | public class PropertiesManager {
18 | private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesManager.class);
19 | private static final String PATH_TO_META_DATA_FILE = "build-meta-data.txt";
20 | public static final String PROP_BUILD_VERSION = "build-version";
21 | public static final String PROP_BUILD_DATE = "build-timestamp";
22 | public static final String PROP_PROPS = "props";
23 | public static final String PROP_PORT = "port";
24 | public static final String PROP_CONFIG = "config";
25 | public static final String PROP_DATA = "data";
26 | private static final String PROP_LOG_CONFIG = "log4j.configurationFile";
27 | private static final String DEFAULT_PORT = "9090";
28 |
29 | /**
30 | * Auxiliary method that loads properties from an embedded file. This file is dynamically updated during each
31 | * build (by Maven) and updates the build version as well as the build timestamp.
32 | *
33 | * @return
34 | * The properties.
35 | */
36 | public static Properties extractMetaData() {
37 | InputStream inputStreamForMetaDataFile = PropertiesManager.class.getClassLoader().getResourceAsStream(PATH_TO_META_DATA_FILE);
38 | Properties properties = new Properties();
39 | try {
40 | properties.load(inputStreamForMetaDataFile);
41 | } catch (IOException e) {
42 | LOGGER.warn("Failed to load meta data properties", e);
43 | }
44 | LOGGER.debug("Got meta data properties: {}", properties.size());
45 | return properties;
46 | }
47 |
48 | /**
49 | * Auxiliary method that creates map of key value pairs (representing the properties) by looking at the provided
50 | * system properties. Part of these properties can be a reference to a properties files.
51 | *
52 | * In case both are specified, that is a properties file containing a definition of a property as well as a provided
53 | * system property the latter wins. As result this method will merge the values.
54 | *
55 | * In case no property file is specified, this method will provide the properties containing the
56 | * provided system properties only.
57 | *
58 | * @return
59 | * The properties.
60 | */
61 | public static Properties extractProperties() {
62 | Properties properties = loadProperties(System.getProperty(PROP_PROPS));
63 | if (System.getProperty(PROP_PORT) != null) {
64 | LOGGER.debug("Configured Port: {}", System.getProperty(PROP_PORT));
65 | }
66 | if (properties.get(PROP_PORT) != null) {
67 | // Defined, potentially override
68 | if (System.getProperty(PROP_PORT) != null) {
69 | properties.put(PROP_PORT, System.getProperty(PROP_PORT));
70 | }
71 | } else {
72 | // Not defined, fetch from system property (or default)
73 | properties.put(PROP_PORT, System.getProperty(PROP_PORT, DEFAULT_PORT));
74 | }
75 | if (System.getProperty(PROP_CONFIG) != null) {
76 | LOGGER.debug("Configured Config: {}", System.getProperty(PROP_CONFIG));
77 | properties.put(PROP_CONFIG, System.getProperty(PROP_CONFIG));
78 | }
79 | if (System.getProperty(PROP_DATA) != null) {
80 | LOGGER.debug("Configured data: {}", System.getProperty(PROP_DATA));
81 | properties.put(PROP_DATA, System.getProperty(PROP_DATA));
82 | }
83 | for (Object key : properties.keySet()) {
84 | LOGGER.debug("Property: {} -> value: {}", key, properties.get(key));
85 | }
86 | return properties;
87 | }
88 |
89 | /**
90 | * Auxiliary method to load the properties.
91 | *
92 | * @param pathToPropertiesFile
93 | * The path to the properties file.
94 | *
95 | * @return
96 | * The properties.
97 | */
98 | private static Properties loadProperties(String pathToPropertiesFile) {
99 | Properties properties = new Properties();
100 | try {
101 | if (pathToPropertiesFile == null) {
102 | return properties;
103 | }
104 | Path path = FileSystems.getDefault().getPath(pathToPropertiesFile);
105 | properties.load(Files.newInputStream(path, READ));
106 | if (properties.get(PROP_LOG_CONFIG) != null) {
107 | // Note that at this point, putting this property back as system property is pointless,
108 | // as the JVM is already started. When there is no CLI property defined proceed by
109 | // delegation towards the LogManager.
110 | if (System.getProperty(PROP_LOG_CONFIG) == null) {
111 | LOGGER.trace("log4j not as system property, do invoke builder");
112 | LogManager.initializeLogging((String) properties.get(PROP_LOG_CONFIG));
113 | } else {
114 | LOGGER.trace("log4j as system property, do nothing with reference in property file");
115 | }
116 | }
117 | } catch (IOException e) {
118 | LOGGER.warn("Unable to read properties -> ignoring values and using defaults", e);
119 | }
120 | return properties;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/filter/InfoFilter.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.filter;
2 |
3 | import static net.technolords.micro.filter.InfoFilter.FILTER_ID;
4 | import static net.technolords.micro.filter.InfoFilter.URL_PATTERNS;
5 |
6 | import java.io.IOException;
7 | import java.util.EnumSet;
8 |
9 | import javax.servlet.DispatcherType;
10 | import javax.servlet.Filter;
11 | import javax.servlet.FilterChain;
12 | import javax.servlet.FilterConfig;
13 | import javax.servlet.ServletException;
14 | import javax.servlet.ServletRequest;
15 | import javax.servlet.ServletResponse;
16 | import javax.servlet.annotation.WebFilter;
17 | import javax.servlet.http.HttpServletRequest;
18 | import javax.servlet.http.HttpServletResponse;
19 |
20 | import org.eclipse.jetty.server.Server;
21 | import org.eclipse.jetty.servlet.ServletContextHandler;
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 | import org.slf4j.MDC;
25 |
26 | @WebFilter (filterName = FILTER_ID, urlPatterns = { URL_PATTERNS })
27 | public class InfoFilter implements Filter {
28 | private static final Logger LOGGER = LoggerFactory.getLogger(InfoFilter.class);
29 | public static final String FILTER_ID = "infoFilter";
30 | public static final String URL_PATTERNS = "/*";
31 | private static final String LOG_CONTEXT_HTTP_URI = "httpUri";
32 | private static final String LOG_CONTEXT_HTTP_STATUS = "httpStatus";
33 |
34 | /**
35 | * Auxiliary method to add the filter directly to the ServlerContextHandler associated with the Jetty Server.
36 | *
37 | * Note that when this filter is annotated with:
38 | * dispatcherTypes = { DispatcherType.ASYNC })
39 | * it does NOT work (nor any other type for that matter)!
40 | *
41 | * @param server
42 | * The Server associated with the Filter.
43 | */
44 | public static void registerFilterDirectlyWithServer(Server server) {
45 | ServletContextHandler servletContextHandler = server.getChildHandlerByClass(ServletContextHandler.class);
46 | servletContextHandler.addFilter(InfoFilter.class, URL_PATTERNS, EnumSet.of(DispatcherType.ASYNC));
47 | }
48 |
49 | /**
50 | * Called when the filter is instantiated, but in this case nothing special needs to be done.
51 | *
52 | * @param filterConfig
53 | * The filter configuration associated with the initialization.
54 | *
55 | * @throws ServletException
56 | * When the initialization fails.
57 | */
58 | @Override
59 | public void init(FilterConfig filterConfig) throws ServletException {
60 | }
61 |
62 | /**
63 | * Execute the filter logic (as part of a chain). In this case, the time before and after the other chain invocation
64 | * is measured. The difference is the elapsed time. Note that both the uri associated with the request as well as
65 | * the http status code associated with the response is 'preserved' in the log context. These values will be
66 | * substituted in the log patterns %X{httpUri} and %X{httpStatus} respectively.
67 | *
68 | * @param servletRequest
69 | * The request associated with the filter (chain).
70 | * @param servletResponse
71 | * The response associated with the filter (chain).
72 | * @param filterChain
73 | * The filter chain.
74 | *
75 | * @throws IOException
76 | * When executing the filter (chain) fails.
77 | * @throws ServletException
78 | * When executing the filter (chain) fails.
79 | */
80 | @Override
81 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
82 | long startTime = System.currentTimeMillis();
83 | filterChain.doFilter(servletRequest, servletResponse);
84 | long endTime = System.currentTimeMillis() - startTime;
85 | // Update logging thread with meta data
86 | this.updateThreadContextWithHttpUri((HttpServletRequest) servletRequest);
87 | this.updateThreadContextWithHttpStatus((HttpServletResponse) servletResponse);
88 | // Log: epoch, uri, response code and elapsed time, using: pattern="%d{UNIX_MILLIS} %X{httpUri} %X{httpStatus} %m%n"
89 | LOGGER.info("{}", endTime);
90 | }
91 |
92 | /**
93 | * Update the thread context associated with the logging with specific data. In this case, it is the request URI.
94 | * The value will eventually end up in the log, where it will substitute for %X{httpUri}
95 | *
96 | * Note that updating the thread context can be done directly (using the org.apache.logging.log4j.ThreadContext
97 | * class, but instead the MDC is used from slf4j)
98 | *
99 | * @param httpServletRequest
100 | * The request associated with the thread context update.
101 | */
102 | private void updateThreadContextWithHttpUri(HttpServletRequest httpServletRequest) {
103 | MDC.put(LOG_CONTEXT_HTTP_URI, String.valueOf(httpServletRequest.getRequestURI()));
104 | }
105 |
106 | /**
107 | * Update the thread context associated with the logging with specific data. In this case, it is the response status.
108 | * The value will eventually end up in the log, where it will be substituted for %X{httpStatus}
109 | *
110 | * Note that updating the thread context can be done directly (using the org.apache.logging.log4j.ThreadContext
111 | * class, but instead the MDC is used from slf4j)
112 | *
113 | * @param httpServletResponse
114 | * The response associated with the thread context update.
115 | */
116 | private void updateThreadContextWithHttpStatus(HttpServletResponse httpServletResponse) {
117 | MDC.put(LOG_CONTEXT_HTTP_STATUS, String.valueOf(httpServletResponse.getStatus()));
118 | }
119 |
120 | /**
121 | * Called when the server is stopped, in this case, there is nothing to clean up.
122 | */
123 | @Override
124 | public void destroy() {
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/input/ConfigurationSelector.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.input;
2 |
3 | import java.util.HashSet;
4 | import java.util.Map;
5 | import java.util.Set;
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import net.technolords.micro.model.jaxb.Configuration;
13 |
14 | public class ConfigurationSelector {
15 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
16 | private static final String WILD_CARD = "\\*";
17 |
18 | /**
19 | * Auxiliary method to find the Configuration associated with a path and a map of configurations. Since wild cards
20 | * are supported, multiple matches can be found. If so, a decision is forced to return one match.
21 | *
22 | * @param path
23 | * The path associated with the Configuration.
24 | * @param configurations
25 | * A sub section of the entire map of Configurations. For example all GET related configurations. The smaller the
26 | * map size, the quicker the matching is done. Note that no match means a null reference is returned (which will
27 | * lead to a 404 not found).
28 | *
29 | * @return
30 | * A matching configuration (or null when none was found).
31 | */
32 | public Configuration findMatchingConfiguration(String path, Map configurations) {
33 | Set matchingConfigurations = new HashSet<>();
34 | // Run through all configurations
35 | for (String key : configurations.keySet()) {
36 | Configuration currentConfiguration = configurations.get(key);
37 | if (key.contains("*")) {
38 | // Key contains one or more wild cards (means evaluation of regular expression)
39 | Pattern pattern = currentConfiguration.getPattern();
40 | if (pattern == null) {
41 | pattern = this.createPattern(key);
42 | currentConfiguration.setPattern(pattern);
43 | }
44 | Matcher matcher = pattern.matcher(path);
45 | if (matcher.matches()) {
46 | LOGGER.debug("Got a match for regex -> possible config");
47 | matchingConfigurations.add(configurations.get(key));
48 | continue;
49 | }
50 | }
51 | if (key.equals(path)) {
52 | LOGGER.debug("Key matches path -> possible config");
53 | matchingConfigurations.add(configurations.get(key));
54 | continue;
55 | }
56 | }
57 | if (matchingConfigurations.size() > 1) {
58 | // Force selection
59 | LOGGER.debug("Problem, need to force selection (first match without wildcard)");
60 | return matchingConfigurations.stream().filter( (configuration -> !configuration.getUrl().contains("*")) ).findFirst().get();
61 | }
62 | if (matchingConfigurations.size() == 1) {
63 | LOGGER.debug("No problem, straightforward selection");
64 | return matchingConfigurations.stream().findFirst().get();
65 | }
66 | return null;
67 | }
68 |
69 | /**
70 | * Auxiliary method which basically turns a wild card into a regular expression.
71 | *
72 | * @param key
73 | * The key associated with the expression (this represents the String to match).
74 | *
75 | * @return
76 | * A regular expression, or rather, the Pattern thereof.
77 | */
78 | private Pattern createPattern(String key) {
79 | LOGGER.trace("Before replace: {}", key);
80 | String alteredKey = key.replaceAll(WILD_CARD, "(.+)");
81 | LOGGER.trace("After replace: {}", alteredKey);
82 | return Pattern.compile(alteredKey);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/input/json/JsonPathEvaluator.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.input.json;
2 |
3 | import java.util.List;
4 |
5 | import org.apache.logging.log4j.util.Strings;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import com.jayway.jsonpath.DocumentContext;
10 | import com.jayway.jsonpath.JsonPath;
11 |
12 | import net.technolords.micro.model.jaxb.Configuration;
13 |
14 | public class JsonPathEvaluator {
15 | private static final Logger LOGGER = LoggerFactory.getLogger(JsonPathEvaluator.class);
16 |
17 | public boolean evaluateXpathExpression(String jsonpathAsString, String message, Configuration configuration) {
18 | DocumentContext jsonContext = JsonPath.parse(message);
19 | LOGGER.trace("Jsoncontext: {}", jsonContext);
20 | LOGGER.debug("About to compile the json expression for: '{}'", jsonpathAsString);
21 | JsonPath compiledJsonPath = JsonPath.compile(jsonpathAsString);
22 | LOGGER.debug("Compiled Jsonpath: {} -> {}", compiledJsonPath, compiledJsonPath.getPath());
23 | LOGGER.debug("Is definite: {}", compiledJsonPath.isDefinite());
24 | if (compiledJsonPath.isDefinite()) {
25 | String match = jsonContext.read(compiledJsonPath);
26 | boolean result = !Strings.isEmpty(match);
27 | LOGGER.debug("evaluated match: {} -> result: {}", match, result);
28 | return result;
29 | } else {
30 | List matches = jsonContext.read(compiledJsonPath);
31 | boolean result = matches != null && matches.size() > 0;
32 | LOGGER.debug("matches: {} -> result: {}", matches, result);
33 | return result;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/input/xml/ConfigurationToNamespaceContext.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.input.xml;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import javax.xml.namespace.NamespaceContext;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import net.technolords.micro.config.ConfigurationManager;
12 | import net.technolords.micro.model.jaxb.Configuration;
13 | import net.technolords.micro.model.jaxb.namespace.NamespaceConfig;
14 | import net.technolords.micro.model.jaxb.namespace.NamespaceList;
15 |
16 | public class ConfigurationToNamespaceContext {
17 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
18 |
19 | /**
20 | * Auxiliary method to convert a Configuration into a NamespaceContext
21 | *
22 | * @param configuration
23 | * A reference to a configuration object.
24 | *
25 | * @return
26 | * A reference to a NamespaceContext.
27 | */
28 | public NamespaceContext createNamespaceContext(Configuration configuration) {
29 | if (configuration != null) {
30 | // Namespaces are only relevant for Post messages
31 | if (ConfigurationManager.HTTP_POST.equals(configuration.getType())) {
32 | return new DefaultNamespaceContext(this.obtainNamespaceMapping(configuration));
33 | }
34 | }
35 | return null;
36 | }
37 |
38 | /**
39 | * Auxiliary method to obtain a name space mapping, which holds a prefix and an associated URI, to
40 | * support a look up mechanism (implemented by the NamespaceContext interface). For example:
41 | *
42 | * "traxis", "urn:eventis:traxisweb:1.0"
43 | *
44 | * @param configuration
45 | * The configuration associated with the name spaces.
46 | *
47 | * @return
48 | * The name space mapping.
49 | */
50 | private Map obtainNamespaceMapping(Configuration configuration) {
51 | Map result = new HashMap<>();
52 | if (configuration != null) {
53 | // Check for cached data
54 | if (configuration.getCachedNamespaceMapping() != null) {
55 | return configuration.getCachedNamespaceMapping();
56 | }
57 | // Namespaces are only relevant for Post messages
58 | if (ConfigurationManager.HTTP_POST.equals(configuration.getType())) {
59 | if (configuration.getNamespaceList() != null) {
60 | NamespaceList namespaceList = configuration.getNamespaceList();
61 | for (NamespaceConfig namespaceConfig : namespaceList.getNamespaces()) {
62 | result.put(namespaceConfig.getPrefix(), namespaceConfig.getNamespaceURI());
63 | LOGGER.debug("Added namespace with prefix: {} to collection, now size {}", namespaceConfig.getPrefix(), result.size());
64 | }
65 | }
66 | }
67 | // Update cache
68 | configuration.setCachedNamespaceMapping(result);
69 | }
70 | return result;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/input/xml/DefaultNamespaceContext.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.input.xml;
2 |
3 | import java.util.Iterator;
4 | import java.util.Map;
5 |
6 | import javax.xml.XMLConstants;
7 | import javax.xml.namespace.NamespaceContext;
8 |
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | public class DefaultNamespaceContext implements NamespaceContext {
13 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
14 | private Map namespaceConfig;
15 |
16 | public DefaultNamespaceContext(Map myNamespaceConfig) {
17 | this.namespaceConfig = myNamespaceConfig;
18 | }
19 |
20 | @Override
21 | public String getNamespaceURI(String prefix) {
22 | LOGGER.debug("getNamespaceURI called with: {}", prefix);
23 | if (this.namespaceConfig.containsKey(prefix)) {
24 | return this.namespaceConfig.get(prefix);
25 | }
26 | return XMLConstants.NULL_NS_URI;
27 | }
28 |
29 | @Override
30 | public String getPrefix(String namespaceURI) {
31 | LOGGER.debug("getPrefix called with: {}", namespaceURI);
32 | for (String key : this.namespaceConfig.keySet()) {
33 | if (this.namespaceConfig.get(key).equals(namespaceURI)) {
34 | return key;
35 | }
36 | }
37 | return XMLConstants.DEFAULT_NS_PREFIX;
38 | }
39 |
40 | @Override
41 | public Iterator getPrefixes(String namespaceURI) {
42 | LOGGER.debug("getPrefixes called with: {}", namespaceURI);
43 | return this.namespaceConfig.keySet().iterator();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/input/xml/XpathEvaluator.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.input.xml;
2 |
3 | import java.io.IOException;
4 | import java.io.StringReader;
5 |
6 | import javax.xml.xpath.XPath;
7 | import javax.xml.xpath.XPathConstants;
8 | import javax.xml.xpath.XPathExpression;
9 | import javax.xml.xpath.XPathExpressionException;
10 | import javax.xml.xpath.XPathFactory;
11 |
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.xml.sax.InputSource;
15 |
16 | import net.technolords.micro.model.jaxb.Configuration;
17 |
18 | public class XpathEvaluator {
19 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
20 | private ConfigurationToNamespaceContext configurationToNamespaceContext = null;
21 | private XPathFactory xPathFactory = null;
22 |
23 | /**
24 | * Auxiliary method that evaluates the given xpath expression with the given message.
25 | *
26 | * NOTE: currently only 'boolean' xpath expressions are supported. Meaning, any node list
27 | * selection or otherwise will fail. TODO: result typing, to support different xpath queries.
28 | *
29 | * @param xpathExpression
30 | * The xpath expression to evaluate.
31 | * @param xmlMessage
32 | * The xml message associated with the xpath evaluation.
33 | * @param configuration
34 | * The configuration associated with the namespaces.
35 | *
36 | * @return
37 | * The result of the xpath expression, which means it is either a match or not.
38 | *
39 | * @throws XPathExpressionException
40 | * When evaluation the xpath expression fails.
41 | * @throws IOException
42 | * When reading the input source fails.
43 | */
44 | public boolean evaluateXpathExpression(String xpathExpression, String xmlMessage, Configuration configuration) throws XPathExpressionException, IOException {
45 | XPathExpression xPathExpression = this.obtainXpathExpression(xpathExpression, configuration);
46 | LOGGER.debug("Xpath expression compiled, and is ready to be used for evaluation...");
47 | StringReader stringReader = new StringReader(xmlMessage);
48 | InputSource inputSource = new InputSource(stringReader);
49 | LOGGER.debug("Xml input source created, size: {}...", xmlMessage.length());
50 | stringReader.reset();
51 | Boolean result = (Boolean) xPathExpression.evaluate(inputSource, XPathConstants.BOOLEAN);
52 | LOGGER.debug("... xpath evaluated: {}", result);
53 | return result;
54 | }
55 |
56 | /**
57 | * Auxiliary method that creates a xpath object for further usage. This is achieved by compiling the given
58 | * xpath expression as well as using any namespaces declared in the given configuration.
59 | *
60 | * @param xpathExpression
61 | * A string representing the xpath expression.
62 | * @param configuration
63 | * The configuration associated with the namespaces.
64 | *
65 | * @return
66 | * The compiled xpath expression.
67 | *
68 | * @throws XPathExpressionException
69 | * When the compilation fails.
70 | */
71 | private XPathExpression obtainXpathExpression(String xpathExpression, Configuration configuration) throws XPathExpressionException {
72 | LOGGER.debug("About to compile xpath expression...");
73 | if (this.xPathFactory == null) {
74 | this.xPathFactory = XPathFactory.newInstance();
75 | }
76 | XPath xPath = this.xPathFactory.newXPath();
77 | if (this.configurationToNamespaceContext == null) {
78 | this.configurationToNamespaceContext = new ConfigurationToNamespaceContext();
79 | }
80 | xPath.setNamespaceContext(this.configurationToNamespaceContext.createNamespaceContext(configuration));
81 | return xPath.compile(xpathExpression);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/log/LogManager.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.log;
2 |
3 | import java.net.HttpURLConnection;
4 | import java.nio.file.FileSystems;
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 |
8 | import org.apache.logging.log4j.Level;
9 | import org.apache.logging.log4j.core.LoggerContext;
10 | import org.apache.logging.log4j.core.config.Configuration;
11 | import org.apache.logging.log4j.core.config.LoggerConfig;
12 | import org.apache.logging.log4j.spi.StandardLevel;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | import net.technolords.micro.model.ResponseContext;
17 |
18 | /**
19 | * This class has the responsibility to interface with the logging library, which is currently
20 | * log4j-2. All log4j-2 dependencies and classes are used here solely, which limits the impact in
21 | * case things change.
22 | *
23 | * This class supports operations from two angles:
24 | * - startup time, where end user overrides default configuration (caller class: PropertiesManager)
25 | * - run time, where end-user changes log level (caller class: LogCommand)
26 | */
27 | public class LogManager {
28 | private static final Logger LOGGER = LoggerFactory.getLogger(LogManager.class);
29 |
30 | /**
31 | * Auxiliary method to (re)initialize the logging. This method is typically called from
32 | * the PropertiesManager when a external log4j2 configuration is provided, while at the
33 | * same time no CLI parameter was given.
34 | *
35 | * Setting the new config location is enough, as it will trigger a reconfigure
36 | * automatically.
37 | *
38 | * @param pathToLogConfiguration
39 | * A path to the external log configuration file.
40 | */
41 | public static void initializeLogging(String pathToLogConfiguration) {
42 | Path path = FileSystems.getDefault().getPath(pathToLogConfiguration);
43 | LOGGER.trace("Path to log configuration: {} -> file exists: {}", pathToLogConfiguration, Files.exists(path));
44 | LoggerContext loggerContext = LoggerContext.getContext(false);
45 | loggerContext.setConfigLocation(path.toUri());
46 | }
47 |
48 | /**
49 | * Auxiliary method to change the log level.
50 | *
51 | * @param logLevel
52 | * The log level to set.
53 | *
54 | * @return
55 | * A ResponseContext containing the result of the command.
56 | */
57 | public static ResponseContext changeLogLevel(String logLevel) {
58 | ResponseContext responseContext = new ResponseContext();
59 | responseContext.setContentType(ResponseContext.PLAIN_TEXT_CONTENT_TYPE);
60 | LoggerContext loggerContext = LoggerContext.getContext(false);
61 | Configuration configuration = loggerContext.getConfiguration();
62 | LoggerConfig rootLogger = configuration.getRootLogger();
63 | if (rootLogger != null) {
64 | switch (StandardLevel.getStandardLevel(Level.toLevel(logLevel, Level.INFO).intLevel())) {
65 | case ERROR:
66 | rootLogger.setLevel(Level.ERROR);
67 | responseContext.setResponse("Log level changed to ERROR");
68 | break;
69 | case WARN:
70 | rootLogger.setLevel(Level.WARN);
71 | responseContext.setResponse("Log level changed to WARN");
72 | break;
73 | case INFO:
74 | rootLogger.setLevel(Level.INFO);
75 | responseContext.setResponse("Log level changed to INFO");
76 | break;
77 | case DEBUG:
78 | rootLogger.setLevel(Level.DEBUG);
79 | responseContext.setResponse("Log level changed to DEBUG");
80 | break;
81 | case OFF:
82 | rootLogger.setLevel(Level.OFF);
83 | responseContext.setResponse("Logging switched off");
84 | break;
85 | default:
86 | responseContext.setResponse("Log level unchanged, unsupported level: " + logLevel);
87 | }
88 | loggerContext.updateLoggers();
89 | } else {
90 | responseContext.setResponse("Unable to change log level, no ROOT logger found...");
91 | responseContext.setErrorCode(String.valueOf(HttpURLConnection.HTTP_INTERNAL_ERROR));
92 | }
93 | return responseContext;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/ResponseContext.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model;
2 |
3 | /**
4 | * This class is a data transfer object and represents the mocked response.
5 | */
6 | public class ResponseContext {
7 | public static final String JSON_CONTENT_TYPE = "application/json";
8 | public static final String XML_CONTENT_TYPE = "application/xml";
9 | public static final String PLAIN_TEXT_CONTENT_TYPE = "text/plain";
10 | public static final String HTML_CONTENT_TYPE = "text/html";
11 | public static final String DEFAULT_CONTENT_TYPE = JSON_CONTENT_TYPE;
12 | private String response;
13 | private String errorCode;
14 | private String contentType = DEFAULT_CONTENT_TYPE;
15 |
16 | public String getResponse() {
17 | return response;
18 | }
19 |
20 | public void setResponse(String response) {
21 | this.response = response;
22 | }
23 |
24 | public String getErrorCode() {
25 | return errorCode;
26 | }
27 |
28 | public void setErrorCode(String errorCode) {
29 | this.errorCode = errorCode;
30 | }
31 |
32 | public String getContentType() {
33 | return contentType;
34 | }
35 |
36 | public void setContentType(String contentType) {
37 | this.contentType = contentType;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/Configuration.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb;
2 |
3 | import java.util.Map;
4 | import java.util.Objects;
5 | import java.util.regex.Pattern;
6 |
7 | import javax.xml.bind.annotation.XmlAttribute;
8 | import javax.xml.bind.annotation.XmlElement;
9 | import javax.xml.bind.annotation.XmlTransient;
10 |
11 | import net.technolords.micro.model.jaxb.namespace.NamespaceList;
12 | import net.technolords.micro.model.jaxb.query.QueryGroups;
13 | import net.technolords.micro.model.jaxb.resource.ResourceGroups;
14 | import net.technolords.micro.model.jaxb.resource.SimpleResource;
15 |
16 | public class Configuration {
17 | private String type;
18 | private String url;
19 | private QueryGroups queryGroups;
20 | private SimpleResource simpleResource;
21 | private ResourceGroups resourceGroups;
22 | private NamespaceList namespaceList;
23 | private Map cachedNamespaceMapping;
24 | private Pattern pattern;
25 |
26 | @XmlAttribute(name = "type")
27 | public String getType() {
28 | return type;
29 | }
30 |
31 | public void setType(String type) {
32 | this.type = type;
33 | }
34 |
35 | @XmlAttribute(name = "url")
36 | public String getUrl() {
37 | return url;
38 | }
39 |
40 | public void setUrl(String url) {
41 | this.url = url;
42 | }
43 |
44 | @XmlElement (name = "query-groups")
45 | public QueryGroups getQueryGroups() {
46 | return queryGroups;
47 | }
48 |
49 | public void setQueryGroups(QueryGroups queryGroups) {
50 | this.queryGroups = queryGroups;
51 | }
52 |
53 | @XmlElement(name = "resource")
54 | public SimpleResource getSimpleResource() {
55 | return simpleResource;
56 | }
57 |
58 | public void setSimpleResource(SimpleResource simpleResource) {
59 | this.simpleResource = simpleResource;
60 | }
61 |
62 | @XmlElement(name = "resource-groups")
63 | public ResourceGroups getResourceGroups() {
64 | return resourceGroups;
65 | }
66 |
67 | public void setResourceGroups(ResourceGroups resourceGroups) {
68 | this.resourceGroups = resourceGroups;
69 | }
70 |
71 | @XmlElement(name = "namespaces")
72 | public NamespaceList getNamespaceList() {
73 | return namespaceList;
74 | }
75 |
76 | public void setNamespaceList(NamespaceList namespaceList) {
77 | this.namespaceList = namespaceList;
78 | }
79 |
80 | @XmlTransient
81 | public Map getCachedNamespaceMapping() {
82 | return cachedNamespaceMapping;
83 | }
84 |
85 | public void setCachedNamespaceMapping(Map cachedNamespaceMapping) {
86 | this.cachedNamespaceMapping = cachedNamespaceMapping;
87 | }
88 |
89 | @XmlTransient
90 | public Pattern getPattern() {
91 | return pattern;
92 | }
93 |
94 | public void setPattern(Pattern pattern) {
95 | this.pattern = pattern;
96 | }
97 |
98 | @Override
99 | public boolean equals(Object obj) {
100 | if(obj == null) {
101 | return false;
102 | }
103 | if(!(obj instanceof Configuration)) {
104 | return false;
105 | }
106 | Configuration ref = (Configuration) obj;
107 | return (Objects.equals(this.getUrl(), ref.getUrl())
108 | && Objects.equals(this.getType(), ref.getType())
109 | && Objects.equals(this.getSimpleResource(), ref.getSimpleResource())
110 | );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/Configurations.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb;
2 |
3 | import java.util.List;
4 |
5 | import javax.xml.bind.annotation.XmlElement;
6 | import javax.xml.bind.annotation.XmlRootElement;
7 |
8 | import net.technolords.micro.model.jaxb.registration.ServiceRegistration;
9 |
10 | @XmlRootElement(name = "configurations", namespace = "http://xsd.technolords.net")
11 | public class Configurations {
12 | private ServiceRegistration serviceRegistration;
13 | private List configurations;
14 |
15 | @XmlElement (name = "service-registrations")
16 | public ServiceRegistration getServiceRegistration() {
17 | return serviceRegistration;
18 | }
19 |
20 | public void setServiceRegistration(ServiceRegistration serviceRegistration) {
21 | this.serviceRegistration = serviceRegistration;
22 | }
23 |
24 | @XmlElement (name = "configuration")
25 | public List getConfigurations() {
26 | return configurations;
27 | }
28 |
29 | public void setConfigurations(List configurations) {
30 | this.configurations = configurations;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/namespace/NamespaceConfig.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.namespace;
2 |
3 | import javax.xml.bind.annotation.XmlAttribute;
4 | import javax.xml.bind.annotation.XmlValue;
5 |
6 | public class NamespaceConfig {
7 | private String prefix;
8 | private String namespaceURI;
9 |
10 | @XmlAttribute(name = "prefix")
11 | public String getPrefix() {
12 | return prefix;
13 | }
14 |
15 | public void setPrefix(String prefix) {
16 | this.prefix = prefix;
17 | }
18 |
19 | @XmlValue
20 | public String getNamespaceURI() {
21 | return namespaceURI;
22 | }
23 |
24 | public void setNamespaceURI(String namespaceURI) {
25 | this.namespaceURI = namespaceURI;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/namespace/NamespaceList.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.namespace;
2 |
3 | import java.util.List;
4 |
5 | import javax.xml.bind.annotation.XmlElement;
6 |
7 | public class NamespaceList {
8 | private List namespaces;
9 |
10 | @XmlElement(name = "namespace")
11 | public List getNamespaces() {
12 | return namespaces;
13 | }
14 |
15 | public void setNamespaces(List namespaces) {
16 | this.namespaces = namespaces;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/package-info.java:
--------------------------------------------------------------------------------
1 | @XmlSchema(
2 | namespace = "http://xsd.technolords.net",
3 | elementFormDefault = XmlNsForm.QUALIFIED
4 | )
5 | package net.technolords.micro.model.jaxb;
6 |
7 | import javax.xml.bind.annotation.XmlNsForm;
8 | import javax.xml.bind.annotation.XmlSchema;
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/query/QueryGroup.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.query;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import javax.xml.bind.annotation.XmlElement;
7 |
8 | import net.technolords.micro.model.jaxb.resource.SimpleResource;
9 |
10 | public class QueryGroup {
11 | private List queryParameters;
12 | private SimpleResource simpleResource;
13 |
14 | public QueryGroup() {
15 | this.queryParameters = new ArrayList<>();
16 | }
17 |
18 | @XmlElement (name = "query-parameter")
19 | public List getQueryParameters() {
20 | return queryParameters;
21 | }
22 |
23 | public void setQueryParameters(List queryParameters) {
24 | this.queryParameters = queryParameters;
25 | }
26 |
27 | @XmlElement (name = "resource")
28 | public SimpleResource getSimpleResource() {
29 | return simpleResource;
30 | }
31 |
32 | public void setSimpleResource(SimpleResource simpleResource) {
33 | this.simpleResource = simpleResource;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/query/QueryGroups.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.query;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import javax.xml.bind.annotation.XmlElement;
7 |
8 | public class QueryGroups {
9 | private List queryGroups;
10 |
11 | public QueryGroups() {
12 | this.queryGroups = new ArrayList<>();
13 | }
14 |
15 | @XmlElement (name = "query-group")
16 | public List getQueryGroups() {
17 | return queryGroups;
18 | }
19 |
20 | public void setQueryGroups(List queryGroups) {
21 | this.queryGroups = queryGroups;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/query/QueryParameter.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.query;
2 |
3 | import javax.xml.bind.annotation.XmlAttribute;
4 | import javax.xml.bind.annotation.XmlValue;
5 |
6 | public class QueryParameter {
7 | private String key;
8 | private String value;
9 |
10 | @XmlAttribute (name = "key")
11 | public String getKey() {
12 | return key;
13 | }
14 |
15 | public void setKey(String key) {
16 | this.key = key;
17 | }
18 |
19 | @XmlValue
20 | public String getValue() {
21 | return value;
22 | }
23 |
24 | public void setValue(String value) {
25 | this.value = value;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/registration/HealthCheck.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.registration;
2 |
3 | import javax.xml.bind.annotation.XmlAttribute;
4 |
5 | public class HealthCheck {
6 | private boolean enabled;
7 | private String interval;
8 | private String deRegisterAfter;
9 |
10 | @XmlAttribute (name = "enabled")
11 | public boolean isEnabled() {
12 | return enabled;
13 | }
14 |
15 | public void setEnabled(boolean enabled) {
16 | this.enabled = enabled;
17 | }
18 |
19 | @XmlAttribute (name = "interval")
20 | public String getInterval() {
21 | return interval;
22 | }
23 |
24 | public void setInterval(String interval) {
25 | this.interval = interval;
26 | }
27 |
28 | @XmlAttribute (name = "deregister-after")
29 | public String getDeRegisterAfter() {
30 | return deRegisterAfter;
31 | }
32 |
33 | public void setDeRegisterAfter(String deRegisterAfter) {
34 | this.deRegisterAfter = deRegisterAfter;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/registration/Registration.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.registration;
2 |
3 | import javax.xml.bind.annotation.XmlAttribute;
4 | import javax.xml.bind.annotation.XmlElement;
5 | import javax.xml.bind.annotation.XmlEnum;
6 |
7 | public class Registration {
8 | private Registrar registrar;
9 | private String address;
10 | private int port;
11 | private Service service;
12 |
13 | @XmlEnum
14 | public enum Registrar { CONSUL, EUREKA }
15 |
16 | @XmlAttribute (name = "registrar", required = true)
17 | public Registrar getRegistrar() {
18 | return registrar;
19 | }
20 |
21 | public void setRegistrar(Registrar registrar) {
22 | this.registrar = registrar;
23 | }
24 |
25 | @XmlAttribute (name = "address")
26 | public String getAddress() {
27 | return address;
28 | }
29 |
30 | public void setAddress(String address) {
31 | this.address = address;
32 | }
33 |
34 | @XmlAttribute (name = "port")
35 | public int getPort() {
36 | return port;
37 | }
38 |
39 | public void setPort(int port) {
40 | this.port = port;
41 | }
42 |
43 | @XmlElement (name = "service")
44 | public Service getService() {
45 | return service;
46 | }
47 |
48 | public void setService(Service service) {
49 | this.service = service;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/registration/Service.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.registration;
2 |
3 | import javax.xml.bind.annotation.XmlAttribute;
4 | import javax.xml.bind.annotation.XmlElement;
5 |
6 | public class Service {
7 | private String address;
8 | private int port;
9 | private String id;
10 | private String name;
11 | private HealthCheck healthCheck;
12 |
13 | @XmlAttribute (name = "address")
14 | public String getAddress() {
15 | return address;
16 | }
17 |
18 | public void setAddress(String address) {
19 | this.address = address;
20 | }
21 |
22 | @XmlAttribute (name = "port")
23 | public int getPort() {
24 | return port;
25 | }
26 |
27 | public void setPort(int port) {
28 | this.port = port;
29 | }
30 |
31 | @XmlAttribute (name = "id")
32 | public String getId() {
33 | return id;
34 | }
35 |
36 | public void setId(String id) {
37 | this.id = id;
38 | }
39 |
40 | @XmlAttribute (name = "name")
41 | public String getName() {
42 | return name;
43 | }
44 |
45 | public void setName(String name) {
46 | this.name = name;
47 | }
48 |
49 | @XmlElement (name = "health-check")
50 | public HealthCheck getHealthCheck() {
51 | return healthCheck;
52 | }
53 |
54 | public void setHealthCheck(HealthCheck healthCheck) {
55 | this.healthCheck = healthCheck;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/registration/ServiceRegistration.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.registration;
2 |
3 | import java.util.List;
4 |
5 | import javax.xml.bind.annotation.XmlElement;
6 |
7 | public class ServiceRegistration {
8 | private List registrations;
9 |
10 | @XmlElement (name = "registration")
11 | public List getRegistrations() {
12 | return registrations;
13 | }
14 |
15 | public void setRegistrations(List registrations) {
16 | this.registrations = registrations;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/resource/JsonpathConfig.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.resource;
2 |
3 | import javax.xml.bind.annotation.XmlValue;
4 |
5 | public class JsonpathConfig {
6 | private String jsonpath;
7 |
8 | @XmlValue
9 | public String getJsonpath() {
10 | return jsonpath;
11 | }
12 |
13 | public void setJsonpath(String jsonpath) {
14 | this.jsonpath = jsonpath;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/resource/ResourceGroup.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.resource;
2 |
3 | import javax.xml.bind.annotation.XmlElement;
4 |
5 | public class ResourceGroup {
6 | private XpathConfig xpathConfig;
7 | private JsonpathConfig jsonpathConfig;
8 | private SimpleResource simpleResource;
9 |
10 | @XmlElement(name = "xpath")
11 | public XpathConfig getXpathConfig() {
12 | return xpathConfig;
13 | }
14 |
15 | public void setXpathConfig(XpathConfig xpathConfig) {
16 | this.xpathConfig = xpathConfig;
17 | }
18 |
19 | @XmlElement(name = "jsonpath")
20 | public JsonpathConfig getJsonpathConfig() {
21 | return jsonpathConfig;
22 | }
23 |
24 | public void setJsonpathConfig(JsonpathConfig jsonpathConfig) {
25 | this.jsonpathConfig = jsonpathConfig;
26 | }
27 |
28 | @XmlElement(name = "resource")
29 | public SimpleResource getSimpleResource() {
30 | return simpleResource;
31 | }
32 |
33 | public void setSimpleResource(SimpleResource simpleResource) {
34 | this.simpleResource = simpleResource;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/resource/ResourceGroups.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.resource;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import javax.xml.bind.annotation.XmlElement;
7 |
8 | public class ResourceGroups {
9 | private List resourceGroup;
10 |
11 | public ResourceGroups() {
12 | this.resourceGroup = new ArrayList<>();
13 | }
14 |
15 | @XmlElement(name = "resource-group")
16 | public List getResourceGroup() {
17 | return resourceGroup;
18 | }
19 |
20 | public void setResourceGroup(List resourceGroup) {
21 | this.resourceGroup = resourceGroup;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/resource/SimpleResource.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.resource;
2 |
3 | import javax.xml.bind.annotation.XmlAttribute;
4 | import javax.xml.bind.annotation.XmlTransient;
5 | import javax.xml.bind.annotation.XmlValue;
6 | import java.util.Objects;
7 |
8 | public class SimpleResource {
9 | private String resource;
10 | private String cachedData;
11 | private int delay;
12 | private String errorCode;
13 | private int errorRate;
14 | private String contentType;
15 |
16 | @XmlValue
17 | public String getResource() {
18 | return resource;
19 | }
20 |
21 | public void setResource(String resource) {
22 | this.resource = resource;
23 | }
24 |
25 | @XmlTransient
26 | public String getCachedData() {
27 | return cachedData;
28 | }
29 |
30 | public void setCachedData(String cachedData) {
31 | this.cachedData = cachedData;
32 | }
33 |
34 | @XmlAttribute(name = "delay")
35 | public int getDelay() {
36 | return delay;
37 | }
38 |
39 | public void setDelay(int delay) {
40 | this.delay = delay;
41 | }
42 |
43 | @XmlAttribute(name = "error-code")
44 | public String getErrorCode() {
45 | return errorCode;
46 | }
47 |
48 | public void setErrorCode(String errorCode) {
49 | this.errorCode = errorCode;
50 | }
51 |
52 | @XmlAttribute(name = "error-rate")
53 | public int getErrorRate() {
54 | return errorRate;
55 | }
56 |
57 | public void setErrorRate(int errorRate) {
58 | this.errorRate = errorRate;
59 | }
60 |
61 | @XmlAttribute(name = "content-type")
62 | public String getContentType() {
63 | return contentType;
64 | }
65 |
66 | public void setContentType(String contentType) {
67 | this.contentType = contentType;
68 | }
69 |
70 | @Override
71 | public boolean equals(Object obj) {
72 | if (obj == null) {
73 | return false;
74 | }
75 | if (!(obj instanceof SimpleResource)) {
76 | return false;
77 | }
78 | SimpleResource ref = (SimpleResource) obj;
79 | return (Objects.equals(this.getContentType(), ref.getContentType())
80 | && Objects.equals(this.getErrorCode(), ref.getErrorCode())
81 | && Objects.equals(this.getResource(), ref.getResource())
82 | );
83 | }
84 | }
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/model/jaxb/resource/XpathConfig.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.model.jaxb.resource;
2 |
3 | import javax.xml.bind.annotation.XmlValue;
4 |
5 | public class XpathConfig {
6 | private String xpath;
7 |
8 | @XmlValue
9 | public String getXpath() {
10 | return xpath;
11 | }
12 |
13 | public void setXpath(String xpath) {
14 | this.xpath = xpath;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/output/ResponseContextGenerator.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.output;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 | import java.nio.file.Files;
8 | import java.nio.file.Path;
9 | import java.util.stream.Collectors;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import net.technolords.micro.model.ResponseContext;
15 | import net.technolords.micro.model.jaxb.resource.SimpleResource;
16 |
17 | public class ResponseContextGenerator {
18 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
19 | private Path pathToDataFolder;
20 |
21 | /**
22 | * Custom constructor, which caches the path to the data folder. Note that this can be null.
23 | *
24 | * @param pathToDataFolder
25 | * The path to the data folder.
26 | */
27 | public ResponseContextGenerator(Path pathToDataFolder) {
28 | this.pathToDataFolder = pathToDataFolder;
29 | }
30 |
31 | /**
32 | * Auxiliary method that reads the response data as well as updating the internal cache so
33 | * subsequent reads will will served from memory. It also implements the delay and updates
34 | * the ResponseContext with an erroneous status code if the error rate is triggered.
35 | *
36 | * @param resource
37 | * The resource to read and cache.
38 | *
39 | * @return
40 | * The data associated with the resource (i.e. response).
41 | *
42 | * @throws IOException
43 | * When reading the resource fails.
44 | */
45 | public ResponseContext readResourceCacheOrFile(SimpleResource resource) throws IOException, InterruptedException {
46 | LOGGER.debug("Resource defined: {}", resource);
47 | if (resource != null) {
48 | LOGGER.debug("Resource defined, will read from: {}", resource.getResource());
49 | }
50 | // Add delay (only when applicable)
51 | if (resource.getDelay() > 0) {
52 | LOGGER.debug("About to delay {} ms", resource.getDelay());
53 | Thread.sleep(resource.getDelay());
54 | }
55 | // Apply response
56 | ResponseContext responseContext = new ResponseContext();
57 | if (resource.getCachedData() == null) {
58 | if (this.pathToDataFolder == null) {
59 | resource.setCachedData(this.readFromPackagedFile(resource.getResource()));
60 | } else {
61 | resource.setCachedData(this.readFromReferencedPath(resource.getResource()));
62 | }
63 | }
64 | // Apply content type
65 | responseContext.setResponse(resource.getCachedData());
66 | if (resource.getContentType() != null) {
67 | responseContext.setContentType(resource.getContentType());
68 | } else {
69 | responseContext.setContentType(this.fallbackLogicForContentType(resource));
70 | }
71 | // Apply custom error (only when applicable)
72 | if (resource.getErrorRate() > 0) {
73 | if (resource.getErrorRate() >= this.generateRandom()) {
74 | responseContext.setErrorCode(resource.getErrorCode());
75 | }
76 | }
77 | return responseContext;
78 | }
79 |
80 | /**
81 | * Auxiliary method to determine the content type (as fall back logic). In this case, the file extension is used.
82 | * When it .xml it will be 'application/xml' and otherwise 'application/json'.
83 | *
84 | * @param resource
85 | * The resource associated with the fall back logic.
86 | *
87 | * @return
88 | * The content type.
89 | */
90 | private String fallbackLogicForContentType(SimpleResource resource) {
91 | if (resource.getResource().toLowerCase().endsWith(".xml")) {
92 | return ResponseContext.XML_CONTENT_TYPE;
93 | } else {
94 | return ResponseContext.DEFAULT_CONTENT_TYPE;
95 | }
96 | }
97 |
98 | /**
99 | * Auxiliary method to read data from a packaged file.
100 | *
101 | * @param resourceReference
102 | * The reference of the resource, or, path of the file (in the jar).
103 | * @return
104 | * The content of the resource.
105 | *
106 | * @throws IOException
107 | * When reading the resource fails.
108 | */
109 | private String readFromPackagedFile(String resourceReference) throws IOException {
110 | LOGGER.trace("About to read from internal source...");
111 | InputStream fileStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceReference);
112 | LOGGER.debug("Path to (internal) file exists: {}", fileStream.available());
113 | return new BufferedReader(new InputStreamReader(fileStream)).lines().collect(Collectors.joining("\n"));
114 | }
115 |
116 | /**
117 | * Auxiliary method to read data from a file.
118 | *
119 | * @param resourceReference
120 | * The reference of the resource, or, path of the file (on file system).
121 | * @return
122 | * The content of the resource.
123 | *
124 | * @throws IOException
125 | * When reading the resource fails.
126 | */
127 | private String readFromReferencedPath(String resourceReference) throws IOException {
128 | LOGGER.trace("About to read from external source...");
129 | Path pathToResource = this.pathToDataFolder.resolve(resourceReference);
130 | LOGGER.debug("Path to (external) file exists: {}", Files.exists(pathToResource));
131 | return Files.lines(pathToResource).collect(Collectors.joining("\n"));
132 | }
133 |
134 | /**
135 | * Auxiliary method to generate a random number. This number will be in the range of [1, 100].
136 | *
137 | * @return
138 | * A random number.
139 | */
140 | protected int generateRandom() {
141 | return (int)(Math.random() * 100 + 1);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/registry/MockRegistry.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry;
2 |
3 | import static net.technolords.micro.config.PropertiesManager.PROP_BUILD_DATE;
4 | import static net.technolords.micro.config.PropertiesManager.PROP_BUILD_VERSION;
5 |
6 | import java.io.IOException;
7 | import java.util.Properties;
8 |
9 | import javax.xml.bind.JAXBException;
10 |
11 | import org.apache.camel.main.Main;
12 | import org.eclipse.jetty.server.Server;
13 | import org.eclipse.jetty.server.handler.StatisticsHandler;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import org.xml.sax.SAXException;
17 |
18 | import net.technolords.micro.camel.processor.EurekaRenewalProcessor;
19 | import net.technolords.micro.camel.processor.ResponseProcessor;
20 | import net.technolords.micro.config.ConfigurationManager;
21 | import net.technolords.micro.config.PropertiesManager;
22 | import net.technolords.micro.filter.InfoFilter;
23 |
24 | /**
25 | * This class 'isolates' all the Registry interfacing with Camel, and basically serves as a centralized
26 | * way of implementation. By no means this class is intended to replace or implement a Registry. This class
27 | * in fact substitutes for a IOC solution (like Spring or Blueprint).
28 | */
29 | public class MockRegistry {
30 | private static final Logger LOGGER = LoggerFactory.getLogger(MockRegistry.class);
31 | private static final String BEAN_PROPERTIES = "props";
32 | private static final String BEAN_META_DATA_PROPERTIES = "propsMetaData";
33 | private static final String BEAN_METRICS = "metrics";
34 | private static final String BEAN_JETTY_SERVER = "jettyServer";
35 | private static final String BEAN_CONFIG = "config";
36 | private static final String BEAN_FILTER_INFO = "infoFilter";
37 | private static final String BEAN_RESPONSE_PROCESSOR = "responseProcessor";
38 | private static final String BEAN_RENEWAL_PROCESSOR = "renewalProcessor";
39 | private static final String BEAN_SERVICE_REGISTRATION = "serviceRegistration";
40 | private static Main main;
41 |
42 | /**
43 | * Custom constructor with a reference of the main which is used to store the properties.
44 | *
45 | * @param mainReference
46 | * A reference of the Main object.
47 | */
48 | public static void registerPropertiesInRegistry(Main mainReference) {
49 | main = mainReference;
50 | main.bind(BEAN_META_DATA_PROPERTIES, PropertiesManager.extractMetaData());
51 | main.bind(BEAN_PROPERTIES, PropertiesManager.extractProperties());
52 | }
53 |
54 | /**
55 | * Auxiliary method to register beans to the Main component, with the purpose of supporting lookup mechanism
56 | * in case references of the beans are required. The latter typically occurs at runtime, but also in cases
57 | * of lazy initialization. Note that this micro service is not using any dependency injection framework.
58 | *
59 | * @throws JAXBException
60 | * When creation the configuration bean fails.
61 | * @throws IOException
62 | * When creation the configuration bean fails.
63 | * @throws SAXException
64 | * When creation the configuration bean fails.
65 | */
66 | public static void registerBeansInRegistryBeforeStart() throws JAXBException, IOException, SAXException {
67 | main.bind(BEAN_METRICS, new StatisticsHandler());
68 | main.bind(BEAN_CONFIG, new ConfigurationManager(findConfiguredConfig(), findConfiguredData()));
69 | main.bind(BEAN_FILTER_INFO, new InfoFilter());
70 | main.bind(BEAN_RESPONSE_PROCESSOR, new ResponseProcessor());
71 | main.bind(BEAN_RENEWAL_PROCESSOR, new EurekaRenewalProcessor());
72 | main.bind(BEAN_SERVICE_REGISTRATION, new ServiceRegistrationManager());
73 | LOGGER.info("Beans added to the registry...");
74 | }
75 |
76 | /**
77 | * Auxiliary method to register beans to the Main component, but after the Main has started. Typically the
78 | * underlying Server is also started and instantiated.
79 | */
80 | public static void registerBeansInRegistryAfterStart() {
81 | StatisticsHandler statisticsHandler = findStatisticsHandler();
82 | Server server = statisticsHandler.getServer();
83 | main.bind(BEAN_JETTY_SERVER, server);
84 | InfoFilter.registerFilterDirectlyWithServer(server);
85 | }
86 |
87 | // -------------------------------
88 | // Find beans (sorted by alphabet)
89 | // -------------------------------
90 |
91 | public static ConfigurationManager findConfigurationManager() {
92 | return main.lookup(BEAN_CONFIG, ConfigurationManager.class);
93 | }
94 |
95 | public static EurekaRenewalProcessor findEurekaRenewalProcessor() {
96 | return main.lookup(BEAN_RENEWAL_PROCESSOR, EurekaRenewalProcessor.class);
97 | }
98 |
99 | public static InfoFilter findInfoFilter() {
100 | return main.lookup(BEAN_FILTER_INFO, InfoFilter.class);
101 | }
102 |
103 | public static Properties findProperties() {
104 | return main.lookup(BEAN_PROPERTIES, Properties.class);
105 | }
106 |
107 | public static ResponseProcessor findResponseProcessor() {
108 | return main.lookup(BEAN_RESPONSE_PROCESSOR, ResponseProcessor.class);
109 | }
110 |
111 | public static Server findJettyServer() {
112 | return main.lookup(BEAN_JETTY_SERVER, Server.class);
113 | }
114 |
115 | public static ServiceRegistrationManager findRegistrationManager() {
116 | return main.lookup(BEAN_SERVICE_REGISTRATION, ServiceRegistrationManager.class);
117 | }
118 |
119 | public static StatisticsHandler findStatisticsHandler() {
120 | return main.lookup(BEAN_METRICS, StatisticsHandler.class);
121 | }
122 |
123 | // -----------------------------------------
124 | // Find property values (sorted by alphabet)
125 | // -----------------------------------------
126 |
127 | public static String findConfiguredPort() {
128 | return (String) findProperties().get(PropertiesManager.PROP_PORT);
129 | }
130 |
131 | public static String findConfiguredConfig() {
132 | String s = (String) findProperties().get(PropertiesManager.PROP_CONFIG);
133 | LOGGER.debug("Property value for {}: {}", PropertiesManager.PROP_CONFIG, s);
134 | return s;
135 | }
136 |
137 | public static String findConfiguredData() {
138 | return (String) findProperties().get(PropertiesManager.PROP_DATA);
139 | }
140 |
141 | public static String findBuildMetaData() {
142 | Properties properties = main.lookup(BEAN_META_DATA_PROPERTIES, Properties.class);
143 | StringBuilder buffer = new StringBuilder();
144 | buffer.append(properties.get(PROP_BUILD_VERSION));
145 | buffer.append(" ");
146 | buffer.append(properties.get(PROP_BUILD_DATE));
147 | return buffer.toString();
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/registry/consul/ConsulPayloadFactory.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.consul;
2 |
3 | import java.util.List;
4 |
5 | import net.technolords.micro.model.jaxb.Configuration;
6 | import net.technolords.micro.model.jaxb.registration.HealthCheck;
7 | import net.technolords.micro.model.jaxb.registration.Service;
8 | import net.technolords.micro.registry.util.MetadataHelper;
9 |
10 | public class ConsulPayloadFactory {
11 |
12 | /**
13 | * Create a payload like:
14 | *
15 | * {
16 | * "ID": "mock-1",
17 | * "Name": "mock-service",
18 | * "Tags": [
19 | * "mock"
20 | * ],
21 | * "Address": "192.168.10.10",
22 | * "Port": 9090,
23 | * "Meta": {
24 | * "get": "/mock/get",
25 | * "post": "/mock/post1, /mock/post2"
26 | * },
27 | * "EnableTagOverride": false,
28 | * "Check": {
29 | * "DeregisterCriticalServiceAfter": "90m",
30 | * "HTTP": "http://192.168.10.10:9090/mock/cmd?config=current",
31 | * "Interval": "30s"
32 | * }
33 | * }
34 | * @param service
35 | * The service associated with the payload.
36 | *
37 | * @return
38 | * The payload in Json format.
39 | */
40 | public static String generatePayloadForRegister(Service service, List configurations) {
41 | StringBuilder buffer = new StringBuilder();
42 | buffer.append("{");
43 | // ID
44 | buffer.append("\"ID\": \"").append(service.getId()).append("\",");
45 | // Name
46 | buffer.append("\"Name\": \"").append(service.getName()).append("\",");
47 | // Tags
48 | buffer.append("\"Tags\": [");
49 | buffer.append("\"mock\"");
50 | buffer.append("],");
51 | // Address
52 | buffer.append("\"Address\": \"").append(service.getAddress()).append("\",");
53 | // Port
54 | buffer.append("\"Port\": ").append(service.getPort()).append(",");
55 | // Meta
56 | buffer.append("\"Meta\": {");
57 | MetadataHelper.addMetadataEntries(buffer, configurations);
58 | buffer.append("},");
59 | // EnableTagOverride
60 | buffer.append("\"EnableTagOverride\": false,");
61 | // Check
62 | HealthCheck healthCheck = service.getHealthCheck();
63 | if (healthCheck != null && healthCheck.isEnabled()) {
64 | buffer.append("\"Check\": {");
65 | buffer.append("\"DeregisterCriticalServiceAfter\": \"").append(healthCheck.getDeRegisterAfter()).append("\",");
66 | buffer.append("\"HTTP\": \"")
67 | .append("http://")
68 | .append(service.getAddress()).append(":")
69 | .append(service.getPort())
70 | .append("/mock/cmd?config=current")
71 | .append("\",");
72 | buffer.append("\"Interval\": \"").append(healthCheck.getInterval()).append("\"");
73 | buffer.append("}");
74 | }
75 | buffer.append("}");
76 | return buffer.toString();
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/registry/consul/ConsulRequestFactory.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.consul;
2 |
3 | import java.util.List;
4 |
5 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
6 | import org.apache.http.client.methods.HttpPut;
7 | import org.apache.http.entity.StringEntity;
8 |
9 | import net.technolords.micro.model.jaxb.Configuration;
10 | import net.technolords.micro.model.jaxb.registration.Registration;
11 |
12 | public class ConsulRequestFactory {
13 | private static final String API_SERVICE_REGISTER = "/v1/agent/service/register";
14 | private static final String API_SERVICE_DEREGISTER = "/v1/agent/service/deregister/";
15 |
16 | /**
17 | * A factory for a HttpPut method, suitable to register the service.
18 | *
19 | * @param registration
20 | * The Registration reference associated with the HttpPut
21 | *
22 | * @return
23 | * The generated HttpPut
24 | */
25 | public static HttpEntityEnclosingRequestBase createRegisterRequest(Registration registration, List configurations) {
26 | HttpPut httpPut = new HttpPut(generateUrlForRegister(registration));
27 | httpPut.setEntity(new StringEntity(ConsulPayloadFactory.generatePayloadForRegister(registration.getService(), configurations), "UTF-8"));
28 | return httpPut;
29 | }
30 |
31 | /**
32 | * http://192.168.10.14:8500/v1/agent/service/register (PUT)
33 | *
34 | * @param registration
35 | * The Registration associated with the URL
36 | *
37 | * @return
38 | * The generated URL in string format
39 | */
40 | private static String generateUrlForRegister(Registration registration) {
41 | StringBuffer buffer = new StringBuffer();
42 | if (!registration.getAddress().startsWith("http")) {
43 | buffer.append("http://");
44 | }
45 | buffer.append(registration.getAddress()).append(":").append(registration.getPort());
46 | buffer.append(API_SERVICE_REGISTER);
47 | return buffer.toString();
48 | }
49 |
50 | /**
51 | * A factory for a HttpPut method, suitable to deregister the service.
52 | *
53 | * @param registration
54 | * The consul reference associated with the HttpPut
55 | *
56 | * @return
57 | * The generated HttpPut
58 | */
59 | public static HttpEntityEnclosingRequestBase createDeregisterRequest(Registration registration) {
60 | return new HttpPut(generatedUrlForDeregister(registration));
61 | }
62 |
63 | /**
64 | * http://192.168.10.14:8500/v1/agent/service/deregister/:serviceId (PUT)
65 | *
66 | * @param registration
67 | * The service associated with the URL
68 | *
69 | * @return
70 | * The generated URL in string format
71 | */
72 | private static String generatedUrlForDeregister(Registration registration) {
73 | StringBuffer buffer = new StringBuffer();
74 | if (!registration.getAddress().startsWith("http")) {
75 | buffer.append("http://");
76 | }
77 | buffer.append(registration.getAddress()).append(":").append(registration.getPort());
78 | buffer.append(API_SERVICE_DEREGISTER);
79 | buffer.append(registration.getService().getId());
80 | return buffer.toString();
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/registry/eureka/EurekaPayloadFactory.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.eureka;
2 |
3 | import java.util.List;
4 |
5 | import net.technolords.micro.model.jaxb.Configuration;
6 | import net.technolords.micro.model.jaxb.registration.Service;
7 | import net.technolords.micro.registry.util.MetadataHelper;
8 |
9 | public class EurekaPayloadFactory {
10 |
11 | /**
12 | * Create a payload like:
13 | *
14 | * {
15 | * "instance": {
16 | * "hostName": "mock1", instanceId
17 | * "app": "mock", appId
18 | * "ipAddr": "10.0.0.10",
19 | * "port": {"$": "8080", "@enabled": "true"},
20 | * "status": "UP",
21 | * "securePort": {"$": "8443", "@enabled": "true"},
22 | * "healthCheckUrl": "http://192.168.10.10:9090/mock/cmd?config=current",
23 | * "dataCenterInfo": {
24 | * "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
25 | * "name": "MyOwn"
26 | * },
27 | * "metadata": {
28 | * "get": "/mock/get",
29 | * "post": "/mock/post1, /mock/post2"
30 | * }
31 | * }
32 | * }
33 | *
34 | * @param service
35 | * The service associated with the payload.
36 | *
37 | * @return
38 | * The payload in Json format.
39 | */
40 | public static String generatePayloadForRegister(Service service, List configurations) {
41 | StringBuilder buffer = new StringBuilder();
42 | buffer.append("{");
43 | buffer.append("\"instance\": {");
44 | // hostname
45 | buffer.append("\"hostName\": \"").append(service.getId()).append("\",");
46 | // app
47 | buffer.append("\"app\": \"").append(service.getName()).append("\",");
48 | // ipAddr
49 | buffer.append("\"ipAddr\": \"").append(service.getAddress()).append("\",");
50 | // port
51 | buffer.append("\"port\": {");
52 | buffer.append("\"$\": \"").append(service.getPort()).append("\", ");
53 | buffer.append("\"@enabled\": \"true\"");
54 | buffer.append("},"); // port
55 | // status
56 | buffer.append("\"status\": \"UP\",");
57 | // securePort
58 | buffer.append("\"securePort\": {");
59 | buffer.append("\"$\": \"8443\", ");
60 | buffer.append("\"@enabled\": \"true\"");
61 | buffer.append("},"); // securePort
62 | // healthCheckUrl
63 | buffer.append("\"healthCheckUrl\": \"http://");
64 | buffer.append(service.getAddress()).append(":").append(service.getPort());
65 | buffer.append("/mock/cmd?config=current\", ");
66 | // dataCenterInfo
67 | buffer.append("\"dataCenterInfo\": {");
68 | buffer.append("\"@class\": \"").append("com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo").append("\", ");
69 | buffer.append("\"name\": \"MyOwn\"");
70 | buffer.append("},"); // dataCenterInfo
71 | // metadata
72 | buffer.append("\"metadata\": {");
73 | MetadataHelper.addMetadataEntries(buffer, configurations);
74 | buffer.append("}"); // metadata
75 | buffer.append("}"); // instance
76 | buffer.append("}");
77 | return buffer.toString();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/registry/eureka/EurekaRequestFactory.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.eureka;
2 |
3 | import java.util.List;
4 |
5 | import org.apache.http.HttpHeaders;
6 | import org.apache.http.client.methods.HttpDelete;
7 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
8 | import org.apache.http.client.methods.HttpPost;
9 | import org.apache.http.client.methods.HttpRequestBase;
10 | import org.apache.http.entity.StringEntity;
11 |
12 | import net.technolords.micro.model.jaxb.Configuration;
13 | import net.technolords.micro.model.jaxb.registration.Registration;
14 |
15 | public class EurekaRequestFactory {
16 | private static final String API_SERVICE_REGISTER = "/eureka/v2/apps/";
17 | private static final String API_SERVICE_DEREGISTER = "/eureka/v2/apps/";
18 |
19 | /**
20 | * A factory for a HttpPost method, suitable to register the service.
21 | *
22 | * @param registration
23 | * The Registration reference associated with the HttpPost
24 | *
25 | * @return
26 | * The generated httpPost
27 | */
28 | public static HttpEntityEnclosingRequestBase createRegisterRequest(Registration registration, List configurations) {
29 | HttpPost httpPost = new HttpPost(generateUrlForRegister(registration));
30 | httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
31 | httpPost.setEntity(new StringEntity(EurekaPayloadFactory.generatePayloadForRegister(registration.getService(), configurations), "UTF-8"));
32 | return httpPost;
33 | }
34 |
35 | /**
36 | * http://localhost:8080/eureka/v2/apps/:appId (POST)
37 | *
38 | * @param registration
39 | * The Registration associated with the URL
40 | *
41 | * @return
42 | * The generated URL in string format
43 | */
44 | protected static String generateUrlForRegister(Registration registration) {
45 | StringBuffer buffer = new StringBuffer();
46 | if (!registration.getAddress().startsWith("http")) {
47 | buffer.append("http://");
48 | }
49 | buffer.append(registration.getAddress()).append(":").append(registration.getPort());
50 | buffer.append(API_SERVICE_REGISTER);
51 | buffer.append(registration.getService().getName());
52 | return buffer.toString();
53 | }
54 |
55 | /**
56 | * A factory for a HttpDelete method, suitable to register the service.
57 | *
58 | * @param registration
59 | * The Registration reference associated with the HttpDelete
60 | *
61 | * @return
62 | * The generated httpDelete
63 | */
64 | public static HttpRequestBase createDeRegisterRequest(Registration registration, List configurations) {
65 | HttpDelete httpDelete = new HttpDelete(generatedUrlForDeregister(registration));
66 | return httpDelete;
67 | }
68 |
69 | /**
70 | * http://localhost:8080/eureka/v2/apps/:appId/:instanceId (DELETE)
71 | *
72 | * @param registration
73 | * The service associated with the URL
74 | *
75 | * @return
76 | * The generated URL in string format
77 | */
78 | private static String generatedUrlForDeregister(Registration registration) {
79 | StringBuffer buffer = new StringBuffer();
80 | if (!registration.getAddress().startsWith("http")) {
81 | buffer.append("http://");
82 | }
83 | buffer.append(registration.getAddress()).append(":").append(registration.getPort());
84 | buffer.append(API_SERVICE_DEREGISTER);
85 | buffer.append(registration.getService().getName());
86 | buffer.append("/");
87 | buffer.append(registration.getService().getId());
88 | return buffer.toString();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/net/technolords/micro/registry/util/MetadataHelper.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.util;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import net.technolords.micro.model.jaxb.Configuration;
9 |
10 | public class MetadataHelper {
11 |
12 | /**
13 | * Auxiliary method to add meta data entries. This method is typically invoked from the PayloadFactories
14 | * i.e. ConsulPayloadFactory and the EurekaPayloadFactory.
15 | *
16 | * Depending on the configuration, the entries are added by http type (get, post, ...) followed
17 | * with a comma separated list of matchers (rest paths). In other words, the buffer is extended with
18 | * something like:
19 | *
20 | * "get": "/mock/get",
21 | * "post": "/mock/post1, /mock/post2"
22 | *
23 | * @param buffer
24 | * The buffer associated with the added entries.
25 | * @param configurations
26 | * The configurations associated with the entries.
27 | */
28 | public static void addMetadataEntries(StringBuilder buffer, List configurations) {
29 | Map> servicesByType = getServicesByType(configurations);
30 | int numberOfTypes = servicesByType.size();
31 | int currentNumber = 1;
32 | for (String type: servicesByType.keySet()) {
33 | // Add entries such as: "post": "/mock/post1, /mock/post2"
34 | buffer.append("\"").append(type).append("\": \"");
35 | List servicesByURL = servicesByType.get(type);
36 | int numberOfUrls = servicesByURL.size();
37 | int currentURL = 1;
38 | for(String url: servicesByURL) {
39 | buffer.append(url);
40 | buffer.append(currentURL < numberOfUrls ? ", " : "");
41 | currentURL++;
42 | }
43 | buffer.append(currentNumber < numberOfTypes ? "\"," : "\"");
44 | currentNumber++;
45 | }
46 | }
47 |
48 | /**
49 | * Auxiliary method to 'convert' a list of configurations to a map. This data structure is more
50 | * convenient to generate the meta data tags.
51 | *
52 | * @param configurations
53 | * The configurations associated with the map.
54 | *
55 | * @return
56 | * A map of services by type.
57 | */
58 | public static Map> getServicesByType(List configurations) {
59 | Map> servicesByType = new HashMap<>();
60 | for (Configuration configuration : configurations) {
61 | String type = configuration.getType();
62 | if (!servicesByType.containsKey(type)) {
63 | List services = new ArrayList<>();
64 | services.add(configuration.getUrl());
65 | servicesByType.put(configuration.getType(), services);
66 | } else {
67 | List services = servicesByType.get(type);
68 | services.add(configuration.getUrl());
69 | }
70 | }
71 | return servicesByType;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/resources/build-meta-data.txt:
--------------------------------------------------------------------------------
1 | build-version=${version}
2 | build-timestamp=${build.timestamp}
3 |
--------------------------------------------------------------------------------
/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/resources/mock/sample-get-complex.json:
--------------------------------------------------------------------------------
1 | {
2 | "person" : "sridevi",
3 | "colour" : "yellow"
4 | }
--------------------------------------------------------------------------------
/src/main/resources/mock/sample-get-default.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "get-request",
3 | "data" : "this is fun"
4 | }
--------------------------------------------------------------------------------
/src/main/resources/mock/sample-get.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "get-request",
3 | "data" : "this is fun"
4 | }
--------------------------------------------------------------------------------
/src/main/resources/mock/sample-post1.json:
--------------------------------------------------------------------------------
1 | {
2 | "label " : "post-request1",
3 | "data" : "this is also fun"
4 | }
--------------------------------------------------------------------------------
/src/main/resources/mock/sample-post2.json:
--------------------------------------------------------------------------------
1 | {
2 | "label " : "post-request2",
3 | "data" : "but only when it works"
4 | }
--------------------------------------------------------------------------------
/src/main/resources/mock/sample-post4.txt:
--------------------------------------------------------------------------------
1 | Plain text file
--------------------------------------------------------------------------------
/src/main/resources/xml/default-configuration.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | value1
10 | value2
11 | mock/sample-get-complex.json
12 |
13 |
14 | {customerNumber}
15 | mock/sample-get-{customerNumber}.json
16 |
17 |
18 | mock/sample-get-default.json
19 |
20 |
21 | mock/sample-get.json
22 |
23 |
24 | mock/sample-get.json
25 |
26 |
27 |
30 |
31 |
32 | urn:some:reference:1.0
33 |
34 |
35 |
36 | /technolords:sample/technolords:message[@id = '1']
37 | mock/sample-post1.json
38 |
39 |
40 | /technolords:sample/technolords:message[@id = '2']
41 | mock/sample-post2.json
42 |
43 |
44 | /technolords:sample/technolords:message[@id = '3']
45 | mock/sample-post3.json
46 |
47 |
48 | /technolords:sample/technolords:message[@id = '4']
49 | mock/sample-post4.txt
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/main/resources/xsd/configurations.xsd:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/RouteTestSupport.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro;
2 |
3 | import java.util.Properties;
4 |
5 | import org.apache.camel.ProducerTemplate;
6 | import org.apache.camel.main.Main;
7 | import org.apache.camel.testng.AvailablePortFinder;
8 | import org.apache.camel.testng.CamelTestSupport;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.testng.annotations.BeforeClass;
12 |
13 | import net.technolords.micro.camel.listener.MockMainListener;
14 | import net.technolords.micro.camel.listener.MockTestListener;
15 | import net.technolords.micro.camel.route.MockRoute;
16 | import net.technolords.micro.registry.MockRegistry;
17 |
18 | public class RouteTestSupport extends CamelTestSupport {
19 | private static final Logger LOGGER = LoggerFactory.getLogger(RouteTestSupport.class);
20 | private Main main;
21 | private ProducerTemplate producerTemplate;
22 | private String availablePort;
23 |
24 | /**
25 | * Find an available port number
26 | *
27 | * @throws Exception
28 | */
29 | @BeforeClass
30 | public void findAvailablePortNumber() throws Exception {
31 | if (this.main == null) {
32 | LOGGER.info("BeforeClass called (from: {})", getClass());
33 | this.availablePort = String.valueOf(AvailablePortFinder.getNextAvailable(10000));
34 | LOGGER.info("Found port: {}", this.availablePort);
35 | this.main = new Main();
36 | MockRegistry.registerPropertiesInRegistry(this.main);
37 | MockRegistry.registerBeansInRegistryBeforeStart();
38 | Properties properties = MockRegistry.findProperties();
39 | properties.put("port", this.availablePort);
40 | // this.main.addMainListener(new MockMainListener()); // Breaks deep within Camel: NPE in org.apache.camel.management.mbean.ManagedCamelContext.(ManagedCamelContext.java:85)
41 | this.main.addMainListener(new MockTestListener()); // Alternative listener
42 | this.main.addRouteBuilder(new MockRoute());
43 | this.main.start();
44 | LOGGER.info("Main started: {}", this.main.isStarted());
45 | MockRegistry.registerBeansInRegistryAfterStart();
46 | this.producerTemplate = this.main.getCamelTemplate();
47 | }
48 | }
49 |
50 | public Main getMain() {
51 | return this.main;
52 | }
53 |
54 | public ProducerTemplate getProducerTemplate() {
55 | return this.producerTemplate;
56 | }
57 |
58 | public String getAvailablePort() {
59 | return this.availablePort;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/camel/listener/MockTestListener.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.listener;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import org.apache.camel.CamelContext;
6 | import org.apache.camel.main.MainListenerSupport;
7 | import org.apache.camel.spi.ShutdownStrategy;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | public class MockTestListener extends MainListenerSupport {
12 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
13 |
14 | @Override
15 | public void configure(CamelContext camelContext) {
16 | LOGGER.debug("Configure called...");
17 | LOGGER.debug("Updating shutdown strategy for camel context: {}", camelContext.getName());
18 | ShutdownStrategy shutdownStrategy = camelContext.getShutdownStrategy();
19 | shutdownStrategy.setTimeUnit(TimeUnit.SECONDS);
20 | shutdownStrategy.setTimeout(1L);
21 | shutdownStrategy.setShutdownNowOnTimeout(true);
22 | shutdownStrategy.setSuppressLoggingOnTimeout(true);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/camel/processor/ResponseProcessorTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.camel.processor;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.nio.file.FileSystems;
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.nio.file.Paths;
9 |
10 | import org.apache.camel.Exchange;
11 | import org.apache.camel.impl.DefaultCamelContext;
12 | import org.apache.camel.impl.DefaultExchange;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.testng.Assert;
16 | import org.testng.annotations.DataProvider;
17 | import org.testng.annotations.Test;
18 |
19 | import net.technolords.micro.config.ConfigurationManager;
20 | import net.technolords.micro.test.PathSupport;
21 |
22 | public class ResponseProcessorTest {
23 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
24 | private static final String DATA_SET_FOR_CONFIGURATIONS = "dataSetMockExpectation";
25 |
26 | /**
27 | * Auxiliary method to declare a data set to support testing of responses with differernt
28 | * configurations. An entry is specified with five elements, each meaning:
29 | *
30 | * [0] : The file name of the configuration
31 | * [1] : The HTTP request type
32 | * [2] : The HTP uri
33 | * [3] : The body associated with the request (= null for GET)
34 | * [4] : The file name of the response file (with expected body)
35 | *
36 | * @return
37 | * The data set.
38 | */
39 | @DataProvider (name = DATA_SET_FOR_CONFIGURATIONS)
40 | public Object[][] dataSetMock() {
41 | return new Object[][] {
42 | { "config-for-ResponseProcessorTest.xml", ConfigurationManager.HTTP_POST, "/mock/post", "post-1-for-ResponseProcessorTest.xml", "post-1-for-ResponseProcessorTest.txt" },
43 | { "config-for-ResponseProcessorTest.xml", ConfigurationManager.HTTP_GET, "/mock/get", null, "get-1-for-ResponseProcessorTest.txt" },
44 | };
45 | }
46 |
47 | @Test (dataProvider = DATA_SET_FOR_CONFIGURATIONS)
48 | public void testMockResponses(final String configFile, final String method, final String uri, final String requestFile, final String responseFile) throws Exception {
49 | LOGGER.info("About to test with request file: {}, and expected response file: {}", requestFile, responseFile);
50 |
51 | // Initialize with configuration
52 | Path pathToConfigFile = FileSystems.getDefault().getPath(PathSupport.getTestConfigResourcesForMockAsString() + File.separator + configFile);
53 | Assert.assertTrue(Files.exists(pathToConfigFile));
54 | ConfigurationManager configurationManager = new ConfigurationManager(pathToConfigFile.toString(), null);
55 | ResponseProcessor responseProcessor = new ResponseProcessor(configurationManager);
56 | Assert.assertNotNull(responseProcessor);
57 |
58 | // Create and send request
59 | Exchange exchange = this.generateExchange(method, uri, requestFile);
60 | responseProcessor.process(exchange);
61 |
62 | // Assert response
63 | Path pathToResponseFile = PathSupport.getPathToTestDataForResponseResources();
64 | Path pathToResource = Paths.get(pathToResponseFile.toString(), responseFile);
65 | Assert.assertTrue(Files.exists(pathToResource));
66 | String actualResponse = exchange.getOut().getBody(String.class);
67 | String expectedResponse = new String(Files.readAllBytes(pathToResource));
68 | Assert.assertEquals(actualResponse, expectedResponse);
69 | }
70 |
71 | private Exchange generateExchange(final String method, final String uri, final String requestFile) throws IOException {
72 | Path pathToRequestFile = PathSupport.getPathToTestDataForRequestResources();
73 | Exchange exchange = new DefaultExchange(new DefaultCamelContext());
74 | exchange.getIn().setHeader(Exchange.HTTP_METHOD, method);
75 | exchange.getIn().setHeader(Exchange.HTTP_URI, uri);
76 | if (requestFile != null) {
77 | Path pathToResource = Paths.get(pathToRequestFile.toString(), requestFile);
78 | Assert.assertTrue(Files.exists(pathToResource));
79 | String requestContent = new String(Files.readAllBytes(pathToResource));
80 | exchange.getIn().setBody(requestContent);
81 | }
82 | return exchange;
83 | }
84 |
85 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/command/CommandManagerTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | import org.apache.camel.Exchange;
9 | import org.apache.camel.impl.DefaultExchange;
10 | import org.custommonkey.xmlunit.XMLAssert;
11 | import org.custommonkey.xmlunit.XMLUnit;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.testng.Assert;
15 | import org.testng.annotations.BeforeClass;
16 | import org.testng.annotations.DataProvider;
17 | import org.testng.annotations.Test;
18 |
19 | import net.technolords.micro.RouteTestSupport;
20 | import net.technolords.micro.config.ConfigurationManager;
21 | import net.technolords.micro.model.ResponseContext;
22 | import net.technolords.micro.test.PathSupport;
23 |
24 | public class CommandManagerTest extends RouteTestSupport {
25 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
26 | private static final String DATA_SET_FOR_COMMAND_MANAGER = "dataSetForCommandManager";
27 |
28 | @BeforeClass (description = "Initialize XMLUnit")
29 | public void initializeXMLUnit() {
30 | XMLUnit.setIgnoreWhitespace(true);
31 | XMLUnit.setIgnoreAttributeOrder(true);
32 | XMLUnit.setIgnoreComments(true);
33 | }
34 |
35 | /**
36 | * Auxiliary method to declare a data set to support testing of the CommandManager. An entry is specified
37 | * with four elements, each meaning:
38 | *
39 | * [0] : The command
40 | * [1] : The expected context type
41 | * [2] : The expected error code
42 | * [3] : The expected message
43 | *
44 | * @return
45 | * The data set.
46 | */
47 | @DataProvider (name = DATA_SET_FOR_COMMAND_MANAGER)
48 | public Object[][] dataSetForCommandManager() throws IOException {
49 | return new Object[][] {
50 | // { "unknown", ResponseContext.PLAIN_TEXT_CONTENT_TYPE, "501", "Currently not supported" },
51 | // { "stop", ResponseContext.PLAIN_TEXT_CONTENT_TYPE, null, "Stopping the mock.." },
52 | { "config", ResponseContext.XML_CONTENT_TYPE, null, expectedResponse() },
53 | // { "log", ResponseContext.PLAIN_TEXT_CONTENT_TYPE, null, "Log level changed to INFO" },
54 | // { "reset", ResponseContext.PLAIN_TEXT_CONTENT_TYPE, null, "Statistics has been reset" },
55 | };
56 | }
57 |
58 | @Test (dataProvider = DATA_SET_FOR_COMMAND_MANAGER, description = "Test the supported commands of the CommandManager")
59 | public void testCommandManager(final String command, final String contentType, final String errorCode, final String response) throws Exception {
60 | // Prepare
61 | Exchange exchange = new DefaultExchange(super.context());
62 | exchange.getIn().setHeader(Exchange.HTTP_METHOD, ConfigurationManager.HTTP_GET);
63 | exchange.getIn().setHeader(Exchange.HTTP_URI, "/mock/get");
64 | exchange.getIn().setHeader(command, contentType);
65 |
66 | // Execute
67 | ResponseContext responseContext = CommandManager.executeCommand(exchange);
68 | LOGGER.info("Response: {}" , responseContext.getResponse());
69 | LOGGER.info("Content Type: {}" , responseContext.getContentType());
70 | LOGGER.info("Error code: {}" , responseContext.getErrorCode());
71 |
72 | // Assert (note we cannot use String compare when we have XML responses)
73 | switch (contentType) {
74 | case ResponseContext.XML_CONTENT_TYPE:
75 | XMLAssert.assertXMLEqual(response, responseContext.getResponse());
76 | break;
77 | case ResponseContext.PLAIN_TEXT_CONTENT_TYPE:
78 | Assert.assertEquals(responseContext.getContentType(), contentType);
79 | break;
80 | default:
81 | Assert.fail("Unsupported contextType: " + contentType + " -> unclear how to compare response versus expected...");
82 | }
83 | Assert.assertEquals(responseContext.getErrorCode(), errorCode);
84 | Assert.assertEquals(responseContext.getContentType(), contentType);
85 | }
86 |
87 | private static String expectedResponse() throws IOException {
88 | Path pathToRequestFile = PathSupport.getPathToTestConfigForMockResources();
89 | Path pathToResource = Paths.get(pathToRequestFile.toString(), "config-for-CommandManagerTest.xml");
90 | Assert.assertTrue(Files.exists(pathToResource));
91 | return new String(Files.readAllBytes(pathToResource));
92 | }
93 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/command/ConfigCommandTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import java.io.InputStream;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import javax.xml.bind.JAXBContext;
11 | import javax.xml.bind.Unmarshaller;
12 |
13 | import org.apache.camel.Exchange;
14 | import org.custommonkey.xmlunit.XMLAssert;
15 | import org.custommonkey.xmlunit.XMLUnit;
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 | import org.testng.Assert;
19 | import org.testng.annotations.BeforeClass;
20 | import org.testng.annotations.DataProvider;
21 | import org.testng.annotations.Test;
22 |
23 | import net.technolords.micro.RouteTestSupport;
24 | import net.technolords.micro.config.ConfigurationManager;
25 | import net.technolords.micro.model.jaxb.Configuration;
26 | import net.technolords.micro.model.jaxb.Configurations;
27 | import net.technolords.micro.registry.MockRegistry;
28 | import net.technolords.micro.test.PathSupport;
29 |
30 | public class ConfigCommandTest extends RouteTestSupport {
31 | private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCommandTest.class);
32 | private static final String DATA_SET_FOR_TEST_CONFIGURATIONS = "dataSetForTestConfigurations";
33 |
34 | @BeforeClass (description = "Initialize XMLUnit")
35 | public void initializeXMLUnit() {
36 | XMLUnit.setIgnoreWhitespace(true);
37 | XMLUnit.setIgnoreAttributeOrder(true);
38 | XMLUnit.setIgnoreComments(true);
39 | }
40 |
41 | @Test (description = "Test with default mock configuration")
42 | public void testConfigCommandWithDefault() throws Exception {
43 | LOGGER.info("About to send Config command (default), total routes: {}", getProducerTemplate().getCamelContext().getRoutes().size());
44 | ConfigurationManager configurationManager = MockRegistry.findConfigurationManager();
45 | Assert.assertNotNull(configurationManager);
46 | Exchange response = getProducerTemplate().request("jetty:http://localhost:" + getAvailablePort() + "/mock/cmd", exchange -> {
47 | exchange.getIn().setHeader(Exchange.HTTP_METHOD, ConfigurationManager.HTTP_GET);
48 | exchange.getIn().setHeader("config", "current");
49 | });
50 | String actualConfig = response.getOut().getBody(String.class);
51 | LOGGER.debug("Got actual: {}", actualConfig);
52 | Path pathToConfigFile = Paths.get(PathSupport.getPathToTestConfigForMockResources().toString(), "config-1-for-ConfigCommandTest.xml");
53 | Assert.assertTrue(Files.exists(pathToConfigFile));
54 | String expectedConfig = new String(Files.readAllBytes(pathToConfigFile));
55 | LOGGER.debug("Got expected: {}", expectedConfig);
56 | XMLAssert.assertXMLEqual(expectedConfig, actualConfig);
57 | }
58 |
59 | @DataProvider (name = DATA_SET_FOR_TEST_CONFIGURATIONS)
60 | public Object[][] dataSetConfigs(){
61 | return new Object[][] {
62 | { "config-2-for-ConfigCommandTest.xml" },
63 | };
64 | }
65 |
66 | @Test (dataProvider = DATA_SET_FOR_TEST_CONFIGURATIONS, description = "Test with custom mock configuration")
67 | public void testWithLoadConfigurations(final String testConfigFile) throws Exception {
68 | LOGGER.debug("About to send Config command (test), total routes: {}", getProducerTemplate().getCamelContext().getRoutes().size());
69 |
70 | // Validate presence of config file
71 | Path pathToConfigFile = Paths.get(PathSupport.getPathToTestConfigForMockResources().toString(), testConfigFile);
72 | Assert.assertTrue(Files.exists(pathToConfigFile));
73 |
74 | // Prepare new configuration
75 | ConfigurationManager configurationManager = MockRegistry.findConfigurationManager();
76 | Configurations configurations = configurationManager.getConfigurations();
77 | List savedConfigurations = new ArrayList<>();
78 | savedConfigurations.addAll(configurations.getConfigurations());
79 | LOGGER.info("Current and saved size: {}", savedConfigurations.size());
80 | configurations.getConfigurations().clear();
81 | configurations.getConfigurations().addAll(this.loadTestConfiguration(pathToConfigFile).getConfigurations());
82 | LOGGER.info("Updated current size: {}", configurations.getConfigurations().size());
83 |
84 | // Request and assert
85 | Exchange response = getProducerTemplate().request("jetty:http://localhost:" + getAvailablePort() + "/mock/cmd", exchange -> {
86 | exchange.getIn().setHeader(Exchange.HTTP_METHOD, ConfigurationManager.HTTP_GET);
87 | exchange.getIn().setHeader("config", "current");
88 | });
89 | String actualConfig = response.getOut().getBody(String.class);
90 | String expectedConfig = new String(Files.readAllBytes(pathToConfigFile));
91 | XMLAssert.assertXMLEqual(expectedConfig, actualConfig);
92 |
93 | // Revert config (as we extend from a shared MockRegistry, and thus the same ConfigurationManager)
94 | LOGGER.debug("Saved size: {}", savedConfigurations.size());
95 | configurations.getConfigurations().clear();
96 | configurations.getConfigurations().addAll(savedConfigurations);
97 | LOGGER.info("Restored size: {}", configurations.getConfigurations().size());
98 | }
99 |
100 | private Configurations loadTestConfiguration(Path pathToConfigFile) throws Exception {
101 | InputStream inputStream = Files.newInputStream(pathToConfigFile);
102 | Unmarshaller unmarshaller = JAXBContext.newInstance(Configurations.class).createUnmarshaller();
103 | Configurations configurations = (Configurations)unmarshaller.unmarshal(inputStream);
104 | LOGGER.info("Loaded Configurations = {}", configurations.getConfigurations().size());
105 | return configurations;
106 | }
107 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/command/StatsCommandTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import org.apache.camel.Exchange;
4 | import org.eclipse.jetty.server.handler.StatisticsHandler;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.testng.Assert;
8 | import org.testng.annotations.Test;
9 |
10 | import net.technolords.micro.RouteTestSupport;
11 | import net.technolords.micro.config.ConfigurationManager;
12 | import net.technolords.micro.registry.MockRegistry;
13 |
14 | public class StatsCommandTest extends RouteTestSupport {
15 | private static final Logger LOGGER = LoggerFactory.getLogger(StatsCommandTest.class);
16 |
17 | @Test (description = "Test stats command with actual endpoint")
18 | public void testStatsCommand() throws Exception{
19 | LOGGER.info("About to send stats command, total routes: {}", super.getProducerTemplate().getCamelContext().getRoutes().size());
20 | Exchange response = super.getProducerTemplate().request("jetty:http://localhost:" + super.getAvailablePort() + "/mock/cmd", exchange -> {
21 | exchange.getIn().setHeader(Exchange.HTTP_METHOD, ConfigurationManager.HTTP_GET);
22 | exchange.getIn().setHeader("stats", "html");
23 | });
24 | StatisticsHandler statisticsHandler = MockRegistry.findStatisticsHandler();
25 | Assert.assertTrue(statisticsHandler.getRequests() == 1);
26 | String html = response.getOut().getBody(String.class);
27 | LOGGER.info("Got html: {}", html);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/command/StopCommandTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.command;
2 |
3 | import org.apache.camel.Exchange;
4 | import org.apache.camel.ServiceStatus;
5 | import org.apache.camel.impl.DefaultExchange;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.testng.Assert;
9 | import org.testng.annotations.Test;
10 |
11 | import net.technolords.micro.RouteTestSupport;
12 | import net.technolords.micro.config.ConfigurationManager;
13 |
14 | public class StopCommandTest extends RouteTestSupport {
15 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
16 |
17 | @Test (description = "Test result of stop command")
18 | public void testStopCommand() throws Exception{
19 | String method = ConfigurationManager.HTTP_GET;
20 | String uri = "/mock/cmd";
21 | Exchange exchange = this.generateExchange(method, uri);
22 | LOGGER.info("About to stop, current current context: {} -> started: {}", super.getProducerTemplate().getCamelContext().getName(), getMain().isStarted());
23 | super.getProducerTemplate().send("direct:main", exchange);
24 | Thread.sleep(1000L);
25 | LOGGER.info("Exchange send, current context: {} -> started: {}", super.getProducerTemplate().getCamelContext().getName(), exchange.getContext().getStatus());
26 | Assert.assertEquals(exchange.getContext().getStatus(), ServiceStatus.Stopped);
27 | }
28 |
29 | private Exchange generateExchange(final String method, final String uri) throws Exception {
30 | LOGGER.info("Producer template: {}", super.getProducerTemplate());
31 | Exchange exchange = new DefaultExchange(super.getProducerTemplate().getCamelContext());
32 | exchange.getIn().setHeader(Exchange.HTTP_METHOD, method);
33 | exchange.getIn().setHeader(Exchange.HTTP_URI, uri);
34 | exchange.getIn().setHeader("stop", "now");
35 | return exchange;
36 | }
37 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/config/ConfigurationsTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.config;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 | import java.util.List;
8 |
9 | import javax.xml.bind.JAXBException;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.testng.Assert;
14 | import org.testng.annotations.DataProvider;
15 | import org.testng.annotations.Test;
16 | import org.xml.sax.SAXException;
17 |
18 | import net.technolords.micro.model.jaxb.Configurations;
19 | import net.technolords.micro.model.jaxb.registration.Registration;
20 | import net.technolords.micro.model.jaxb.registration.ServiceRegistration;
21 | import net.technolords.micro.test.PathSupport;
22 |
23 | public class ConfigurationsTest {
24 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
25 | private static final String DATA_SET_FOR_CONFIG_FILES = "dataSetForConfigFiles";
26 |
27 | @DataProvider(name = DATA_SET_FOR_CONFIG_FILES)
28 | public Object[][] dataSetForDefaultConfiguration() throws IOException {
29 | return new Object[][]{
30 | { "config-for-registrations.xml", "192.168.10.14", 8500 },
31 | };
32 | }
33 |
34 | @Test (dataProvider = DATA_SET_FOR_CONFIG_FILES)
35 | public void testConfigurations(final String configuration, final String consulAddress, final int consulPort) throws JAXBException, IOException, SAXException {
36 | LOGGER.info("About to test with file: {}", configuration);
37 | Path pathToDirectory = PathSupport.getTestConfigResourcesForRegistration();
38 | Path pathToConfigurationFile = Paths.get(pathToDirectory.toString(), configuration);
39 | Assert.assertTrue(Files.exists(pathToConfigurationFile));
40 | ConfigurationManager configurationManager = new ConfigurationManager(pathToConfigurationFile.toString(), null);
41 | Configurations configurations = configurationManager.getConfigurations();
42 | Assert.assertNotNull(configurations);
43 | ServiceRegistration serviceRegistration = configurations.getServiceRegistration();
44 | Assert.assertNotNull(serviceRegistration);
45 | List registrations = serviceRegistration.getRegistrations();
46 | Assert.assertNotNull(registrations);
47 | Assert.assertTrue(registrations.size() > 0);
48 | Registration registration= registrations.get(0);
49 | Assert.assertEquals(registration.getAddress(), consulAddress);
50 | Assert.assertEquals(registration.getPort(), consulPort);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/input/ConfigurationSelectorTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.input;
2 |
3 | import java.io.IOException;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 | import java.util.Objects;
7 |
8 | import javax.xml.bind.JAXBException;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.testng.Assert;
13 | import org.testng.annotations.DataProvider;
14 | import org.testng.annotations.Test;
15 | import org.xml.sax.SAXException;
16 |
17 | import net.technolords.micro.RouteTestSupport;
18 | import net.technolords.micro.model.jaxb.Configuration;
19 | import net.technolords.micro.model.jaxb.resource.SimpleResource;
20 |
21 | public class ConfigurationSelectorTest extends RouteTestSupport {
22 | private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationSelectorTest.class);
23 | private static final String DATA_SET_FOR_TEST_CONFIGURATION_SELECTION = "dataSetForTestConfigurationSelection";
24 | private ConfigurationSelector configurationSelector = new ConfigurationSelector();
25 |
26 | @DataProvider(name = DATA_SET_FOR_TEST_CONFIGURATION_SELECTION)
27 | public Object[][] dataSetConfigs(){
28 | return new Object[][] {
29 | { "/mock/get", getConfigs(), expectedConfig("/mock/get", "GET", "configManagerTest/getResponse1.txt", null, null, null)},
30 | { "/mock/100/get", getConfigs(), expectedConfig("/mock/*/get", "GET", "configManagerTest/getResponse2.txt", null, null, null)},
31 | { "/mock/1/get", getConfigs(), expectedConfig("/mock/1/get", "GET", "configManagerTest/getResponse1.txt", null, null, null)},
32 | { "/mock/1/get/0/data", getConfigs(), expectedConfig("/mock/*/get/*/data", "GET", "mock/sample-get.json", null, null, null)},
33 | { "/mock/post", postConfigs1(), expectedConfig("/mock/post", "POST", "mock/sample-post4.txt", null, "text/plain", null)},
34 | { "/mock/post", postConfigs2(), expectedConfig("/mock/post", "POST", "mock/sample-post3.json", "206", null, null)},
35 | { "/angry/kid", postConfigs1(), null},
36 | };
37 | }
38 |
39 | @Test(dataProvider = DATA_SET_FOR_TEST_CONFIGURATION_SELECTION)
40 | public void testConfigurationSelection(final String url, final Map testConfigs, final Configuration expectedConfiguration) throws IOException, JAXBException, SAXException, InterruptedException {
41 | Configuration actualConfiguration = configurationSelector.findMatchingConfiguration(url, testConfigs);
42 | Assert.assertTrue(Objects.equals(actualConfiguration, expectedConfiguration));
43 | }
44 |
45 | private Map getConfigs() {
46 | Map getConfigurations = new HashMap<>();
47 | getConfigurations.put("/mock/get", expectedConfig("/mock/get", "GET", "configManagerTest/getResponse1.txt", null, null, null));
48 | getConfigurations.put("/mock/*/get", expectedConfig("/mock/*/get", "GET", "configManagerTest/getResponse2.txt", null, null, null));
49 | getConfigurations.put("/mock/1/get", expectedConfig("/mock/1/get", "GET", "configManagerTest/getResponse1.txt", null, null, null));
50 | getConfigurations.put("/mock/*/get/*/data", expectedConfig("/mock/*/get/*/data", "GET", "mock/sample-get.json", null, null, null));
51 | return getConfigurations;
52 | }
53 |
54 | private Map postConfigs1() {
55 | Map postConfigurations = new HashMap<>();
56 | postConfigurations.put("/mock/post", expectedConfig("/mock/post", "POST", "mock/sample-post4.txt", null, "text/plain", null));
57 | return postConfigurations;
58 | }
59 |
60 | private Map postConfigs2() {
61 | Map postConfigurations = new HashMap<>();
62 | postConfigurations.put("/mock/post", expectedConfig("/mock/post", "POST", "mock/sample-post3.json", "206", null, null));
63 | return postConfigurations;
64 | }
65 |
66 | private Configuration expectedConfig(final String url, final String type, final String resource, final String errorcode, final String contentType, final String cachedData) {
67 | SimpleResource simpleResource = new SimpleResource();
68 | Configuration createdConfig = new Configuration();
69 | createdConfig.setUrl(url);
70 | createdConfig.setType(type);
71 | simpleResource.setResource(resource);
72 | simpleResource.setErrorCode(errorcode);
73 | simpleResource.setContentType(contentType);
74 | simpleResource.setCachedData(cachedData);
75 | createdConfig.setSimpleResource(simpleResource);
76 | return createdConfig;
77 | }
78 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/log/LogManagerTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.log;
2 |
3 | import java.util.Map;
4 |
5 | import org.apache.logging.log4j.Level;
6 | import org.apache.logging.log4j.core.Appender;
7 | import org.apache.logging.log4j.core.LoggerContext;
8 | import org.apache.logging.log4j.core.config.Configuration;
9 | import org.apache.logging.log4j.core.config.LoggerConfig;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.testng.Assert;
13 | import org.testng.annotations.BeforeMethod;
14 | import org.testng.annotations.DataProvider;
15 | import org.testng.annotations.Test;
16 |
17 | import net.technolords.micro.model.ResponseContext;
18 |
19 | public class LogManagerTest {
20 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
21 | private static final String DATASET_FOR_CHANGING_LOG_LEVELS = "datasetForChangingLogLevels";
22 | private static final String GROUP_CHANGE_CONFIG = "changeConfig";
23 | private static final String GROUP_CHANGE_LEVEL = "changeLevel";
24 |
25 | /**
26 | * This test asserts that after re-configuration of the log engine the total appenders are
27 | * different. The 'comparison' will be done between:
28 | *
29 | * - default config (src/main/resources/log4j2.xml)
30 | * - alternative config (src/test/resources/xml/config-for-LogManagerTest.xml)
31 | */
32 | @Test (groups = { GROUP_CHANGE_CONFIG }, description = "Validate the numbers of Appenders associated with the LoggerContext")
33 | public void testLogReconfiguration() {
34 | LOGGER.debug("About to test re-configuration of the logger context");
35 | final String pathToAlternativeLogConfig = "src/test/resources/config/log/config-for-LogManagerTest.xml";
36 | LoggerContext loggerContext = LoggerContext.getContext(false);
37 | Configuration configuration = loggerContext.getConfiguration();
38 | Map appenderMap = configuration.getAppenders();
39 | Assert.assertTrue(appenderMap.size() == 1, "Expected 1 appender");
40 | Assert.assertTrue(appenderMap.containsKey("console"));
41 |
42 | LogManager.initializeLogging(pathToAlternativeLogConfig);
43 | // Refresh reference of configuration as it changed
44 | configuration = loggerContext.getConfiguration();
45 | appenderMap = configuration.getAppenders();
46 | Assert.assertTrue(appenderMap.size() == 2, "Expected 2 appenders");
47 | Assert.assertTrue(appenderMap.containsKey("console"));
48 | Assert.assertTrue(appenderMap.containsKey("filterAppender"));
49 | }
50 |
51 | /**
52 | * Auxiliary method to declare a data set to support changing log levels. An entry is specified
53 | * with three elements, each meaning:
54 | *
55 | * [0] : The new log level to set
56 | * [1] : The expected log level
57 | * [2] : The expected message
58 | *
59 | * @return
60 | * The data set.
61 | */
62 | @DataProvider(name = DATASET_FOR_CHANGING_LOG_LEVELS)
63 | public Object[][] dataSetMock(){
64 | return new Object[][] {
65 | { "error", Level.ERROR, "Log level changed to ERROR" },
66 | { "warn", Level.WARN, "Log level changed to WARN" },
67 | { "info", Level.INFO, "Log level changed to INFO" },
68 | { "debug", Level.DEBUG, "Log level changed to DEBUG" },
69 | { "off", Level.OFF, "Logging switched off" },
70 | { "oops", Level.INFO, "Log level changed to INFO" },
71 | };
72 | }
73 |
74 | /**
75 | * Auxiliary method to reset the log info, in case logging is actually required during development
76 | * of the test.
77 | */
78 | @BeforeMethod (groups = { GROUP_CHANGE_LEVEL })
79 | public void resetLogLevelToInfo() {
80 | LoggerConfig rootLogger = this.getRootLogger();
81 | rootLogger.setLevel(Level.INFO);
82 | }
83 |
84 | /**
85 | * This test asserts the new log level has been set as well as the expected message
86 | * to be returned is correct.
87 | *
88 | * @param newLevel
89 | * The new log level.
90 | * @param expectedLevel
91 | * The expected log level.
92 | * @param expectedMessage
93 | * The expected message.
94 | */
95 | @Test (dataProvider = DATASET_FOR_CHANGING_LOG_LEVELS, groups = { GROUP_CHANGE_LEVEL} )
96 | public void testChangeLogLevels(final String newLevel, final Level expectedLevel, final String expectedMessage) {
97 | ResponseContext responseContext = LogManager.changeLogLevel(newLevel);
98 | LoggerConfig rootLogger = this.getRootLogger();
99 | Assert.assertTrue(rootLogger.getLevel().equals(expectedLevel));
100 | Assert.assertEquals(responseContext.getResponse(), expectedMessage);
101 | }
102 |
103 | /**
104 | * Auxiliary method to find the root logger.
105 | *
106 | * @return
107 | * A reference of the root logger.
108 | */
109 | private LoggerConfig getRootLogger() {
110 | LoggerContext loggerContext = LoggerContext.getContext(false);
111 | Configuration configuration = loggerContext.getConfiguration();
112 | return configuration.getRootLogger();
113 | }
114 |
115 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/registry/consul/ConsulPayloadFactoryTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.consul;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.testng.Assert;
11 | import org.testng.annotations.Test;
12 |
13 | import net.technolords.micro.test.PathSupport;
14 | import net.technolords.micro.test.factory.ConfigurationsFactory;
15 | import net.technolords.micro.test.factory.ServiceFactory;
16 | import net.technolords.micro.util.WhitespaceFilter;
17 |
18 | public class ConsulPayloadFactoryTest {
19 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
20 |
21 | @Test
22 | public void testPayloadGenerationForRegistration() throws IOException {
23 | Path resources = PathSupport.getPathToTestResources();
24 | Path jsonFile = Paths.get(resources.toString(), "/json/consul-payload-register.json");
25 | LOGGER.debug("Json file exists: {}", Files.exists(jsonFile));
26 | String expected = new String(Files.readAllBytes(jsonFile));
27 | String actual = ConsulPayloadFactory.generatePayloadForRegister(ServiceFactory.createService(), ConfigurationsFactory.createConfigurations());
28 | Assert.assertEquals(WhitespaceFilter.filter(actual), WhitespaceFilter.filter(expected));
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/registry/eureka/EurekaPayloadFactoryTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.eureka;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.testng.Assert;
11 | import org.testng.annotations.Test;
12 |
13 | import net.technolords.micro.test.PathSupport;
14 | import net.technolords.micro.test.factory.ConfigurationsFactory;
15 | import net.technolords.micro.test.factory.ServiceFactory;
16 | import net.technolords.micro.util.WhitespaceFilter;
17 |
18 | public class EurekaPayloadFactoryTest {
19 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
20 |
21 | @Test
22 | public void testPayloadGenerationForRegistration() throws IOException {
23 | Path resources = PathSupport.getPathToTestResources();
24 | Path jsonFile = Paths.get(resources.toString(), "/json/eureka-payload-register.json");
25 | LOGGER.debug("Json file exists: {}", Files.exists(jsonFile));
26 | String expected = new String(Files.readAllBytes(jsonFile));
27 | String actual = EurekaPayloadFactory.generatePayloadForRegister(ServiceFactory.createService(), ConfigurationsFactory.createConfigurations());
28 | Assert.assertEquals(WhitespaceFilter.filter(actual), WhitespaceFilter.filter(expected));
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/registry/eureka/EurekaRequestFactoryTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.eureka;
2 |
3 | import org.apache.http.client.methods.HttpPost;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.testng.Assert;
7 | import org.testng.annotations.DataProvider;
8 | import org.testng.annotations.Test;
9 |
10 | import net.technolords.micro.model.jaxb.registration.Registration;
11 | import net.technolords.micro.model.jaxb.registration.Service;
12 | import net.technolords.micro.test.factory.ConfigurationsFactory;
13 |
14 | public class EurekaRequestFactoryTest {
15 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
16 | private static final String DATASET_FOR_REGISTER = "dataSetForRegister";
17 |
18 | @Test
19 | public void testCreateRegisterRequest() {
20 | Registration registration = this.createRegistration("mock-service", "mock-1", "localhost", 9090);
21 | HttpPost httpPost = (HttpPost) EurekaRequestFactory.createRegisterRequest(registration, ConfigurationsFactory.createConfigurations());
22 | Assert.assertNotNull(httpPost);
23 | }
24 |
25 | /**
26 | * - service name
27 | * - service instance
28 | * - host
29 | * - port
30 | * - expected
31 | *
32 | * @return
33 | */
34 | @DataProvider(name = DATASET_FOR_REGISTER)
35 | public Object[][] dataSetMock(){
36 | return new Object[][] {
37 | { "mock-service", "mock-1", "localhost", 9090, "http://localhost:9090/eureka/v2/apps/mock-service"},
38 | };
39 | }
40 |
41 | @Test (dataProvider = DATASET_FOR_REGISTER)
42 | public void testGenerateUrlForRegister(String name, String id, String host, int port, String expected) {
43 | Registration registration = this.createRegistration(name, id, host, port);
44 | String actual = EurekaRequestFactory.generateUrlForRegister(registration);
45 | Assert.assertEquals(expected, actual);
46 | }
47 |
48 | protected Registration createRegistration(String name, String id, String host, int port) {
49 | Registration registration = new Registration();
50 | registration.setAddress(host);
51 | registration.setPort(port);
52 | Service service = new Service();
53 | service.setName(name);
54 | service.setId(id);
55 | registration.setService(service);
56 | return registration;
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/registry/util/MetadataHelperTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.registry.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.testng.Assert;
6 | import org.testng.annotations.Test;
7 |
8 | import net.technolords.micro.test.factory.ConfigurationsFactory;
9 |
10 | public class MetadataHelperTest {
11 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
12 |
13 | @Test (description = "Test creation of the meta data string")
14 | public void testAddMetadataEntries() {
15 | StringBuilder buffer = new StringBuilder();
16 | MetadataHelper.addMetadataEntries(buffer, ConfigurationsFactory.createConfigurations());
17 | String expected = "\"post\": \"/mock/post1, /mock/post2\",\"get\": \"/mock/get\"";
18 | Assert.assertEquals(buffer.toString(), expected);
19 | }
20 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/test/PathSupportTest.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.test;
2 |
3 | import java.nio.file.Files;
4 | import java.nio.file.Path;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.testng.Assert;
9 | import org.testng.annotations.Test;
10 |
11 | public class PathSupportTest {
12 | private final Logger LOGGER = LoggerFactory.getLogger(getClass());
13 |
14 | // src/main/resources
15 | @Test (description = "Validate path to main resources")
16 | public void testPathToMainResources() {
17 | LOGGER.debug("About to validate path to main resources...");
18 | Path path = PathSupport.getPathToMainResources();
19 | Assert.assertTrue(Files.exists(path));
20 | Assert.assertTrue(Files.isDirectory(path));
21 | }
22 |
23 | // src/test/resources
24 | @Test (description = "Validate path to test resources")
25 | public void testPathToTestResources() {
26 | LOGGER.debug("About to validate path to test resources...");
27 | Path path = PathSupport.getPathToTestResources();
28 | Assert.assertTrue(Files.exists(path));
29 | Assert.assertTrue(Files.isDirectory(path));
30 | }
31 |
32 | // src/test/resources/config/log
33 | @Test (description = "Validate path to test configuration for log resources")
34 | public void testPathToTestConfigurationForLogResources() {
35 | LOGGER.debug("About to validate path to test configuration for log resources");
36 | Path path = PathSupport.getPathToTestConfigForLogResources();
37 | Assert.assertTrue(Files.exists(path));
38 | Assert.assertTrue(Files.isDirectory(path));
39 | }
40 |
41 | // src/test/resources/config/mock
42 | @Test (description = "Validate path to test configuration for mock resources")
43 | public void testPathToTestConfigurationForMockResources() {
44 | LOGGER.debug("About to validate path to test configuration for mock resources");
45 | Path path = PathSupport.getPathToTestConfigForMockResources();
46 | Assert.assertTrue(Files.exists(path));
47 | Assert.assertTrue(Files.isDirectory(path));
48 | }
49 |
50 | @Test (description = "Validate path to test configuration for registration resources")
51 | public void testPathToTestConfigurationForRegistrationResources() {
52 | LOGGER.debug("About to validate path to test configuration for registration resources");
53 | Path path = PathSupport.getTestConfigResourcesForRegistration();
54 | Assert.assertTrue(Files.exists(path));
55 | Assert.assertTrue(Files.isDirectory(path));
56 | }
57 |
58 | // src/test/resources/data/request
59 | @Test (description = "Validate path to test data for request resources")
60 | public void testPathToTestDataForRequestResources() {
61 | LOGGER.debug("About to validate path to test data for request resources");
62 | Path path = PathSupport.getPathToTestDataForRequestResources();
63 | Assert.assertTrue(Files.exists(path));
64 | Assert.assertTrue(Files.isDirectory(path));
65 | }
66 |
67 | // src/test/resources/data/response
68 | @Test (description = "Validate path to test data for response resources")
69 | public void testPathToTestDataForResponseResources() {
70 | LOGGER.debug("About to validate path to test data for request resources");
71 | Path path = PathSupport.getPathToTestDataForResponseResources();
72 | Assert.assertTrue(Files.exists(path));
73 | Assert.assertTrue(Files.isDirectory(path));
74 | }
75 | }
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/test/factory/ConfigurationsFactory.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.test.factory;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import net.technolords.micro.model.jaxb.Configuration;
7 |
8 | public class ConfigurationsFactory {
9 |
10 | public static List createConfigurations() {
11 | List configurations = new ArrayList<>();
12 | // Get
13 | Configuration configuration = new Configuration();
14 | configuration.setType("get");
15 | configuration.setUrl("/mock/get");
16 | configurations.add(configuration);
17 | // Post 1
18 | configuration = new Configuration();
19 | configuration.setType("post");
20 | configuration.setUrl("/mock/post1");
21 | configurations.add(configuration);
22 | // Post 2
23 | configuration = new Configuration();
24 | configuration.setType("post");
25 | configuration.setUrl("/mock/post2");
26 | configurations.add(configuration);
27 | return configurations;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/test/factory/ServiceFactory.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.test.factory;
2 |
3 | import net.technolords.micro.model.jaxb.registration.HealthCheck;
4 | import net.technolords.micro.model.jaxb.registration.Service;
5 |
6 | public class ServiceFactory {
7 |
8 | /**
9 | * Create a service like:
10 | *
11 | *
12 | *
13 | *
14 | *
15 | * @return
16 | * A service
17 | */
18 | public static Service createService() {
19 | Service service = new Service();
20 | service.setId("mock-1");
21 | service.setName("mock-service");
22 | service.setAddress("192.168.10.10");
23 | service.setPort(9090);
24 | HealthCheck healthCheck = new HealthCheck();
25 | healthCheck.setEnabled(true);
26 | healthCheck.setInterval("30s");
27 | healthCheck.setDeRegisterAfter("90m");
28 | service.setHealthCheck(healthCheck);
29 | return service;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/net/technolords/micro/util/WhitespaceFilter.java:
--------------------------------------------------------------------------------
1 | package net.technolords.micro.util;
2 |
3 | public class WhitespaceFilter {
4 |
5 | /**
6 | * Auiliary method to filter some white space (spaces and carriage return)
7 | *
8 | * @param original
9 | * The original to be filtered.
10 | *
11 | * @return
12 | * The filtered original.
13 | */
14 | public static String filter(String original) {
15 | return original.replaceAll(" |\n", "");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/resources/config/log/config-for-LogManagerTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-1-for-ConfigCommandTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | value1
7 | value2
8 | mock/sample-get-complex.json
9 |
10 |
11 | {customerNumber}
12 | mock/sample-get-{customerNumber}.json
13 |
14 |
15 | mock/sample-get-default.json
16 |
17 |
18 | mock/sample-get.json
19 |
20 |
21 | mock/sample-get.json
22 |
23 |
24 |
25 | urn:some:reference:1.0
26 |
27 |
28 |
29 | mock/sample-post1.json
30 | /technolords:sample/technolords:message[@id = '1']
31 |
32 |
33 | mock/sample-post2.json
34 | /technolords:sample/technolords:message[@id = '2']
35 |
36 |
37 | mock/sample-post3.json
38 | /technolords:sample/technolords:message[@id = '3']
39 |
40 |
41 | mock/sample-post4.txt
42 | /technolords:sample/technolords:message[@id = '4']
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-2-for-ConfigCommandTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | configManagerTest/getResponse1.txt
5 |
6 |
7 | configManagerTest/getResponse2.txt
8 |
9 |
10 | configManagerTest/getResponse1.txt
11 |
12 |
13 | mock/sample-get.json
14 |
15 |
16 |
17 | urn:some:reference:1.0
18 |
19 |
20 |
21 | mock/sample-post1.json
22 | /technolords:sample/technolords:message[@id = '1']
23 |
24 |
25 | mock/sample-post2.json
26 | /technolords:sample/technolords:message[@id = '2']
27 |
28 |
29 | mock/sample-post3.json
30 | /technolords:sample/technolords:message[@id = '3']
31 |
32 |
33 | mock/sample-post4.txt
34 | /technolords:sample/technolords:message[@id = '4']
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-for-AllOperationsTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | get-1-for-ConfigurationManagerTest.txt
8 |
9 |
10 | get-2-for-ConfigurationManagerTest.txt
11 |
12 |
13 | get-1-for-ConfigurationManagerTest.txt
14 |
15 |
16 | mock/sample-get.json
17 |
18 |
19 |
22 |
23 |
24 | urn:some:reference:1.0
25 |
26 |
27 |
28 | /technolords:sample/technolords:message[@id = '1']
29 | mock/sample-post1.json
30 |
31 |
32 | /technolords:sample/technolords:message[@id = '2']
33 | mock/sample-post2.json
34 |
35 |
36 | /technolords:sample/technolords:message[@id = '3']
37 | mock/sample-post3.json
38 |
39 |
40 | /technolords:sample/technolords:message[@id = '4']
41 | mock/sample-post4.txt
42 |
43 |
44 |
45 |
46 |
49 |
50 | mock/sample-put.json
51 |
52 |
53 |
56 |
57 | mock/sample-patch.json
58 |
59 |
60 |
63 |
64 | mock/sample-delete.json
65 |
66 |
67 |
70 |
71 |
74 |
75 |
78 |
79 |
82 |
83 |
86 |
87 |
90 |
91 |
94 |
95 |
98 |
99 |
102 |
103 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-for-CommandManagerTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | value1
7 | value2
8 | mock/sample-get-complex.json
9 |
10 |
11 | {customerNumber}
12 | mock/sample-get-{customerNumber}.json
13 |
14 |
15 | mock/sample-get-default.json
16 |
17 |
18 | mock/sample-get.json
19 |
20 |
21 | mock/sample-get.json
22 |
23 |
24 |
25 | urn:some:reference:1.0
26 |
27 |
28 |
29 | mock/sample-post1.json
30 | /technolords:sample/technolords:message[@id = '1']
31 |
32 |
33 | mock/sample-post2.json
34 | /technolords:sample/technolords:message[@id = '2']
35 |
36 |
37 | mock/sample-post3.json
38 | /technolords:sample/technolords:message[@id = '3']
39 |
40 |
41 | mock/sample-post4.txt
42 | /technolords:sample/technolords:message[@id = '4']
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-for-ConfigSelectorTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | configManagerTest/getResponse1.txt
5 |
6 |
7 | configManagerTest/getResponse2.txt
8 |
9 |
10 | configManagerTest/getResponse1.txt
11 |
12 |
13 | mock/sample-get.json
14 |
15 |
16 |
17 | urn:some:reference:1.0
18 |
19 |
20 |
21 | /technolords:sample/technolords:message[@id = '1']
22 | mock/sample-post1.json
23 |
24 |
25 | /technolords:sample/technolords:message[@id = '2']
26 | mock/sample-post2.json
27 |
28 |
29 | /technolords:sample/technolords:message[@id = '3']
30 | mock/sample-post3.json
31 |
32 |
33 | /technolords:sample/technolords:message[@id = '4']
34 | mock/sample-post4.txt
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-for-ConfigurationManagerTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | get-1-for-ConfigurationManagerTest.txt
8 |
9 |
10 | get-2-for-ConfigurationManagerTest.txt
11 |
12 |
13 | get-1-for-ConfigurationManagerTest.txt
14 |
15 |
16 | mock/sample-get.json
17 |
18 |
19 |
22 |
23 |
24 | urn:some:reference:1.0
25 |
26 |
27 |
28 | /technolords:sample/technolords:message[@id = '1']
29 | mock/sample-post1.json
30 |
31 |
32 | /technolords:sample/technolords:message[@id = '2']
33 | mock/sample-post2.json
34 |
35 |
36 | /technolords:sample/technolords:message[@id = '3']
37 | mock/sample-post3.json
38 |
39 |
40 | /technolords:sample/technolords:message[@id = '4']
41 | mock/sample-post4.txt
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/config-for-ResponseProcessorTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | data/response/get-1-for-ResponseProcessorTest.txt
7 |
8 |
11 |
12 |
13 | urn:eventis:testMock:1.0
14 |
15 |
16 |
17 | /anyMock:sample/anyMock:message[@id = '1']
18 | data/response/post-1-for-ResponseProcessorTest.txt
19 |
20 |
21 | /anyMock:sample/anyMock:message[@id = '2']
22 | data/response/post-2-for-ResponseProcessor.txt
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/test/resources/config/mock/test-configuration-with-queryParams.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | value1
10 | value2
11 | sample-get-complex.json
12 |
13 |
14 | 122333
15 | sample-get-122333.json
16 |
17 |
18 | sample-get-default.json
19 |
20 |
21 | mock/sample-get.json
22 |
23 |
24 | mock/sample-get.json
25 |
26 |
27 |
30 |
31 |
32 | urn:some:reference:1.0
33 |
34 |
35 |
36 | /technolords:sample/technolords:message[@id = '1']
37 | mock/sample-post1.json
38 |
39 |
40 | /technolords:sample/technolords:message[@id = '2']
41 | mock/sample-post2.json
42 |
43 |
44 | /technolords:sample/technolords:message[@id = '3']
45 | mock/sample-post3.json
46 |
47 |
48 | /technolords:sample/technolords:message[@id = '4']
49 | mock/sample-post4.txt
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/test/resources/config/registration/config-for-registrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
50 |
51 |
54 |
55 |
56 |
57 | value1
58 | value2
59 | mock/sample-get-complex.json
60 |
61 |
62 | {customerNumber}
63 | mock/sample-get-{customerNumber}.json
64 |
65 |
66 | mock/sample-get-default.json
67 |
68 |
69 | mock/sample-get.json
70 |
71 |
72 | mock/sample-get.json
73 |
74 |
75 |
78 |
79 |
80 | urn:some:reference:1.0
81 |
82 |
83 |
84 | /technolords:sample/technolords:message[@id = '1']
85 | mock/sample-post1.json
86 |
87 |
88 | /technolords:sample/technolords:message[@id = '2']
89 | mock/sample-post2.json
90 |
91 |
92 | /technolords:sample/technolords:message[@id = '3']
93 | mock/sample-post3.json
94 |
95 |
96 | /technolords:sample/technolords:message[@id = '4']
97 | mock/sample-post4.txt
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/test/resources/data/request/post-1-for-ResponseProcessorTest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/test/resources/data/response/get-1-for-ConfigurationManagerTest.txt:
--------------------------------------------------------------------------------
1 | response/1
--------------------------------------------------------------------------------
/src/test/resources/data/response/get-1-for-ResponseProcessorTest.txt:
--------------------------------------------------------------------------------
1 | This is response of GET request.
--------------------------------------------------------------------------------
/src/test/resources/data/response/get-2-for-ConfigurationManagerTest.txt:
--------------------------------------------------------------------------------
1 | response/2
--------------------------------------------------------------------------------
/src/test/resources/data/response/get-3-for-ConfigurationManagerTest.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "get-request",
3 | "data" : "this is fun"
4 | }
--------------------------------------------------------------------------------
/src/test/resources/data/response/post-1-for-ResponseProcessorTest.txt:
--------------------------------------------------------------------------------
1 | This is Sample Response #1 of Post Call.
--------------------------------------------------------------------------------
/src/test/resources/data/response/post-2-for-ResponseProcessorTest.txt:
--------------------------------------------------------------------------------
1 | This is Sample Response #2 of Post Call.
--------------------------------------------------------------------------------
/src/test/resources/data/response/sample-get-122333.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "get-request",
3 | "data" : "this is data for Customer : 122333"
4 | }
--------------------------------------------------------------------------------
/src/test/resources/data/response/sample-get-complex.json:
--------------------------------------------------------------------------------
1 | {
2 | "person" : "sridevi",
3 | "colour" : "yellow"
4 | }
--------------------------------------------------------------------------------
/src/test/resources/data/response/sample-get-default.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "get-request",
3 | "data" : "this is fun"
4 | }
--------------------------------------------------------------------------------
/src/test/resources/json/consul-payload-register.json:
--------------------------------------------------------------------------------
1 | {
2 | "ID": "mock-1",
3 | "Name": "mock-service",
4 | "Tags": [
5 | "mock"
6 | ],
7 | "Address": "192.168.10.10",
8 | "Port": 9090,
9 | "Meta": {
10 | "post": "/mock/post1, /mock/post2",
11 | "get": "/mock/get"
12 | },
13 | "EnableTagOverride": false,
14 | "Check": {
15 | "DeregisterCriticalServiceAfter": "90m",
16 | "HTTP": "http://192.168.10.10:9090/mock/cmd?config=current",
17 | "Interval": "30s"
18 | }
19 | }
--------------------------------------------------------------------------------
/src/test/resources/json/eureka-payload-register.json:
--------------------------------------------------------------------------------
1 | {
2 | "instance": {
3 | "hostName": "mock-1",
4 | "app": "mock-service",
5 | "ipAddr": "192.168.10.10",
6 | "port": {
7 | "$": "9090",
8 | "@enabled": "true"
9 | },
10 | "status": "UP",
11 | "securePort": {
12 | "$": "8443",
13 | "@enabled": "true"
14 | },
15 | "healthCheckUrl": "http://192.168.10.10:9090/mock/cmd?config=current",
16 | "dataCenterInfo": {
17 | "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
18 | "name": "MyOwn"
19 | },
20 | "metadata": {
21 | "post": "/mock/post1, /mock/post2",
22 | "get": "/mock/get"
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------