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.List;
021
022import org.apache.camel.Consumer;
023import org.apache.camel.Endpoint;
024import org.apache.camel.Navigate;
025import org.apache.camel.Processor;
026import org.apache.camel.RouteAware;
027import org.apache.camel.Service;
028import org.apache.camel.Suspendable;
029import org.apache.camel.SuspendableService;
030import org.apache.camel.spi.IdAware;
031import org.apache.camel.spi.RouteContext;
032import org.apache.camel.util.EndpointHelper;
033
034/**
035 * A {@link DefaultRoute} which starts with an
036 * <a href="http://camel.apache.org/event-driven-consumer.html">Event Driven Consumer</a>
037 * <p/>
038 * Use the API from {@link org.apache.camel.CamelContext} to control the lifecycle of a route,
039 * such as starting and stopping using the {@link org.apache.camel.CamelContext#startRoute(String)}
040 * and {@link org.apache.camel.CamelContext#stopRoute(String)} methods.
041 *
042 * @version 
043 */
044public class EventDrivenConsumerRoute extends DefaultRoute {
045    private final Processor processor;
046    private Consumer consumer;
047
048    public EventDrivenConsumerRoute(RouteContext routeContext, Endpoint endpoint, Processor processor) {
049        super(routeContext, endpoint);
050        this.processor = processor;
051    }
052
053    @Override
054    public String toString() {
055        return "EventDrivenConsumerRoute[" + getEndpoint() + " -> " + processor + "]";
056    }
057
058    public Processor getProcessor() {
059        return processor;
060    }
061
062    /**
063     * Factory method to lazily create the complete list of services required for this route
064     * such as adding the processor or consumer
065     */
066    @Override
067    protected void addServices(List<Service> services) throws Exception {
068        Endpoint endpoint = getEndpoint();
069        consumer = endpoint.createConsumer(processor);
070        if (consumer != null) {
071            services.add(consumer);
072            if (consumer instanceof RouteAware) {
073                ((RouteAware) consumer).setRoute(this);
074            }
075        }
076        Processor processor = getProcessor();
077        if (processor instanceof Service) {
078            services.add((Service)processor);
079        }
080    }
081
082    @SuppressWarnings("unchecked")
083    public Navigate<Processor> navigate() {
084        Processor answer = getProcessor();
085
086        // we want navigating routes to be easy, so skip the initial channel
087        // and navigate to its output where it all starts from end user point of view
088        if (answer instanceof Navigate) {
089            Navigate<Processor> nav = (Navigate<Processor>) answer;
090            if (nav.next().size() == 1) {
091                Object first = nav.next().get(0);
092                if (first instanceof Navigate) {
093                    return (Navigate<Processor>) first;
094                }
095            }
096            return (Navigate<Processor>) answer;
097        }
098        return null;
099    }
100
101    public List<Processor> filter(String pattern) {
102        List<Processor> match = new ArrayList<>();
103        doFilter(pattern, navigate(), match);
104        return match;
105    }
106
107    @SuppressWarnings("unchecked")
108    private void doFilter(String pattern, Navigate<Processor> nav, List<Processor> match) {
109        List<Processor> list = nav.next();
110        if (list != null) {
111            for (Processor proc : list) {
112                String id = null;
113                if (proc instanceof IdAware) {
114                    id = ((IdAware) proc).getId();
115                }
116                if (EndpointHelper.matchPattern(id, pattern)) {
117                    match.add(proc);
118                }
119                if (proc instanceof Navigate) {
120                    Navigate<Processor> child = (Navigate<Processor>) proc;
121                    doFilter(pattern, child, match);
122                }
123            }
124        }
125    }
126
127    public Consumer getConsumer() {
128        return consumer;
129    }
130
131    public boolean supportsSuspension() {
132        return consumer instanceof Suspendable && consumer instanceof SuspendableService;
133    }
134}