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;
018
019import java.util.concurrent.Future;
020import java.util.function.Supplier;
021
022import org.apache.camel.util.ObjectHelper;
023
024/**
025 * Template for working with Camel and sending {@link Message} instances in an
026 * {@link Exchange} to an {@link Endpoint} using a <i>fluent</i> build style.
027 * <br/>
028 * <p/><b>Important:</b> Read the javadoc of each method carefully to ensure the behavior of the method is understood.
029 * Some methods is for <tt>InOnly</tt>, others for <tt>InOut</tt> MEP. And some methods throws
030 * {@link org.apache.camel.CamelExecutionException} while others stores any thrown exception on the returned
031 * {@link Exchange}.
032 * <br/>
033 * <p/>The {@link FluentProducerTemplate} is <b>thread safe</b>.
034 * <br/>
035 * <p/>All the methods which sends a message may throw {@link FailedToCreateProducerException} in
036 * case the {@link Producer} could not be created. Or a {@link NoSuchEndpointException} if the endpoint could
037 * not be resolved. There may be other related exceptions being thrown which occurs <i>before</i> the {@link Producer}
038 * has started sending the message.
039 * <br/>
040 * <p/>All the send or request methods will return the content according to this strategy:
041 * <ul>
042 *   <li>throws {@link org.apache.camel.CamelExecutionException} if processing failed <i>during</i> routing
043 *       with the caused exception wrapped</li>
044 *   <li>The <tt>fault.body</tt> if there is a fault message set and its not <tt>null</tt></li>
045 *   <li>Either <tt>IN</tt> or <tt>OUT</tt> body according to the message exchange pattern. If the pattern is
046 *   Out capable then the <tt>OUT</tt> body is returned, otherwise <tt>IN</tt>.
047 * </ul>
048 * <br/>
049 * <p/>Before using the template it must be started.
050 * And when you are done using the template, make sure to {@link #stop()} the template.
051 * <br/>
052 * <p/><b>Important note on usage:</b> See this
053 * <a href="http://camel.apache.org/why-does-camel-use-too-many-threads-with-producertemplate.html">FAQ entry</a>
054 * before using.
055 *
056 * @see ProducerTemplate
057 * @see ConsumerTemplate
058 */
059public interface FluentProducerTemplate extends Service {
060
061    /**
062     * Get the {@link CamelContext}
063     *
064     * @return camelContext the Camel context
065     */
066    CamelContext getCamelContext();
067
068    // Configuration methods
069    // -----------------------------------------------------------------------
070
071    /**
072     * Gets the maximum cache size used in the backing cache pools.
073     *
074     * @return the maximum cache size
075     */
076    int getMaximumCacheSize();
077
078    /**
079     * Sets a custom maximum cache size to use in the backing cache pools.
080     *
081     * @param maximumCacheSize the custom maximum cache size
082     */
083    void setMaximumCacheSize(int maximumCacheSize);
084
085    /**
086     * Gets an approximated size of the current cached resources in the backing cache pools.
087     *
088     * @return the size of current cached resources
089     */
090    int getCurrentCacheSize();
091
092    /**
093     * Get the default endpoint to use if none is specified
094     *
095     * @return the default endpoint instance
096     */
097    Endpoint getDefaultEndpoint();
098
099    /**
100     * Sets the default endpoint to use if none is specified
101     *
102     * @param defaultEndpoint the default endpoint instance
103     */
104    void setDefaultEndpoint(Endpoint defaultEndpoint);
105
106    /**
107     * Sets the default endpoint uri to use if none is specified
108     *
109     *  @param endpointUri the default endpoint uri
110     */
111    void setDefaultEndpointUri(String endpointUri);
112
113    /**
114     * Sets whether the {@link org.apache.camel.spi.EventNotifier} should be
115     * used by this {@link ProducerTemplate} to send events about the {@link Exchange}
116     * being sent.
117     * <p/>
118     * By default this is enabled.
119     *
120     * @param enabled <tt>true</tt> to enable, <tt>false</tt> to disable.
121     */
122    void setEventNotifierEnabled(boolean enabled);
123
124    /**
125     * Whether the {@link org.apache.camel.spi.EventNotifier} should be
126     * used by this {@link ProducerTemplate} to send events about the {@link Exchange}
127     * being sent.
128     *
129     * @return <tt>true</tt> if enabled, <tt>false</tt> otherwise
130     */
131    boolean isEventNotifierEnabled();
132
133    /**
134     * Cleanup the cache (purging stale entries)
135     */
136    void cleanUp();
137
138    // Fluent methods
139    // -----------------------------------------------------------------------
140
141    /**
142     * Remove the body and headers.
143     */
144    FluentProducerTemplate clearAll();
145
146    /**
147     * Set the header
148     *
149     * @param key the key of the header
150     * @param value the value of the header
151     */
152    FluentProducerTemplate withHeader(String key, Object value);
153
154    /**
155     * Remove the headers.
156     */
157    FluentProducerTemplate clearHeaders();
158
159    /**
160     * Set the message body
161     *
162     * @param body the body
163     */
164    FluentProducerTemplate withBody(Object body);
165
166    /**
167     * Set the message body after converting it to the given type
168     *
169     * @param body the body
170     * @param type the type which the body should be converted to
171     */
172    FluentProducerTemplate withBodyAs(Object body, Class<?> type);
173
174    /**
175     * Remove the body.
176     */
177    FluentProducerTemplate clearBody();
178
179    /**
180     * To customize the producer template for advanced usage like to set the
181     * executor service to use.
182     *
183     * <pre>
184     * {@code
185     * FluentProducerTemplate.on(context)
186     *     .withTemplateCustomizer(
187     *         template -> {
188     *             template.setExecutorService(myExecutor);
189     *             template.setMaximumCacheSize(10);
190     *         }
191     *      )
192     *     .withBody("the body")
193     *     .to("direct:start")
194     *     .request()}
195     * </pre>
196     *
197     * Note that it is invoked only once.
198     *
199     * @param templateCustomizer the customizer
200     */
201    FluentProducerTemplate withTemplateCustomizer(java.util.function.Consumer<ProducerTemplate> templateCustomizer);
202
203    /**
204     * Set the exchange to use for send.
205     *
206     * When using withExchange then you must use the send method (request is not supported).
207     *
208     * @param exchange the exchange
209     */
210    FluentProducerTemplate withExchange(Exchange exchange);
211
212    /**
213     * Set the exchangeSupplier which will be invoke to get the exchange to be
214     * used for send.
215     *
216     * When using withExchange then you must use the send method (request is not supported).
217     *
218     * @param exchangeSupplier the supplier
219     */
220    FluentProducerTemplate withExchange(Supplier<Exchange> exchangeSupplier);
221
222    /**
223     * Set the processor to use for send/request.
224     *
225     * <pre>
226     * {@code
227     * FluentProducerTemplate.on(context)
228     *     .withProcessor(
229     *         exchange -> {
230     *             exchange.getIn().setHeader("Key1", "Val1");
231     *             exchange.getIn().setHeader("Key2", "Val2");
232     *             exchange.getIn().setBody("the body");
233     *         }
234     *      )
235     *     .to("direct:start")
236     *     .request()}
237     * </pre>
238     *
239     * @param processor
240     */
241    FluentProducerTemplate withProcessor(Processor processor);
242
243    /**
244     * Set the processorSupplier which will be invoke to get the processor to be
245     * used for send/request.
246     *
247     * @param processorSupplier the supplier
248     */
249    FluentProducerTemplate withProcessor(Supplier<Processor> processorSupplier);
250
251    /**
252     * Endpoint to send to
253     *
254     * @param endpointUri the endpoint URI to send to
255     */
256    default FluentProducerTemplate to(String endpointUri) {
257        final CamelContext context = ObjectHelper.notNull(getCamelContext(), "camel context");
258
259        return to(context.getEndpoint(endpointUri));
260    }
261
262    /**
263     * Endpoint to send to
264     *
265     * @param uri the String formatted endpoint uri to send to
266     * @param args arguments for the string formatting of the uri
267     */
268    default FluentProducerTemplate toF(String uri, Object... args) {
269        return to(String.format(uri, args));
270    }
271
272    /**
273     * Endpoint to send to
274     *
275     * @param endpoint the endpoint to send to
276     */
277    FluentProducerTemplate to(Endpoint endpoint);
278
279    /**
280     * Send to an endpoint (InOut) returning any result output body.
281     *
282     * @return the result
283     * @throws CamelExecutionException is thrown if error occurred
284     */
285    Object request() throws CamelExecutionException;
286
287    /**
288     * Send to an endpoint (InOut).
289     *
290     * @param type the expected response type
291     * @return the result
292     * @throws CamelExecutionException is thrown if error occurred
293     */
294    <T> T request(Class<T> type) throws CamelExecutionException;
295
296    /**
297     * Sends asynchronously to the given endpoint (InOut).
298     *
299     * @return a handle to be used to get the response in the future
300     */
301    Future<Object> asyncRequest();
302
303    /**
304     * Sends asynchronously to the given endpoint (InOut).
305     *
306     * @param type the expected response type
307     * @return a handle to be used to get the response in the future
308     */
309    <T> Future<T> asyncRequest(Class<T> type);
310
311    /**
312     * Send to an endpoint (InOnly)
313     *
314     * @throws CamelExecutionException is thrown if error occurred
315     */
316    Exchange send() throws CamelExecutionException;
317
318    /**
319     * Sends asynchronously to the given endpoint (InOnly).
320     *
321     * @return a handle to be used to get the response in the future
322     */
323    Future<Exchange> asyncSend();
324}