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