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 */ 017 package org.apache.camel.processor; 018 019 import org.apache.camel.Exchange; 020 import org.apache.camel.ExchangePattern; 021 import org.apache.camel.Processor; 022 import org.apache.camel.Producer; 023 import org.apache.camel.impl.DefaultExchange; 024 import org.apache.camel.impl.ServiceSupport; 025 import org.apache.camel.processor.aggregate.AggregationStrategy; 026 import org.apache.camel.util.ExchangeHelper; 027 import org.apache.commons.logging.Log; 028 import org.apache.commons.logging.LogFactory; 029 030 import static org.apache.camel.util.ExchangeHelper.copyResultsPreservePattern; 031 032 /** 033 * A content enricher that enriches input data by first obtaining additional 034 * data from a <i>resource</i> represented by an endpoint <code>producer</code> 035 * and second by aggregating input data and additional data. Aggregation of 036 * input data and additional data is delegated to an {@link AggregationStrategy} 037 * object. 038 * <p/> 039 * Uses a {@link org.apache.camel.Producer} to obatin the additional data as opposed to {@link PollEnricher} 040 * that uses a {@link org.apache.camel.PollingConsumer}. 041 * 042 * @see PollEnricher 043 */ 044 public class Enricher extends ServiceSupport implements Processor { 045 046 private static final transient Log LOG = LogFactory.getLog(Enricher.class); 047 private AggregationStrategy aggregationStrategy; 048 private Producer producer; 049 050 /** 051 * Creates a new {@link Enricher}. The default aggregation strategy is to 052 * copy the additional data obtained from the enricher's resource over the 053 * input data. When using the copy aggregation strategy the enricher 054 * degenerates to a normal transformer. 055 * 056 * @param producer producer to resource endpoint. 057 */ 058 public Enricher(Producer producer) { 059 this(defaultAggregationStrategy(), producer); 060 } 061 062 /** 063 * Creates a new {@link Enricher}. 064 * 065 * @param aggregationStrategy aggregation strategy to aggregate input data and additional data. 066 * @param producer producer to resource endpoint. 067 */ 068 public Enricher(AggregationStrategy aggregationStrategy, Producer producer) { 069 this.aggregationStrategy = aggregationStrategy; 070 this.producer = producer; 071 } 072 073 /** 074 * Sets the aggregation strategy for this enricher. 075 * 076 * @param aggregationStrategy the aggregationStrategy to set 077 */ 078 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) { 079 this.aggregationStrategy = aggregationStrategy; 080 } 081 082 /** 083 * Sets the default aggregation strategy for this enricher. 084 */ 085 public void setDefaultAggregationStrategy() { 086 this.aggregationStrategy = defaultAggregationStrategy(); 087 } 088 089 /** 090 * Enriches the input data (<code>exchange</code>) by first obtaining 091 * additional data from an endpoint represented by an endpoint 092 * <code>producer</code> and second by aggregating input data and additional 093 * data. Aggregation of input data and additional data is delegated to an 094 * {@link AggregationStrategy} object set at construction time. If the 095 * message exchange with the resource endpoint fails then no aggregation 096 * will be done and the failed exchange content is copied over to the 097 * original message exchange. 098 * 099 * @param exchange input data. 100 */ 101 public void process(Exchange exchange) throws Exception { 102 Exchange resourceExchange = createResourceExchange(exchange, ExchangePattern.InOut); 103 producer.process(resourceExchange); 104 105 if (resourceExchange.isFailed()) { 106 // copy resource exchange onto original exchange (preserving pattern) 107 copyResultsPreservePattern(exchange, resourceExchange); 108 } else { 109 prepareResult(exchange); 110 111 // aggregate original exchange and resource exchange 112 // but do not aggregate if the resource exchange was filtered 113 Boolean filtered = resourceExchange.getProperty(Exchange.FILTERED, Boolean.class); 114 if (filtered == null || !filtered) { 115 // prepare the exchanges for aggregation 116 ExchangeHelper.prepareAggregation(exchange, resourceExchange); 117 Exchange aggregatedExchange = aggregationStrategy.aggregate(exchange, resourceExchange); 118 // copy aggregation result onto original exchange (preserving pattern) 119 copyResultsPreservePattern(exchange, aggregatedExchange); 120 } else { 121 if (LOG.isTraceEnabled()) { 122 LOG.trace("Cannot aggregate exchange as its filtered: " + resourceExchange); 123 } 124 } 125 } 126 } 127 128 /** 129 * Creates a new {@link DefaultExchange} instance from the given 130 * <code>exchange</code>. The resulting exchange's pattern is defined by 131 * <code>pattern</code>. 132 * 133 * @param source exchange to copy from. 134 * @param pattern exchange pattern to set. 135 * @return created exchange. 136 */ 137 protected Exchange createResourceExchange(Exchange source, ExchangePattern pattern) { 138 Exchange target = source.copy(); 139 target.setPattern(pattern); 140 return target; 141 } 142 143 private static void prepareResult(Exchange exchange) { 144 if (exchange.getPattern().isOutCapable()) { 145 exchange.getOut().copyFrom(exchange.getIn()); 146 } 147 } 148 149 private static AggregationStrategy defaultAggregationStrategy() { 150 return new CopyAggregationStrategy(); 151 } 152 153 @Override 154 public String toString() { 155 return "Enrich[" + producer.getEndpoint().getEndpointUri() + "]"; 156 } 157 158 protected void doStart() throws Exception { 159 producer.start(); 160 } 161 162 protected void doStop() throws Exception { 163 producer.stop(); 164 } 165 166 private static class CopyAggregationStrategy implements AggregationStrategy { 167 168 public Exchange aggregate(Exchange oldExchange, Exchange newExchange) { 169 copyResultsPreservePattern(oldExchange, newExchange); 170 return oldExchange; 171 } 172 173 } 174 175 }