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