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.ArrayList; 020import java.util.List; 021import java.util.concurrent.ExecutorService; 022 023import javax.xml.bind.annotation.XmlAccessType; 024import javax.xml.bind.annotation.XmlAccessorType; 025import javax.xml.bind.annotation.XmlAttribute; 026import javax.xml.bind.annotation.XmlElement; 027import javax.xml.bind.annotation.XmlElementRef; 028import javax.xml.bind.annotation.XmlRootElement; 029import javax.xml.bind.annotation.XmlTransient; 030import javax.xml.bind.annotation.XmlType; 031 032import org.apache.camel.Predicate; 033import org.apache.camel.spi.AsPredicate; 034import org.apache.camel.spi.Metadata; 035 036/** 037 * Route to be executed when normal route processing completes 038 */ 039@Metadata(label = "configuration") 040@XmlRootElement(name = "onCompletion") 041@XmlType(propOrder = {"onWhen", "outputs"}) 042@XmlAccessorType(XmlAccessType.FIELD) 043public class OnCompletionDefinition extends OutputDefinition<OnCompletionDefinition> implements ExecutorServiceAwareDefinition<OnCompletionDefinition> { 044 @XmlAttribute 045 @Metadata(javaType = "org.apache.camel.model.OnCompletionMode", defaultValue = "AfterConsumer", 046 enums = "AfterConsumer,BeforeConsumer") 047 private String mode; 048 @XmlAttribute 049 private String onCompleteOnly; 050 @XmlAttribute 051 private String onFailureOnly; 052 @XmlElement(name = "onWhen") 053 @AsPredicate 054 private WhenDefinition onWhen; 055 @XmlAttribute 056 private String parallelProcessing; 057 @XmlAttribute 058 private String executorServiceRef; 059 @XmlAttribute(name = "useOriginalMessage") 060 private String useOriginalMessage; 061 @XmlTransient 062 private ExecutorService executorService; 063 @XmlTransient 064 private Boolean routeScoped; 065 066 public OnCompletionDefinition() { 067 } 068 069 public boolean isRouteScoped() { 070 // is context scoped by default 071 return routeScoped != null ? routeScoped : false; 072 } 073 074 public Boolean getRouteScoped() { 075 return routeScoped; 076 } 077 078 @Override 079 public String toString() { 080 return "onCompletion[" + getOutputs() + "]"; 081 } 082 083 @Override 084 public String getShortName() { 085 return "onCompletion"; 086 } 087 088 @Override 089 public String getLabel() { 090 return "onCompletion"; 091 } 092 093 @Override 094 public boolean isAbstract() { 095 return true; 096 } 097 098 @Override 099 public boolean isTopLevelOnly() { 100 return true; 101 } 102 103 /** 104 * Removes all existing 105 * {@link org.apache.camel.model.OnCompletionDefinition} from the 106 * definition. 107 * <p/> 108 * This is used to let route scoped <tt>onCompletion</tt> overrule any 109 * global <tt>onCompletion</tt>. Hence we remove all existing as they are 110 * global. 111 * 112 * @param definition the parent definition that is the route 113 */ 114 public void removeAllOnCompletionDefinition(ProcessorDefinition<?> definition) { 115 definition.getOutputs().removeIf(out -> out instanceof OnCompletionDefinition); 116 } 117 118 @Override 119 public ProcessorDefinition<?> end() { 120 // pop parent block, as we added our self as block to parent when 121 // synchronized was defined in the route 122 getParent().popBlock(); 123 return super.end(); 124 } 125 126 /** 127 * Sets the mode to be after route is done (default due backwards 128 * compatible). 129 * <p/> 130 * This executes the on completion work <i>after</i> the route consumer have 131 * written response back to the callee (if its InOut mode). 132 * 133 * @return the builder 134 */ 135 public OnCompletionDefinition modeAfterConsumer() { 136 setMode(OnCompletionMode.AfterConsumer.name()); 137 return this; 138 } 139 140 /** 141 * Sets the mode to be before consumer is done. 142 * <p/> 143 * This allows the on completion work to execute <i>before</i> the route 144 * consumer, writes any response back to the callee (if its InOut mode). 145 * 146 * @return the builder 147 */ 148 public OnCompletionDefinition modeBeforeConsumer() { 149 setMode(OnCompletionMode.BeforeConsumer.name()); 150 return this; 151 } 152 153 /** 154 * Will only synchronize when the {@link org.apache.camel.Exchange} 155 * completed successfully (no errors). 156 * 157 * @return the builder 158 */ 159 public OnCompletionDefinition onCompleteOnly() { 160 boolean isOnFailureOnly = Boolean.toString(true).equals(onFailureOnly); 161 if (isOnFailureOnly) { 162 throw new IllegalArgumentException("Both onCompleteOnly and onFailureOnly cannot be true. Only one of them can be true. On node: " + this); 163 } 164 // must define return type as OutputDefinition and not this type to 165 // avoid end user being able 166 // to invoke onFailureOnly/onCompleteOnly more than once 167 setOnCompleteOnly(Boolean.toString(true)); 168 setOnFailureOnly(Boolean.toString(false)); 169 return this; 170 } 171 172 /** 173 * Will only synchronize when the {@link org.apache.camel.Exchange} ended 174 * with failure (exception or FAULT message). 175 * 176 * @return the builder 177 */ 178 public OnCompletionDefinition onFailureOnly() { 179 boolean isOnCompleteOnly = Boolean.toString(true).equals(onCompleteOnly); 180 if (isOnCompleteOnly) { 181 throw new IllegalArgumentException("Both onCompleteOnly and onFailureOnly cannot be true. Only one of them can be true. On node: " + this); 182 } 183 // must define return type as OutputDefinition and not this type to 184 // avoid end user being able 185 // to invoke onFailureOnly/onCompleteOnly more than once 186 setOnCompleteOnly(Boolean.toString(false)); 187 setOnFailureOnly(Boolean.toString(true)); 188 return this; 189 } 190 191 /** 192 * Sets an additional predicate that should be true before the onCompletion 193 * is triggered. 194 * <p/> 195 * To be used for fine grained controlling whether a completion callback 196 * should be invoked or not 197 * 198 * @param predicate predicate that determines true or false 199 * @return the builder 200 */ 201 public OnCompletionDefinition onWhen(@AsPredicate Predicate predicate) { 202 setOnWhen(new WhenDefinition(predicate)); 203 return this; 204 } 205 206 /** 207 * Will use the original input message body when an 208 * {@link org.apache.camel.Exchange} for this on completion. 209 * <p/> 210 * By default this feature is off. 211 * 212 * @return the builder 213 */ 214 public OnCompletionDefinition useOriginalBody() { 215 setUseOriginalMessage(Boolean.toString(true)); 216 return this; 217 } 218 219 /** 220 * To use a custom Thread Pool to be used for parallel processing. Notice if 221 * you set this option, then parallel processing is automatic implied, and 222 * you do not have to enable that option as well. 223 */ 224 @Override 225 public OnCompletionDefinition executorService(ExecutorService executorService) { 226 setExecutorService(executorService); 227 return this; 228 } 229 230 /** 231 * Refers to a custom Thread Pool to be used for parallel processing. Notice 232 * if you set this option, then parallel processing is automatic implied, 233 * and you do not have to enable that option as well. 234 */ 235 @Override 236 public OnCompletionDefinition executorServiceRef(String executorServiceRef) { 237 setExecutorServiceRef(executorServiceRef); 238 return this; 239 } 240 241 /** 242 * If enabled then the on completion process will run asynchronously by a 243 * separate thread from a thread pool. By default this is false, meaning the 244 * on completion process will run synchronously using the same caller thread 245 * as from the route. 246 * 247 * @return the builder 248 */ 249 public OnCompletionDefinition parallelProcessing() { 250 setParallelProcessing(Boolean.toString(true)); 251 return this; 252 } 253 254 /** 255 * If enabled then the on completion process will run asynchronously by a 256 * separate thread from a thread pool. By default this is false, meaning the 257 * on completion process will run synchronously using the same caller thread 258 * as from the route. 259 * 260 * @return the builder 261 */ 262 public OnCompletionDefinition parallelProcessing(boolean parallelProcessing) { 263 setParallelProcessing(Boolean.toString(parallelProcessing)); 264 return this; 265 } 266 267 @Override 268 public List<ProcessorDefinition<?>> getOutputs() { 269 return outputs; 270 } 271 272 @XmlElementRef 273 @Override 274 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 275 super.setOutputs(outputs); 276 } 277 278 public String getMode() { 279 return mode; 280 } 281 282 /** 283 * Sets the on completion mode. 284 * <p/> 285 * The default value is AfterConsumer 286 */ 287 public void setMode(String mode) { 288 this.mode = mode; 289 } 290 291 public String getOnCompleteOnly() { 292 return onCompleteOnly; 293 } 294 295 public void setOnCompleteOnly(String onCompleteOnly) { 296 this.onCompleteOnly = onCompleteOnly; 297 } 298 299 public String getOnFailureOnly() { 300 return onFailureOnly; 301 } 302 303 public void setOnFailureOnly(String onFailureOnly) { 304 this.onFailureOnly = onFailureOnly; 305 } 306 307 public WhenDefinition getOnWhen() { 308 return onWhen; 309 } 310 311 public void setOnWhen(WhenDefinition onWhen) { 312 this.onWhen = onWhen; 313 } 314 315 @Override 316 public ExecutorService getExecutorService() { 317 return executorService; 318 } 319 320 @Override 321 public void setExecutorService(ExecutorService executorService) { 322 this.executorService = executorService; 323 } 324 325 @Override 326 public String getExecutorServiceRef() { 327 return executorServiceRef; 328 } 329 330 @Override 331 public void setExecutorServiceRef(String executorServiceRef) { 332 this.executorServiceRef = executorServiceRef; 333 } 334 335 public String getUseOriginalMessage() { 336 return useOriginalMessage; 337 } 338 339 /** 340 * Will use the original input message body when an 341 * {@link org.apache.camel.Exchange} for this on completion. 342 * <p/> 343 * By default this feature is off. 344 */ 345 public void setUseOriginalMessage(String useOriginalMessage) { 346 this.useOriginalMessage = useOriginalMessage; 347 } 348 349 public String getParallelProcessing() { 350 return parallelProcessing; 351 } 352 353 public void setParallelProcessing(String parallelProcessing) { 354 this.parallelProcessing = parallelProcessing; 355 } 356 357}