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 }