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.model;
018    
019    import java.util.ArrayList;
020    import java.util.Iterator;
021    import java.util.List;
022    
023    /**
024     * Helper class for ProcessorDefinition and the other model classes.
025     */
026    public final class ProcessorDefinitionHelper {
027    
028        private ProcessorDefinitionHelper() {
029        }
030    
031        /**
032         * Looks for the given type in the list of outputs and recurring all the children as well.
033         *
034         * @param outputs  list of outputs, can be null or empty.
035         * @param type     the type to look for
036         * @return         the found definitions, or <tt>null</tt> if not found
037         */
038        public static <T> Iterator<T> filterTypeInOutputs(List<ProcessorDefinition> outputs, Class<T> type) {
039            List<T> found = new ArrayList<T>();
040            doFindType(outputs, type, found);
041            return found.iterator();
042        }
043    
044        /**
045         * Looks for the given type in the list of outputs and recurring all the children as well.
046         * Will stop at first found and return it.
047         *
048         * @param outputs  list of outputs, can be null or empty.
049         * @param type     the type to look for
050         * @return         the first found type, or <tt>null</tt> if not found
051         */
052        public static <T> T findFirstTypeInOutputs(List<ProcessorDefinition> outputs, Class<T> type) {
053            List<T> found = new ArrayList<T>();
054            doFindType(outputs, type, found);
055            if (found.isEmpty()) {
056                return null;
057            }
058            return found.iterator().next();
059        }
060    
061        /**
062         * Is the given child the first in the outputs from the parent?
063         *
064         * @param parentType the type the parent must be
065         * @param node the node
066         * @return <tt>true</tt> if first child, <tt>false</tt> otherwise
067         */
068        public static boolean isFirstChildOfType(Class<?> parentType, ProcessorDefinition<?> node) {
069            if (node == null || node.getParent() == null) {
070                return false;
071            }
072    
073            if (node.getParent().getOutputs().isEmpty()) {
074                return false;
075            }
076    
077            if (!(node.getParent().getClass().equals(parentType))) {
078                return false;
079            }
080    
081            return node.getParent().getOutputs().get(0).equals(node);
082        }
083    
084        /**
085         * Gets the route definition the given node belongs to.
086         *
087         * @param node the node
088         * @return the route, or <tt>null</tt> if not possible to find
089         */
090        public static RouteDefinition getRoute(ProcessorDefinition<?> node) {
091            if (node == null) {
092                return null;
093            }
094    
095            ProcessorDefinition def = node;
096            // drill to the top
097            while (def != null && def.getParent() != null) {
098                def = def.getParent();
099            }
100    
101            if (def instanceof RouteDefinition) {
102                return (RouteDefinition) def;
103            } else {
104                // not found
105                return null;
106            }
107    
108        }
109    
110        @SuppressWarnings("unchecked")
111        private static <T> void doFindType(List<ProcessorDefinition> outputs, Class<T> type, List<T> found) {
112            if (outputs == null || outputs.isEmpty()) {
113                return;
114            }
115    
116            for (ProcessorDefinition out : outputs) {
117                if (type.isInstance(out)) {
118                    found.add((T)out);
119                }
120    
121                // send is much common
122                if (out instanceof SendDefinition) {
123                    SendDefinition send = (SendDefinition) out;
124                    List<ProcessorDefinition> children = send.getOutputs();
125                    doFindType(children, type, found);
126                }
127    
128                // special for choice
129                if (out instanceof ChoiceDefinition) {
130                    ChoiceDefinition choice = (ChoiceDefinition) out;
131                    for (WhenDefinition when : choice.getWhenClauses()) {
132                        List<ProcessorDefinition> children = when.getOutputs();
133                        doFindType(children, type, found);
134                    }
135    
136                    // otherwise is optional
137                    if (choice.getOtherwise() != null) {
138                        List<ProcessorDefinition> children = choice.getOtherwise().getOutputs();
139                        doFindType(children, type, found);
140                    }
141                }
142    
143                // try children as well
144                List<ProcessorDefinition> children = out.getOutputs();
145                doFindType(children, type, found);
146            }
147        }
148    
149    }