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