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