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.

Reply via email to