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.Endpoint; 027import org.apache.camel.Processor; 028import org.apache.camel.processor.Enricher; 029import org.apache.camel.processor.aggregate.AggregationStrategy; 030import org.apache.camel.processor.aggregate.AggregationStrategyBeanAdapter; 031import org.apache.camel.spi.Metadata; 032import org.apache.camel.spi.RouteContext; 033import org.apache.camel.util.ObjectHelper; 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 NoOutputDefinition<EnrichDefinition> implements EndpointRequiredDefinition { 044 @XmlAttribute(name = "uri") 045 private String resourceUri; 046 // TODO: For Camel 3.0 we should remove this ref attribute as you can do that in the uri, by prefixing with ref: 047 @XmlAttribute(name = "ref") 048 @Deprecated 049 private String resourceRef; 050 @XmlAttribute(name = "strategyRef") 051 private String aggregationStrategyRef; 052 @XmlAttribute(name = "strategyMethodName") 053 private String aggregationStrategyMethodName; 054 @XmlAttribute(name = "strategyMethodAllowNull") 055 private Boolean aggregationStrategyMethodAllowNull; 056 @XmlAttribute 057 private Boolean aggregateOnException; 058 @XmlTransient 059 private AggregationStrategy aggregationStrategy; 060 061 public EnrichDefinition() { 062 this(null, null); 063 } 064 065 public EnrichDefinition(String resourceUri) { 066 this(null, resourceUri); 067 } 068 069 public EnrichDefinition(AggregationStrategy aggregationStrategy, String resourceUri) { 070 this.aggregationStrategy = aggregationStrategy; 071 this.resourceUri = resourceUri; 072 } 073 074 @Override 075 public String toString() { 076 return "Enrich[" + description() + " " + aggregationStrategy + "]"; 077 } 078 079 protected String description() { 080 return FromDefinition.description(resourceUri, resourceRef, (Endpoint) null); 081 } 082 083 @Override 084 public String getLabel() { 085 return "enrich[" + description() + "]"; 086 } 087 088 @Override 089 public String getEndpointUri() { 090 if (resourceUri != null) { 091 return resourceUri; 092 } else { 093 return null; 094 } 095 } 096 097 @Override 098 public Processor createProcessor(RouteContext routeContext) throws Exception { 099 if (ObjectHelper.isEmpty(resourceUri) && ObjectHelper.isEmpty(resourceRef)) { 100 throw new IllegalArgumentException("Either uri or ref must be provided for resource endpoint"); 101 } 102 103 // lookup endpoint 104 Endpoint endpoint; 105 if (resourceUri != null) { 106 endpoint = routeContext.resolveEndpoint(resourceUri); 107 } else { 108 endpoint = routeContext.resolveEndpoint(null, resourceRef); 109 } 110 111 Enricher enricher = new Enricher(null, endpoint.createProducer()); 112 AggregationStrategy strategy = createAggregationStrategy(routeContext); 113 if (strategy == null) { 114 enricher.setDefaultAggregationStrategy(); 115 } else { 116 enricher.setAggregationStrategy(strategy); 117 } 118 if (getAggregateOnException() != null) { 119 enricher.setAggregateOnException(getAggregateOnException()); 120 } 121 return enricher; 122 } 123 124 private AggregationStrategy createAggregationStrategy(RouteContext routeContext) { 125 AggregationStrategy strategy = getAggregationStrategy(); 126 if (strategy == null && aggregationStrategyRef != null) { 127 Object aggStrategy = routeContext.lookup(aggregationStrategyRef, Object.class); 128 if (aggStrategy instanceof AggregationStrategy) { 129 strategy = (AggregationStrategy) aggStrategy; 130 } else if (aggStrategy != null) { 131 AggregationStrategyBeanAdapter adapter = new AggregationStrategyBeanAdapter(aggStrategy, getAggregationStrategyMethodName()); 132 if (getAggregationStrategyMethodAllowNull() != null) { 133 adapter.setAllowNullNewExchange(getAggregationStrategyMethodAllowNull()); 134 adapter.setAllowNullOldExchange(getAggregationStrategyMethodAllowNull()); 135 } 136 strategy = adapter; 137 } else { 138 throw new IllegalArgumentException("Cannot find AggregationStrategy in Registry with name: " + aggregationStrategyRef); 139 } 140 } 141 142 if (strategy != null && strategy instanceof CamelContextAware) { 143 ((CamelContextAware) strategy).setCamelContext(routeContext.getCamelContext()); 144 } 145 146 return strategy; 147 } 148 149 public String getResourceUri() { 150 return resourceUri; 151 } 152 153 /** 154 * The endpoint uri for the external service to enrich from. You must use either uri or ref. 155 */ 156 public void setResourceUri(String resourceUri) { 157 this.resourceUri = resourceUri; 158 } 159 160 public String getResourceRef() { 161 return resourceRef; 162 } 163 164 /** 165 * Refers to the endpoint for the external service to enrich from. You must use either uri or ref. 166 * 167 * @deprecated use uri with ref:uri instead 168 */ 169 @Deprecated 170 public void setResourceRef(String resourceRef) { 171 this.resourceRef = resourceRef; 172 } 173 174 public String getAggregationStrategyRef() { 175 return aggregationStrategyRef; 176 } 177 178 /** 179 * Refers to an AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. 180 * By default Camel will use the reply from the external service as outgoing message. 181 */ 182 public void setAggregationStrategyRef(String aggregationStrategyRef) { 183 this.aggregationStrategyRef = aggregationStrategyRef; 184 } 185 186 public String getAggregationStrategyMethodName() { 187 return aggregationStrategyMethodName; 188 } 189 190 /** 191 * This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy. 192 */ 193 public void setAggregationStrategyMethodName(String aggregationStrategyMethodName) { 194 this.aggregationStrategyMethodName = aggregationStrategyMethodName; 195 } 196 197 public Boolean getAggregationStrategyMethodAllowNull() { 198 return aggregationStrategyMethodAllowNull; 199 } 200 201 /** 202 * If this option is false then the aggregate method is not used if there was no data to enrich. 203 * If this option is true then null values is used as the oldExchange (when no data to enrich), 204 * when using POJOs as the AggregationStrategy. 205 */ 206 public void setAggregationStrategyMethodAllowNull(Boolean aggregationStrategyMethodAllowNull) { 207 this.aggregationStrategyMethodAllowNull = aggregationStrategyMethodAllowNull; 208 } 209 210 public AggregationStrategy getAggregationStrategy() { 211 return aggregationStrategy; 212 } 213 214 /** 215 * Sets the AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. 216 * By default Camel will use the reply from the external service as outgoing message. 217 */ 218 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) { 219 this.aggregationStrategy = aggregationStrategy; 220 } 221 222 public Boolean getAggregateOnException() { 223 return aggregateOnException; 224 } 225 226 /** 227 * If this option is false then the aggregate method is not used if there was an exception thrown while trying 228 * to retrieve the data to enrich from the resource. Setting this option to true allows end users to control what 229 * to do if there was an exception in the aggregate method. For example to suppress the exception 230 * or set a custom message body etc. 231 */ 232 public void setAggregateOnException(Boolean aggregateOnException) { 233 this.aggregateOnException = aggregateOnException; 234 } 235}