Enriching your content with some help from other endpoints

The Content Enricher EIP is used when you need to call out to some other endpoint (for example, a web service or Java method) to get additional content based on all, or parts, of your message. This recipe focuses on the most common scenario—when you want to modify the contents of your original message (including its body, headers, or properties) with the contents of the returned message.

When using the Enricher EIP, it is a common requirement to include a processing step before the enrich call to set up the message body to an appropriate request format for the enriching endpoint. It is also likely that you will need to define an additional processing step to merge the results of the endpoint invocation with your original exchange. This recipe will show you, through a simple example, how to perform these setup and enrichment steps when using the Enricher EIP.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.transformation.enrich package. The Spring XML files are located under src/main/resources/META-INF/spring and prefixed with enrich.

This recipe will call out to an example Java method that will expand a US state's abbreviation into its full name. This recipe's approach would work equally well with any Camel endpoint, such as a SOAP web service or a database lookup.

The code for the AbbreviationExpander class is as follows:

public class AbbreviationExpander {
  public String expand(String abbreviation) {
    if ("MA".equalsIgnoreCase(abbreviation)) {
      return "Massachusetts";
    }

    if ("CA".equalsIgnoreCase(abbreviation)) {
      return "California";
    }

    throw new IllegalArgumentException(
      "Unknown abbreviation '" + abbreviation + ";");
  }
}

This Expander code is called from a wrapper Camel route, direct:expander, that will be called by the Enricher EIP:

from("direct:expander")
  .bean(AbbreviationExpander.class, "expand");

How to do it...

In order to enrich your exchange with the results of another route you will need to create:

  • An AggregationStrategy to combine the results of your original message, and the response from the enrichment endpoint
  • Code to setup the call to the enrichment endpoint
  • A Camel route to tie them all together

These steps are performed as follows:

  1. Create an AggregationStrategy implementation and associated setup code. This code combines the enrichment endpoint setup code with the AggregationStrategy code that will merge the results with the original message, as they are dependent on each other:
    public class MergeInReplacementText 
        implements AggregationStrategy {
      public static final String ENRICH_EXAMPLE_ORIGINAL_BODY = 
          "EnrichExample.originalBody";
      public static final String 
          ENRICH_EXAMPLE_REPLACEMENT_STRING = 
            "EnrichExample.replacementString";
    
      /**
       * When using this AggregationStrategy, this
       * method must be called <b>before</b> the enrich call 
       * as this method sets up the message body, and adds some
       * properties needed by the aggregate method.
       */
      public void setup(Exchange exchange) {
        final String originalBody = 
            exchange.getIn().getBody(String.class);
    
        exchange.setProperty(ENRICH_EXAMPLE_ORIGINAL_BODY, 
                             originalBody);
    
        final String enrichParameter = 
            originalBody.substring(
              originalBody.lastIndexOf(" ") + 1);
    
        exchange.setProperty(ENRICH_EXAMPLE_REPLACEMENT_STRING, 
                             enrichParameter);
    
        exchange.getIn().setBody(enrichParameter);
      }
    
      @Override
      public Exchange aggregate(Exchange original, 
                                Exchange enrichResponse) {
        // The original.In.Body was changed to the replacement
        // string, so need to retrieve property with original 
        // body
        final String originalBody = 
            original.getProperty(ENRICH_EXAMPLE_ORIGINAL_BODY, 
                                 String.class);
        Validate.notEmpty(originalBody,
            "The property '" + ENRICH_EXAMPLE_ORIGINAL_BODY
            + "' must be set with the original message body.");
    
        final String replacementString = 
            original.getProperty(
              ENRICH_EXAMPLE_REPLACEMENT_STRING, String.class);
        Validate.notEmpty(replacementString,
            "The property '" 
            + ENRICH_EXAMPLE_REPLACEMENT_STRING
            + "' must be set with the value to be replaced.");
    
        final String replacementValue = 
            enrichResponse.getIn().getBody(String.class);
    
        // Use regular expression to replace the last 
        // occurrence of the replacement string
        final String mergeResult = 
            originalBody.replaceAll(replacementString + "$", 
                                    replacementValue);
    
        original.getIn().setBody(mergeResult);
    
        return original;
      }
    }
  2. Within the Camel route, set up the call to the enrichment endpoint. This example involves calling another Camel route, but using any of Camel's endpoints will also work.

    In the XML DSL, define a bean and use it in a route as follows:

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi=
             "http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation= "
             http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
             http://camel.apache.org/schema/spring
             http://camel.apache.org/schema/spring/camel-spring.xsd
           ">
    
      <bean id="myMerger"
            class="org.camelcookbook.transformation.enrich.MergeInReplacementText"/>
    
      <camelContext 
          xmlns="http://camel.apache.org/schema/spring">
        <route>
          <from uri="direct:start"/>
          <bean ref="myMerger" method="setup"/>
          <enrich uri="direct:expander"
                  strategyRef="myMerger"/>
        </route>
      </camelContext>
    </beans>

    In the Java DSL, the same idea is expressed as follows:

    public class EnrichWithAggregatorRouteBuilder 
            extends RouteBuilder {
        private MergeInReplacementText myMerger;
    
        @Override
        public void configure() throws Exception {
            from("direct:start")
                .bean(myMerger, "setup")
                .enrich("direct:expander", myMerger);
        }
    
        // Getters and Setters
    }
  3. Use the enrich DSL statement to call your enrichment endpoint, and reference your AggregationStrategy to process the results.

    In the XML DSL, this is written as follows:

    <route>
      <from uri="direct:start"/>
      <bean ref="myMerger" method="setup"/>
      <enrich uri="direct:expander"
              strategyRef="myMerger"/>
    </route>

    In the Java DSL, the same thing is expressed as:

    from("direct:start")
      .bean(myMerger, "setup")
      .enrich("direct:expander", myMerger);
    

Note

The Java DSL version of enrich expects a reference to an AggregationStrategy instance; in this example this instance is injected into the RouteBuilder.

How it works...

The enrich EIP calls the referenced endpoint as Request-Response (MEP InOut), and merges the response with the original message through an AggregationStrategy implementation. If no AggregationStrategy reference is provided, the enricher will replace the original message body with the response from the enrichment endpoint call.

Camel will send the current message to the reference enrichment endpoint, so most of the time you will need to alter (set up) the message to be appropriate to call the external endpoint. In the provided example code for this recipe, the enrichment endpoint expects a US state abbreviation such as "MA", but if the original message is "Hello MA", then the Camel route alters the message to be just the state abbreviation "MA".

The associated Aggregator merges the results with the original message, so for this example it would replace the abbreviation "MA" with "Massachusetts" within the original source message: "Hello MA". The AggregationStrategy receives two Camel exchanges: the first parameter is the original exchange before the enrichment endpoint is called, and the second parameter is the exchange returned from the enrichment endpoint (that is, its response).

The Aggregator needs the original message, since it needs to replace the state abbreviation with the long version. In the setup method we store the original message and the abbreviated state value to be replaced in the Camel exchange as properties. This allows the aggregate method, called after the enrich callout, to merge in the endpoint's response ("Massachusetts") with the original message ("Hello MA"), and give us the desired end result ("Hello Massachusetts").

There's more...

There is a variant of enrich called pollEnrich that is used with endpoints that are Polling Consumers, such as file or database. For example, if you want to append data from a file in a directory that you expect to be created externally as part of an integration, you should use pollEnrich to fetch its contents:

from("direct:start")
  .pollEnrich("file:/path/to/data", myAppender);

Tip

When using pollEnrich, it is a good idea to set its timeout option, which controls how many milliseconds it will wait for data. By default, the timeout is set to -1 meaning that it will wait forever for enrichment data. We recommend always setting this to some meaningful value for your integration so that your integrations do not appear to get stuck (hang).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.57.172