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 javax.xml.bind.annotation.XmlAccessType;
020import javax.xml.bind.annotation.XmlAccessorType;
021import javax.xml.bind.annotation.XmlAttribute;
022import javax.xml.bind.annotation.XmlRootElement;
023import javax.xml.bind.annotation.XmlTransient;
024
025import org.apache.camel.CamelContextAware;
026import org.apache.camel.Expression;
027import org.apache.camel.Processor;
028import org.apache.camel.model.language.ExpressionDefinition;
029import org.apache.camel.processor.Enricher;
030import org.apache.camel.processor.aggregate.AggregationStrategy;
031import org.apache.camel.processor.aggregate.AggregationStrategyBeanAdapter;
032import org.apache.camel.spi.Metadata;
033import org.apache.camel.spi.RouteContext;
034
035/**
036 * Enriches a message with data from a secondary resource
037 *
038 * @see Enricher
039 */
040@Metadata(label = "eip,transformation")
041@XmlRootElement(name = "enrich")
042@XmlAccessorType(XmlAccessType.FIELD)
043public class EnrichDefinition extends NoOutputExpressionNode {
044    @XmlAttribute(name = "strategyRef")
045    private String aggregationStrategyRef;
046    @XmlAttribute(name = "strategyMethodName")
047    private String aggregationStrategyMethodName;
048    @XmlAttribute(name = "strategyMethodAllowNull")
049    private Boolean aggregationStrategyMethodAllowNull;
050    @XmlAttribute
051    private Boolean aggregateOnException;
052    @XmlTransient
053    private AggregationStrategy aggregationStrategy;
054    @XmlAttribute
055    private Boolean shareUnitOfWork;
056    @XmlAttribute
057    private Integer cacheSize;
058    @XmlAttribute
059    private Boolean ignoreInvalidEndpoint;
060
061    public EnrichDefinition() {
062        this(null);
063    }
064
065    public EnrichDefinition(AggregationStrategy aggregationStrategy) {
066        this.aggregationStrategy = aggregationStrategy;
067    }
068    
069    @Override
070    public String toString() {
071        return "Enrich[" + getExpression() + "]";
072    }
073    
074    @Override
075    public String getLabel() {
076        return "enrich[" + getExpression() + "]";
077    }
078
079    @Override
080    public Processor createProcessor(RouteContext routeContext) throws Exception {
081
082        Expression exp = getExpression().createExpression(routeContext);
083        boolean isShareUnitOfWork = getShareUnitOfWork() != null && getShareUnitOfWork();
084        boolean isIgnoreInvalidEndpoint = getIgnoreInvalidEndpoint() != null && getIgnoreInvalidEndpoint();
085
086        Enricher enricher = new Enricher(exp);
087        enricher.setShareUnitOfWork(isShareUnitOfWork);
088        enricher.setIgnoreInvalidEndpoint(isIgnoreInvalidEndpoint);
089        AggregationStrategy strategy = createAggregationStrategy(routeContext);
090        if (strategy != null) {
091            enricher.setAggregationStrategy(strategy);
092        }
093        if (aggregateOnException != null) {
094            enricher.setAggregateOnException(aggregateOnException);
095        }
096        return enricher;
097    }
098
099    private AggregationStrategy createAggregationStrategy(RouteContext routeContext) {
100        AggregationStrategy strategy = getAggregationStrategy();
101        if (strategy == null && aggregationStrategyRef != null) {
102            Object aggStrategy = routeContext.lookup(aggregationStrategyRef, Object.class);
103            if (aggStrategy instanceof AggregationStrategy) {
104                strategy = (AggregationStrategy) aggStrategy;
105            } else if (aggStrategy != null) {
106                AggregationStrategyBeanAdapter adapter = new AggregationStrategyBeanAdapter(aggStrategy, getAggregationStrategyMethodName());
107                if (getAggregationStrategyMethodAllowNull() != null) {
108                    adapter.setAllowNullNewExchange(getAggregationStrategyMethodAllowNull());
109                    adapter.setAllowNullOldExchange(getAggregationStrategyMethodAllowNull());
110                }
111                strategy = adapter;
112            } else {
113                throw new IllegalArgumentException("Cannot find AggregationStrategy in Registry with name: " + aggregationStrategyRef);
114            }
115        }
116
117        if (strategy instanceof CamelContextAware) {
118            ((CamelContextAware) strategy).setCamelContext(routeContext.getCamelContext());
119        }
120
121        return strategy;
122    }
123
124    // Fluent API
125    // -------------------------------------------------------------------------
126
127    /**
128     * Sets the AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message.
129     * By default Camel will use the reply from the external service as outgoing message.
130     */
131    public EnrichDefinition aggregationStrategy(AggregationStrategy aggregationStrategy) {
132        setAggregationStrategy(aggregationStrategy);
133        return this;
134    }
135
136    /**
137     * Refers to an AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message.
138     * By default Camel will use the reply from the external service as outgoing message.
139     */
140    public EnrichDefinition aggregationStrategyRef(String aggregationStrategyRef) {
141        setAggregationStrategyRef(aggregationStrategyRef);
142        return this;
143    }
144
145    /**
146     * This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy.
147     */
148    public EnrichDefinition aggregationStrategyMethodName(String aggregationStrategyMethodName) {
149        setAggregationStrategyMethodName(aggregationStrategyMethodName);
150        return this;
151    }
152
153    /**
154     * If this option is false then the aggregate method is not used if there was no data to enrich.
155     * If this option is true then null values is used as the oldExchange (when no data to enrich),
156     * when using POJOs as the AggregationStrategy.
157     */
158    public EnrichDefinition aggregationStrategyMethodAllowNull(boolean aggregationStrategyMethodAllowNull) {
159        setAggregationStrategyMethodAllowNull(aggregationStrategyMethodAllowNull);
160        return this;
161    }
162
163    /**
164     * If this option is false then the aggregate method is not used if there was an exception thrown while trying
165     * to retrieve the data to enrich from the resource. Setting this option to true allows end users to control what
166     * to do if there was an exception in the aggregate method. For example to suppress the exception
167     * or set a custom message body etc.
168     */
169    public EnrichDefinition aggregateOnException(boolean aggregateOnException) {
170        setAggregateOnException(aggregateOnException);
171        return this;
172    }
173
174    /**
175     * Shares the {@link org.apache.camel.spi.UnitOfWork} with the parent and the resource exchange.
176     * Enrich will by default not share unit of work between the parent exchange and the resource exchange.
177     * This means the resource exchange has its own individual unit of work.
178     */
179    public EnrichDefinition shareUnitOfWork() {
180        setShareUnitOfWork(true);
181        return this;
182    }
183
184    /**
185     * Sets the maximum size used by the {@link org.apache.camel.impl.ProducerCache} which is used
186     * to cache and reuse producer when uris are reused.
187     *
188     * @param cacheSize  the cache size, use <tt>0</tt> for default cache size, or <tt>-1</tt> to turn cache off.
189     * @return the builder
190     */
191    public EnrichDefinition cacheSize(int cacheSize) {
192        setCacheSize(cacheSize);
193        return this;
194    }
195
196    /**
197     * Ignore the invalidate endpoint exception when try to create a producer with that endpoint
198     *
199     * @return the builder
200     */
201    public EnrichDefinition ignoreInvalidEndpoint() {
202        setIgnoreInvalidEndpoint(true);
203        return this;
204    }
205
206    // Properties
207    // -------------------------------------------------------------------------
208
209    /**
210     * Expression that computes the endpoint uri to use as the resource endpoint to enrich from
211     */
212    @Override
213    public void setExpression(ExpressionDefinition expression) {
214        // override to include javadoc what the expression is used for
215        super.setExpression(expression);
216    }
217
218    public String getAggregationStrategyRef() {
219        return aggregationStrategyRef;
220    }
221
222    public void setAggregationStrategyRef(String aggregationStrategyRef) {
223        this.aggregationStrategyRef = aggregationStrategyRef;
224    }
225
226    public String getAggregationStrategyMethodName() {
227        return aggregationStrategyMethodName;
228    }
229
230    public void setAggregationStrategyMethodName(String aggregationStrategyMethodName) {
231        this.aggregationStrategyMethodName = aggregationStrategyMethodName;
232    }
233
234    public Boolean getAggregationStrategyMethodAllowNull() {
235        return aggregationStrategyMethodAllowNull;
236    }
237
238    public void setAggregationStrategyMethodAllowNull(Boolean aggregationStrategyMethodAllowNull) {
239        this.aggregationStrategyMethodAllowNull = aggregationStrategyMethodAllowNull;
240    }
241
242    public AggregationStrategy getAggregationStrategy() {
243        return aggregationStrategy;
244    }
245
246    public void setAggregationStrategy(AggregationStrategy aggregationStrategy) {
247        this.aggregationStrategy = aggregationStrategy;
248    }
249
250    public Boolean getAggregateOnException() {
251        return aggregateOnException;
252    }
253
254    public void setAggregateOnException(Boolean aggregateOnException) {
255        this.aggregateOnException = aggregateOnException;
256    }
257
258    public Boolean getShareUnitOfWork() {
259        return shareUnitOfWork;
260    }
261
262    public void setShareUnitOfWork(Boolean shareUnitOfWork) {
263        this.shareUnitOfWork = shareUnitOfWork;
264    }
265
266    public Integer getCacheSize() {
267        return cacheSize;
268    }
269
270    public void setCacheSize(Integer cacheSize) {
271        this.cacheSize = cacheSize;
272    }
273
274    public Boolean getIgnoreInvalidEndpoint() {
275        return ignoreInvalidEndpoint;
276    }
277
278    public void setIgnoreInvalidEndpoint(Boolean ignoreInvalidEndpoint) {
279        this.ignoreInvalidEndpoint = ignoreInvalidEndpoint;
280    }
281}