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.AbstractList;
020    import java.util.ArrayList;
021    import java.util.List;
022    import javax.xml.bind.annotation.XmlAccessType;
023    import javax.xml.bind.annotation.XmlAccessorType;
024    import javax.xml.bind.annotation.XmlElement;
025    import javax.xml.bind.annotation.XmlElementRef;
026    import javax.xml.bind.annotation.XmlRootElement;
027    
028    import org.apache.camel.Predicate;
029    import org.apache.camel.Processor;
030    import org.apache.camel.builder.ExpressionClause;
031    import org.apache.camel.processor.ChoiceProcessor;
032    import org.apache.camel.spi.RouteContext;
033    import org.apache.camel.util.CollectionStringBuffer;
034    import org.apache.camel.util.ObjectHelper;
035    
036    /**
037     * Represents an XML <choice/> element
038     *
039     * @version
040     */
041    @XmlRootElement(name = "choice")
042    @XmlAccessorType(XmlAccessType.FIELD)
043    public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> {
044        @XmlElementRef
045        private List<WhenDefinition> whenClauses = new ArrayList<WhenDefinition>();
046        @XmlElement
047        private OtherwiseDefinition otherwise;
048    
049        public ChoiceDefinition() {
050        }
051        
052        @Override
053        public List<ProcessorDefinition<?>> getOutputs() {
054            // wrap the outputs into a list where we can on the inside control the when/otherwise
055            // but make it appear as a list on the outside
056            return new AbstractList<ProcessorDefinition<?>>() {
057    
058                public ProcessorDefinition<?> get(int index) {
059                    if (index < whenClauses.size()) {
060                        return whenClauses.get(index);
061                    } 
062                    if (index == whenClauses.size()) {
063                        return otherwise;
064                    }
065                    throw new IndexOutOfBoundsException("Index " + index + " is out of bounds with size " + size());
066                }
067    
068                public boolean add(ProcessorDefinition<?> def) {
069                    if (def instanceof WhenDefinition) {
070                        return whenClauses.add((WhenDefinition)def);
071                    } else if (def instanceof OtherwiseDefinition) {
072                        otherwise = (OtherwiseDefinition)def;
073                        return true;
074                    }
075                    throw new IllegalArgumentException("Expected either a WhenDefinition or OtherwiseDefinition but was "
076                            + ObjectHelper.classCanonicalName(def));
077                }
078    
079                public int size() {
080                    return whenClauses.size() + (otherwise == null ? 0 : 1);
081                }
082    
083                public void clear() {
084                    whenClauses.clear();
085                    otherwise = null;
086                }
087    
088                public ProcessorDefinition<?> set(int index, ProcessorDefinition<?> element) {
089                    if (index < whenClauses.size()) {
090                        if (element instanceof WhenDefinition) {
091                            return whenClauses.set(index, (WhenDefinition)element);
092                        }
093                        throw new IllegalArgumentException("Expected WhenDefinition but was "
094                                + ObjectHelper.classCanonicalName(element));
095                    } else if (index == whenClauses.size()) {
096                        ProcessorDefinition<?> old = otherwise;
097                        otherwise = (OtherwiseDefinition)element;
098                        return old;
099                    }
100                    throw new IndexOutOfBoundsException("Index " + index + " is out of bounds with size " + size());
101                }
102    
103                public ProcessorDefinition<?> remove(int index) {
104                    if (index < whenClauses.size()) {
105                        return whenClauses.remove(index);
106                    } else if (index == whenClauses.size()) {
107                        ProcessorDefinition<?> old = otherwise;
108                        otherwise = null;
109                        return old;
110                    }
111                    throw new IndexOutOfBoundsException("Index " + index + " is out of bounds with size " + size());
112                }
113            };
114        }
115    
116        @Override
117        public boolean isOutputSupported() {
118            return true;
119        }
120        
121        @Override
122        public String toString() {
123            return "Choice[" + getWhenClauses() + (getOtherwise() != null ? " " + getOtherwise() : "") + "]";
124        }
125    
126        @Override
127        public String getShortName() {
128            return "choice";
129        }
130    
131        @Override
132        public Processor createProcessor(RouteContext routeContext) throws Exception {
133            List<Processor> filters = new ArrayList<Processor>();
134            for (WhenDefinition whenClause : whenClauses) {
135                filters.add(createProcessor(routeContext, whenClause));
136            }
137            Processor otherwiseProcessor = null;
138            if (otherwise != null) {
139                otherwiseProcessor = createProcessor(routeContext, otherwise);
140            }
141            return new ChoiceProcessor(filters, otherwiseProcessor);
142        }
143    
144        // Fluent API
145        // -------------------------------------------------------------------------
146    
147        /**
148         * Sets the predicate for the when node
149         *
150         * @param predicate the predicate
151         * @return the builder
152         */
153        public ChoiceDefinition when(Predicate predicate) {
154            addClause(new WhenDefinition(predicate));
155            return this;
156        }
157    
158        /**
159         * Creates an expression for the when node
160         *
161         * @return expression to be used as builder to configure the when node
162         */
163        public ExpressionClause<ChoiceDefinition> when() {
164            ExpressionClause<ChoiceDefinition> clause = new ExpressionClause<ChoiceDefinition>(this);
165            addClause(new WhenDefinition(clause));
166            return clause;
167        }
168        
169        private void addClause(ProcessorDefinition<?> when) {
170            popBlock();
171            addOutput(when);
172            pushBlock(when);
173        }
174        
175        /**
176         * Sets the otherwise node
177         *
178         * @return the builder
179         */
180        public ChoiceDefinition otherwise() {
181            OtherwiseDefinition answer = new OtherwiseDefinition();
182            addClause(answer);
183            return this;
184        }
185    
186        @Override
187        public void setId(String value) {
188            // when setting id, we should set it on the fine grained element, if possible
189            if (otherwise != null) {
190                otherwise.setId(value);
191            } else if (!getWhenClauses().isEmpty()) {
192                int size = getWhenClauses().size();
193                getWhenClauses().get(size - 1).setId(value);
194            } else {
195                super.setId(value);
196            }
197        }
198    
199        // Properties
200        // -------------------------------------------------------------------------
201    
202        @Override
203        public String getLabel() {
204            CollectionStringBuffer buffer = new CollectionStringBuffer("choice[");
205            List<WhenDefinition> list = getWhenClauses();
206            for (WhenDefinition whenType : list) {
207                buffer.append(whenType.getLabel());
208            }
209            buffer.append("]");
210            return buffer.toString();
211        }
212    
213        public List<WhenDefinition> getWhenClauses() {
214            return whenClauses;
215        }
216    
217        public void setWhenClauses(List<WhenDefinition> whenClauses) {
218            this.whenClauses = whenClauses;
219        }
220    
221        public OtherwiseDefinition getOtherwise() {
222            return otherwise;
223        }
224    
225        public void setOtherwise(OtherwiseDefinition otherwise) {
226            this.otherwise = otherwise;
227        }
228    
229        @Override
230        protected void configureChild(ProcessorDefinition<?> output) {
231            if (whenClauses == null || whenClauses.isEmpty()) {
232                return;
233            }
234            for (WhenDefinition when : whenClauses) {
235                if (when.getExpression() instanceof ExpressionClause) {
236                    ExpressionClause<?> clause = (ExpressionClause<?>) when.getExpression();
237                    if (clause.getExpressionType() != null) {
238                        // if using the Java DSL then the expression may have been set using the
239                        // ExpressionClause which is a fancy builder to define expressions and predicates
240                        // using fluent builders in the DSL. However we need afterwards a callback to
241                        // reset the expression to the expression type the ExpressionClause did build for us
242                        when.setExpression(clause.getExpressionType());
243                    }
244                }
245            }
246        }
247    }