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