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.concurrent.ExecutorService; 020import java.util.function.Supplier; 021 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlRootElement; 026import javax.xml.bind.annotation.XmlTransient; 027 028import org.apache.camel.AggregationStrategy; 029import org.apache.camel.Expression; 030import org.apache.camel.Processor; 031import org.apache.camel.model.language.ExpressionDefinition; 032import org.apache.camel.spi.Metadata; 033 034/** 035 * Splits a single message into many sub-messages. 036 */ 037@Metadata(label = "eip,routing") 038@XmlRootElement(name = "split") 039@XmlAccessorType(XmlAccessType.FIELD) 040public class SplitDefinition extends OutputExpressionNode implements ExecutorServiceAwareDefinition<SplitDefinition> { 041 @XmlTransient 042 private AggregationStrategy aggregationStrategy; 043 @XmlTransient 044 private ExecutorService executorService; 045 @XmlAttribute 046 @Metadata(javaType = "java.lang.Boolean") 047 private String parallelProcessing; 048 @XmlAttribute 049 private String strategyRef; 050 @XmlAttribute 051 private String strategyMethodName; 052 @XmlAttribute 053 @Metadata(javaType = "java.lang.Boolean") 054 private String strategyMethodAllowNull; 055 @XmlAttribute 056 private String executorServiceRef; 057 @XmlAttribute 058 @Metadata(javaType = "java.lang.Boolean") 059 private String streaming; 060 @XmlAttribute 061 @Metadata(javaType = "java.lang.Boolean") 062 private String stopOnException; 063 @XmlAttribute 064 @Metadata(defaultValue = "0", javaType = "java.time.Duration") 065 private String timeout; 066 @XmlAttribute 067 private String onPrepareRef; 068 @XmlTransient 069 private Processor onPrepare; 070 @XmlAttribute 071 @Metadata(javaType = "java.lang.Boolean") 072 private String shareUnitOfWork; 073 @XmlAttribute 074 @Metadata(javaType = "java.lang.Boolean") 075 private String parallelAggregate; 076 @XmlAttribute 077 @Metadata(javaType = "java.lang.Boolean") 078 private String stopOnAggregateException; 079 080 public SplitDefinition() { 081 } 082 083 public SplitDefinition(Expression expression) { 084 super(expression); 085 } 086 087 public SplitDefinition(ExpressionDefinition expression) { 088 super(expression); 089 } 090 091 @Override 092 public String toString() { 093 return "Split[" + getExpression() + " -> " + getOutputs() + "]"; 094 } 095 096 @Override 097 public String getShortName() { 098 return "split"; 099 } 100 101 @Override 102 public String getLabel() { 103 return "split[" + getExpression() + "]"; 104 } 105 106 // Fluent API 107 // ------------------------------------------------------------------------- 108 109 /** 110 * Sets the AggregationStrategy to be used to assemble the replies from the 111 * splitted messages, into a single outgoing message from the Splitter. By 112 * default Camel will use the original incoming message to the splitter 113 * (leave it unchanged). You can also use a POJO as the AggregationStrategy 114 */ 115 public SplitDefinition aggregationStrategy(AggregationStrategy aggregationStrategy) { 116 setAggregationStrategy(aggregationStrategy); 117 return this; 118 } 119 120 /** 121 * Sets the AggregationStrategy to be used to assemble the replies from the 122 * splitted messages, into a single outgoing message from the Splitter. By 123 * default Camel will use the original incoming message to the splitter 124 * (leave it unchanged). You can also use a POJO as the AggregationStrategy 125 */ 126 public SplitDefinition aggregationStrategy(Supplier<AggregationStrategy> aggregationStrategy) { 127 setAggregationStrategy(aggregationStrategy.get()); 128 return this; 129 } 130 131 /** 132 * Sets a reference to the AggregationStrategy to be used to assemble the 133 * replies from the splitted messages, into a single outgoing message from 134 * the Splitter. By default Camel will use the original incoming message to 135 * the splitter (leave it unchanged). You can also use a POJO as the 136 * AggregationStrategy 137 */ 138 public SplitDefinition aggregationStrategyRef(String aggregationStrategyRef) { 139 setStrategyRef(aggregationStrategyRef); 140 return this; 141 } 142 143 /** 144 * This option can be used to explicit declare the method name to use, when 145 * using POJOs as the AggregationStrategy. 146 * 147 * @param methodName the method name to call 148 * @return the builder 149 */ 150 public SplitDefinition aggregationStrategyMethodName(String methodName) { 151 setStrategyMethodName(methodName); 152 return this; 153 } 154 155 /** 156 * If this option is false then the aggregate method is not used if there 157 * was no data to enrich. If this option is true then null values is used as 158 * the oldExchange (when no data to enrich), when using POJOs as the 159 * AggregationStrategy 160 * 161 * @return the builder 162 */ 163 public SplitDefinition aggregationStrategyMethodAllowNull() { 164 return aggregationStrategyMethodAllowNull(true); 165 } 166 167 /** 168 * If this option is false then the aggregate method is not used if there 169 * was no data to enrich. If this option is true then null values is used as 170 * the oldExchange (when no data to enrich), when using POJOs as the 171 * AggregationStrategy 172 * 173 * @return the builder 174 */ 175 public SplitDefinition aggregationStrategyMethodAllowNull(boolean aggregationStrategyMethodAllowNull) { 176 return aggregationStrategyMethodAllowNull(Boolean.toString(aggregationStrategyMethodAllowNull)); 177 } 178 179 /** 180 * If this option is false then the aggregate method is not used if there 181 * was no data to enrich. If this option is true then null values is used as 182 * the oldExchange (when no data to enrich), when using POJOs as the 183 * AggregationStrategy 184 * 185 * @return the builder 186 */ 187 public SplitDefinition aggregationStrategyMethodAllowNull(String aggregationStrategyMethodAllowNull) { 188 setStrategyMethodAllowNull(aggregationStrategyMethodAllowNull); 189 return this; 190 } 191 192 /** 193 * If enabled then processing each splitted messages occurs concurrently. 194 * Note the caller thread will still wait until all messages has been fully 195 * processed, before it continues. Its only processing the sub messages from 196 * the splitter which happens concurrently. 197 * 198 * @return the builder 199 */ 200 public SplitDefinition parallelProcessing() { 201 return parallelProcessing(true); 202 } 203 204 /** 205 * If enabled then processing each splitted messages occurs concurrently. 206 * Note the caller thread will still wait until all messages has been fully 207 * processed, before it continues. Its only processing the sub messages from 208 * the splitter which happens concurrently. 209 * 210 * @return the builder 211 */ 212 public SplitDefinition parallelProcessing(boolean parallelProcessing) { 213 return parallelProcessing(Boolean.toString(parallelProcessing)); 214 } 215 216 /** 217 * If enabled then processing each splitted messages occurs concurrently. 218 * Note the caller thread will still wait until all messages has been fully 219 * processed, before it continues. Its only processing the sub messages from 220 * the splitter which happens concurrently. 221 * 222 * @return the builder 223 */ 224 public SplitDefinition parallelProcessing(String parallelProcessing) { 225 setParallelProcessing(parallelProcessing); 226 return this; 227 } 228 229 /** 230 * If enabled then the aggregate method on AggregationStrategy can be called 231 * concurrently. Notice that this would require the implementation of 232 * AggregationStrategy to be implemented as thread-safe. By default this is 233 * false meaning that Camel synchronizes the call to the aggregate method. 234 * Though in some use-cases this can be used to archive higher performance 235 * when the AggregationStrategy is implemented as thread-safe. 236 * 237 * @return the builder 238 */ 239 public SplitDefinition parallelAggregate() { 240 return parallelAggregate(true); 241 } 242 243 /** 244 * If enabled then the aggregate method on AggregationStrategy can be called 245 * concurrently. Notice that this would require the implementation of 246 * AggregationStrategy to be implemented as thread-safe. By default this is 247 * false meaning that Camel synchronizes the call to the aggregate method. 248 * Though in some use-cases this can be used to archive higher performance 249 * when the AggregationStrategy is implemented as thread-safe. 250 * 251 * @return the builder 252 */ 253 public SplitDefinition parallelAggregate(boolean parallelAggregate) { 254 return parallelAggregate(Boolean.toString(parallelAggregate)); 255 } 256 257 /** 258 * If enabled then the aggregate method on AggregationStrategy can be called 259 * concurrently. Notice that this would require the implementation of 260 * AggregationStrategy to be implemented as thread-safe. By default this is 261 * false meaning that Camel synchronizes the call to the aggregate method. 262 * Though in some use-cases this can be used to archive higher performance 263 * when the AggregationStrategy is implemented as thread-safe. 264 * 265 * @return the builder 266 */ 267 public SplitDefinition parallelAggregate(String parallelAggregate) { 268 setParallelAggregate(parallelAggregate); 269 return this; 270 } 271 272 /** 273 * If enabled, unwind exceptions occurring at aggregation time to the error 274 * handler when parallelProcessing is used. Currently, aggregation time 275 * exceptions do not stop the route processing when parallelProcessing is 276 * used. Enabling this option allows to work around this behavior. The 277 * default value is <code>false</code> for the sake of backward 278 * compatibility. 279 * 280 * @return the builder 281 */ 282 public SplitDefinition stopOnAggregateException() { 283 return stopOnAggregateException(true); 284 } 285 286 /** 287 * If enabled, unwind exceptions occurring at aggregation time to the error 288 * handler when parallelProcessing is used. Currently, aggregation time 289 * exceptions do not stop the route processing when parallelProcessing is 290 * used. Enabling this option allows to work around this behavior. The 291 * default value is <code>false</code> for the sake of backward 292 * compatibility. 293 * 294 * @return the builder 295 */ 296 public SplitDefinition stopOnAggregateException(boolean stopOnAggregateException) { 297 return stopOnAggregateException(Boolean.toString(stopOnAggregateException)); 298 } 299 300 /** 301 * If enabled, unwind exceptions occurring at aggregation time to the error 302 * handler when parallelProcessing is used. Currently, aggregation time 303 * exceptions do not stop the route processing when parallelProcessing is 304 * used. Enabling this option allows to work around this behavior. The 305 * default value is <code>false</code> for the sake of backward 306 * compatibility. 307 * 308 * @return the builder 309 */ 310 public SplitDefinition stopOnAggregateException(String stopOnAggregateException) { 311 setStopOnAggregateException(stopOnAggregateException); 312 return this; 313 } 314 315 /** 316 * When in streaming mode, then the splitter splits the original message 317 * on-demand, and each splitted message is processed one by one. This 318 * reduces memory usage as the splitter do not split all the messages first, 319 * but then we do not know the total size, and therefore the 320 * {@link org.apache.camel.Exchange#SPLIT_SIZE} is empty. 321 * <p/> 322 * In non-streaming mode (default) the splitter will split each message 323 * first, to know the total size, and then process each message one by one. 324 * This requires to keep all the splitted messages in memory and therefore 325 * requires more memory. The total size is provided in the 326 * {@link org.apache.camel.Exchange#SPLIT_SIZE} header. 327 * <p/> 328 * The streaming mode also affects the aggregation behavior. If enabled then 329 * Camel will process replies out-of-order, eg in the order they come back. 330 * If disabled, Camel will process replies in the same order as the messages 331 * was splitted. 332 * 333 * @return the builder 334 */ 335 public SplitDefinition streaming() { 336 return streaming(true); 337 } 338 339 /** 340 * When in streaming mode, then the splitter splits the original message 341 * on-demand, and each splitted message is processed one by one. This 342 * reduces memory usage as the splitter do not split all the messages first, 343 * but then we do not know the total size, and therefore the 344 * {@link org.apache.camel.Exchange#SPLIT_SIZE} is empty. 345 * <p/> 346 * In non-streaming mode (default) the splitter will split each message 347 * first, to know the total size, and then process each message one by one. 348 * This requires to keep all the splitted messages in memory and therefore 349 * requires more memory. The total size is provided in the 350 * {@link org.apache.camel.Exchange#SPLIT_SIZE} header. 351 * <p/> 352 * The streaming mode also affects the aggregation behavior. If enabled then 353 * Camel will process replies out-of-order, eg in the order they come back. 354 * If disabled, Camel will process replies in the same order as the messages 355 * was splitted. 356 * 357 * @return the builder 358 */ 359 public SplitDefinition streaming(boolean streaming) { 360 return streaming(Boolean.toString(streaming)); 361 } 362 363 /** 364 * When in streaming mode, then the splitter splits the original message 365 * on-demand, and each splitted message is processed one by one. This 366 * reduces memory usage as the splitter do not split all the messages first, 367 * but then we do not know the total size, and therefore the 368 * {@link org.apache.camel.Exchange#SPLIT_SIZE} is empty. 369 * <p/> 370 * In non-streaming mode (default) the splitter will split each message 371 * first, to know the total size, and then process each message one by one. 372 * This requires to keep all the splitted messages in memory and therefore 373 * requires more memory. The total size is provided in the 374 * {@link org.apache.camel.Exchange#SPLIT_SIZE} header. 375 * <p/> 376 * The streaming mode also affects the aggregation behavior. If enabled then 377 * Camel will process replies out-of-order, eg in the order they come back. 378 * If disabled, Camel will process replies in the same order as the messages 379 * was splitted. 380 * 381 * @return the builder 382 */ 383 public SplitDefinition streaming(String streaming) { 384 setStreaming(streaming); 385 return this; 386 } 387 388 /** 389 * Will now stop further processing if an exception or failure occurred 390 * during processing of an {@link org.apache.camel.Exchange} and the caused 391 * exception will be thrown. 392 * <p/> 393 * Will also stop if processing the exchange failed (has a fault message) or 394 * an exception was thrown and handled by the error handler (such as using 395 * onException). In all situations the splitter will stop further 396 * processing. This is the same behavior as in pipeline, which is used by 397 * the routing engine. 398 * <p/> 399 * The default behavior is to <b>not</b> stop but continue processing till 400 * the end 401 * 402 * @return the builder 403 */ 404 public SplitDefinition stopOnException() { 405 return stopOnException(true); 406 } 407 408 /** 409 * Will now stop further processing if an exception or failure occurred 410 * during processing of an {@link org.apache.camel.Exchange} and the caused 411 * exception will be thrown. 412 * <p/> 413 * Will also stop if processing the exchange failed (has a fault message) or 414 * an exception was thrown and handled by the error handler (such as using 415 * onException). In all situations the splitter will stop further 416 * processing. This is the same behavior as in pipeline, which is used by 417 * the routing engine. 418 * <p/> 419 * The default behavior is to <b>not</b> stop but continue processing till 420 * the end 421 * 422 * @return the builder 423 */ 424 public SplitDefinition stopOnException(boolean stopOnException) { 425 return stopOnException(Boolean.toString(stopOnException)); 426 } 427 428 /** 429 * Will now stop further processing if an exception or failure occurred 430 * during processing of an {@link org.apache.camel.Exchange} and the caused 431 * exception will be thrown. 432 * <p/> 433 * Will also stop if processing the exchange failed (has a fault message) or 434 * an exception was thrown and handled by the error handler (such as using 435 * onException). In all situations the splitter will stop further 436 * processing. This is the same behavior as in pipeline, which is used by 437 * the routing engine. 438 * <p/> 439 * The default behavior is to <b>not</b> stop but continue processing till 440 * the end 441 * 442 * @return the builder 443 */ 444 public SplitDefinition stopOnException(String stopOnException) { 445 setStopOnException(stopOnException); 446 return this; 447 } 448 449 /** 450 * To use a custom Thread Pool to be used for parallel processing. Notice if 451 * you set this option, then parallel processing is automatic implied, and 452 * you do not have to enable that option as well. 453 */ 454 @Override 455 public SplitDefinition executorService(ExecutorService executorService) { 456 setExecutorService(executorService); 457 return this; 458 } 459 460 /** 461 * Refers to a custom Thread Pool to be used for parallel processing. Notice 462 * if you set this option, then parallel processing is automatic implied, 463 * and you do not have to enable that option as well. 464 */ 465 @Override 466 public SplitDefinition executorServiceRef(String executorServiceRef) { 467 setExecutorServiceRef(executorServiceRef); 468 return this; 469 } 470 471 /** 472 * Uses the {@link Processor} when preparing the 473 * {@link org.apache.camel.Exchange} to be send. This can be used to 474 * deep-clone messages that should be send, or any custom logic needed 475 * before the exchange is send. 476 * 477 * @param onPrepare the processor 478 * @return the builder 479 */ 480 public SplitDefinition onPrepare(Processor onPrepare) { 481 setOnPrepare(onPrepare); 482 return this; 483 } 484 485 /** 486 * Uses the {@link Processor} when preparing the 487 * {@link org.apache.camel.Exchange} to be send. This can be used to 488 * deep-clone messages that should be send, or any custom logic needed 489 * before the exchange is send. 490 * 491 * @param onPrepareRef reference to the processor to lookup in the 492 * {@link org.apache.camel.spi.Registry} 493 * @return the builder 494 */ 495 public SplitDefinition onPrepareRef(String onPrepareRef) { 496 setOnPrepareRef(onPrepareRef); 497 return this; 498 } 499 500 /** 501 * Sets a total timeout specified in millis, when using parallel processing. 502 * If the Splitter hasn't been able to split and process all the sub 503 * messages within the given timeframe, then the timeout triggers and the 504 * Splitter breaks out and continues. Notice if you provide a 505 * TimeoutAwareAggregationStrategy then the timeout method is invoked before 506 * breaking out. If the timeout is reached with running tasks still 507 * remaining, certain tasks for which it is difficult for Camel to shut down 508 * in a graceful manner may continue to run. So use this option with a bit 509 * of care. 510 * 511 * @param timeout timeout in millis 512 * @return the builder 513 */ 514 public SplitDefinition timeout(long timeout) { 515 return timeout(Long.toString(timeout)); 516 } 517 518 /** 519 * Sets a total timeout specified in millis, when using parallel processing. 520 * If the Splitter hasn't been able to split and process all the sub 521 * messages within the given timeframe, then the timeout triggers and the 522 * Splitter breaks out and continues. Notice if you provide a 523 * TimeoutAwareAggregationStrategy then the timeout method is invoked before 524 * breaking out. If the timeout is reached with running tasks still 525 * remaining, certain tasks for which it is difficult for Camel to shut down 526 * in a graceful manner may continue to run. So use this option with a bit 527 * of care. 528 * 529 * @param timeout timeout in millis 530 * @return the builder 531 */ 532 public SplitDefinition timeout(String timeout) { 533 setTimeout(timeout); 534 return this; 535 } 536 537 /** 538 * Shares the {@link org.apache.camel.spi.UnitOfWork} with the parent and 539 * each of the sub messages. Splitter will by default not share unit of work 540 * between the parent exchange and each splitted exchange. This means each 541 * splitted exchange has its own individual unit of work. 542 * 543 * @return the builder. 544 */ 545 public SplitDefinition shareUnitOfWork() { 546 return shareUnitOfWork(true); 547 } 548 549 /** 550 * Shares the {@link org.apache.camel.spi.UnitOfWork} with the parent and 551 * each of the sub messages. Splitter will by default not share unit of work 552 * between the parent exchange and each splitted exchange. This means each 553 * splitted exchange has its own individual unit of work. 554 * 555 * @return the builder. 556 */ 557 public SplitDefinition shareUnitOfWork(boolean shareUnitOfWork) { 558 return shareUnitOfWork(Boolean.toString(shareUnitOfWork)); 559 } 560 561 /** 562 * Shares the {@link org.apache.camel.spi.UnitOfWork} with the parent and 563 * each of the sub messages. Splitter will by default not share unit of work 564 * between the parent exchange and each splitted exchange. This means each 565 * splitted exchange has its own individual unit of work. 566 * 567 * @return the builder. 568 */ 569 public SplitDefinition shareUnitOfWork(String shareUnitOfWork) { 570 setShareUnitOfWork(shareUnitOfWork); 571 return this; 572 } 573 574 // Properties 575 // ------------------------------------------------------------------------- 576 577 /** 578 * Expression of how to split the message body, such as as-is, using a 579 * tokenizer, or using an xpath. 580 */ 581 @Override 582 public void setExpression(ExpressionDefinition expression) { 583 // override to include javadoc what the expression is used for 584 super.setExpression(expression); 585 } 586 587 public AggregationStrategy getAggregationStrategy() { 588 return aggregationStrategy; 589 } 590 591 /** 592 * Sets the AggregationStrategy to be used to assemble the replies from the 593 * splitted messages, into a single outgoing message from the Splitter. By 594 * default Camel will use the original incoming message to the splitter 595 * (leave it unchanged). You can also use a POJO as the AggregationStrategy 596 */ 597 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) { 598 this.aggregationStrategy = aggregationStrategy; 599 } 600 601 public String getParallelProcessing() { 602 return parallelProcessing; 603 } 604 605 public void setParallelProcessing(String parallelProcessing) { 606 this.parallelProcessing = parallelProcessing; 607 } 608 609 public String getStreaming() { 610 return streaming; 611 } 612 613 public void setStreaming(String streaming) { 614 this.streaming = streaming; 615 } 616 617 public String getParallelAggregate() { 618 return parallelAggregate; 619 } 620 621 public void setParallelAggregate(String parallelAggregate) { 622 this.parallelAggregate = parallelAggregate; 623 } 624 625 public String getStopOnAggregateException() { 626 return this.stopOnAggregateException; 627 } 628 629 public void setStopOnAggregateException(String stopOnAggregateException) { 630 this.stopOnAggregateException = stopOnAggregateException; 631 } 632 633 public String getStopOnException() { 634 return stopOnException; 635 } 636 637 public void setStopOnException(String stopOnException) { 638 this.stopOnException = stopOnException; 639 } 640 641 @Override 642 public ExecutorService getExecutorService() { 643 return executorService; 644 } 645 646 @Override 647 public void setExecutorService(ExecutorService executorService) { 648 this.executorService = executorService; 649 } 650 651 public String getStrategyRef() { 652 return strategyRef; 653 } 654 655 /** 656 * Sets a reference to the AggregationStrategy to be used to assemble the 657 * replies from the splitted messages, into a single outgoing message from 658 * the Splitter. By default Camel will use the original incoming message to 659 * the splitter (leave it unchanged). You can also use a POJO as the 660 * AggregationStrategy 661 */ 662 public void setStrategyRef(String strategyRef) { 663 this.strategyRef = strategyRef; 664 } 665 666 public String getStrategyMethodName() { 667 return strategyMethodName; 668 } 669 670 /** 671 * This option can be used to explicit declare the method name to use, when 672 * using POJOs as the AggregationStrategy. 673 */ 674 public void setStrategyMethodName(String strategyMethodName) { 675 this.strategyMethodName = strategyMethodName; 676 } 677 678 public String getStrategyMethodAllowNull() { 679 return strategyMethodAllowNull; 680 } 681 682 /** 683 * If this option is false then the aggregate method is not used if there 684 * was no data to enrich. If this option is true then null values is used as 685 * the oldExchange (when no data to enrich), when using POJOs as the 686 * AggregationStrategy 687 */ 688 public void setStrategyMethodAllowNull(String strategyMethodAllowNull) { 689 this.strategyMethodAllowNull = strategyMethodAllowNull; 690 } 691 692 @Override 693 public String getExecutorServiceRef() { 694 return executorServiceRef; 695 } 696 697 @Override 698 public void setExecutorServiceRef(String executorServiceRef) { 699 this.executorServiceRef = executorServiceRef; 700 } 701 702 public String getTimeout() { 703 return timeout; 704 } 705 706 public void setTimeout(String timeout) { 707 this.timeout = timeout; 708 } 709 710 public String getOnPrepareRef() { 711 return onPrepareRef; 712 } 713 714 public void setOnPrepareRef(String onPrepareRef) { 715 this.onPrepareRef = onPrepareRef; 716 } 717 718 public Processor getOnPrepare() { 719 return onPrepare; 720 } 721 722 public void setOnPrepare(Processor onPrepare) { 723 this.onPrepare = onPrepare; 724 } 725 726 public String getShareUnitOfWork() { 727 return shareUnitOfWork; 728 } 729 730 public void setShareUnitOfWork(String shareUnitOfWork) { 731 this.shareUnitOfWork = shareUnitOfWork; 732 } 733 734}