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 }