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