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}