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.remote; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Optional; 022import java.util.Set; 023 024import org.apache.camel.CamelContextAware; 025import org.apache.camel.ExchangePattern; 026import org.apache.camel.Processor; 027import org.apache.camel.model.ProcessorDefinition; 028import org.apache.camel.model.PropertyDefinition; 029import org.apache.camel.model.remote.ServiceCallConfigurationDefinition; 030import org.apache.camel.model.remote.ServiceCallDefinition; 031import org.apache.camel.spi.ProcessorFactory; 032import org.apache.camel.spi.RouteContext; 033import org.apache.camel.spi.ServiceCallLoadBalancer; 034import org.apache.camel.spi.ServiceCallServer; 035import org.apache.camel.spi.ServiceCallServerListStrategy; 036import org.apache.camel.util.CamelContextHelper; 037import org.apache.camel.util.IntrospectionSupport; 038import org.apache.camel.util.ObjectHelper; 039 040public abstract class DefaultServiceCallProcessorFactory<C, S extends ServiceCallServer> implements ProcessorFactory { 041 @Override 042 public Processor createChildProcessor(RouteContext routeContext, ProcessorDefinition<?> definition, boolean mandatory) throws Exception { 043 // not in use 044 return null; 045 } 046 047 @Override 048 @SuppressWarnings("unchecked") 049 public Processor createProcessor(RouteContext routeContext, ProcessorDefinition<?> definition) throws Exception { 050 return definition instanceof ServiceCallDefinition 051 ? createProcessor(routeContext, (ServiceCallDefinition) definition, createConfiguration(routeContext)) 052 : null; 053 } 054 055 protected Processor createProcessor(RouteContext routeContext, ServiceCallDefinition definition, C cfg) throws Exception { 056 String name = definition.getName(); 057 String uri = definition.getUri(); 058 ExchangePattern mep = definition.getPattern(); 059 060 ServiceCallConfigurationDefinition config = definition.getServiceCallConfiguration(); 061 ServiceCallConfigurationDefinition configRef = null; 062 if (definition.getServiceCallConfigurationRef() != null) { 063 // lookup in registry first 064 configRef = CamelContextHelper.lookup(routeContext.getCamelContext(), definition.getServiceCallConfigurationRef(), ServiceCallConfigurationDefinition.class); 065 if (configRef == null) { 066 // and fallback as service configuration 067 routeContext.getCamelContext().getServiceCallConfiguration(definition.getServiceCallConfigurationRef(), ServiceCallConfigurationDefinition.class); 068 } 069 } 070 071 // if no configuration explicit configured then use default 072 if (config == null && configRef == null) { 073 config = routeContext.getCamelContext().getServiceCallConfiguration(null, ServiceCallConfigurationDefinition.class); 074 } 075 if (config == null) { 076 // if no default then try to find if there configuration in the registry of the given type 077 Set<ServiceCallConfigurationDefinition> set = routeContext.getCamelContext().getRegistry().findByType(ServiceCallConfigurationDefinition.class); 078 if (set.size() == 1) { 079 config = set.iterator().next(); 080 } 081 } 082 083 if (config == null && configRef == null) { 084 throw new IllegalStateException("The ServiceCall: " + definition + " must be configured before it can be used."); 085 } 086 087 if (cfg != null) { 088 // extract the properties from the configuration from the model 089 Map<String, Object> parameters = new HashMap<>(); 090 if (configRef != null) { 091 IntrospectionSupport.getProperties(configRef, parameters, null); 092 } 093 if (config != null) { 094 IntrospectionSupport.getProperties(config, parameters, null); 095 } 096 097 IntrospectionSupport.setProperties(cfg, parameters); 098 } 099 100 // lookup the load balancer to use (configured on EIP takes precedence vs configured on configuration) 101 ServiceCallLoadBalancer lb = configureLoadBalancer(cfg, routeContext, definition); 102 if (lb == null && config != null) { 103 lb = configureLoadBalancer(cfg, routeContext, config); 104 } 105 if (lb == null && configRef != null) { 106 lb = configureLoadBalancer(cfg, routeContext, configRef); 107 } 108 109 // lookup the server list strategy to use (configured on EIP takes precedence vs configured on configuration) 110 ServiceCallServerListStrategy sl = configureServerListStrategy(cfg, routeContext, definition); 111 if (sl == null && config != null) { 112 sl = configureServerListStrategy(cfg, routeContext, config); 113 } 114 if (sl == null && configRef != null) { 115 sl = configureServerListStrategy(cfg, routeContext, configRef); 116 } 117 118 // the component is used to configure what the default scheme to use (eg camel component name) 119 String component = config != null ? config.getComponent() : null; 120 if (component == null && configRef != null) { 121 component = configRef.getComponent(); 122 } 123 124 if (ObjectHelper.isNotEmpty(lb) && lb instanceof CamelContextAware) { 125 ((CamelContextAware)lb).setCamelContext(routeContext.getCamelContext()); 126 } 127 128 if (ObjectHelper.isNotEmpty(sl) && sl instanceof CamelContextAware) { 129 ((CamelContextAware)sl).setCamelContext(routeContext.getCamelContext()); 130 } 131 132 if (sl == null) { 133 sl = createDefaultServerListStrategy(cfg); 134 } 135 if (lb == null) { 136 lb = createDefaultLoadBalancer(cfg); 137 } 138 139 Map<String, String> properties = configureProperties(routeContext, config, configRef); 140 141 DefaultServiceCallProcessor processor = createProcessor(name, component, uri, mep, cfg, properties); 142 if (sl != null && processor.getServerListStrategy() == null) { 143 processor.setServerListStrategy(sl); 144 } 145 if (lb != null && processor.getLoadBalancer() == null) { 146 processor.setLoadBalancer(lb); 147 } 148 149 return processor; 150 } 151 152 protected Map<String, String> configureProperties(RouteContext routeContext, ServiceCallConfigurationDefinition config, ServiceCallConfigurationDefinition configRef) throws Exception { 153 Map<String, String> answer = new HashMap<>(); 154 if (config != null && config.getProperties() != null) { 155 for (PropertyDefinition prop : config.getProperties()) { 156 // support property placeholders 157 String key = CamelContextHelper.parseText(routeContext.getCamelContext(), prop.getKey()); 158 String value = CamelContextHelper.parseText(routeContext.getCamelContext(), prop.getValue()); 159 answer.put(key, value); 160 } 161 } 162 if (configRef != null && configRef.getProperties() != null) { 163 for (PropertyDefinition prop : configRef.getProperties()) { 164 // support property placeholders 165 String key = CamelContextHelper.parseText(routeContext.getCamelContext(), prop.getKey()); 166 String value = CamelContextHelper.parseText(routeContext.getCamelContext(), prop.getValue()); 167 answer.put(key, value); 168 } 169 } 170 return answer; 171 } 172 173 protected ServiceCallLoadBalancer configureLoadBalancer(C conf, RouteContext routeContext, ServiceCallDefinition sd) throws Exception { 174 ServiceCallLoadBalancer lb = null; 175 String ref; 176 177 if (sd != null) { 178 lb = sd.getLoadBalancer(); 179 ref = sd.getLoadBalancerRef(); 180 if (lb == null && ref != null) { 181 lb = builtInLoadBalancer( 182 conf, 183 ref) 184 .orElseGet(() -> CamelContextHelper.mandatoryLookup( 185 routeContext.getCamelContext(), 186 ref, 187 ServiceCallLoadBalancer.class) 188 ); 189 } 190 } 191 192 return lb; 193 } 194 195 protected ServiceCallLoadBalancer configureLoadBalancer(C conf, RouteContext routeContext, ServiceCallConfigurationDefinition config) throws Exception { 196 ServiceCallLoadBalancer lb = config.getLoadBalancer(); 197 String ref = config.getLoadBalancerRef(); 198 if (lb == null && ref != null) { 199 lb = builtInLoadBalancer( 200 conf, 201 ref) 202 .orElseGet(() ->CamelContextHelper.mandatoryLookup( 203 routeContext.getCamelContext(), 204 ref, 205 ServiceCallLoadBalancer.class) 206 ); 207 } 208 return lb; 209 } 210 211 protected ServiceCallServerListStrategy configureServerListStrategy(C conf, RouteContext routeContext, ServiceCallDefinition sd) throws Exception { 212 ServiceCallServerListStrategy sl = null; 213 String ref; 214 if (sd != null) { 215 sl = sd.getServerListStrategy(); 216 ref = sd.getServerListStrategyRef(); 217 if (sl == null && ref != null) { 218 sl = builtInServerListStrategy( 219 conf, 220 ref) 221 .orElseGet(() -> CamelContextHelper.mandatoryLookup( 222 routeContext.getCamelContext(), 223 ref, 224 ServiceCallServerListStrategy.class) 225 ); 226 } 227 } 228 229 return sl; 230 } 231 232 protected ServiceCallServerListStrategy configureServerListStrategy(C conf, RouteContext routeContext, ServiceCallConfigurationDefinition config) throws Exception { 233 ServiceCallServerListStrategy sl = config.getServerListStrategy(); 234 String ref = config.getServerListStrategyRef(); 235 if (sl == null && ref != null) { 236 sl = builtInServerListStrategy( 237 conf, 238 ref) 239 .orElseGet(() -> CamelContextHelper.mandatoryLookup( 240 routeContext.getCamelContext(), 241 ref, 242 ServiceCallServerListStrategy.class) 243 ); 244 } 245 246 return sl; 247 } 248 249 // special for ref is referring to built-in load balancers 250 protected Optional<ServiceCallLoadBalancer> builtInLoadBalancer(C conf, String name) throws Exception { 251 ServiceCallLoadBalancer lb = null; 252 if (ObjectHelper.equal(name, "random", true)) { 253 lb = new RandomServiceCallLoadBalancer(); 254 } else if (ObjectHelper.equal(name, "roundrobin", true)) { 255 lb = new RoundRobinServiceCallLoadBalancer(); 256 } 257 258 return Optional.ofNullable(lb); 259 } 260 261 // special for ref is referring to built-in server list strategies 262 protected Optional<ServiceCallServerListStrategy> builtInServerListStrategy(C conf, String name) throws Exception { 263 return Optional.empty(); 264 } 265 266 protected DefaultServiceCallProcessor createProcessor( 267 String name, 268 String component, 269 String uri, 270 ExchangePattern mep, 271 C conf, 272 Map<String, String> properties) throws Exception { 273 274 return new DefaultServiceCallProcessor(name, component, uri, mep); 275 } 276 277 // TODO: rename 278 protected abstract C createConfiguration(RouteContext routeContext) throws Exception; 279 280 281 protected ServiceCallLoadBalancer<S> createDefaultLoadBalancer(C conf) throws Exception { 282 return new RoundRobinServiceCallLoadBalancer<>(); 283 } 284 285 protected ServiceCallServerListStrategy<S> createDefaultServerListStrategy(C conf) throws Exception { 286 return null; 287 } 288}