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 */
017package org.apache.camel.impl;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.concurrent.atomic.AtomicInteger;
025
026import org.apache.camel.CamelContext;
027import org.apache.camel.Endpoint;
028import org.apache.camel.NoSuchEndpointException;
029import org.apache.camel.Processor;
030import org.apache.camel.Route;
031import org.apache.camel.RuntimeCamelException;
032import org.apache.camel.ShutdownRoute;
033import org.apache.camel.ShutdownRunningTask;
034import org.apache.camel.model.FromDefinition;
035import org.apache.camel.model.ProcessorDefinition;
036import org.apache.camel.model.RouteDefinition;
037import org.apache.camel.processor.CamelInternalProcessor;
038import org.apache.camel.processor.Pipeline;
039import org.apache.camel.spi.InterceptStrategy;
040import org.apache.camel.spi.RouteContext;
041import org.apache.camel.spi.RoutePolicy;
042import org.apache.camel.util.CamelContextHelper;
043import org.apache.camel.util.ObjectHelper;
044
045/**
046 * The context used to activate new routing rules
047 *
048 * @version 
049 */
050public class DefaultRouteContext implements RouteContext {
051    private final Map<ProcessorDefinition<?>, AtomicInteger> nodeIndex = new HashMap<ProcessorDefinition<?>, AtomicInteger>();
052    private final RouteDefinition route;
053    private FromDefinition from;
054    private final Collection<Route> routes;
055    private Endpoint endpoint;
056    private final List<Processor> eventDrivenProcessors = new ArrayList<Processor>();
057    private CamelContext camelContext;
058    private List<InterceptStrategy> interceptStrategies = new ArrayList<InterceptStrategy>();
059    private InterceptStrategy managedInterceptStrategy;
060    private boolean routeAdded;
061    private Boolean trace;
062    private Boolean messageHistory;
063    private Boolean streamCache;
064    private Boolean handleFault;
065    private Long delay;
066    private Boolean autoStartup = Boolean.TRUE;
067    private List<RoutePolicy> routePolicyList = new ArrayList<RoutePolicy>();
068    private ShutdownRoute shutdownRoute;
069    private ShutdownRunningTask shutdownRunningTask;
070
071    public DefaultRouteContext(CamelContext camelContext, RouteDefinition route, FromDefinition from, Collection<Route> routes) {
072        this.camelContext = camelContext;
073        this.route = route;
074        this.from = from;
075        this.routes = routes;
076    }
077
078    /**
079     * Only used for lazy construction from inside ExpressionType
080     */
081    public DefaultRouteContext(CamelContext camelContext) {
082        this.camelContext = camelContext;
083        this.routes = new ArrayList<Route>();
084        this.route = new RouteDefinition("temporary");
085    }
086
087    public Endpoint getEndpoint() {
088        if (endpoint == null) {
089            endpoint = from.resolveEndpoint(this);
090        }
091        return endpoint;
092    }
093
094    public FromDefinition getFrom() {
095        return from;
096    }
097
098    public RouteDefinition getRoute() {
099        return route;
100    }
101
102    public CamelContext getCamelContext() {
103        return camelContext;
104    }
105
106    public Endpoint resolveEndpoint(String uri) {
107        return route.resolveEndpoint(getCamelContext(), uri);
108    }
109
110    public Endpoint resolveEndpoint(String uri, String ref) {
111        Endpoint endpoint = null;
112        if (uri != null) {
113            endpoint = resolveEndpoint(uri);
114            if (endpoint == null) {
115                throw new NoSuchEndpointException(uri);
116            }
117        }
118        if (ref != null) {
119            endpoint = lookup(ref, Endpoint.class);
120            if (endpoint == null) {
121                throw new NoSuchEndpointException("ref:" + ref, "check your camel registry with id " + ref);
122            }
123            // Check the endpoint has the right CamelContext 
124            if (!this.getCamelContext().equals(endpoint.getCamelContext())) {
125                throw new NoSuchEndpointException("ref:" + ref, "make sure the endpoint has the same camel context as the route does.");
126            }
127            try {
128                // need add the endpoint into service
129                getCamelContext().addService(endpoint);
130            } catch (Exception ex) {
131                throw new RuntimeCamelException(ex);
132            }
133        }
134        if (endpoint == null) {
135            throw new IllegalArgumentException("Either 'uri' or 'ref' must be specified on: " + this);
136        } else {
137            return endpoint;
138        }
139    }
140
141    public <T> T lookup(String name, Class<T> type) {
142        return getCamelContext().getRegistry().lookupByNameAndType(name, type);
143    }
144
145    public <T> Map<String, T> lookupByType(Class<T> type) {
146        return getCamelContext().getRegistry().findByTypeWithName(type);
147    }
148
149    @Override
150    public <T> T mandatoryLookup(String name, Class<T> type) {
151        return CamelContextHelper.mandatoryLookup(getCamelContext(), name, type);
152    }
153
154    public void commit() {
155        // now lets turn all of the event driven consumer processors into a single route
156        if (!eventDrivenProcessors.isEmpty()) {
157            Processor target = Pipeline.newInstance(getCamelContext(), eventDrivenProcessors);
158
159            String routeId = route.idOrCreate(getCamelContext().getNodeIdFactory());
160
161            // and wrap it in a unit of work so the UoW is on the top, so the entire route will be in the same UoW
162            CamelInternalProcessor internal = new CamelInternalProcessor(target);
163            internal.addAdvice(new CamelInternalProcessor.UnitOfWorkProcessorAdvice(routeId));
164
165            // and then in route context so we can keep track which route this is at runtime
166            internal.addAdvice(new CamelInternalProcessor.RouteContextAdvice(this));
167
168            // and then optionally add route policy processor if a custom policy is set
169            List<RoutePolicy> routePolicyList = getRoutePolicyList();
170            if (routePolicyList != null && !routePolicyList.isEmpty()) {
171                for (RoutePolicy policy : routePolicyList) {
172                    // add policy as service if we have not already done that (eg possible if two routes have the same service)
173                    // this ensures Camel can control the lifecycle of the policy
174                    if (!camelContext.hasService(policy)) {
175                        try {
176                            camelContext.addService(policy);
177                        } catch (Exception e) {
178                            throw ObjectHelper.wrapRuntimeCamelException(e);
179                        }
180                    }
181                }
182
183                internal.addAdvice(new CamelInternalProcessor.RoutePolicyAdvice(routePolicyList));
184            }
185
186            // wrap in route inflight processor to track number of inflight exchanges for the route
187            internal.addAdvice(new CamelInternalProcessor.RouteInflightRepositoryAdvice(camelContext.getInflightRepository(), routeId));
188
189            // wrap in JMX instrumentation processor that is used for performance stats
190            internal.addAdvice(new CamelInternalProcessor.InstrumentationAdvice("route"));
191
192            // wrap in route lifecycle
193            internal.addAdvice(new CamelInternalProcessor.RouteLifecycleAdvice());
194
195            // and create the route that wraps the UoW
196            Route edcr = new EventDrivenConsumerRoute(this, getEndpoint(), internal);
197            edcr.getProperties().put(Route.ID_PROPERTY, routeId);
198            edcr.getProperties().put(Route.PARENT_PROPERTY, Integer.toHexString(route.hashCode()));
199            edcr.getProperties().put(Route.DESCRIPTION_PROPERTY, route.getDescriptionText());
200            if (route.getGroup() != null) {
201                edcr.getProperties().put(Route.GROUP_PROPERTY, route.getGroup());
202            }
203            String rest = "false";
204            if (route.isRest() != null && route.isRest()) {
205                rest = "true";
206            }
207            edcr.getProperties().put(Route.REST_PROPERTY, rest);
208
209            // after the route is created then set the route on the policy processor so we get hold of it
210            CamelInternalProcessor.RoutePolicyAdvice task = internal.getAdvice(CamelInternalProcessor.RoutePolicyAdvice.class);
211            if (task != null) {
212                task.setRoute(edcr);
213            }
214            CamelInternalProcessor.RouteLifecycleAdvice task2 = internal.getAdvice(CamelInternalProcessor.RouteLifecycleAdvice.class);
215            if (task2 != null) {
216                task2.setRoute(edcr);
217            }
218
219            // invoke init on route policy
220            if (routePolicyList != null && !routePolicyList.isEmpty()) {
221                for (RoutePolicy policy : routePolicyList) {
222                    policy.onInit(edcr);
223                }
224            }
225
226            routes.add(edcr);
227        }
228    }
229
230    public void addEventDrivenProcessor(Processor processor) {
231        eventDrivenProcessors.add(processor);
232    }
233
234    public List<InterceptStrategy> getInterceptStrategies() {
235        return interceptStrategies;
236    }
237
238    public void setInterceptStrategies(List<InterceptStrategy> interceptStrategies) {
239        this.interceptStrategies = interceptStrategies;
240    }
241
242    public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
243        getInterceptStrategies().add(interceptStrategy);
244    }
245
246    public void setManagedInterceptStrategy(InterceptStrategy interceptStrategy) {
247        this.managedInterceptStrategy = interceptStrategy;
248    }
249
250    public InterceptStrategy getManagedInterceptStrategy() {
251        return managedInterceptStrategy;
252    }
253
254    public boolean isRouteAdded() {
255        return routeAdded;
256    }
257
258    public void setIsRouteAdded(boolean routeAdded) {
259        this.routeAdded = routeAdded;
260    }
261
262    public void setTracing(Boolean tracing) {
263        this.trace = tracing;
264    }
265
266    public Boolean isTracing() {
267        if (trace != null) {
268            return trace;
269        } else {
270            // fallback to the option from camel context
271            return getCamelContext().isTracing();
272        }
273    }
274
275    public void setMessageHistory(Boolean messageHistory) {
276        this.messageHistory = messageHistory;
277    }
278
279    public Boolean isMessageHistory() {
280        if (messageHistory != null) {
281            return messageHistory;
282        } else {
283            // fallback to the option from camel context
284            return getCamelContext().isMessageHistory();
285        }
286    }
287
288    public void setStreamCaching(Boolean cache) {
289        this.streamCache = cache;
290    }
291
292    public Boolean isStreamCaching() {
293        if (streamCache != null) {
294            return streamCache;
295        } else {
296            // fallback to the option from camel context
297            return getCamelContext().isStreamCaching();
298        }
299    }
300
301    public void setHandleFault(Boolean handleFault) {
302        this.handleFault = handleFault;
303    }
304
305    public Boolean isHandleFault() {
306        if (handleFault != null) {
307            return handleFault;
308        } else {
309            // fallback to the option from camel context
310            return getCamelContext().isHandleFault();
311        }
312    }
313
314    public void setDelayer(Long delay) {
315        this.delay = delay;
316    }
317
318    public Long getDelayer() {
319        if (delay != null) {
320            return delay;
321        } else {
322            // fallback to the option from camel context
323            return getCamelContext().getDelayer();
324        }
325    }
326
327    public void setAutoStartup(Boolean autoStartup) {
328        this.autoStartup = autoStartup;
329    }
330
331    public Boolean isAutoStartup() {
332        if (autoStartup != null) {
333            return autoStartup;
334        }
335        // default to true
336        return true;
337    }
338
339    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
340        this.shutdownRoute = shutdownRoute;
341    }
342
343    public void setAllowUseOriginalMessage(Boolean allowUseOriginalMessage) {
344        throw new IllegalArgumentException("This option can only be configured on CamelContext");
345    }
346
347    public Boolean isAllowUseOriginalMessage() {
348        return getCamelContext().isAllowUseOriginalMessage();
349    }
350
351    public ShutdownRoute getShutdownRoute() {
352        if (shutdownRoute != null) {
353            return shutdownRoute;
354        } else {
355            // fallback to the option from camel context
356            return getCamelContext().getShutdownRoute();
357        }
358    }
359
360    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
361        this.shutdownRunningTask = shutdownRunningTask;
362    }
363
364    public ShutdownRunningTask getShutdownRunningTask() {
365        if (shutdownRunningTask != null) {
366            return shutdownRunningTask;
367        } else {
368            // fallback to the option from camel context
369            return getCamelContext().getShutdownRunningTask();
370        }
371    }
372    
373    public int getAndIncrement(ProcessorDefinition<?> node) {
374        AtomicInteger count = nodeIndex.get(node);
375        if (count == null) {
376            count = new AtomicInteger();
377            nodeIndex.put(node, count);
378        }
379        return count.getAndIncrement();
380    }
381
382    public void setRoutePolicyList(List<RoutePolicy> routePolicyList) {
383        this.routePolicyList = routePolicyList;
384    }
385
386    public List<RoutePolicy> getRoutePolicyList() {
387        return routePolicyList;
388    }
389}