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     */
017    package org.apache.camel.impl;
018    
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.TreeMap;
026    import java.util.concurrent.Callable;
027    
028    import javax.naming.Context;
029    
030    import org.apache.camel.CamelContext;
031    import org.apache.camel.Component;
032    import org.apache.camel.ConsumerTemplate;
033    import org.apache.camel.Endpoint;
034    import org.apache.camel.IsSingleton;
035    import org.apache.camel.NoFactoryAvailableException;
036    import org.apache.camel.Processor;
037    import org.apache.camel.Producer;
038    import org.apache.camel.ProducerTemplate;
039    import org.apache.camel.ResolveEndpointFailedException;
040    import org.apache.camel.Route;
041    import org.apache.camel.Routes;
042    import org.apache.camel.RuntimeCamelException;
043    import org.apache.camel.Service;
044    import org.apache.camel.ServiceStatus;
045    import org.apache.camel.TypeConverter;
046    import org.apache.camel.builder.ErrorHandlerBuilder;
047    import org.apache.camel.impl.converter.DefaultTypeConverter;
048    import org.apache.camel.management.InstrumentationLifecycleStrategy;
049    import org.apache.camel.management.JmxSystemPropertyKeys;
050    import org.apache.camel.model.DataFormatDefinition;
051    import org.apache.camel.model.RouteDefinition;
052    import org.apache.camel.processor.interceptor.Delayer;
053    import org.apache.camel.processor.interceptor.HandleFault;
054    import org.apache.camel.processor.interceptor.StreamCaching;
055    import org.apache.camel.processor.interceptor.TraceFormatter;
056    import org.apache.camel.processor.interceptor.Tracer;
057    import org.apache.camel.spi.ClassResolver;
058    import org.apache.camel.spi.ComponentResolver;
059    import org.apache.camel.spi.EndpointStrategy;
060    import org.apache.camel.spi.ExchangeConverter;
061    import org.apache.camel.spi.FactoryFinder;
062    import org.apache.camel.spi.FactoryFinderResolver;
063    import org.apache.camel.spi.Injector;
064    import org.apache.camel.spi.InterceptStrategy;
065    import org.apache.camel.spi.Language;
066    import org.apache.camel.spi.LanguageResolver;
067    import org.apache.camel.spi.LifecycleStrategy;
068    import org.apache.camel.spi.PackageScanClassResolver;
069    import org.apache.camel.spi.Registry;
070    import org.apache.camel.spi.RouteContext;
071    import org.apache.camel.spi.ServicePool;
072    import org.apache.camel.spi.TypeConverterRegistry;
073    import org.apache.camel.util.ObjectHelper;
074    import org.apache.camel.util.ReflectionInjector;
075    import org.apache.camel.util.SystemHelper;
076    import org.apache.commons.logging.Log;
077    import org.apache.commons.logging.LogFactory;
078    
079    import static org.apache.camel.util.ServiceHelper.startServices;
080    import static org.apache.camel.util.ServiceHelper.stopServices;
081    
082    /**
083     * Represents the context used to configure routes and the policies to use.
084     *
085     * @version $Revision: 782535 $
086     */
087    public class DefaultCamelContext extends ServiceSupport implements CamelContext, Service {
088        private static final transient Log LOG = LogFactory.getLog(DefaultCamelContext.class);
089        private static final String NAME_PREFIX = "camel-";
090        private static int nameSuffix;
091        private boolean routeDefinitionInitiated;
092        private String name;  
093        private final Map<String, Endpoint> endpoints = new HashMap<String, Endpoint>();
094        private final List<EndpointStrategy> endpointStrategies = new ArrayList<EndpointStrategy>();
095        private final Map<String, Component> components = new HashMap<String, Component>();
096        private List<Route> routes;
097        private final List<Service> servicesToClose = new ArrayList<Service>();
098        private TypeConverter typeConverter;
099        private TypeConverterRegistry typeConverterRegistry;
100        private ExchangeConverter exchangeConverter;
101        private Injector injector;
102        private ComponentResolver componentResolver;
103        private boolean autoCreateComponents = true;
104        private LanguageResolver languageResolver = new DefaultLanguageResolver();
105        private final Map<String, Language> languages = new HashMap<String, Language>();
106        private Registry registry;
107        private LifecycleStrategy lifecycleStrategy;
108        private final List<RouteDefinition> routeDefinitions = new ArrayList<RouteDefinition>();
109        private List<InterceptStrategy> interceptStrategies = new ArrayList<InterceptStrategy>();
110        private Boolean trace;
111        private Boolean streamCache = Boolean.TRUE;
112        private Boolean handleFault = Boolean.FALSE;
113        private Long delay;
114        private ErrorHandlerBuilder errorHandlerBuilder;
115        private Map<String, DataFormatDefinition> dataFormats = new HashMap<String, DataFormatDefinition>();
116        private Map<String, String> properties = new HashMap<String, String>();
117        private FactoryFinderResolver factoryFinderResolver = new DefaultFactoryFinderResolver();
118        private FactoryFinder defaultFactoryFinder;
119        private final Map<String, FactoryFinder> factories = new HashMap<String, FactoryFinder>();
120        private final Map<String, RouteService> routeServices = new HashMap<String, RouteService>();
121        private ClassResolver classResolver;
122        private PackageScanClassResolver packageScanClassResolver;
123        // we use a capacity of 100 per endpoint, so for the same endpoint we have at most 100 producers in the pool
124        // so if we have 6 endpoints in the pool, we have 6 x 100 producers in total
125        private ServicePool<Endpoint, Producer> producerServicePool = new DefaultProducerServicePool(100);
126    
127        public DefaultCamelContext() {
128            name = NAME_PREFIX + ++nameSuffix;
129    
130            if (Boolean.getBoolean(JmxSystemPropertyKeys.DISABLED)) {
131                LOG.info("JMX is disabled. Using DefaultLifecycleStrategy.");
132                lifecycleStrategy = new DefaultLifecycleStrategy();
133            } else {
134                try {
135                    LOG.info("JMX enabled. Using InstrumentationLifecycleStrategy.");
136                    lifecycleStrategy = new InstrumentationLifecycleStrategy();
137                } catch (NoClassDefFoundError e) {
138                    // if we can't instantiate the JMX enabled strategy then fallback to default
139                    // could be because of missing .jars on the classpath
140                    LOG.warn("Could not find needed classes for JMX lifecycle strategy."
141                            + " Needed class is in spring-context.jar using Spring 2.5 or newer ("
142                            + " spring-jmx.jar using Spring 2.0.x)."
143                            + " NoClassDefFoundError: " + e.getMessage());
144                } catch (Exception e) {
145                    LOG.warn("Could not create JMX lifecycle strategy, caused by: " + e.getMessage());
146                }
147                // if not created then fallback to default
148                if (lifecycleStrategy == null) {
149                    LOG.warn("Cannot use JMX lifecycle strategy. Using DefaultLifecycleStrategy instead.");
150                    lifecycleStrategy = new DefaultLifecycleStrategy();
151                }
152            }
153    
154            if (classResolver == null) {
155                classResolver = new DefaultClassResolver();
156            }
157    
158            if (packageScanClassResolver == null) {
159                // use WebSphere specific resolver if running on WebSphere
160                if (WebSpherePacakageScanClassResolver.isWebSphereClassLoader(this.getClass().getClassLoader())) {
161                    LOG.info("Using WebSphere specific PackageScanClassResolver");
162                    packageScanClassResolver = new WebSpherePacakageScanClassResolver("META-INF/services/org/apache/camel/TypeConverter");
163                } else {
164                    packageScanClassResolver = new DefaultPackageScanClassResolver();
165                }
166    
167            }
168        }
169    
170        /**
171         * Creates the {@link CamelContext} using the given JNDI context as the
172         * registry
173         */
174        public DefaultCamelContext(Context jndiContext) {
175            this();
176            setJndiContext(jndiContext);
177        }
178    
179        /**
180         * Creates the {@link CamelContext} using the given registry
181         */
182        public DefaultCamelContext(Registry registry) {
183            this();
184            this.registry = registry;
185        }
186    
187        public String getName() {
188            return name;
189        }
190    
191        /**
192         * Sets the name of the this context.
193         */
194        public void setName(String name) {
195            this.name = name;
196        }
197    
198        public void addComponent(String componentName, final Component component) {
199            ObjectHelper.notNull(component, "component");
200            synchronized (components) {
201                if (components.containsKey(componentName)) {
202                    throw new IllegalArgumentException("Cannot add component as its already previously added: " + componentName);
203                }
204                component.setCamelContext(this);
205                components.put(componentName, component);
206            }
207        }
208    
209        public Component getComponent(String name) {
210            // synchronize the look up and auto create so that 2 threads can't
211            // concurrently auto create the same component.
212            synchronized (components) {
213                Component component = components.get(name);
214                if (component == null && autoCreateComponents) {
215                    try {
216                        component = getComponentResolver().resolveComponent(name, this);
217                        if (component != null) {
218                            addComponent(name, component);
219                            if (isStarted() || isStarting()) {
220                                // If the component is looked up after the context is started,
221                                // lets start it up.
222                                startServices(component);
223                            }
224                        }
225                    } catch (Exception e) {
226                        throw new RuntimeCamelException("Could not auto create component: " + name, e);
227                    }
228                }
229                return component;
230            }
231        }
232    
233        public <T extends Component> T getComponent(String name, Class<T> componentType) {
234            Component component = getComponent(name);
235            if (componentType.isInstance(component)) {
236                return componentType.cast(component);
237            } else {
238                throw new IllegalArgumentException("The component is not of type: " + componentType + " but is: "
239                        + component);
240            }
241        }
242    
243        public Component removeComponent(String componentName) {
244            synchronized (components) {
245                return components.remove(componentName);
246            }
247        }
248    
249        public Component getOrCreateComponent(String componentName, Callable<Component> factory) {
250            synchronized (components) {
251                Component component = components.get(componentName);
252                if (component == null) {
253                    try {
254                        component = factory.call();
255                        if (component == null) {
256                            throw new RuntimeCamelException("Factory failed to create the " + componentName
257                                    + " component, it returned null.");
258                        }
259                        components.put(componentName, component);
260                        component.setCamelContext(this);
261                    } catch (Exception e) {
262                        throw new RuntimeCamelException("Factory failed to create the " + componentName
263                                + " component", e);
264                    }
265                }
266                return component;
267            }
268        }
269    
270        // Endpoint Management Methods
271        // -----------------------------------------------------------------------
272    
273        public Collection<Endpoint> getEndpoints() {
274            synchronized (endpoints) {
275                return new ArrayList<Endpoint>(endpoints.values());
276            }
277        }
278    
279        public Map<String, Endpoint> getEndpointMap() {
280            synchronized (endpoints) {
281                return new TreeMap<String, Endpoint>(endpoints);
282            }
283        }
284    
285        public Collection<Endpoint> getEndpoints(String uri) {
286            Collection<Endpoint> answer = new ArrayList<Endpoint>();
287            Collection<Endpoint> coll;
288            synchronized (endpoints) {
289                Endpoint ep = endpoints.get(uri);
290                if (ep != null) {
291                    answer.add(ep);
292                    return answer;
293                }
294                coll = new ArrayList<Endpoint>(endpoints.values());
295            }
296            for (Endpoint ep : coll) {
297                if (!ep.isSingleton() && uri.equals(ep.getEndpointUri())) {
298                    answer.add(ep);
299                }
300            }
301            return answer;
302        }
303    
304        public Collection<Endpoint> getSingletonEndpoints() {
305            Collection<Endpoint> answer = new ArrayList<Endpoint>();
306            Collection<Endpoint> coll = getEndpoints();
307            for (Endpoint ep : coll) {
308                if (ep.isSingleton()) {
309                    answer.add(ep);
310                }
311            }
312            return answer;
313        }
314    
315        public Endpoint addEndpoint(String uri, Endpoint endpoint) throws Exception {
316            Endpoint oldEndpoint;
317            synchronized (endpoints) {
318                startServices(endpoint);
319                oldEndpoint = endpoints.remove(uri);
320                addEndpointToRegistry(uri, endpoint);
321                if (oldEndpoint != null) {
322                    stopServices(oldEndpoint);
323                }
324            }
325            return oldEndpoint;
326        }
327    
328        public Collection<Endpoint> removeEndpoints(String uri) throws Exception {
329            Collection<Endpoint> answer = new ArrayList<Endpoint>();
330            synchronized (endpoints) {
331                Endpoint oldEndpoint = endpoints.remove(uri);
332                if (oldEndpoint != null) {
333                    answer.add(oldEndpoint);
334                    stopServices(oldEndpoint);
335                } else {
336                    for (Map.Entry entry : endpoints.entrySet()) {
337                        oldEndpoint = (Endpoint) entry.getValue();
338                        if (!oldEndpoint.isSingleton() && uri.equals(oldEndpoint.getEndpointUri())) {
339                            answer.add(oldEndpoint);
340                            stopServices(oldEndpoint);
341                            endpoints.remove(entry.getKey());
342                        }
343                    }
344                }
345            }
346            return answer;
347        }
348    
349        public Endpoint addSingletonEndpoint(String uri, Endpoint endpoint) throws Exception {
350            return addEndpoint(uri, endpoint);
351        }
352    
353        public Endpoint removeSingletonEndpoint(String uri) throws Exception {
354            Collection<Endpoint> answer = removeEndpoints(uri);
355            return (Endpoint) (answer.size() > 0 ? answer.toArray()[0] : null);
356        }
357    
358        public Endpoint getEndpoint(String uri) {
359            ObjectHelper.notEmpty(uri, "uri");
360    
361            Endpoint answer;
362            String scheme = null;
363            synchronized (endpoints) {
364                answer = endpoints.get(uri);
365                if (answer == null) {
366                    try {
367                        // Use the URI prefix to find the component.
368                        String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2);
369                        if (splitURI[1] != null) {
370                            scheme = splitURI[0];
371                            Component component = getComponent(scheme);
372    
373                            // Ask the component to resolve the endpoint.
374                            if (component != null) {
375                                // Have the component create the endpoint if it can.
376                                answer = component.createEndpoint(uri);
377    
378                                if (answer != null && LOG.isDebugEnabled()) {
379                                    LOG.debug(uri + " converted to endpoint: " + answer + " by component: " + component);
380                                }
381                            }
382                        }
383    
384                        if (answer == null) {
385                            // no component then try in registry and elsewhere
386                            answer = createEndpoint(uri);
387                        }
388    
389                        if (answer != null) {
390                            addService(answer);
391                            Endpoint newAnswer = addEndpointToRegistry(uri, answer);
392                            lifecycleStrategy.onEndpointAdd(answer);
393                            answer = newAnswer;
394                        }
395                    } catch (Exception e) {
396                        throw new ResolveEndpointFailedException(uri, e);
397                    }
398                }
399            }
400    
401            // unknown scheme
402            if (answer == null && scheme != null) {
403                throw new ResolveEndpointFailedException(uri, "No component found with scheme: " + scheme);
404            }
405    
406            return answer;
407        }
408    
409        public <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType) {
410            Endpoint endpoint = getEndpoint(name);
411    
412            if (endpoint instanceof InterceptSendToEndpoint) {
413                endpoint = ((InterceptSendToEndpoint) endpoint).getDelegate();
414            }
415            if (endpointType.isInstance(endpoint)) {
416                return endpointType.cast(endpoint);
417            } else {
418                throw new IllegalArgumentException("The endpoint is not of type: " + endpointType + " but is: "
419                        + endpoint.getClass().getCanonicalName());
420            }
421        }
422    
423        public void addRegisterEndpointCallback(EndpointStrategy strategy) {
424            if (!endpointStrategies.contains(strategy)) {
425                // let it be invoked for already registered endpoints so it can catch-up.
426                endpointStrategies.add(strategy);
427                for (Endpoint endpoint : getEndpoints()) {
428                    Endpoint newEndpoint = strategy.registerEndpoint(endpoint.getEndpointUri(), endpoint);
429                    if (newEndpoint != endpoint) {
430                        endpoints.put(getEndpointKey(newEndpoint.getEndpointUri(), newEndpoint), newEndpoint);
431                    }
432                }
433            }
434        }
435    
436        /**
437         * Strategy to add the given endpoint to the internal endpoint registry
438         *
439         * @param uri  uri of endpoint
440         * @param endpoint the endpoint to add
441         * @return the added endpoint
442         */
443        protected Endpoint addEndpointToRegistry(String uri, Endpoint endpoint) {
444            for (EndpointStrategy strategy : endpointStrategies) {
445                endpoint = strategy.registerEndpoint(uri, endpoint);
446            }
447            endpoints.put(getEndpointKey(uri, endpoint), endpoint);
448            return endpoint;
449        }
450    
451        // Route Management Methods
452        // -----------------------------------------------------------------------
453        public synchronized List<Route> getRoutes() {
454            if (routes == null) {
455                routes = new ArrayList<Route>();
456            }
457    
458            // lets return a copy of the collection as objects are removed later
459            // when services are stopped
460            return new ArrayList<Route>(routes);
461        }
462    
463        public void setRoutes(List<Route> routes) {
464            this.routes = routes;
465            throw new UnsupportedOperationException("Overriding existing routes is not supported yet, use addRoutes instead");
466        }
467    
468        synchronized void removeRouteCollection(Collection<Route> routes) {
469            if (this.routes != null) {
470                this.routes.removeAll(routes);
471            }
472        }
473    
474        synchronized void addRouteCollection(Collection<Route> routes) throws Exception {
475            if (this.routes == null) {
476                this.routes = new ArrayList<Route>();
477            }
478    
479            if (routes != null) {
480                this.routes.addAll(routes);
481    /*
482                TODO we should have notified the lifecycle strategy via the RouteService
483    
484                lifecycleStrategy.onRoutesAdd(routes);
485                if (shouldStartRoutes()) {
486                    startRoutes(routes);
487                }
488    */
489            }
490        }
491    
492        public void addRoutes(Routes builder) throws Exception {
493            // lets now add the routes from the builder
494            builder.setContext(this);
495            List<Route> routeList = builder.getRouteList();
496            if (LOG.isDebugEnabled()) {
497                LOG.debug("Adding routes from: " + builder + " routes: " + routeList);
498            }
499            //addRouteCollection(routeList);
500        }
501    
502        public void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
503            for (RouteDefinition routeDefinition : routeDefinitions) {
504                routeDefinition.setCamelContext(this);
505                removeRouteDefinition(routeDefinition);
506            }
507            this.routeDefinitions.addAll(routeDefinitions);
508            if (shouldStartRoutes()) {
509                startRouteDefinitions(routeDefinitions);
510            }
511        }
512    
513        /**
514         * Removes the route definition with the given key.
515         *
516         * @return true if one or more routes was removed
517         */
518        public boolean removeRouteDefinition(String key) {
519            boolean answer = false;
520            Iterator<RouteDefinition> iter = routeDefinitions.iterator();
521            while (iter.hasNext()) {
522                RouteDefinition route = iter.next();
523                if (route.idOrCreate().equals(key)) {
524                    iter.remove();
525                    answer = true;
526                }
527            }
528            return answer;
529        }
530    
531        public void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
532            this.routeDefinitions.removeAll(routeDefinitions);
533            for (RouteDefinition routeDefinition : routeDefinitions) {
534                removeRouteDefinition(routeDefinition);
535            }
536        }
537    
538        public void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception {
539            String key = routeDefinition.idOrCreate();
540            stopRoute(key);
541            removeRouteDefinition(key);
542        }
543    
544        public ServiceStatus getRouteStatus(RouteDefinition route) {
545            return getRouteStatus(route.idOrCreate());
546        }
547    
548        /**
549         * Returns the status of the service of the given ID or null if there is no service created yet
550         */
551        public ServiceStatus getRouteStatus(String key) {
552            RouteService routeService = routeServices.get(key);
553            if (routeService != null) {
554                return routeService.getStatus();
555            }
556            return null;
557        }
558    
559        public void startRoute(RouteDefinition route) throws Exception {
560            Collection<Route> routes = new ArrayList<Route>();
561            List<RouteContext> routeContexts = route.addRoutes(this, routes);
562            RouteService routeService = new RouteService(this, route, routeContexts, routes);
563            startRouteService(routeService);
564        }
565    
566    
567        public void stopRoute(RouteDefinition route) throws Exception {
568            stopRoute(route.idOrCreate());
569        }
570    
571        /**
572         * Stops the route denoted by the given RouteType id
573         */
574        public synchronized void stopRoute(String key) throws Exception {
575            RouteService routeService = routeServices.remove(key);
576            if (routeService != null) {
577                routeService.stop();
578            }
579        }
580    
581    
582        /**
583         * Adds a service, starting it so that it will be stopped with this context
584         */
585        public void addService(Object object) throws Exception {
586            if (object instanceof Service) {
587                Service service = (Service) object;
588                getLifecycleStrategy().onServiceAdd(this, service);
589                service.start();
590                servicesToClose.add(service);
591            }
592        }
593    
594        // Helper methods
595        // -----------------------------------------------------------------------
596    
597        public Language resolveLanguage(String language) {
598            Language answer;
599            synchronized (languages) {
600                answer = languages.get(language);
601    
602                // check if the language is singleton, if so return the shared instance
603                if (answer instanceof IsSingleton) {
604                    boolean singleton = ((IsSingleton) answer).isSingleton();
605                    if (singleton) {
606                        return answer;
607                    }
608                }
609    
610                // language not known or not singleton, then use resolver
611                answer = getLanguageResolver().resolveLanguage(language, this);
612                if (answer != null) {
613                    languages.put(language, answer);
614                }
615            }
616    
617            // no language resolved
618            return answer;
619        }
620    
621        // Properties
622        // -----------------------------------------------------------------------
623        public ExchangeConverter getExchangeConverter() {
624            if (exchangeConverter == null) {
625                exchangeConverter = createExchangeConverter();
626            }
627            return exchangeConverter;
628        }
629    
630        public void setExchangeConverter(ExchangeConverter exchangeConverter) {
631            this.exchangeConverter = exchangeConverter;
632        }
633    
634        public TypeConverter getTypeConverter() {
635            if (typeConverter == null) {
636                typeConverter = createTypeConverter();
637            }
638            return typeConverter;
639        }
640    
641        public void setTypeConverter(TypeConverter typeConverter) {
642            this.typeConverter = typeConverter;
643        }
644    
645        public TypeConverterRegistry getTypeConverterRegistry() {
646            if (typeConverterRegistry == null) {
647                // init type converter as its lazy
648                if (typeConverter == null) {
649                    getTypeConverter();
650                }
651                // type converter is usually the default one that also is the registry
652                if (typeConverter instanceof DefaultTypeConverter) {
653                    typeConverterRegistry = (DefaultTypeConverter) typeConverter;
654                }
655            }
656            return typeConverterRegistry;
657        }
658    
659        public void setTypeConverterRegistry(TypeConverterRegistry typeConverterRegistry) {
660            this.typeConverterRegistry = typeConverterRegistry;
661        }
662        
663        public Injector getInjector() {
664            if (injector == null) {
665                injector = createInjector();
666            }
667            return injector;
668        }
669    
670        public void setInjector(Injector injector) {
671            this.injector = injector;
672        }
673    
674        public ComponentResolver getComponentResolver() {
675            if (componentResolver == null) {
676                componentResolver = createComponentResolver();
677            }
678            return componentResolver;
679        }
680    
681        public void setComponentResolver(ComponentResolver componentResolver) {
682            this.componentResolver = componentResolver;
683        }
684    
685        public LanguageResolver getLanguageResolver() {
686            return languageResolver;
687        }
688    
689        public void setLanguageResolver(LanguageResolver languageResolver) {
690            this.languageResolver = languageResolver;
691        }
692    
693        public boolean isAutoCreateComponents() {
694            return autoCreateComponents;
695        }
696    
697        public void setAutoCreateComponents(boolean autoCreateComponents) {
698            this.autoCreateComponents = autoCreateComponents;
699        }
700    
701        public Registry getRegistry() {
702            if (registry == null) {
703                registry = createRegistry();
704            }
705            return registry;
706        }
707    
708        /**
709         * Sets the registry to the given JNDI context
710         *
711         * @param jndiContext is the JNDI context to use as the registry
712         * @see #setRegistry(org.apache.camel.spi.Registry)
713         */
714        public void setJndiContext(Context jndiContext) {
715            setRegistry(new JndiRegistry(jndiContext));
716        }
717    
718        public void setRegistry(Registry registry) {
719            this.registry = registry;
720        }
721    
722        public LifecycleStrategy getLifecycleStrategy() {
723            return lifecycleStrategy;
724        }
725    
726        public void setLifecycleStrategy(LifecycleStrategy lifecycleStrategy) {
727            this.lifecycleStrategy = lifecycleStrategy;
728        }
729    
730        public List<RouteDefinition> getRouteDefinitions() {
731            return routeDefinitions;
732        }
733    
734        public List<InterceptStrategy> getInterceptStrategies() {
735            return interceptStrategies;
736        }
737    
738        public void setInterceptStrategies(List<InterceptStrategy> interceptStrategies) {
739            this.interceptStrategies = interceptStrategies;
740        }
741    
742        public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
743            getInterceptStrategies().add(interceptStrategy);
744        }
745    
746        /**
747         * Returns true if tracing has been enabled or disabled via the {@link #setTrace(Boolean)} method
748         * or it has not been specified then default to the <b>camel.streamCache</b> system property
749         */
750        public boolean isStreamCacheEnabled() {
751            final Boolean value = getStreamCaching();
752            if (value != null) {
753                return value;
754            } else {
755                return SystemHelper.isSystemProperty("camel.streamCache");
756            }
757        }
758    
759        public Boolean getStreamCaching() {
760            return streamCache;
761        }
762    
763        public void setStreamCaching(Boolean trace) {
764            this.streamCache = trace;
765        }
766    
767        /**
768         * Returns true if handle fault has been enabled
769         */
770        public boolean isHandleFaultEnabled() {
771            final Boolean value = getHandleFault();
772            if (value != null) {
773                return value;
774            } else {
775                return SystemHelper.isSystemProperty("camel.handleFault");
776            }
777        }
778    
779        public Boolean getHandleFault() {
780            return handleFault;
781        }
782    
783        public void setHandleFault(Boolean handleFault) {
784            this.handleFault = handleFault;
785        }
786    
787        /**
788         * Returns true if tracing has been enabled
789         */
790        public boolean isTraceEnabled() {
791            final Boolean value = getTrace();
792            if (value != null) {
793                return value;
794            } else {
795                return SystemHelper.isSystemProperty("camel.trace");
796            }
797        }
798    
799        public Boolean getTrace() {
800            return trace;
801        }
802    
803        public void setTrace(Boolean trace) {
804            this.trace = trace;
805        }
806    
807        /**
808         * Returns the delay in millis if delaying has been enabled. Returns 0 if not enabled.
809         */
810        public long isDelayEnabled() {
811            final Long value = getDelay();
812            if (value != null) {
813                return value;
814            } else {
815                String prop = SystemHelper.getSystemProperty("camel.delay");
816                return prop != null ? Long.getLong(prop) : 0;
817            }
818        }
819    
820        public Long getDelay() {
821            return delay;
822        }
823    
824        public void setDelay(Long delay) {
825            this.delay = delay;
826        }
827    
828        public ProducerTemplate createProducerTemplate() {
829            return new DefaultProducerTemplate(this);
830        }
831    
832        public ConsumerTemplate createConsumerTemplate() {
833            return new DefaultConsumerTemplate(this);
834        }
835    
836        public ErrorHandlerBuilder getErrorHandlerBuilder() {
837            return errorHandlerBuilder;
838        }
839    
840        /**
841         * Sets the default error handler builder which is inherited by the routes
842         */
843        public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
844            this.errorHandlerBuilder = errorHandlerBuilder;
845        }
846    
847        public void setProducerServicePool(ServicePool<Endpoint, Producer> producerServicePool) {
848            this.producerServicePool = producerServicePool;
849        }
850    
851        public ServicePool<Endpoint, Producer> getProducerServicePool() {
852            return producerServicePool;
853        }
854    
855        public void start() throws Exception {
856            super.start();
857            
858            // the context is now considered started (i.e. isStarted() == true))
859            // starting routes is done after, not during context startup
860            synchronized (this) {
861                for (RouteService routeService : routeServices.values()) {
862                    routeService.start();
863                }
864            }
865    
866            producerServicePool.stop();
867    
868            LOG.info("Apache Camel " + getVersion() + " (CamelContext:" + getName() + ") started");
869        }
870    
871        // Implementation methods
872        // -----------------------------------------------------------------------
873    
874        protected void doStart() throws Exception {
875            LOG.info("Apache Camel " + getVersion() + " (CamelContext:" + getName() + ") is starting");
876    
877            producerServicePool.start();
878    
879            if (isStreamCacheEnabled()) {
880                // only add a new stream cache if not already configured
881                if (StreamCaching.getStreamCaching(this) == null) {
882                    LOG.debug("StreamCaching is enabled");
883                    addInterceptStrategy(new StreamCaching());
884                }
885            }
886    
887            if (isTraceEnabled()) {
888                // only add a new tracer if not already configured
889                if (Tracer.getTracer(this) == null) {
890                    Tracer tracer = new Tracer();
891                    // lets see if we have a formatter if so use it
892                    TraceFormatter formatter = this.getRegistry().lookup("traceFormatter", TraceFormatter.class);
893                    if (formatter != null) {
894                        tracer.setFormatter(formatter);
895                    }
896                    LOG.debug("Tracing is enabled");
897                    addInterceptStrategy(tracer);
898                }
899            }
900    
901            long delayInMillis = isDelayEnabled();
902            if (delayInMillis > 0) {
903                // only add a new delayer if not already configured
904                if (Delayer.getDelayer(this) == null) {
905                    LOG.debug("Delayer is enabled with: " + delayInMillis + " ms.");
906                    addInterceptStrategy(new Delayer(delayInMillis));
907                }
908            }
909    
910            if (isHandleFaultEnabled()) {
911                // only add a new handle fault if not already configured
912                if (HandleFault.getHandleFault(this) == null) {
913                    LOG.debug("HandleFault is enabled");
914                    addInterceptStrategy(new HandleFault());
915                }
916            }
917    
918            try {
919                lifecycleStrategy.onContextStart(this);
920            } catch (Exception e) {
921                // not all containers allow access to its MBeanServer (such as OC4j)
922                LOG.warn("Cannot start lifecycleStrategy: " + lifecycleStrategy + ". Cause: " + e.getMessage());
923                if (lifecycleStrategy instanceof InstrumentationLifecycleStrategy) {
924                    // fallback to non JMX lifecycle to allow Camel to startup
925                    LOG.warn("Will fallback to use default (non JMX) lifecycle strategy");
926                    lifecycleStrategy = new DefaultLifecycleStrategy();
927                    lifecycleStrategy.onContextStart(this);
928                }
929            }
930    
931            forceLazyInitialization();
932            if (components != null) {
933                for (Component component : components.values()) {
934                    startServices(component);
935                }
936            }
937             // To avoid initiating the routeDefinitions after stopping the camel context
938            if (!routeDefinitionInitiated) {            
939                startRouteDefinitions(routeDefinitions);
940                routeDefinitionInitiated = true;
941            }        
942        }
943    
944        protected void startRouteDefinitions(Collection<RouteDefinition> list) throws Exception {
945            if (list != null) {
946                for (RouteDefinition route : list) {
947                    startRoute(route);
948                }
949            }
950        }
951    
952        /**
953         * Starts the given route service
954         */
955        protected synchronized void startRouteService(RouteService routeService) throws Exception {
956            String key = routeService.getId();
957            stopRoute(key);
958            routeServices.put(key, routeService);
959            if (shouldStartRoutes()) {
960                routeService.start();
961            }
962        }
963    
964        protected synchronized void doStop() throws Exception {
965            LOG.info("Apache Camel " + getVersion() + " (CamelContext:" + getName() + ") is stopping");
966            stopServices(routeServices.values());
967            stopServices(servicesToClose);
968            if (components != null) {
969                for (Component component : components.values()) {
970                    stopServices(component);
971                }
972            }
973            
974            servicesToClose.clear();
975            LOG.info("Apache Camel " + getVersion() + " (CamelContext:" + getName() + ") stopped");
976        }
977    
978        /**
979         * Lets force some lazy initialization to occur upfront before we start any
980         * components and create routes
981         */
982        protected void forceLazyInitialization() {
983            getExchangeConverter();
984            getInjector();
985            getLanguageResolver();
986            getTypeConverter();
987        }
988    
989        /**
990         * Lazily create a default implementation
991         */
992        protected ExchangeConverter createExchangeConverter() {
993            return new DefaultExchangeConverter();
994        }
995    
996        /**
997         * Lazily create a default implementation
998         */
999        protected TypeConverter createTypeConverter() {
1000            DefaultTypeConverter answer = new DefaultTypeConverter(packageScanClassResolver, getInjector(), getDefaultFactoryFinder());
1001            typeConverterRegistry = answer;
1002            return answer;
1003        }
1004    
1005        /**
1006         * Lazily create a default implementation
1007         */
1008        protected Injector createInjector() {
1009            FactoryFinder finder = getDefaultFactoryFinder();
1010            try {
1011                return (Injector) finder.newInstance("Injector");
1012            } catch (NoFactoryAvailableException e) {
1013                // lets use the default
1014                return new ReflectionInjector();
1015            }
1016        }
1017    
1018        /**
1019         * Lazily create a default implementation
1020         */
1021        protected ComponentResolver createComponentResolver() {
1022            return new DefaultComponentResolver();
1023        }
1024    
1025        /**
1026         * Lazily create a default implementation
1027         */
1028        protected Registry createRegistry() {
1029            return new JndiRegistry();
1030        }
1031    
1032        /**
1033         * A pluggable strategy to allow an endpoint to be created without requiring
1034         * a component to be its factory, such as for looking up the URI inside some
1035         * {@link Registry}
1036         *
1037         * @param uri the uri for the endpoint to be created
1038         * @return the newly created endpoint or null if it could not be resolved
1039         */
1040        protected Endpoint createEndpoint(String uri) {
1041            Object value = getRegistry().lookup(uri);
1042            if (value instanceof Endpoint) {
1043                return (Endpoint) value;
1044            } else if (value instanceof Processor) {
1045                return new ProcessorEndpoint(uri, this, (Processor) value);
1046            } else if (value != null) {
1047                return convertBeanToEndpoint(uri, value);
1048            }
1049            return null;
1050        }
1051    
1052        /**
1053         * Strategy method for attempting to convert the bean from a {@link Registry} to an endpoint using
1054         * some kind of transformation or wrapper
1055         *
1056         * @param uri  the uri for the endpoint (and name in the registry)
1057         * @param bean the bean to be converted to an endpoint, which will be not null
1058         * @return a new endpoint
1059         */
1060        protected Endpoint convertBeanToEndpoint(String uri, Object bean) {
1061            throw new IllegalArgumentException("uri: " + uri + " bean: " + bean
1062                    + " could not be converted to an Endpoint");
1063        }
1064    
1065        /**
1066         * Should we start newly added routes?
1067         */
1068        protected boolean shouldStartRoutes() {
1069            return isStarted() && !isStarting();
1070        }
1071    
1072        public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) {
1073            this.dataFormats = dataFormats;
1074        }
1075    
1076        public Map<String, DataFormatDefinition> getDataFormats() {
1077            return dataFormats;
1078        }
1079    
1080        public Map<String, String> getProperties() {
1081            return properties;
1082        }
1083    
1084        public void setProperties(Map<String, String> properties) {
1085            this.properties = properties;
1086        }
1087    
1088        public FactoryFinder getDefaultFactoryFinder() {
1089            if (defaultFactoryFinder == null) {
1090                defaultFactoryFinder = factoryFinderResolver.resolveDefaultFactoryFinder(getClassResolver());
1091            }
1092            return defaultFactoryFinder;
1093        }
1094    
1095        public void setFactoryFinderResolver(FactoryFinderResolver resolver) {
1096            this.factoryFinderResolver = resolver;
1097        }
1098    
1099        public FactoryFinder getFactoryFinder(String path) throws NoFactoryAvailableException {
1100            synchronized (factories) {
1101                FactoryFinder answer = factories.get(path);
1102                if (answer == null) {
1103                    answer = factoryFinderResolver.resolveFactoryFinder(getClassResolver(), path);
1104                    factories.put(path, answer);
1105                }
1106                return answer;
1107            }
1108        }
1109    
1110        public ClassResolver getClassResolver() {
1111            return classResolver;
1112        }
1113    
1114        public void setClassResolver(ClassResolver classResolver) {
1115            this.classResolver = classResolver;
1116        }
1117    
1118        public PackageScanClassResolver getPackageScanClassResolver() {
1119            return packageScanClassResolver;
1120        }
1121    
1122        public void setPackageScanClassResolver(PackageScanClassResolver packageScanClassResolver) {
1123            this.packageScanClassResolver = packageScanClassResolver;
1124        }
1125    
1126        public List<String> getComponentNames() {
1127            synchronized (components) {
1128                List<String> answer = new ArrayList<String>();
1129                for (String name : components.keySet()) {
1130                    answer.add(name);
1131                }
1132                return answer;
1133            }
1134        }
1135    
1136        public List<String> getLanguageNames() {
1137            synchronized (languages) {
1138                List<String> answer = new ArrayList<String>();
1139                for (String name : languages.keySet()) {
1140                    answer.add(name);
1141                }
1142                return answer;
1143            }
1144        }
1145    
1146        protected synchronized String getEndpointKey(String uri, Endpoint endpoint) {
1147            if (endpoint.isSingleton()) {
1148                return uri;
1149            } else {
1150                // lets try find the first endpoint key which is free
1151                for (int counter = 0; true; counter++) {
1152                    String key = (counter > 0) ? uri + ":" + counter : uri;
1153                    if (!endpoints.containsKey(key)) {
1154                        return key;
1155                    }
1156                }
1157            }
1158        }
1159        
1160        protected Map<String, RouteService> getRouteServices() {
1161            return routeServices;
1162        }
1163    
1164    }