001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.impl.cloud; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Optional; 022 023import org.apache.camel.CamelContext; 024import org.apache.camel.CamelContextAware; 025import org.apache.camel.Endpoint; 026import org.apache.camel.Route; 027import org.apache.camel.api.management.ManagedResource; 028import org.apache.camel.cloud.DiscoverableService; 029import org.apache.camel.cloud.ServiceDefinition; 030import org.apache.camel.cloud.ServiceRegistry; 031import org.apache.camel.support.RoutePolicySupport; 032import org.apache.camel.util.ObjectHelper; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036@ManagedResource(description = "Service Registration Route policy") 037public class ServiceRegistrationRoutePolicy extends RoutePolicySupport implements CamelContextAware { 038 private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistrationRoutePolicy.class); 039 040 private final ServiceRegistry.Selector serviceRegistrySelector; 041 042 private ServiceRegistry serviceRegistry; 043 private CamelContext camelContext; 044 045 public ServiceRegistrationRoutePolicy() { 046 this(null, ServiceRegistrySelectors.DEFAULT_SELECTOR); 047 } 048 049 public ServiceRegistrationRoutePolicy(ServiceRegistry.Selector serviceRegistrySelector) { 050 this(null, serviceRegistrySelector); 051 } 052 053 public ServiceRegistrationRoutePolicy(ServiceRegistry serviceRegistry, ServiceRegistry.Selector serviceRegistrySelector) { 054 this.serviceRegistry = serviceRegistry; 055 this.serviceRegistrySelector = serviceRegistrySelector; 056 } 057 058 @Override 059 public CamelContext getCamelContext() { 060 return camelContext; 061 } 062 063 @Override 064 public void setCamelContext(CamelContext camelContext) { 065 this.camelContext = camelContext; 066 } 067 068 // *********************** 069 // policy life-cycle 070 // *********************** 071 072 @Override 073 public void doStart() throws Exception { 074 if (serviceRegistry == null) { 075 serviceRegistry = ServiceRegistryHelper.lookupService(camelContext, serviceRegistrySelector).orElseThrow( 076 () -> new IllegalStateException("ServiceRegistry service not found") 077 ); 078 } 079 080 LOGGER.debug("ServiceRegistrationRoutePolicy {} is using ServiceRegistry instance {} (id={}, type={})", 081 this, 082 serviceRegistry, 083 serviceRegistry.getId(), 084 serviceRegistry.getClass().getName() 085 ); 086 } 087 088 // *********************** 089 // route life-cycle 090 // *********************** 091 092 @Override 093 public void onStart(Route route) { 094 register(route); 095 } 096 097 @Override 098 public void onStop(Route route) { 099 deregister(route); 100 } 101 102 @Override 103 public void onSuspend(Route route) { 104 deregister(route); 105 } 106 107 @Override 108 public void onResume(Route route) { 109 register(route); 110 } 111 112 // *********************** 113 // registration helpers 114 // *********************** 115 116 private void register(Route route) { 117 computeServiceDefinition(route).ifPresent(serviceRegistry::register); 118 } 119 120 private void deregister(Route route) { 121 computeServiceDefinition(route).ifPresent(serviceRegistry::deregister); 122 } 123 124 private Optional<ServiceDefinition> computeServiceDefinition(Route route) { 125 final Endpoint endpoint = route.getConsumer().getEndpoint(); 126 final Map<String, String> properties = new HashMap<>(); 127 128 if (endpoint instanceof DiscoverableService) { 129 final DiscoverableService service = (DiscoverableService) endpoint; 130 131 // first load all the properties from the endpoint 132 properties.putAll(service.getServiceProperties()); 133 } 134 135 // then add additional properties from route with ServiceDefinition.SERVICE_META_PREFIX, 136 // note that route defined properties may override DiscoverableService 137 // provided ones 138 for (Map.Entry<String, Object> entry: route.getProperties().entrySet()) { 139 if (!entry.getKey().startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { 140 continue; 141 } 142 143 final String key = entry.getKey(); 144 final String val = camelContext.getTypeConverter().convertTo(String.class, entry.getValue()); 145 146 properties.put(key, val); 147 } 148 149 // try to get the service name from route properties 150 String serviceName = properties.get(ServiceDefinition.SERVICE_META_NAME); 151 if (serviceName == null) { 152 // if not check if the route group is defined use the route group 153 serviceName = route.getGroup(); 154 155 if (serviceName != null) { 156 properties.put(ServiceDefinition.SERVICE_META_NAME, serviceName); 157 } 158 } 159 160 if (ObjectHelper.isEmpty(serviceName)) { 161 LOGGER.debug("Route {} has not enough information for service registration", route); 162 return Optional.empty(); 163 } 164 165 // try to get the service id from route properties 166 String serviceId = properties.get(ServiceDefinition.SERVICE_META_ID); 167 if (serviceId == null) { 168 // if not check if the route id is custom and use it 169 if (route.getRouteContext().getRoute().hasCustomIdAssigned()) { 170 serviceId = route.getId(); 171 } 172 173 if (serviceId != null) { 174 properties.put(ServiceDefinition.SERVICE_META_ID, serviceId); 175 } 176 } 177 if (serviceId == null) { 178 // finally auto generate the service id 179 serviceId = getCamelContext().getUuidGenerator().generateUuid(); 180 } 181 182 final String serviceHost = properties.get(ServiceDefinition.SERVICE_META_HOST); 183 final String servicePort = properties.getOrDefault(ServiceDefinition.SERVICE_META_PORT, "-1"); 184 185 // Build the final resource definition from bits collected from the 186 // endpoint and the route. 187 return Optional.of( 188 new DefaultServiceDefinition( 189 serviceId, 190 serviceName, 191 serviceHost, 192 Integer.parseInt(servicePort), 193 properties 194 ) 195 ); 196 } 197} 198