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.builder; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Optional; 022import java.util.concurrent.Future; 023import java.util.function.Consumer; 024import java.util.function.Supplier; 025 026import org.apache.camel.CamelContext; 027import org.apache.camel.CamelExecutionException; 028import org.apache.camel.Endpoint; 029import org.apache.camel.Exchange; 030import org.apache.camel.ExchangePattern; 031import org.apache.camel.FluentProducerTemplate; 032import org.apache.camel.Message; 033import org.apache.camel.Processor; 034import org.apache.camel.ProducerTemplate; 035import org.apache.camel.processor.ConvertBodyProcessor; 036import org.apache.camel.support.ServiceSupport; 037import org.apache.camel.util.ExchangeHelper; 038import org.apache.camel.util.ObjectHelper; 039import org.apache.camel.util.ServiceHelper; 040 041public class DefaultFluentProducerTemplate extends ServiceSupport implements FluentProducerTemplate { 042 private final CamelContext context; 043 private final ClassValue<ConvertBodyProcessor> resultProcessors; 044 private Map<String, Object> headers; 045 private Object body; 046 private Optional<Consumer<ProducerTemplate>> templateCustomizer; 047 private Optional<Supplier<Exchange>> exchangeSupplier; 048 private Optional<Supplier<Processor>> processorSupplier; 049 private Optional<Endpoint> endpoint; 050 private Optional<Endpoint> defaultEndpoint; 051 private int maximumCacheSize; 052 private boolean eventNotifierEnabled; 053 private volatile ProducerTemplate template; 054 055 public DefaultFluentProducerTemplate(CamelContext context) { 056 this.context = context; 057 this.endpoint = Optional.empty(); 058 this.defaultEndpoint = Optional.empty(); 059 this.eventNotifierEnabled = true; 060 this.templateCustomizer = Optional.empty(); 061 this.exchangeSupplier = Optional.empty(); 062 this.processorSupplier = Optional.empty(); 063 this.resultProcessors = new ClassValue<ConvertBodyProcessor>() { 064 @Override 065 protected ConvertBodyProcessor computeValue(Class<?> type) { 066 return new ConvertBodyProcessor(type); 067 } 068 }; 069 } 070 071 @Override 072 public CamelContext getCamelContext() { 073 return context; 074 } 075 076 @Override 077 public int getCurrentCacheSize() { 078 if (template == null) { 079 return 0; 080 } 081 return template.getCurrentCacheSize(); 082 } 083 084 @Override 085 public void cleanUp() { 086 if (template != null) { 087 template.cleanUp(); 088 } 089 } 090 091 @Override 092 public void setDefaultEndpointUri(String endpointUri) { 093 setDefaultEndpoint(getCamelContext().getEndpoint(endpointUri)); 094 } 095 096 @Override 097 public Endpoint getDefaultEndpoint() { 098 return defaultEndpoint.orElse(null); 099 } 100 101 @Override 102 public void setDefaultEndpoint(Endpoint defaultEndpoint) { 103 this.defaultEndpoint = Optional.of(defaultEndpoint); 104 } 105 106 @Override 107 public int getMaximumCacheSize() { 108 return maximumCacheSize; 109 } 110 111 @Override 112 public void setMaximumCacheSize(int maximumCacheSize) { 113 this.maximumCacheSize = maximumCacheSize; 114 } 115 116 @Override 117 public boolean isEventNotifierEnabled() { 118 return eventNotifierEnabled; 119 } 120 121 @Override 122 public void setEventNotifierEnabled(boolean eventNotifierEnabled) { 123 this.eventNotifierEnabled = eventNotifierEnabled; 124 } 125 126 @Override 127 public FluentProducerTemplate withHeader(String key, Object value) { 128 if (headers == null) { 129 headers = new HashMap<>(); 130 } 131 132 headers.put(key, value); 133 134 return this; 135 } 136 137 @Override 138 public FluentProducerTemplate clearHeaders() { 139 if (headers != null) { 140 headers.clear(); 141 } 142 143 return this; 144 } 145 146 @Override 147 public FluentProducerTemplate withBody(Object body) { 148 this.body = body; 149 150 return this; 151 } 152 153 @Override 154 public FluentProducerTemplate withBodyAs(Object body, Class<?> type) { 155 this.body = type != null 156 ? context.getTypeConverter().convertTo(type, body) 157 : body; 158 159 return this; 160 } 161 162 @Override 163 public FluentProducerTemplate clearBody() { 164 this.body = null; 165 166 return this; 167 } 168 169 @Override 170 public FluentProducerTemplate withTemplateCustomizer(final Consumer<ProducerTemplate> templateCustomizer) { 171 this.templateCustomizer = Optional.of(templateCustomizer); 172 return this; 173 } 174 175 @Override 176 public FluentProducerTemplate withExchange(final Exchange exchange) { 177 return withExchange(() -> exchange); 178 } 179 180 @Override 181 public FluentProducerTemplate withExchange(final Supplier<Exchange> exchangeSupplier) { 182 this.exchangeSupplier = Optional.of(exchangeSupplier); 183 return this; 184 } 185 186 @Override 187 public FluentProducerTemplate withProcessor(final Processor processor) { 188 return withProcessor(() -> processor); 189 } 190 191 @Override 192 public FluentProducerTemplate withProcessor(final Supplier<Processor> processorSupplier) { 193 this.processorSupplier = Optional.of(processorSupplier); 194 return this; 195 } 196 197 @Override 198 public FluentProducerTemplate to(String endpointUri) { 199 return to(context.getEndpoint(endpointUri)); 200 } 201 202 @Override 203 public FluentProducerTemplate to(Endpoint endpoint) { 204 this.endpoint = Optional.of(endpoint); 205 return this; 206 } 207 208 // ************************ 209 // REQUEST 210 // ************************ 211 212 @Override 213 public Object request() throws CamelExecutionException { 214 return request(Object.class); 215 } 216 217 @Override 218 @SuppressWarnings("unchecked") 219 public <T> T request(Class<T> type) throws CamelExecutionException { 220 // Determine the target endpoint 221 final Endpoint target = target(); 222 223 // Create the default processor if not provided. 224 final Supplier<Processor> processorSupplier = this.processorSupplier.orElse(() -> defaultProcessor()); 225 226 T result; 227 if (type == Exchange.class) { 228 result = (T)template().request(target, processorSupplier.get()); 229 } else if (type == Message.class) { 230 Exchange exchange = template().request(target, processorSupplier.get()); 231 result = exchange.hasOut() ? (T)exchange.getOut() : (T)exchange.getIn(); 232 } else { 233 Exchange exchange = template().send( 234 target, 235 ExchangePattern.InOut, 236 processorSupplier.get(), 237 resultProcessors.get(type) 238 ); 239 240 result = context.getTypeConverter().convertTo( 241 type, 242 ExchangeHelper.extractResultBody(exchange, exchange.getPattern()) 243 ); 244 } 245 246 return result; 247 } 248 249 @Override 250 public Future<Object> asyncRequest() { 251 return asyncRequest(Object.class); 252 } 253 254 @Override 255 public <T> Future<T> asyncRequest(Class<T> type) { 256 // Determine the target endpoint 257 final Endpoint target = target(); 258 259 Future<T> result; 260 if (ObjectHelper.isNotEmpty(headers)) { 261 // Make a copy of the headers and body so that async processing won't 262 // be invalidated by subsequent reuse of the template 263 final Map<String, Object> headersCopy = new HashMap<>(headers); 264 final Object bodyCopy = body; 265 266 result = template().asyncRequestBodyAndHeaders(target, bodyCopy, headersCopy, type); 267 } else { 268 // Make a copy of the and body so that async processing won't be 269 // invalidated by subsequent reuse of the template 270 final Object bodyCopy = body; 271 272 result = template().asyncRequestBody(target, bodyCopy, type); 273 } 274 275 return result; 276 } 277 278 // ************************ 279 // SEND 280 // ************************ 281 282 @Override 283 public Exchange send() throws CamelExecutionException { 284 // Determine the target endpoint 285 final Endpoint target = target(); 286 287 return exchangeSupplier.isPresent() 288 ? template().send(target, exchangeSupplier.get().get()) 289 : template().send(target, processorSupplier.orElse(() -> defaultProcessor()).get()); 290 } 291 292 @Override 293 public Future<Exchange> asyncSend() { 294 // Determine the target endpoint 295 final Endpoint target = target(); 296 297 return exchangeSupplier.isPresent() 298 ? template().asyncSend(target, exchangeSupplier.get().get()) 299 : template().asyncSend(target, processorSupplier.orElse(() -> defaultAsyncProcessor()).get()); 300 } 301 302 // ************************ 303 // HELPERS 304 // ************************ 305 306 /** 307 * Create the FluentProducerTemplate by setting the camel context 308 * 309 * @param context the camel context 310 */ 311 public static FluentProducerTemplate on(CamelContext context) { 312 return new DefaultFluentProducerTemplate(context); 313 } 314 315 private ProducerTemplate template() { 316 ObjectHelper.notNull(context, "CamelContext"); 317 318 if (template == null) { 319 template = maximumCacheSize > 0 ? context.createProducerTemplate(maximumCacheSize) : context.createProducerTemplate(); 320 defaultEndpoint.ifPresent(template::setDefaultEndpoint); 321 template.setEventNotifierEnabled(eventNotifierEnabled); 322 templateCustomizer.ifPresent(tc -> tc.accept(template)); 323 } 324 325 return template; 326 } 327 328 private Processor defaultProcessor() { 329 return exchange -> { 330 ObjectHelper.ifNotEmpty(headers, exchange.getIn().getHeaders()::putAll); 331 ObjectHelper.ifNotEmpty(body, exchange.getIn()::setBody); 332 }; 333 } 334 335 private Processor defaultAsyncProcessor() { 336 final Map<String, Object> headersCopy = ObjectHelper.isNotEmpty(this.headers) ? new HashMap<>(this.headers) : null; 337 final Object bodyCopy = this.body; 338 339 return exchange -> { 340 ObjectHelper.ifNotEmpty(headersCopy, exchange.getIn().getHeaders()::putAll); 341 ObjectHelper.ifNotEmpty(bodyCopy, exchange.getIn()::setBody); 342 }; 343 } 344 345 private Endpoint target() { 346 if (endpoint.isPresent()) { 347 return endpoint.get(); 348 } 349 if (defaultEndpoint.isPresent()) { 350 return defaultEndpoint.get(); 351 } 352 353 throw new IllegalArgumentException("No endpoint configured on FluentProducerTemplate. You can configure an endpoint with to(uri)"); 354 } 355 356 @Override 357 protected void doStart() throws Exception { 358 if (template == null) { 359 template = template(); 360 } 361 ServiceHelper.startService(template); 362 } 363 364 @Override 365 protected void doStop() throws Exception { 366 ServiceHelper.stopService(template); 367 } 368}