This is an automated email from the ASF dual-hosted git repository. lburgazzoli pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit f3a29a0bef59cfc84df7389fcfd359400fca7645 Author: lburgazzoli <lburgazz...@gmail.com> AuthorDate: Thu May 10 18:33:38 2018 +0200 CAMEL-12502: camel cloud : create a service route policy --- .../org/apache/camel/cloud/ServiceDefinition.java | 4 + .../impl/cloud/ServiceRegistrationRoutePolicy.java | 186 +++++++++++++++++++++ .../ServiceRegistrationRoutePolicyFactory.java | 50 ++++++ ...java => ConsulServiceRegistrationTestBase.java} | 47 ++---- ...viceRegistrationWithRoutePolicyFactoryTest.java | 46 +++++ ...nsulServiceRegistrationWithRoutePolicyTest.java | 38 +++++ ...erviceRegistrationWithServiceComponentTest.java | 46 +++++ 7 files changed, 382 insertions(+), 35 deletions(-) diff --git a/camel-core/src/main/java/org/apache/camel/cloud/ServiceDefinition.java b/camel-core/src/main/java/org/apache/camel/cloud/ServiceDefinition.java index ee99441..3007e8c 100644 --- a/camel-core/src/main/java/org/apache/camel/cloud/ServiceDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/cloud/ServiceDefinition.java @@ -28,7 +28,11 @@ import org.apache.camel.util.StringHelper; * @see ServiceDiscovery */ public interface ServiceDefinition { + String SERVICE_META_PREFIX = "service."; + // default service meta-data keys + String SERVICE_META_ID = "service.id"; + String SERVICE_META_NAME = "service.name"; String SERVICE_META_PORT = "service.port"; String SERVICE_META_PROTOCOL= "service.protocol"; String SERVICE_META_PATH = "service.path"; diff --git a/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java b/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java new file mode 100644 index 0000000..ce05a03 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java @@ -0,0 +1,186 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.impl.cloud; + +import java.util.Map; +import java.util.Optional; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.Endpoint; +import org.apache.camel.Route; +import org.apache.camel.api.management.ManagedResource; +import org.apache.camel.cloud.DiscoverableService; +import org.apache.camel.cloud.ServiceDefinition; +import org.apache.camel.cloud.ServiceRegistry; +import org.apache.camel.support.RoutePolicySupport; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ManagedResource(description = "Clustered Route policy using") +public class ServiceRegistrationRoutePolicy extends RoutePolicySupport implements CamelContextAware { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistrationRoutePolicy.class); + + private final ServiceRegistry.Selector serviceRegistrySelector; + + private ServiceRegistry serviceRegistry; + private CamelContext camelContext; + + public ServiceRegistrationRoutePolicy() { + this(null, ServiceRegistrySelectors.DEFAULT_SELECTOR); + } + + public ServiceRegistrationRoutePolicy(ServiceRegistry.Selector serviceRegistrySelector) { + this(null, serviceRegistrySelector); + } + + public ServiceRegistrationRoutePolicy(ServiceRegistry serviceRegistry, ServiceRegistry.Selector serviceRegistrySelector) { + this.serviceRegistry = serviceRegistry; + this.serviceRegistrySelector = serviceRegistrySelector; + } + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + // *********************** + // policy life-cycle + // *********************** + + @Override + public void doStart() throws Exception { + if (serviceRegistry == null) { + serviceRegistry = ServiceRegistryHelper.lookupService(camelContext, serviceRegistrySelector).orElseThrow( + () -> new IllegalStateException("ServiceRegistry service not found") + ); + } + + LOGGER.debug("ServiceRegistrationRoutePolicy {} is using ServiceRegistry instance {} (id={}, type={})", + this, + serviceRegistry, + serviceRegistry.getId(), + serviceRegistry.getClass().getName() + ); + } + + // *********************** + // route life-cycle + // *********************** + + @Override + public void onStart(Route route) { + register(route); + } + + @Override + public void onStop(Route route) { + deregister(route); + } + + @Override + public void onSuspend(Route route) { + deregister(route); + } + + @Override + public void onResume(Route route) { + register(route); + } + + // *********************** + // registration helpers + // *********************** + + private void register(Route route) { + computeServiceDefinition(route).ifPresent(serviceRegistry::register); + } + + private void deregister(Route route) { + computeServiceDefinition(route).ifPresent(serviceRegistry::deregister); + } + + private Optional<ServiceDefinition> computeServiceDefinition(Route route) { + Endpoint endpoint = route.getConsumer().getEndpoint(); + + if (endpoint instanceof DiscoverableService) { + final DiscoverableService service = (DiscoverableService)endpoint; + final ServiceDefinition definition = service.getServiceDefinition(); + + // try to get the service id from route properties + String serviceId = (String)route.getProperties().get(ServiceDefinition.SERVICE_META_ID); + if (serviceId == null) { + // if not check if the route id is custom and use it + if (route.getRouteContext().getRoute().hasCustomIdAssigned()) { + serviceId = route.getId(); + } + } + if (serviceId == null) { + // finally get the id from the DiscoverableService + serviceId = definition.getId(); + } + + // try to get the service name from route properties + String serviceName = (String)route.getProperties().get(ServiceDefinition.SERVICE_META_NAME); + if (serviceName == null) { + // if not check if the route group is defined use the route group + serviceName = route.getGroup(); + } + if (serviceName == null) { + // finally get the name from the DiscoverableService + serviceName = definition.getName(); + } + + ObjectHelper.notNull(serviceId, "Service ID"); + ObjectHelper.notNull(serviceName, "Service Name"); + + // Build the final resource definition from bits collected from the + // endpoint and the route. + DefaultServiceDefinition.Builder builder = DefaultServiceDefinition.builder() + .from(definition) + .withId(serviceId) + .withName(serviceName); + + // Add additional metadata from route properties whose name starts + // with ServiceDefinition.SERVICE_META_PREFIX. + // + // NOTE: At the moment it is not possible to add properties to a route + // with fluent DSL + for (Map.Entry<String, Object> entry: route.getProperties().entrySet()) { + if (!entry.getKey().startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { + continue; + } + + final String key = entry.getKey().substring(ServiceDefinition.SERVICE_META_PREFIX.length()); + final String val = camelContext.getTypeConverter().convertTo(String.class, entry.getValue()); + + builder.addMeta(key, val); + } + + return Optional.of(builder.build()); + } + + return Optional.empty(); + } +} + diff --git a/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicyFactory.java b/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicyFactory.java new file mode 100644 index 0000000..54825fc --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicyFactory.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.impl.cloud; + +import org.apache.camel.CamelContext; +import org.apache.camel.cloud.ServiceRegistry; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.spi.RoutePolicy; +import org.apache.camel.spi.RoutePolicyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ServiceRegistrationRoutePolicyFactory implements RoutePolicyFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistrationRoutePolicyFactory.class); + + private final ServiceRegistry.Selector serviceRegistrySelector; + private final ServiceRegistry serviceRegistry; + + public ServiceRegistrationRoutePolicyFactory() { + this(null, ServiceRegistrySelectors.DEFAULT_SELECTOR); + } + + public ServiceRegistrationRoutePolicyFactory(ServiceRegistry.Selector serviceRegistrySelector) { + this(null, serviceRegistrySelector); + } + + public ServiceRegistrationRoutePolicyFactory(ServiceRegistry serviceRegistry, ServiceRegistry.Selector serviceRegistrySelector) { + this.serviceRegistry = serviceRegistry; + this.serviceRegistrySelector = serviceRegistrySelector; + } + + @Override + public RoutePolicy createRoutePolicy(CamelContext camelContext, String routeId, RouteDefinition route) { + return new ServiceRegistrationRoutePolicy(serviceRegistry, serviceRegistrySelector); + } +} diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationTestBase.java similarity index 65% rename from components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationTest.java rename to components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationTestBase.java index be189cb..a6ef5c9 100644 --- a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationTest.java +++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationTestBase.java @@ -17,32 +17,23 @@ package org.apache.camel.component.consul.cloud; import java.util.List; +import java.util.UUID; import com.orbitz.consul.CatalogClient; import com.orbitz.consul.HealthClient; import com.orbitz.consul.model.catalog.CatalogService; import com.orbitz.consul.model.health.ServiceHealth; import org.apache.camel.CamelContext; -import org.apache.camel.RoutesBuilder; -import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.cloud.ServiceDefinition; import org.apache.camel.component.consul.support.ConsulTestSupport; -import org.apache.camel.component.service.ServiceComponent; -import org.apache.camel.impl.JndiRegistry; import org.junit.Test; import org.springframework.util.SocketUtils; -public class ConsulServiceRegistrationTest extends ConsulTestSupport { - private final static String SERVICE_NAME = "my-service"; - private final static String SERVICE_HOST = "localhost"; - private final static int SERVICE_PORT = SocketUtils.findAvailableTcpPort(); - - @Override - protected JndiRegistry createRegistry() throws Exception { - JndiRegistry registry = super.createRegistry(); - registry.bind("service", new ServiceComponent()); - - return registry; - } +public abstract class ConsulServiceRegistrationTestBase extends ConsulTestSupport { + protected final static String SERVICE_ID = UUID.randomUUID().toString(); + protected final static String SERVICE_NAME = "my-service"; + protected final static String SERVICE_HOST = "localhost"; + protected final static int SERVICE_PORT = SocketUtils.findAvailableTcpPort(); @Override protected CamelContext createCamelContext() throws Exception { @@ -60,19 +51,6 @@ public class ConsulServiceRegistrationTest extends ConsulTestSupport { return context; } - @Override - protected RoutesBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - fromF("service:%s:jetty:http://0.0.0.0:%d?serviceMeta.type=consul", SERVICE_NAME, SERVICE_PORT) - .routeId("exposed") - .noAutoStartup() - .to("log:service-registry?level=INFO"); - } - }; - } - @Test public void testRegistrationFromRoute() throws Exception { final CatalogClient catalog = getConsul().catalogClient(); @@ -82,17 +60,16 @@ public class ConsulServiceRegistrationTest extends ConsulTestSupport { assertTrue(catalog.getService(SERVICE_NAME).getResponse().isEmpty()); // let start the route - context().startRoute("exposed"); + context().startRoute(SERVICE_ID); // check that service has been registered List<CatalogService> services = catalog.getService(SERVICE_NAME).getResponse(); assertEquals(1, services.size()); assertEquals(SERVICE_PORT, services.get(0).getServicePort()); assertEquals("localhost", services.get(0).getServiceAddress()); - assertTrue(services.get(0).getServiceTags().contains("type=consul")); - assertTrue(services.get(0).getServiceTags().contains("service.protocol=http")); - assertTrue(services.get(0).getServiceTags().contains("service.path=/")); - assertTrue(services.get(0).getServiceTags().contains("service.port=" + SERVICE_PORT)); + assertTrue(services.get(0).getServiceTags().contains(ServiceDefinition.SERVICE_META_PROTOCOL + "=http")); + assertTrue(services.get(0).getServiceTags().contains(ServiceDefinition.SERVICE_META_PATH + "=/service/endpoint/")); + assertTrue(services.get(0).getServiceTags().contains(ServiceDefinition.SERVICE_META_PORT + "=" + SERVICE_PORT)); List<ServiceHealth> checks = health.getHealthyServiceInstances(SERVICE_NAME).getResponse(); assertEquals(1, checks.size()); @@ -100,7 +77,7 @@ public class ConsulServiceRegistrationTest extends ConsulTestSupport { assertEquals("localhost", checks.get(0).getService().getAddress()); // let stop the route - context().stopRoute("exposed"); + context().stopRoute(SERVICE_ID); // the service should be removed once the route is stopped assertTrue(catalog.getService(SERVICE_NAME).getResponse().isEmpty()); diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithRoutePolicyFactoryTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithRoutePolicyFactoryTest.java new file mode 100644 index 0000000..cb2c51a --- /dev/null +++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithRoutePolicyFactoryTest.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.consul.cloud; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.cloud.ServiceRegistrationRoutePolicyFactory; + +public class ConsulServiceRegistrationWithRoutePolicyFactoryTest extends ConsulServiceRegistrationTestBase { + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.addRoutePolicyFactory(new ServiceRegistrationRoutePolicyFactory()); + + return context; + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + fromF("jetty:http://0.0.0.0:%d/service/endpoint/", SERVICE_PORT) + .routeId(SERVICE_ID) + .routeGroup(SERVICE_NAME) + .noAutoStartup() + .to("log:service-registry?level=INFO"); + } + }; + } +} diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithRoutePolicyTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithRoutePolicyTest.java new file mode 100644 index 0000000..d79c306 --- /dev/null +++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithRoutePolicyTest.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.consul.cloud; + +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.cloud.ServiceRegistrationRoutePolicy; + +public class ConsulServiceRegistrationWithRoutePolicyTest extends ConsulServiceRegistrationTestBase { + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + fromF("jetty:http://0.0.0.0:%d/service/endpoint/", SERVICE_PORT) + .routeId(SERVICE_ID) + .routeGroup(SERVICE_NAME) + .routePolicy(new ServiceRegistrationRoutePolicy()) + .noAutoStartup() + .to("log:service-registry?level=INFO"); + } + }; + } +} diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithServiceComponentTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithServiceComponentTest.java new file mode 100644 index 0000000..6738c12 --- /dev/null +++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistrationWithServiceComponentTest.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.consul.cloud; + +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.service.ServiceComponent; +import org.apache.camel.impl.JndiRegistry; + +public class ConsulServiceRegistrationWithServiceComponentTest extends ConsulServiceRegistrationTestBase { + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + registry.bind("service", new ServiceComponent()); + + return registry; + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + fromF("service:%s:jetty:http://0.0.0.0:%d/service/endpoint/", SERVICE_NAME, SERVICE_PORT) + .routeId(SERVICE_ID) + .routeGroup(SERVICE_NAME) + .noAutoStartup() + .to("log:service-registry?level=INFO"); + } + }; + } +} -- To stop receiving notification emails like this one, please contact lburgazz...@apache.org.