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