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