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