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 }