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 }