001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.camel.impl; 019 020 import org.apache.camel.CamelContext; 021 import org.apache.camel.Component; 022 import org.apache.camel.Endpoint; 023 import org.apache.camel.Exchange; 024 import org.apache.camel.ResolveEndpointFailedException; 025 import org.apache.camel.Route; 026 import org.apache.camel.RuntimeCamelException; 027 import org.apache.camel.Service; 028 import org.apache.camel.TypeConverter; 029 import org.apache.camel.builder.RouteBuilder; 030 import org.apache.camel.impl.converter.DefaultTypeConverter; 031 import org.apache.camel.spi.ComponentResolver; 032 import org.apache.camel.spi.ExchangeConverter; 033 import org.apache.camel.spi.Injector; 034 import org.apache.camel.util.FactoryFinder; 035 import org.apache.camel.util.NoFactoryAvailableException; 036 import org.apache.camel.util.ObjectHelper; 037 import static org.apache.camel.util.ServiceHelper.startServices; 038 import static org.apache.camel.util.ServiceHelper.stopServices; 039 040 import java.io.IOException; 041 import java.util.ArrayList; 042 import java.util.Collection; 043 import java.util.HashMap; 044 import java.util.List; 045 import java.util.Map; 046 import java.util.concurrent.Callable; 047 048 /** 049 * Represents the context used to configure routes and the policies to use. 050 * 051 * @version $Revision: 520517 $ 052 * @org.apache.xbean.XBean element="container" rootElement="true" 053 */ 054 public class DefaultCamelContext extends ServiceSupport implements CamelContext, Service { 055 private Map<String, Endpoint> endpoints = new HashMap<String, Endpoint>(); 056 private Map<String, Component> components = new HashMap<String, Component>(); 057 private List<Route> routes; 058 private List<Service> servicesToClose = new ArrayList<Service>(); 059 private TypeConverter typeConverter; 060 private ExchangeConverter exchangeConverter; 061 private Injector injector; 062 private ComponentResolver componentResolver; 063 private boolean autoCreateComponents = true; 064 065 /** 066 * Adds a component to the container. 067 */ 068 public void addComponent(String componentName, final Component component) { 069 if (component == null) { 070 throw new IllegalArgumentException("Component cannot be null"); 071 } 072 synchronized (components) { 073 if (components.containsKey(componentName)) { 074 throw new IllegalArgumentException("Component previously added: " + componentName); 075 } 076 component.setCamelContext(this); 077 components.put(componentName, component); 078 } 079 } 080 081 public Component getComponent(String name) { 082 // synchronize the look up and auto create so that 2 threads can't 083 // concurrently auto create the same component. 084 synchronized (components) { 085 Component component = components.get(name); 086 if (component == null && autoCreateComponents) { 087 try { 088 component = getComponentResolver().resolveComponent(name, this); 089 if (component != null) { 090 addComponent(name, component); 091 if (isStarted()) { 092 // If the component is looked up after the context is started, 093 // lets start it up. 094 startServices(component); 095 } 096 } 097 } 098 catch (Exception e) { 099 throw new RuntimeCamelException("Could not auto create component: " + name, e); 100 } 101 } 102 return component; 103 } 104 } 105 106 public <T extends Component> T getComponent(String name, Class<T> componentType) { 107 Component component = getComponent(name); 108 if (componentType.isInstance(component)) { 109 return componentType.cast(component); 110 } 111 else { 112 throw new IllegalArgumentException("The component is not of type: " + componentType + " but is: " + component); 113 } 114 } 115 116 /** 117 * Removes a previously added component. 118 * 119 * @param componentName 120 * @return the previously added component or null if it had not been previously added. 121 */ 122 public Component removeComponent(String componentName) { 123 synchronized (components) { 124 return components.remove(componentName); 125 } 126 } 127 128 /** 129 * Gets the a previously added component by name or lazily creates the component 130 * using the factory Callback. 131 * 132 * @param componentName 133 * @param factory used to create a new component instance if the component was not previously added. 134 * @return 135 */ 136 public Component getOrCreateComponent(String componentName, Callable<Component> factory) { 137 synchronized (components) { 138 Component component = components.get(componentName); 139 if (component == null) { 140 try { 141 component = factory.call(); 142 if (component == null) { 143 throw new RuntimeCamelException("Factory failed to create the " + componentName + " component, it returned null."); 144 } 145 components.put(componentName, component); 146 component.setCamelContext(this); 147 } 148 catch (Exception e) { 149 throw new RuntimeCamelException("Factory failed to create the " + componentName + " component", e); 150 } 151 } 152 return component; 153 } 154 } 155 156 // Endpoint Management Methods 157 //----------------------------------------------------------------------- 158 159 public Collection<Endpoint> getSingletonEndpoints() { 160 synchronized (endpoints) { 161 return new ArrayList<Endpoint>(endpoints.values()); 162 } 163 } 164 165 public Endpoint addSingletonEndpoint(String uri, Endpoint endpoint) throws Exception { 166 Endpoint oldEndpoint; 167 synchronized (endpoints) { 168 startServices(endpoint); 169 oldEndpoint = endpoints.remove(uri); 170 endpoints.put(uri, endpoint); 171 stopServices(oldEndpoint); 172 } 173 return oldEndpoint; 174 } 175 176 public Endpoint removeSingletonEndpoint(String uri) throws Exception { 177 Endpoint oldEndpoint; 178 synchronized (endpoints) { 179 oldEndpoint = endpoints.remove(uri); 180 stopServices(oldEndpoint); 181 } 182 return oldEndpoint; 183 } 184 185 /** 186 * Resolves the given URI to an endpoint 187 */ 188 public Endpoint getEndpoint(String uri) { 189 Endpoint answer; 190 synchronized (endpoints) { 191 answer = endpoints.get(uri); 192 if (answer == null) { 193 try { 194 195 // Use the URI prefix to find the component. 196 String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2); 197 if (splitURI[1] == null) { 198 throw new IllegalArgumentException("Invalid URI, it did not contain a scheme: " + uri); 199 } 200 String scheme = splitURI[0]; 201 Component component = getComponent(scheme); 202 203 // Ask the component to resolve the endpoint. 204 if (component != null) { 205 206 // Have the component create the endpoint if it can. 207 answer = component.createEndpoint(uri); 208 209 // If it's a singleton then auto register it. 210 if (answer != null && answer.isSingleton()) { 211 if (answer != null) { 212 startServices(answer); 213 endpoints.put(uri, answer); 214 } 215 } 216 } 217 } 218 catch (Exception e) { 219 throw new ResolveEndpointFailedException(uri, e); 220 } 221 } 222 } 223 return answer; 224 } 225 226 public <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType) { 227 Endpoint endpoint = getEndpoint(name); 228 if (endpointType.isInstance(endpoint)) { 229 return endpointType.cast(endpoint); 230 } 231 else { 232 throw new IllegalArgumentException("The endpoint is not of type: " + endpointType + " but is: " + endpoint); 233 } 234 } 235 236 // Route Management Methods 237 //----------------------------------------------------------------------- 238 public List<Route> getRoutes() { 239 return routes; 240 } 241 242 public void setRoutes(List<Route> routes) { 243 this.routes = routes; 244 } 245 246 public void addRoutes(Collection<Route> routes) throws Exception { 247 if (this.routes == null) { 248 this.routes = new ArrayList<Route>(routes); 249 } 250 else { 251 this.routes.addAll(routes); 252 } 253 if (isStarted()) { 254 startRoutes(routes); 255 } 256 } 257 258 public void addRoutes(RouteBuilder builder) throws Exception { 259 // lets now add the routes from the builder 260 builder.setContext(this); 261 addRoutes(builder.getRouteList()); 262 } 263 264 // Properties 265 //----------------------------------------------------------------------- 266 public ExchangeConverter getExchangeConverter() { 267 if (exchangeConverter == null) { 268 exchangeConverter = createExchangeConverter(); 269 } 270 return exchangeConverter; 271 } 272 273 public void setExchangeConverter(ExchangeConverter exchangeConverter) { 274 this.exchangeConverter = exchangeConverter; 275 } 276 277 public TypeConverter getTypeConverter() { 278 if (typeConverter == null) { 279 typeConverter = createTypeConverter(); 280 } 281 return typeConverter; 282 } 283 284 public void setTypeConverter(TypeConverter typeConverter) { 285 this.typeConverter = typeConverter; 286 } 287 288 public Injector getInjector() { 289 if (injector == null) { 290 injector = createInjector(); 291 } 292 return injector; 293 } 294 295 public void setInjector(Injector injector) { 296 this.injector = injector; 297 } 298 299 public ComponentResolver getComponentResolver() { 300 if (componentResolver == null) { 301 componentResolver = createComponentResolver(); 302 } 303 return componentResolver; 304 } 305 306 public void setComponentResolver(ComponentResolver componentResolver) { 307 this.componentResolver = componentResolver; 308 } 309 310 // Implementation methods 311 //----------------------------------------------------------------------- 312 313 protected void doStart() throws Exception { 314 if (components != null) { 315 for (Component component : components.values()) { 316 startServices(component); 317 } 318 } 319 startRoutes(routes); 320 } 321 322 protected void doStop() throws Exception { 323 stopServices(servicesToClose); 324 if (components != null) { 325 for (Component component : components.values()) { 326 stopServices(component); 327 } 328 } 329 } 330 331 protected void startRoutes(Collection<Route> routeList) throws Exception { 332 if (routeList != null) { 333 for (Route<Exchange> route : routeList) { 334 List<Service> services = route.getServicesForRoute(); 335 servicesToClose.addAll(services); 336 startServices(services); 337 } 338 } 339 } 340 341 /** 342 * Lazily create a default implementation 343 */ 344 protected ExchangeConverter createExchangeConverter() { 345 return new DefaultExchangeConverter(); 346 } 347 348 /** 349 * Lazily create a default implementation 350 */ 351 protected TypeConverter createTypeConverter() { 352 return new DefaultTypeConverter(); 353 } 354 355 /** 356 * Lazily create a default implementation 357 */ 358 protected Injector createInjector() { 359 FactoryFinder finder = new FactoryFinder(); 360 try { 361 return (Injector) finder.newInstance("Injector"); 362 } 363 catch (NoFactoryAvailableException e) { 364 // lets use the default 365 return new ReflectionInjector(); 366 } 367 catch (IllegalAccessException e) { 368 throw new RuntimeCamelException(e); 369 } 370 catch (InstantiationException e) { 371 throw new RuntimeCamelException(e); 372 } 373 catch (IOException e) { 374 throw new RuntimeCamelException(e); 375 } 376 catch (ClassNotFoundException e) { 377 throw new RuntimeCamelException(e); 378 } 379 } 380 381 /** 382 * Lazily create a default implementation 383 */ 384 protected ComponentResolver createComponentResolver() { 385 return new DefaultComponentResolver(); 386 } 387 388 public boolean isAutoCreateComponents() { 389 return autoCreateComponents; 390 } 391 392 public void setAutoCreateComponents(boolean autoCreateComponents) { 393 this.autoCreateComponents = autoCreateComponents; 394 } 395 }