├── .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 | 19 | 20 | 22 | 23 | 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 | [![maven-central](https://img.shields.io/badge/Maven%20Central-v1.6.0-green.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22net.technolords.micro.service%22%20mock) 4 | [![docker-hub](https://img.shields.io/badge/Docker%20Hub-v1.6.0-green.svg)](https://hub.docker.com/r/technolords/mock/) 5 | [![slack](https://img.shields.io/badge/Slack-channel-green.svg)](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 | } --------------------------------------------------------------------------------