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.reifier;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.function.Function;
025
026import org.apache.camel.Channel;
027import org.apache.camel.ErrorHandlerFactory;
028import org.apache.camel.ExtendedCamelContext;
029import org.apache.camel.Processor;
030import org.apache.camel.model.AggregateDefinition;
031import org.apache.camel.model.BeanDefinition;
032import org.apache.camel.model.CatchDefinition;
033import org.apache.camel.model.ChoiceDefinition;
034import org.apache.camel.model.ClaimCheckDefinition;
035import org.apache.camel.model.ConvertBodyDefinition;
036import org.apache.camel.model.DelayDefinition;
037import org.apache.camel.model.DynamicRouterDefinition;
038import org.apache.camel.model.EnrichDefinition;
039import org.apache.camel.model.ExpressionNode;
040import org.apache.camel.model.FilterDefinition;
041import org.apache.camel.model.FinallyDefinition;
042import org.apache.camel.model.HystrixDefinition;
043import org.apache.camel.model.IdempotentConsumerDefinition;
044import org.apache.camel.model.InOnlyDefinition;
045import org.apache.camel.model.InOutDefinition;
046import org.apache.camel.model.InterceptDefinition;
047import org.apache.camel.model.InterceptFromDefinition;
048import org.apache.camel.model.InterceptSendToEndpointDefinition;
049import org.apache.camel.model.LoadBalanceDefinition;
050import org.apache.camel.model.LogDefinition;
051import org.apache.camel.model.LoopDefinition;
052import org.apache.camel.model.MarshalDefinition;
053import org.apache.camel.model.MulticastDefinition;
054import org.apache.camel.model.OnCompletionDefinition;
055import org.apache.camel.model.OnExceptionDefinition;
056import org.apache.camel.model.OnFallbackDefinition;
057import org.apache.camel.model.OptionalIdentifiedDefinition;
058import org.apache.camel.model.OtherwiseDefinition;
059import org.apache.camel.model.PipelineDefinition;
060import org.apache.camel.model.PolicyDefinition;
061import org.apache.camel.model.PollEnrichDefinition;
062import org.apache.camel.model.ProcessDefinition;
063import org.apache.camel.model.ProcessorDefinition;
064import org.apache.camel.model.ProcessorDefinitionHelper;
065import org.apache.camel.model.RecipientListDefinition;
066import org.apache.camel.model.RemoveHeaderDefinition;
067import org.apache.camel.model.RemoveHeadersDefinition;
068import org.apache.camel.model.RemovePropertiesDefinition;
069import org.apache.camel.model.RemovePropertyDefinition;
070import org.apache.camel.model.ResequenceDefinition;
071import org.apache.camel.model.RollbackDefinition;
072import org.apache.camel.model.RouteDefinition;
073import org.apache.camel.model.RouteDefinitionHelper;
074import org.apache.camel.model.RoutingSlipDefinition;
075import org.apache.camel.model.SagaDefinition;
076import org.apache.camel.model.SamplingDefinition;
077import org.apache.camel.model.ScriptDefinition;
078import org.apache.camel.model.SetBodyDefinition;
079import org.apache.camel.model.SetExchangePatternDefinition;
080import org.apache.camel.model.SetHeaderDefinition;
081import org.apache.camel.model.SetPropertyDefinition;
082import org.apache.camel.model.SortDefinition;
083import org.apache.camel.model.SplitDefinition;
084import org.apache.camel.model.StepDefinition;
085import org.apache.camel.model.StopDefinition;
086import org.apache.camel.model.ThreadsDefinition;
087import org.apache.camel.model.ThrottleDefinition;
088import org.apache.camel.model.ThrowExceptionDefinition;
089import org.apache.camel.model.ToDefinition;
090import org.apache.camel.model.ToDynamicDefinition;
091import org.apache.camel.model.TransactedDefinition;
092import org.apache.camel.model.TransformDefinition;
093import org.apache.camel.model.TryDefinition;
094import org.apache.camel.model.UnmarshalDefinition;
095import org.apache.camel.model.ValidateDefinition;
096import org.apache.camel.model.WhenDefinition;
097import org.apache.camel.model.WhenSkipSendToEndpointDefinition;
098import org.apache.camel.model.WireTapDefinition;
099import org.apache.camel.model.cloud.ServiceCallDefinition;
100import org.apache.camel.model.language.ExpressionDefinition;
101import org.apache.camel.processor.InterceptEndpointProcessor;
102import org.apache.camel.processor.Pipeline;
103import org.apache.camel.processor.channel.DefaultChannel;
104import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier;
105import org.apache.camel.spi.IdAware;
106import org.apache.camel.spi.InterceptStrategy;
107import org.apache.camel.spi.LifecycleStrategy;
108import org.apache.camel.spi.RouteContext;
109import org.slf4j.Logger;
110import org.slf4j.LoggerFactory;
111
112public abstract class ProcessorReifier<T extends ProcessorDefinition<?>> {
113
114    private static final Map<Class<?>, Function<ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>>> PROCESSORS;
115    static {
116        // NOTE: if adding a new class then update the initial capacity of the
117        // HashMap
118        Map<Class<?>, Function<ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>>> map = new HashMap<>(65);
119        map.put(AggregateDefinition.class, AggregateReifier::new);
120        map.put(BeanDefinition.class, BeanReifier::new);
121        map.put(CatchDefinition.class, CatchReifier::new);
122        map.put(ChoiceDefinition.class, ChoiceReifier::new);
123        map.put(ClaimCheckDefinition.class, ClaimCheckReifier::new);
124        map.put(ConvertBodyDefinition.class, ConvertBodyReifier::new);
125        map.put(DelayDefinition.class, DelayReifier::new);
126        map.put(DynamicRouterDefinition.class, DynamicRouterReifier::new);
127        map.put(EnrichDefinition.class, EnrichReifier::new);
128        map.put(FilterDefinition.class, FilterReifier::new);
129        map.put(FinallyDefinition.class, FinallyReifier::new);
130        map.put(HystrixDefinition.class, HystrixReifier::new);
131        map.put(IdempotentConsumerDefinition.class, IdempotentConsumerReifier::new);
132        map.put(InOnlyDefinition.class, SendReifier::new);
133        map.put(InOutDefinition.class, SendReifier::new);
134        map.put(InterceptDefinition.class, InterceptReifier::new);
135        map.put(InterceptFromDefinition.class, InterceptFromReifier::new);
136        map.put(InterceptSendToEndpointDefinition.class, InterceptSendToEndpointReifier::new);
137        map.put(LoadBalanceDefinition.class, LoadBalanceReifier::new);
138        map.put(LogDefinition.class, LogReifier::new);
139        map.put(LoopDefinition.class, LoopReifier::new);
140        map.put(MarshalDefinition.class, MarshalReifier::new);
141        map.put(MulticastDefinition.class, MulticastReifier::new);
142        map.put(OnCompletionDefinition.class, OnCompletionReifier::new);
143        map.put(OnExceptionDefinition.class, OnExceptionReifier::new);
144        map.put(OnFallbackDefinition.class, OnFallbackReifier::new);
145        map.put(OtherwiseDefinition.class, OtherwiseReifier::new);
146        map.put(PipelineDefinition.class, PipelineReifier::new);
147        map.put(PolicyDefinition.class, PolicyReifier::new);
148        map.put(PollEnrichDefinition.class, PollEnrichReifier::new);
149        map.put(ProcessDefinition.class, ProcessReifier::new);
150        map.put(RecipientListDefinition.class, RecipientListReifier::new);
151        map.put(RemoveHeaderDefinition.class, RemoveHeaderReifier::new);
152        map.put(RemoveHeadersDefinition.class, RemoveHeadersReifier::new);
153        map.put(RemovePropertiesDefinition.class, RemovePropertiesReifier::new);
154        map.put(RemovePropertyDefinition.class, RemovePropertyReifier::new);
155        map.put(ResequenceDefinition.class, ResequenceReifier::new);
156        map.put(RollbackDefinition.class, RollbackReifier::new);
157        map.put(RouteDefinition.class, RouteReifier::new);
158        map.put(RoutingSlipDefinition.class, RoutingSlipReifier::new);
159        map.put(SagaDefinition.class, SagaReifier::new);
160        map.put(SamplingDefinition.class, SamplingReifier::new);
161        map.put(ScriptDefinition.class, ScriptReifier::new);
162        map.put(ServiceCallDefinition.class, ServiceCallReifier::new);
163        map.put(SetBodyDefinition.class, SetBodyReifier::new);
164        map.put(SetExchangePatternDefinition.class, SetExchangePatternReifier::new);
165        map.put(SetHeaderDefinition.class, SetHeaderReifier::new);
166        map.put(SetPropertyDefinition.class, SetPropertyReifier::new);
167        map.put(SortDefinition.class, SortReifier::new);
168        map.put(SplitDefinition.class, SplitReifier::new);
169        map.put(StepDefinition.class, StepReifier::new);
170        map.put(StopDefinition.class, StopReifier::new);
171        map.put(ThreadsDefinition.class, ThreadsReifier::new);
172        map.put(ThrottleDefinition.class, ThrottleReifier::new);
173        map.put(ThrowExceptionDefinition.class, ThrowExceptionReifier::new);
174        map.put(ToDefinition.class, SendReifier::new);
175        map.put(ToDynamicDefinition.class, ToDynamicReifier::new);
176        map.put(TransactedDefinition.class, TransactedReifier::new);
177        map.put(TransformDefinition.class, TransformReifier::new);
178        map.put(TryDefinition.class, TryReifier::new);
179        map.put(UnmarshalDefinition.class, UnmarshalReifier::new);
180        map.put(ValidateDefinition.class, ValidateReifier::new);
181        map.put(WireTapDefinition.class, WireTapReifier::new);
182        map.put(WhenSkipSendToEndpointDefinition.class, WhenSkipSendToEndpointReifier::new);
183        map.put(WhenDefinition.class, WhenReifier::new);
184        PROCESSORS = map;
185    }
186    protected final Logger log = LoggerFactory.getLogger(getClass());
187
188    protected final T definition;
189
190    public ProcessorReifier(T definition) {
191        this.definition = definition;
192    }
193
194    public static void registerReifier(Class<?> processorClass, Function<ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>> creator) {
195        PROCESSORS.put(processorClass, creator);
196    }
197
198    public static ProcessorReifier<? extends ProcessorDefinition<?>> reifier(ProcessorDefinition<?> definition) {
199        Function<ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>> reifier = PROCESSORS.get(definition.getClass());
200        if (reifier != null) {
201            return reifier.apply(definition);
202        }
203        throw new IllegalStateException("Unsupported definition: " + definition);
204    }
205
206    /**
207     * Override this in definition class and implement logic to create the
208     * processor based on the definition model.
209     */
210    public abstract Processor createProcessor(RouteContext routeContext) throws Exception;
211
212    /**
213     * Prefer to use {#link #createChildProcessor}.
214     */
215    protected Processor createOutputsProcessor(RouteContext routeContext) throws Exception {
216        Collection<ProcessorDefinition<?>> outputs = definition.getOutputs();
217        return createOutputsProcessor(routeContext, outputs);
218    }
219
220    /**
221     * Creates the child processor (outputs) from the current definition
222     *
223     * @param routeContext the route context
224     * @param mandatory whether or not children is mandatory (ie the definition
225     *            should have outputs)
226     * @return the created children, or <tt>null</tt> if definition had no
227     *         output
228     * @throws Exception is thrown if error creating the child or if it was
229     *             mandatory and there was no output defined on definition
230     */
231    protected Processor createChildProcessor(RouteContext routeContext, boolean mandatory) throws Exception {
232        Processor children = null;
233        // at first use custom factory
234        if (routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getProcessorFactory() != null) {
235            children = routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getProcessorFactory().createChildProcessor(routeContext, definition, mandatory);
236        }
237        // fallback to default implementation if factory did not create the
238        // child
239        if (children == null) {
240            children = createOutputsProcessor(routeContext);
241        }
242
243        if (children == null && mandatory) {
244            throw new IllegalArgumentException("Definition has no children on " + definition);
245        }
246        return children;
247    }
248
249    public void addRoutes(RouteContext routeContext) throws Exception {
250        Channel processor = makeProcessor(routeContext);
251        if (processor == null) {
252            // no processor to add
253            return;
254        }
255
256        if (!routeContext.isRouteAdded()) {
257            // are we routing to an endpoint interceptor, if so we should not
258            // add it as an event driven
259            // processor as we use the producer to trigger the interceptor
260            boolean endpointInterceptor = processor.getNextProcessor() instanceof InterceptEndpointProcessor;
261
262            // only add regular processors as event driven
263            if (endpointInterceptor) {
264                log.debug("Endpoint interceptor should not be added as an event driven consumer route: {}", processor);
265            } else {
266                log.trace("Adding event driven processor: {}", processor);
267                routeContext.addEventDrivenProcessor(processor);
268            }
269        }
270    }
271
272    /**
273     * Wraps the child processor in whatever necessary interceptors and error
274     * handlers
275     */
276    public Channel wrapProcessor(RouteContext routeContext, Processor processor) throws Exception {
277        // don't double wrap
278        if (processor instanceof Channel) {
279            return (Channel)processor;
280        }
281        return wrapChannel(routeContext, processor, null);
282    }
283
284    protected Channel wrapChannel(RouteContext routeContext, Processor processor, ProcessorDefinition<?> child) throws Exception {
285        return wrapChannel(routeContext, processor, child, definition.isInheritErrorHandler());
286    }
287
288    protected Channel wrapChannel(RouteContext routeContext, Processor processor, ProcessorDefinition<?> child, Boolean inheritErrorHandler) throws Exception {
289        // put a channel in between this and each output to control the route
290        // flow logic
291        DefaultChannel channel = new DefaultChannel();
292
293        // add interceptor strategies to the channel must be in this order:
294        // camel context, route context, local
295        List<InterceptStrategy> interceptors = new ArrayList<>();
296        addInterceptStrategies(routeContext, interceptors, routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getInterceptStrategies());
297        addInterceptStrategies(routeContext, interceptors, routeContext.getInterceptStrategies());
298        addInterceptStrategies(routeContext, interceptors, definition.getInterceptStrategies());
299
300        // force the creation of an id
301        RouteDefinitionHelper.forceAssignIds(routeContext.getCamelContext(), definition);
302
303        // fix parent/child relationship. This will be the case of the routes
304        // has been
305        // defined using XML DSL or end user may have manually assembled a route
306        // from the model.
307        // Background note: parent/child relationship is assembled on-the-fly
308        // when using Java DSL (fluent builders)
309        // where as when using XML DSL (JAXB) then it fixed after, but if people
310        // are using custom interceptors
311        // then we need to fix the parent/child relationship beforehand, and
312        // thus we can do it here
313        // ideally we need the design time route -> runtime route to be a
314        // 2-phase pass (scheduled work for Camel 3.0)
315        if (child != null && definition != child) {
316            child.setParent(definition);
317        }
318
319        // set the child before init the channel
320        RouteDefinition route = ProcessorDefinitionHelper.getRoute(definition);
321        boolean first = false;
322        if (route != null && !route.getOutputs().isEmpty()) {
323            first = route.getOutputs().get(0) == definition;
324        }
325        // set scoping
326        boolean routeScoped = true;
327        if (definition instanceof OnExceptionDefinition) {
328            routeScoped = ((OnExceptionDefinition)definition).isRouteScoped();
329        } else if (this.definition instanceof OnCompletionDefinition) {
330            routeScoped = ((OnCompletionDefinition)definition).isRouteScoped();
331        }
332        // initialize the channel
333        channel.initChannel(routeContext, definition, child, interceptors, processor, route, first, routeScoped);
334
335        boolean wrap = false;
336        // set the error handler, must be done after init as we can set the
337        // error handler as first in the chain
338        if (definition instanceof TryDefinition || definition instanceof CatchDefinition || definition instanceof FinallyDefinition) {
339            // do not use error handler for try .. catch .. finally blocks as it
340            // will handle errors itself
341            log.trace("{} is part of doTry .. doCatch .. doFinally so no error handler is applied", definition);
342        } else if (ProcessorDefinitionHelper.isParentOfType(TryDefinition.class, definition, true)
343                   || ProcessorDefinitionHelper.isParentOfType(CatchDefinition.class, definition, true)
344                   || ProcessorDefinitionHelper.isParentOfType(FinallyDefinition.class, definition, true)) {
345            // do not use error handler for try .. catch .. finally blocks as it
346            // will handle errors itself
347            // by checking that any of our parent(s) is not a try .. catch or
348            // finally type
349            log.trace("{} is part of doTry .. doCatch .. doFinally so no error handler is applied", definition);
350        } else if (definition instanceof OnExceptionDefinition || ProcessorDefinitionHelper.isParentOfType(OnExceptionDefinition.class, definition, true)) {
351            log.trace("{} is part of OnException so no error handler is applied", definition);
352            // do not use error handler for onExceptions blocks as it will
353            // handle errors itself
354        } else if (definition instanceof HystrixDefinition || ProcessorDefinitionHelper.isParentOfType(HystrixDefinition.class, definition, true)) {
355            // do not use error handler for hystrix as it offers circuit
356            // breaking with fallback for its outputs
357            // however if inherit error handler is enabled, we need to wrap an
358            // error handler on the hystrix parent
359            if (inheritErrorHandler != null && inheritErrorHandler && child == null) {
360                // only wrap the parent (not the children of the hystrix)
361                wrap = true;
362            } else {
363                log.trace("{} is part of HystrixCircuitBreaker so no error handler is applied", definition);
364            }
365        } else if (definition instanceof MulticastDefinition) {
366            // do not use error handler for multicast as it offers fine grained
367            // error handlers for its outputs
368            // however if share unit of work is enabled, we need to wrap an
369            // error handler on the multicast parent
370            MulticastDefinition def = (MulticastDefinition)definition;
371            boolean isShareUnitOfWork = def.getShareUnitOfWork() != null && def.getShareUnitOfWork();
372            if (isShareUnitOfWork && child == null) {
373                // only wrap the parent (not the children of the multicast)
374                wrap = true;
375            } else {
376                log.trace("{} is part of multicast which have special error handling so no error handler is applied", definition);
377            }
378        } else {
379            // use error handler by default or if configured to do so
380            wrap = true;
381        }
382        if (wrap) {
383            wrapChannelInErrorHandler(channel, routeContext, inheritErrorHandler);
384        }
385
386        // do post init at the end
387        channel.postInitChannel();
388        log.trace("{} wrapped in Channel: {}", definition, channel);
389
390        return channel;
391    }
392
393    /**
394     * Wraps the given channel in error handler (if error handler is inherited)
395     *
396     * @param channel the channel
397     * @param routeContext the route context
398     * @param inheritErrorHandler whether to inherit error handler
399     * @throws Exception can be thrown if failed to create error handler builder
400     */
401    private void wrapChannelInErrorHandler(DefaultChannel channel, RouteContext routeContext, Boolean inheritErrorHandler) throws Exception {
402        if (inheritErrorHandler == null || inheritErrorHandler) {
403            log.trace("{} is configured to inheritErrorHandler", definition);
404            Processor output = channel.getOutput();
405            Processor errorHandler = wrapInErrorHandler(routeContext, output);
406            // set error handler on channel
407            channel.setErrorHandler(errorHandler);
408        } else {
409            log.debug("{} is configured to not inheritErrorHandler.", definition);
410        }
411    }
412
413    /**
414     * Wraps the given output in an error handler
415     *
416     * @param routeContext the route context
417     * @param output the output
418     * @return the output wrapped with the error handler
419     * @throws Exception can be thrown if failed to create error handler builder
420     */
421    protected Processor wrapInErrorHandler(RouteContext routeContext, Processor output) throws Exception {
422        ErrorHandlerFactory builder = routeContext.getErrorHandlerFactory();
423        // create error handler
424        Processor errorHandler = ErrorHandlerReifier.reifier(builder).createErrorHandler(routeContext, output);
425
426        // invoke lifecycles so we can manage this error handler builder
427        for (LifecycleStrategy strategy : routeContext.getCamelContext().getLifecycleStrategies()) {
428            strategy.onErrorHandlerAdd(routeContext, errorHandler, builder);
429        }
430
431        return errorHandler;
432    }
433
434    /**
435     * Adds the given list of interceptors to the channel.
436     *
437     * @param routeContext the route context
438     * @param interceptors the list to add strategies
439     * @param strategies list of strategies to add.
440     */
441    protected void addInterceptStrategies(RouteContext routeContext, List<InterceptStrategy> interceptors, List<InterceptStrategy> strategies) {
442        interceptors.addAll(strategies);
443    }
444
445    /**
446     * Creates a new instance of some kind of composite processor which defaults
447     * to using a {@link Pipeline} but derived classes could change the
448     * behaviour
449     */
450    protected Processor createCompositeProcessor(RouteContext routeContext, List<Processor> list) throws Exception {
451        return Pipeline.newInstance(routeContext.getCamelContext(), list);
452    }
453
454    protected Processor createOutputsProcessor(RouteContext routeContext, Collection<ProcessorDefinition<?>> outputs) throws Exception {
455        // We will save list of actions to restore the outputs back to the
456        // original state.
457        Runnable propertyPlaceholdersChangeReverter = ProcessorDefinitionHelper.createPropertyPlaceholdersChangeReverter();
458        try {
459            return createOutputsProcessorImpl(routeContext, outputs);
460        } finally {
461            propertyPlaceholdersChangeReverter.run();
462        }
463    }
464
465    protected Processor createOutputsProcessorImpl(RouteContext routeContext, Collection<ProcessorDefinition<?>> outputs) throws Exception {
466        List<Processor> list = new ArrayList<>();
467        for (ProcessorDefinition<?> output : outputs) {
468
469            // allow any custom logic before we create the processor
470            reifier(output).preCreateProcessor();
471
472            // resolve properties before we create the processor
473            ProcessorDefinitionHelper.resolvePropertyPlaceholders(routeContext.getCamelContext(), output);
474
475            // also resolve properties and constant fields on embedded
476            // expressions
477            ProcessorDefinition<?> me = (ProcessorDefinition<?>)output;
478            if (me instanceof ExpressionNode) {
479                ExpressionNode exp = (ExpressionNode)me;
480                ExpressionDefinition expressionDefinition = exp.getExpression();
481                if (expressionDefinition != null) {
482                    // resolve properties before we create the processor
483                    ProcessorDefinitionHelper.resolvePropertyPlaceholders(routeContext.getCamelContext(), expressionDefinition);
484                }
485            }
486
487            Processor processor = createProcessor(routeContext, output);
488
489            // inject id
490            if (processor instanceof IdAware) {
491                String id = getId(output, routeContext);
492                ((IdAware)processor).setId(id);
493            }
494
495            if (output instanceof Channel && processor == null) {
496                continue;
497            }
498
499            Processor channel = wrapChannel(routeContext, processor, output);
500            list.add(channel);
501        }
502
503        // if more than one output wrap than in a composite processor else just
504        // keep it as is
505        Processor processor = null;
506        if (!list.isEmpty()) {
507            if (list.size() == 1) {
508                processor = list.get(0);
509            } else {
510                processor = createCompositeProcessor(routeContext, list);
511            }
512        }
513
514        return processor;
515    }
516
517    protected Processor createProcessor(RouteContext routeContext, ProcessorDefinition<?> output) throws Exception {
518        Processor processor = null;
519        // at first use custom factory
520        if (routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getProcessorFactory() != null) {
521            processor = routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getProcessorFactory().createProcessor(routeContext, output);
522        }
523        // fallback to default implementation if factory did not create the
524        // processor
525        if (processor == null) {
526            processor = reifier(output).createProcessor(routeContext);
527        }
528        return processor;
529    }
530
531    /**
532     * Creates the processor and wraps it in any necessary interceptors and
533     * error handlers
534     */
535    protected Channel makeProcessor(RouteContext routeContext) throws Exception {
536        // We will save list of actions to restore the definition back to the
537        // original state.
538        Runnable propertyPlaceholdersChangeReverter = ProcessorDefinitionHelper.createPropertyPlaceholdersChangeReverter();
539        try {
540            return makeProcessorImpl(routeContext);
541        } finally {
542            // Lets restore
543            propertyPlaceholdersChangeReverter.run();
544        }
545    }
546
547    private Channel makeProcessorImpl(RouteContext routeContext) throws Exception {
548        Processor processor = null;
549
550        // allow any custom logic before we create the processor
551        preCreateProcessor();
552
553        // resolve properties before we create the processor
554        ProcessorDefinitionHelper.resolvePropertyPlaceholders(routeContext.getCamelContext(), definition);
555
556        // also resolve properties and constant fields on embedded expressions
557        ProcessorDefinition<?> me = definition;
558        if (me instanceof ExpressionNode) {
559            ExpressionNode exp = (ExpressionNode)me;
560            ExpressionDefinition expressionDefinition = exp.getExpression();
561            if (expressionDefinition != null) {
562                // resolve properties before we create the processor
563                ProcessorDefinitionHelper.resolvePropertyPlaceholders(routeContext.getCamelContext(), expressionDefinition);
564            }
565        }
566
567        // at first use custom factory
568        if (routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getProcessorFactory() != null) {
569            processor = routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getProcessorFactory().createProcessor(routeContext, definition);
570        }
571        // fallback to default implementation if factory did not create the
572        // processor
573        if (processor == null) {
574            processor = createProcessor(routeContext);
575        }
576
577        // inject id
578        if (processor instanceof IdAware) {
579            String id = getId(definition, routeContext);
580            ((IdAware)processor).setId(id);
581        }
582
583        if (processor == null) {
584            // no processor to make
585            return null;
586        }
587        return wrapProcessor(routeContext, processor);
588    }
589
590    /**
591     * Strategy to execute any custom logic before the {@link Processor} is
592     * created.
593     */
594    protected void preCreateProcessor() {
595        definition.preCreateProcessor();
596    }
597
598    /**
599     * Strategy for children to do any custom configuration
600     *
601     * @param output the child to be added as output to this
602     */
603    public void configureChild(ProcessorDefinition<?> output) {
604        // noop
605    }
606
607    protected String getId(OptionalIdentifiedDefinition<?> def, RouteContext routeContext) {
608        return def.idOrCreate(routeContext.getCamelContext().adapt(ExtendedCamelContext.class).getNodeIdFactory());
609    }
610}