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.util; 018 019import java.util.HashMap; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.ExecutionException; 024import java.util.concurrent.Future; 025import java.util.concurrent.TimeUnit; 026import java.util.concurrent.TimeoutException; 027import java.util.function.Predicate; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.CamelExchangeException; 031import org.apache.camel.CamelExecutionException; 032import org.apache.camel.Endpoint; 033import org.apache.camel.Exchange; 034import org.apache.camel.ExchangePattern; 035import org.apache.camel.InvalidPayloadException; 036import org.apache.camel.Message; 037import org.apache.camel.MessageHistory; 038import org.apache.camel.NoSuchBeanException; 039import org.apache.camel.NoSuchEndpointException; 040import org.apache.camel.NoSuchHeaderException; 041import org.apache.camel.NoSuchPropertyException; 042import org.apache.camel.NoTypeConversionAvailableException; 043import org.apache.camel.Route; 044import org.apache.camel.TypeConversionException; 045import org.apache.camel.TypeConverter; 046import org.apache.camel.impl.DefaultExchange; 047import org.apache.camel.impl.MessageSupport; 048import org.apache.camel.spi.Synchronization; 049import org.apache.camel.spi.UnitOfWork; 050 051/** 052 * Some helper methods for working with {@link Exchange} objects 053 * 054 * @version 055 */ 056public final class ExchangeHelper { 057 058 /** 059 * Utility classes should not have a public constructor. 060 */ 061 private ExchangeHelper() { 062 } 063 064 /** 065 * Extracts the Exchange.BINDING of the given type or null if not present 066 * 067 * @param exchange the message exchange 068 * @param type the expected binding type 069 * @return the binding object of the given type or null if it could not be found or converted 070 */ 071 public static <T> T getBinding(Exchange exchange, Class<T> type) { 072 return exchange != null ? exchange.getProperty(Exchange.BINDING, type) : null; 073 } 074 075 /** 076 * Attempts to resolve the endpoint for the given value 077 * 078 * @param exchange the message exchange being processed 079 * @param value the value which can be an {@link Endpoint} or an object 080 * which provides a String representation of an endpoint via 081 * {@link #toString()} 082 * @return the endpoint 083 * @throws NoSuchEndpointException if the endpoint cannot be resolved 084 */ 085 public static Endpoint resolveEndpoint(Exchange exchange, Object value) throws NoSuchEndpointException { 086 Endpoint endpoint; 087 if (value instanceof Endpoint) { 088 endpoint = (Endpoint) value; 089 } else { 090 String uri = value.toString().trim(); 091 endpoint = CamelContextHelper.getMandatoryEndpoint(exchange.getContext(), uri); 092 } 093 return endpoint; 094 } 095 096 /** 097 * Gets the mandatory property of the exchange of the correct type 098 * 099 * @param exchange the exchange 100 * @param propertyName the property name 101 * @param type the type 102 * @return the property value 103 * @throws TypeConversionException is thrown if error during type conversion 104 * @throws NoSuchPropertyException is thrown if no property exists 105 */ 106 public static <T> T getMandatoryProperty(Exchange exchange, String propertyName, Class<T> type) throws NoSuchPropertyException { 107 T result = exchange.getProperty(propertyName, type); 108 if (result != null) { 109 return result; 110 } 111 throw new NoSuchPropertyException(exchange, propertyName, type); 112 } 113 114 /** 115 * Gets the mandatory inbound header of the correct type 116 * 117 * @param exchange the exchange 118 * @param headerName the header name 119 * @param type the type 120 * @return the header value 121 * @throws TypeConversionException is thrown if error during type conversion 122 * @throws NoSuchHeaderException is thrown if no headers exists 123 */ 124 public static <T> T getMandatoryHeader(Exchange exchange, String headerName, Class<T> type) throws TypeConversionException, NoSuchHeaderException { 125 T answer = exchange.getIn().getHeader(headerName, type); 126 if (answer == null) { 127 throw new NoSuchHeaderException(exchange, headerName, type); 128 } 129 return answer; 130 } 131 132 /** 133 * Gets the mandatory inbound header of the correct type 134 * 135 * @param message the message 136 * @param headerName the header name 137 * @param type the type 138 * @return the header value 139 * @throws TypeConversionException is thrown if error during type conversion 140 * @throws NoSuchHeaderException is thrown if no headers exists 141 */ 142 public static <T> T getMandatoryHeader(Message message, String headerName, Class<T> type) throws TypeConversionException, NoSuchHeaderException { 143 T answer = message.getHeader(headerName, type); 144 if (answer == null) { 145 throw new NoSuchHeaderException(message.getExchange(), headerName, type); 146 } 147 return answer; 148 } 149 150 /** 151 * Gets an header or property of the correct type 152 * 153 * @param exchange the exchange 154 * @param name the name of the header or the property 155 * @param type the type 156 * @return the header or property value 157 * @throws TypeConversionException is thrown if error during type conversion 158 * @throws NoSuchHeaderException is thrown if no headers exists 159 */ 160 public static <T> T getHeaderOrProperty(Exchange exchange, String name, Class<T> type) throws TypeConversionException { 161 T answer = exchange.getIn().getHeader(name, type); 162 if (answer == null) { 163 answer = exchange.getProperty(name, type); 164 } 165 return answer; 166 } 167 168 /** 169 * Returns the mandatory inbound message body of the correct type or throws 170 * an exception if it is not present 171 * 172 * @param exchange the exchange 173 * @return the body, is never <tt>null</tt> 174 * @throws InvalidPayloadException Is thrown if the body being <tt>null</tt> or wrong class type 175 * @deprecated use {@link org.apache.camel.Message#getMandatoryBody()} 176 */ 177 @Deprecated 178 public static Object getMandatoryInBody(Exchange exchange) throws InvalidPayloadException { 179 return exchange.getIn().getMandatoryBody(); 180 } 181 182 /** 183 * Returns the mandatory inbound message body of the correct type or throws 184 * an exception if it is not present 185 * @deprecated use {@link org.apache.camel.Message#getMandatoryBody(Class)} 186 */ 187 @Deprecated 188 public static <T> T getMandatoryInBody(Exchange exchange, Class<T> type) throws InvalidPayloadException { 189 return exchange.getIn().getMandatoryBody(type); 190 } 191 192 /** 193 * Returns the mandatory outbound message body of the correct type or throws 194 * an exception if it is not present 195 * @deprecated use {@link org.apache.camel.Message#getMandatoryBody()} 196 */ 197 @Deprecated 198 public static Object getMandatoryOutBody(Exchange exchange) throws InvalidPayloadException { 199 return exchange.getOut().getMandatoryBody(); 200 } 201 202 /** 203 * Returns the mandatory outbound message body of the correct type or throws 204 * an exception if it is not present 205 * @deprecated use {@link org.apache.camel.Message#getMandatoryBody(Class)} 206 */ 207 @Deprecated 208 public static <T> T getMandatoryOutBody(Exchange exchange, Class<T> type) throws InvalidPayloadException { 209 return exchange.getOut().getMandatoryBody(type); 210 } 211 212 /** 213 * Converts the value to the given expected type or throws an exception 214 * 215 * @return the converted value 216 * @throws TypeConversionException is thrown if error during type conversion 217 * @throws NoTypeConversionAvailableException} if no type converters exists to convert to the given type 218 */ 219 public static <T> T convertToMandatoryType(Exchange exchange, Class<T> type, Object value) 220 throws TypeConversionException, NoTypeConversionAvailableException { 221 CamelContext camelContext = exchange.getContext(); 222 ObjectHelper.notNull(camelContext, "CamelContext of Exchange"); 223 TypeConverter converter = camelContext.getTypeConverter(); 224 if (converter != null) { 225 return converter.mandatoryConvertTo(type, exchange, value); 226 } 227 throw new NoTypeConversionAvailableException(value, type); 228 } 229 230 /** 231 * Converts the value to the given expected type 232 * 233 * @return the converted value 234 * @throws org.apache.camel.TypeConversionException is thrown if error during type conversion 235 */ 236 public static <T> T convertToType(Exchange exchange, Class<T> type, Object value) throws TypeConversionException { 237 CamelContext camelContext = exchange.getContext(); 238 ObjectHelper.notNull(camelContext, "CamelContext of Exchange"); 239 TypeConverter converter = camelContext.getTypeConverter(); 240 if (converter != null) { 241 return converter.convertTo(type, exchange, value); 242 } 243 return null; 244 } 245 246 /** 247 * Creates a new instance and copies from the current message exchange so that it can be 248 * forwarded to another destination as a new instance. Unlike regular copy this operation 249 * will not share the same {@link org.apache.camel.spi.UnitOfWork} so its should be used 250 * for async messaging, where the original and copied exchange are independent. 251 * 252 * @param exchange original copy of the exchange 253 * @param handover whether the on completion callbacks should be handed over to the new copy. 254 */ 255 public static Exchange createCorrelatedCopy(Exchange exchange, boolean handover) { 256 return createCorrelatedCopy(exchange, handover, false); 257 } 258 259 /** 260 * Creates a new instance and copies from the current message exchange so that it can be 261 * forwarded to another destination as a new instance. Unlike regular copy this operation 262 * will not share the same {@link org.apache.camel.spi.UnitOfWork} so its should be used 263 * for async messaging, where the original and copied exchange are independent. 264 * 265 * @param exchange original copy of the exchange 266 * @param handover whether the on completion callbacks should be handed over to the new copy. 267 * @param useSameMessageId whether to use same message id on the copy message. 268 */ 269 public static Exchange createCorrelatedCopy(Exchange exchange, boolean handover, boolean useSameMessageId) { 270 return createCorrelatedCopy(exchange, handover, useSameMessageId, null); 271 } 272 273 /** 274 * Creates a new instance and copies from the current message exchange so that it can be 275 * forwarded to another destination as a new instance. Unlike regular copy this operation 276 * will not share the same {@link org.apache.camel.spi.UnitOfWork} so its should be used 277 * for async messaging, where the original and copied exchange are independent. 278 * 279 * @param exchange original copy of the exchange 280 * @param handover whether the on completion callbacks should be handed over to the new copy. 281 * @param useSameMessageId whether to use same message id on the copy message. 282 * @param filter whether to handover the on completion 283 */ 284 public static Exchange createCorrelatedCopy(Exchange exchange, boolean handover, boolean useSameMessageId, Predicate<Synchronization> filter) { 285 String id = exchange.getExchangeId(); 286 287 // make sure to do a safe copy as the correlated copy can be routed independently of the source. 288 Exchange copy = exchange.copy(true); 289 // do not reuse message id on copy 290 if (!useSameMessageId) { 291 if (copy.hasOut()) { 292 copy.getOut().setMessageId(null); 293 } 294 copy.getIn().setMessageId(null); 295 } 296 // do not share the unit of work 297 copy.setUnitOfWork(null); 298 // do not reuse the message id 299 // hand over on completion to the copy if we got any 300 UnitOfWork uow = exchange.getUnitOfWork(); 301 if (handover && uow != null) { 302 uow.handoverSynchronization(copy, filter); 303 } 304 // set a correlation id so we can track back the original exchange 305 copy.setProperty(Exchange.CORRELATION_ID, id); 306 return copy; 307 } 308 309 /** 310 * Creates a new instance and copies from the current message exchange so that it can be 311 * forwarded to another destination as a new instance. 312 * 313 * @param exchange original copy of the exchange 314 * @param preserveExchangeId whether or not the exchange id should be preserved 315 * @return the copy 316 */ 317 public static Exchange createCopy(Exchange exchange, boolean preserveExchangeId) { 318 Exchange copy = exchange.copy(); 319 if (preserveExchangeId) { 320 // must preserve exchange id 321 copy.setExchangeId(exchange.getExchangeId()); 322 } 323 return copy; 324 } 325 326 /** 327 * Copies the results of a message exchange from the source exchange to the result exchange 328 * which will copy the message contents, exchange properties and the exception. 329 * Notice the {@link ExchangePattern} is <b>not</b> copied/altered. 330 * 331 * @param result the result exchange which will have the output and error state added 332 * @param source the source exchange which is not modified 333 */ 334 public static void copyResults(Exchange result, Exchange source) { 335 336 // -------------------------------------------------------------------- 337 // TODO: merge logic with that of copyResultsPreservePattern() 338 // -------------------------------------------------------------------- 339 340 if (result == source) { 341 // we just need to ensure MEP is as expected (eg copy result to OUT if out capable) 342 // and the result is not failed 343 if (result.getPattern() == ExchangePattern.InOptionalOut) { 344 // keep as is 345 } else if (result.getPattern().isOutCapable() && !result.hasOut() && !result.isFailed()) { 346 // copy IN to OUT as we expect a OUT response 347 result.getOut().copyFrom(source.getIn()); 348 } 349 return; 350 } 351 352 if (result != source) { 353 result.setException(source.getException()); 354 if (source.hasOut()) { 355 result.getOut().copyFrom(source.getOut()); 356 } else if (result.getPattern() == ExchangePattern.InOptionalOut) { 357 // special case where the result is InOptionalOut and with no OUT response 358 // so we should return null to indicate this fact 359 result.setOut(null); 360 } else { 361 // no results so lets copy the last input 362 // as the final processor on a pipeline might not 363 // have created any OUT; such as a mock:endpoint 364 // so lets assume the last IN is the OUT 365 if (result.getPattern().isOutCapable()) { 366 // only set OUT if its OUT capable 367 result.getOut().copyFrom(source.getIn()); 368 } else { 369 // if not replace IN instead to keep the MEP 370 result.getIn().copyFrom(source.getIn()); 371 // clear any existing OUT as the result is on the IN 372 if (result.hasOut()) { 373 result.setOut(null); 374 } 375 } 376 } 377 378 if (source.hasProperties()) { 379 result.getProperties().putAll(source.getProperties()); 380 } 381 } 382 } 383 384 /** 385 * Copies the <code>source</code> exchange to <code>target</code> exchange 386 * preserving the {@link ExchangePattern} of <code>target</code>. 387 * 388 * @param result target exchange. 389 * @param source source exchange. 390 */ 391 public static void copyResultsPreservePattern(Exchange result, Exchange source) { 392 393 // -------------------------------------------------------------------- 394 // TODO: merge logic with that of copyResults() 395 // -------------------------------------------------------------------- 396 397 if (result == source) { 398 // we just need to ensure MEP is as expected (eg copy result to OUT if out capable) 399 // and the result is not failed 400 if (result.getPattern() == ExchangePattern.InOptionalOut) { 401 // keep as is 402 } else if (result.getPattern().isOutCapable() && !result.hasOut() && !result.isFailed()) { 403 // copy IN to OUT as we expect a OUT response 404 result.getOut().copyFrom(source.getIn()); 405 } 406 return; 407 } 408 409 // copy in message 410 result.getIn().copyFrom(source.getIn()); 411 412 // copy out message 413 if (source.hasOut()) { 414 // exchange pattern sensitive 415 Message resultMessage = source.getOut().isFault() ? result.getOut() : getResultMessage(result); 416 resultMessage.copyFrom(source.getOut()); 417 } 418 419 // copy exception 420 result.setException(source.getException()); 421 422 // copy properties 423 if (source.hasProperties()) { 424 result.getProperties().putAll(source.getProperties()); 425 } 426 } 427 428 /** 429 * Returns the message where to write results in an 430 * exchange-pattern-sensitive way. 431 * 432 * @param exchange message exchange. 433 * @return result message. 434 */ 435 public static Message getResultMessage(Exchange exchange) { 436 if (exchange.getPattern().isOutCapable()) { 437 return exchange.getOut(); 438 } else { 439 return exchange.getIn(); 440 } 441 } 442 443 /** 444 * Returns true if the given exchange pattern (if defined) can support OUT messages 445 * 446 * @param exchange the exchange to interrogate 447 * @return true if the exchange is defined as an {@link ExchangePattern} which supports 448 * OUT messages 449 */ 450 public static boolean isOutCapable(Exchange exchange) { 451 ExchangePattern pattern = exchange.getPattern(); 452 return pattern != null && pattern.isOutCapable(); 453 } 454 455 /** 456 * Creates a new instance of the given type from the injector 457 * 458 * @param exchange the exchange 459 * @param type the given type 460 * @return the created instance of the given type 461 */ 462 public static <T> T newInstance(Exchange exchange, Class<T> type) { 463 return exchange.getContext().getInjector().newInstance(type); 464 } 465 466 /** 467 * Creates a Map of the variables which are made available to a script or template 468 * 469 * @param exchange the exchange to make available 470 * @return a Map populated with the require variables 471 */ 472 public static Map<String, Object> createVariableMap(Exchange exchange) { 473 Map<String, Object> answer = new HashMap<>(); 474 populateVariableMap(exchange, answer); 475 return answer; 476 } 477 478 /** 479 * Populates the Map with the variables which are made available to a script or template 480 * 481 * @param exchange the exchange to make available 482 * @param map the map to populate 483 */ 484 public static void populateVariableMap(Exchange exchange, Map<String, Object> map) { 485 map.put("exchange", exchange); 486 Message in = exchange.getIn(); 487 map.put("in", in); 488 map.put("request", in); 489 map.put("headers", in.getHeaders()); 490 map.put("body", in.getBody()); 491 if (isOutCapable(exchange)) { 492 // if we are out capable then set out and response as well 493 // however only grab OUT if it exists, otherwise reuse IN 494 // this prevents side effects to alter the Exchange if we force creating an OUT message 495 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 496 map.put("out", msg); 497 map.put("response", msg); 498 } 499 map.put("camelContext", exchange.getContext()); 500 } 501 502 /** 503 * Returns the MIME content type on the input message or null if one is not defined 504 * 505 * @param exchange the exchange 506 * @return the MIME content type 507 */ 508 public static String getContentType(Exchange exchange) { 509 return MessageHelper.getContentType(exchange.getIn()); 510 } 511 512 /** 513 * Returns the MIME content encoding on the input message or null if one is not defined 514 * 515 * @param exchange the exchange 516 * @return the MIME content encoding 517 */ 518 public static String getContentEncoding(Exchange exchange) { 519 return MessageHelper.getContentEncoding(exchange.getIn()); 520 } 521 522 /** 523 * Performs a lookup in the registry of the mandatory bean name and throws an exception if it could not be found 524 * 525 * @param exchange the exchange 526 * @param name the bean name 527 * @return the bean 528 * @throws NoSuchBeanException if no bean could be found in the registry 529 */ 530 public static Object lookupMandatoryBean(Exchange exchange, String name) throws NoSuchBeanException { 531 Object value = lookupBean(exchange, name); 532 if (value == null) { 533 throw new NoSuchBeanException(name); 534 } 535 return value; 536 } 537 538 /** 539 * Performs a lookup in the registry of the mandatory bean name and throws an exception if it could not be found 540 * 541 * @param exchange the exchange 542 * @param name the bean name 543 * @param type the expected bean type 544 * @return the bean 545 * @throws NoSuchBeanException if no bean could be found in the registry 546 */ 547 public static <T> T lookupMandatoryBean(Exchange exchange, String name, Class<T> type) { 548 T value = lookupBean(exchange, name, type); 549 if (value == null) { 550 throw new NoSuchBeanException(name); 551 } 552 return value; 553 } 554 555 /** 556 * Performs a lookup in the registry of the bean name 557 * 558 * @param exchange the exchange 559 * @param name the bean name 560 * @return the bean, or <tt>null</tt> if no bean could be found 561 */ 562 public static Object lookupBean(Exchange exchange, String name) { 563 return exchange.getContext().getRegistry().lookupByName(name); 564 } 565 566 /** 567 * Performs a lookup in the registry of the bean name and type 568 * 569 * @param exchange the exchange 570 * @param name the bean name 571 * @param type the expected bean type 572 * @return the bean, or <tt>null</tt> if no bean could be found 573 */ 574 public static <T> T lookupBean(Exchange exchange, String name, Class<T> type) { 575 return exchange.getContext().getRegistry().lookupByNameAndType(name, type); 576 } 577 578 /** 579 * Returns the first exchange in the given collection of exchanges which has the same exchange ID as the one given 580 * or null if none could be found 581 * 582 * @param exchanges the exchanges 583 * @param exchangeId the exchangeId to find 584 * @return matching exchange, or <tt>null</tt> if none found 585 */ 586 public static Exchange getExchangeById(Iterable<Exchange> exchanges, String exchangeId) { 587 for (Exchange exchange : exchanges) { 588 String id = exchange.getExchangeId(); 589 if (id != null && id.equals(exchangeId)) { 590 return exchange; 591 } 592 } 593 return null; 594 } 595 596 /** 597 * Prepares the exchanges for aggregation. 598 * <p/> 599 * This implementation will copy the OUT body to the IN body so when you do 600 * aggregation the body is <b>only</b> in the IN body to avoid confusing end users. 601 * 602 * @param oldExchange the old exchange 603 * @param newExchange the new exchange 604 */ 605 public static void prepareAggregation(Exchange oldExchange, Exchange newExchange) { 606 // move body/header from OUT to IN 607 if (oldExchange != null) { 608 if (oldExchange.hasOut()) { 609 oldExchange.setIn(oldExchange.getOut()); 610 oldExchange.setOut(null); 611 } 612 } 613 614 if (newExchange != null) { 615 if (newExchange.hasOut()) { 616 newExchange.setIn(newExchange.getOut()); 617 newExchange.setOut(null); 618 } 619 } 620 } 621 622 /** 623 * Checks whether the exchange has been failure handed 624 * 625 * @param exchange the exchange 626 * @return <tt>true</tt> if failure handled, <tt>false</tt> otherwise 627 */ 628 public static boolean isFailureHandled(Exchange exchange) { 629 return exchange.getProperty(Exchange.FAILURE_HANDLED, false, Boolean.class); 630 } 631 632 /** 633 * Checks whether the exchange {@link UnitOfWork} is exhausted 634 * 635 * @param exchange the exchange 636 * @return <tt>true</tt> if exhausted, <tt>false</tt> otherwise 637 */ 638 public static boolean isUnitOfWorkExhausted(Exchange exchange) { 639 return exchange.getProperty(Exchange.UNIT_OF_WORK_EXHAUSTED, false, Boolean.class); 640 } 641 642 /** 643 * Sets the exchange to be failure handled. 644 * 645 * @param exchange the exchange 646 */ 647 public static void setFailureHandled(Exchange exchange) { 648 exchange.setProperty(Exchange.FAILURE_HANDLED, Boolean.TRUE); 649 // clear exception since its failure handled 650 exchange.setException(null); 651 } 652 653 /** 654 * Checks whether the exchange is redelivery exhausted 655 * 656 * @param exchange the exchange 657 * @return <tt>true</tt> if exhausted, <tt>false</tt> otherwise 658 */ 659 public static boolean isRedeliveryExhausted(Exchange exchange) { 660 return exchange.getProperty(Exchange.REDELIVERY_EXHAUSTED, false, Boolean.class); 661 } 662 663 /** 664 * Checks whether the exchange {@link UnitOfWork} is redelivered 665 * 666 * @param exchange the exchange 667 * @return <tt>true</tt> if redelivered, <tt>false</tt> otherwise 668 */ 669 public static boolean isRedelivered(Exchange exchange) { 670 return exchange.getIn().hasHeaders() && exchange.getIn().getHeader(Exchange.REDELIVERED, false, Boolean.class); 671 } 672 673 /** 674 * Checks whether the exchange {@link UnitOfWork} has been interrupted during processing 675 * 676 * @param exchange the exchange 677 * @return <tt>true</tt> if interrupted, <tt>false</tt> otherwise 678 */ 679 public static boolean isInterrupted(Exchange exchange) { 680 Object value = exchange.getProperty(Exchange.INTERRUPTED); 681 return value != null && Boolean.TRUE == value; 682 } 683 684 /** 685 * Check whether or not stream caching is enabled for the given route or globally. 686 * 687 * @param exchange the exchange 688 * @return <tt>true</tt> if enabled, <tt>false</tt> otherwise 689 */ 690 public static boolean isStreamCachingEnabled(final Exchange exchange) { 691 Route route = exchange.getContext().getRoute(exchange.getFromRouteId()); 692 if (route != null) { 693 return route.getRouteContext().isStreamCaching(); 694 } else { 695 return exchange.getContext().getStreamCachingStrategy().isEnabled(); 696 } 697 } 698 699 /** 700 * Extracts the body from the given exchange. 701 * <p/> 702 * If the exchange pattern is provided it will try to honor it and retrieve the body 703 * from either IN or OUT according to the pattern. 704 * 705 * @param exchange the exchange 706 * @param pattern exchange pattern if given, can be <tt>null</tt> 707 * @return the result body, can be <tt>null</tt>. 708 * @throws CamelExecutionException is thrown if the processing of the exchange failed 709 */ 710 public static Object extractResultBody(Exchange exchange, ExchangePattern pattern) { 711 Object answer = null; 712 if (exchange != null) { 713 // rethrow if there was an exception during execution 714 if (exchange.getException() != null) { 715 throw ObjectHelper.wrapCamelExecutionException(exchange, exchange.getException()); 716 } 717 718 // result could have a fault message 719 if (hasFaultMessage(exchange)) { 720 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 721 answer = msg.getBody(); 722 return answer; 723 } 724 725 // okay no fault then return the response according to the pattern 726 // try to honor pattern if provided 727 boolean notOut = pattern != null && !pattern.isOutCapable(); 728 boolean hasOut = exchange.hasOut(); 729 if (hasOut && !notOut) { 730 // we have a response in out and the pattern is out capable 731 answer = exchange.getOut().getBody(); 732 } else if (!hasOut && exchange.getPattern() == ExchangePattern.InOptionalOut) { 733 // special case where the result is InOptionalOut and with no OUT response 734 // so we should return null to indicate this fact 735 answer = null; 736 } else { 737 // use IN as the response 738 answer = exchange.getIn().getBody(); 739 } 740 } 741 return answer; 742 } 743 744 /** 745 * Tests whether the exchange has a fault message set and that its not null. 746 * 747 * @param exchange the exchange 748 * @return <tt>true</tt> if fault message exists 749 */ 750 public static boolean hasFaultMessage(Exchange exchange) { 751 Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 752 return msg.isFault() && msg.getBody() != null; 753 } 754 755 /** 756 * Tests whether the exchange has already been handled by the error handler 757 * 758 * @param exchange the exchange 759 * @return <tt>true</tt> if handled already by error handler, <tt>false</tt> otherwise 760 */ 761 public static boolean hasExceptionBeenHandledByErrorHandler(Exchange exchange) { 762 return Boolean.TRUE.equals(exchange.getProperty(Exchange.ERRORHANDLER_HANDLED)); 763 } 764 765 /** 766 * Extracts the body from the given future, that represents a handle to an asynchronous exchange. 767 * <p/> 768 * Will wait until the future task is complete. 769 * 770 * @param context the camel context 771 * @param future the future handle 772 * @param type the expected body response type 773 * @return the result body, can be <tt>null</tt>. 774 * @throws CamelExecutionException is thrown if the processing of the exchange failed 775 */ 776 public static <T> T extractFutureBody(CamelContext context, Future<?> future, Class<T> type) { 777 try { 778 return doExtractFutureBody(context, future.get(), type); 779 } catch (InterruptedException e) { 780 throw ObjectHelper.wrapRuntimeCamelException(e); 781 } catch (ExecutionException e) { 782 // execution failed due to an exception so rethrow the cause 783 throw ObjectHelper.wrapCamelExecutionException(null, e.getCause()); 784 } finally { 785 // its harmless to cancel if task is already completed 786 // and in any case we do not want to get hold of the task a 2nd time 787 // and its recommended to cancel according to Brian Goetz in his Java Concurrency in Practice book 788 future.cancel(true); 789 } 790 } 791 792 /** 793 * Extracts the body from the given future, that represents a handle to an asynchronous exchange. 794 * <p/> 795 * Will wait for the future task to complete, but waiting at most the timeout value. 796 * 797 * @param context the camel context 798 * @param future the future handle 799 * @param timeout timeout value 800 * @param unit timeout unit 801 * @param type the expected body response type 802 * @return the result body, can be <tt>null</tt>. 803 * @throws CamelExecutionException is thrown if the processing of the exchange failed 804 * @throws java.util.concurrent.TimeoutException is thrown if a timeout triggered 805 */ 806 public static <T> T extractFutureBody(CamelContext context, Future<?> future, long timeout, TimeUnit unit, Class<T> type) throws TimeoutException { 807 try { 808 if (timeout > 0) { 809 return doExtractFutureBody(context, future.get(timeout, unit), type); 810 } else { 811 return doExtractFutureBody(context, future.get(), type); 812 } 813 } catch (InterruptedException e) { 814 // execution failed due interruption so rethrow the cause 815 throw ObjectHelper.wrapCamelExecutionException(null, e); 816 } catch (ExecutionException e) { 817 // execution failed due to an exception so rethrow the cause 818 throw ObjectHelper.wrapCamelExecutionException(null, e.getCause()); 819 } finally { 820 // its harmless to cancel if task is already completed 821 // and in any case we do not want to get hold of the task a 2nd time 822 // and its recommended to cancel according to Brian Goetz in his Java Concurrency in Practice book 823 future.cancel(true); 824 } 825 } 826 827 private static <T> T doExtractFutureBody(CamelContext context, Object result, Class<T> type) { 828 if (result == null) { 829 return null; 830 } 831 if (type.isAssignableFrom(result.getClass())) { 832 return type.cast(result); 833 } 834 if (result instanceof Exchange) { 835 Exchange exchange = (Exchange) result; 836 Object answer = ExchangeHelper.extractResultBody(exchange, exchange.getPattern()); 837 return context.getTypeConverter().convertTo(type, exchange, answer); 838 } 839 return context.getTypeConverter().convertTo(type, result); 840 } 841 842 /** 843 * @deprecated use org.apache.camel.CamelExchangeException.createExceptionMessage instead 844 */ 845 @Deprecated 846 public static String createExceptionMessage(String message, Exchange exchange, Throwable cause) { 847 return CamelExchangeException.createExceptionMessage(message, exchange, cause); 848 } 849 850 /** 851 * Strategy to prepare results before next iterator or when we are complete, 852 * which is done by copying OUT to IN, so there is only an IN as input 853 * for the next iteration. 854 * 855 * @param exchange the exchange to prepare 856 */ 857 public static void prepareOutToIn(Exchange exchange) { 858 // we are routing using pipes and filters so we need to manually copy OUT to IN 859 if (exchange.hasOut()) { 860 exchange.setIn(exchange.getOut()); 861 exchange.setOut(null); 862 } 863 } 864 865 /** 866 * Gets both the messageId and exchangeId to be used for logging purposes. 867 * <p/> 868 * Logging both ids, can help to correlate exchanges which may be redelivered messages 869 * from for example a JMS broker. 870 * 871 * @param exchange the exchange 872 * @return a log message with both the messageId and exchangeId 873 */ 874 public static String logIds(Exchange exchange) { 875 String msgId = exchange.hasOut() ? exchange.getOut().getMessageId() : exchange.getIn().getMessageId(); 876 return "(MessageId: " + msgId + " on ExchangeId: " + exchange.getExchangeId() + ")"; 877 } 878 879 /** 880 * Copies the exchange but the copy will be tied to the given context 881 * 882 * @param exchange the source exchange 883 * @param context the camel context 884 * @return a copy with the given camel context 885 */ 886 public static Exchange copyExchangeAndSetCamelContext(Exchange exchange, CamelContext context) { 887 return copyExchangeAndSetCamelContext(exchange, context, true); 888 } 889 890 /** 891 * Copies the exchange but the copy will be tied to the given context 892 * 893 * @param exchange the source exchange 894 * @param context the camel context 895 * @param handover whether to handover on completions from the source to the copy 896 * @return a copy with the given camel context 897 */ 898 public static Exchange copyExchangeAndSetCamelContext(Exchange exchange, CamelContext context, boolean handover) { 899 DefaultExchange answer = new DefaultExchange(context, exchange.getPattern()); 900 if (exchange.hasProperties()) { 901 answer.setProperties(safeCopyProperties(exchange.getProperties())); 902 } 903 if (handover) { 904 // Need to hand over the completion for async invocation 905 exchange.handoverCompletions(answer); 906 } 907 answer.setIn(exchange.getIn().copy()); 908 if (exchange.hasOut()) { 909 answer.setOut(exchange.getOut().copy()); 910 } 911 answer.setException(exchange.getException()); 912 return answer; 913 } 914 915 /** 916 * Replaces the existing message with the new message 917 * 918 * @param exchange the exchange 919 * @param newMessage the new message 920 * @param outOnly whether to replace the message as OUT message 921 */ 922 public static void replaceMessage(Exchange exchange, Message newMessage, boolean outOnly) { 923 Message old = exchange.hasOut() ? exchange.getOut() : exchange.getIn(); 924 if (outOnly || exchange.hasOut()) { 925 exchange.setOut(newMessage); 926 } else { 927 exchange.setIn(newMessage); 928 } 929 930 // need to de-reference old from the exchange so it can be GC 931 if (old instanceof MessageSupport) { 932 ((MessageSupport) old).setExchange(null); 933 } 934 } 935 936 /** 937 * Gets the original IN {@link Message} this Unit of Work was started with. 938 * <p/> 939 * The original message is only returned if the option {@link org.apache.camel.RuntimeConfiguration#isAllowUseOriginalMessage()} 940 * is enabled. If its disabled, then <tt>null</tt> is returned. 941 * 942 * @return the original IN {@link Message}, or <tt>null</tt> if using original message is disabled. 943 */ 944 public static Message getOriginalInMessage(Exchange exchange) { 945 Message answer = null; 946 947 // try parent first 948 UnitOfWork uow = exchange.getProperty(Exchange.PARENT_UNIT_OF_WORK, UnitOfWork.class); 949 if (uow != null) { 950 answer = uow.getOriginalInMessage(); 951 } 952 // fallback to the current exchange 953 if (answer == null) { 954 uow = exchange.getUnitOfWork(); 955 if (uow != null) { 956 answer = uow.getOriginalInMessage(); 957 } 958 } 959 return answer; 960 } 961 962 /** 963 * Resolve the component scheme (aka name) from the given endpoint uri 964 * 965 * @param uri the endpoint uri 966 * @return the component scheme (name), or <tt>null</tt> if not possible to resolve 967 */ 968 public static String resolveScheme(String uri) { 969 String scheme = null; 970 if (uri != null) { 971 // Use the URI prefix to find the component. 972 String splitURI[] = StringHelper.splitOnCharacter(uri, ":", 2); 973 if (splitURI[1] != null) { 974 scheme = splitURI[0]; 975 } 976 } 977 return scheme; 978 } 979 980 @SuppressWarnings("unchecked") 981 private static Map<String, Object> safeCopyProperties(Map<String, Object> properties) { 982 if (properties == null) { 983 return null; 984 } 985 986 Map<String, Object> answer = new HashMap<>(properties); 987 988 // safe copy message history using a defensive copy 989 List<MessageHistory> history = (List<MessageHistory>) answer.remove(Exchange.MESSAGE_HISTORY); 990 if (history != null) { 991 answer.put(Exchange.MESSAGE_HISTORY, new LinkedList<>(history)); 992 } 993 994 return answer; 995 } 996}