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.spi;
018
019import java.util.function.Predicate;
020
021import org.apache.camel.AsyncCallback;
022import org.apache.camel.Exchange;
023import org.apache.camel.Message;
024import org.apache.camel.Processor;
025import org.apache.camel.Route;
026import org.apache.camel.Service;
027
028/**
029 * An object representing the unit of work processing an {@link Exchange}
030 * which allows the use of {@link Synchronization} hooks. This object might map one-to-one with
031 * a transaction in JPA or Spring; or might not.
032 */
033public interface UnitOfWork extends Service {
034
035    String MDC_BREADCRUMB_ID = "camel.breadcrumbId";
036    String MDC_EXCHANGE_ID = "camel.exchangeId";
037    String MDC_MESSAGE_ID = "camel.messageId";
038    String MDC_CORRELATION_ID = "camel.correlationId";
039    String MDC_ROUTE_ID = "camel.routeId";
040    String MDC_STEP_ID = "camel.stepId";
041    String MDC_CAMEL_CONTEXT_ID = "camel.contextId";
042    String MDC_TRANSACTION_KEY = "camel.transactionKey";
043
044    /**
045     * Adds a synchronization hook
046     *
047     * @param synchronization the hook
048     */
049    void addSynchronization(Synchronization synchronization);
050
051    /**
052     * Removes a synchronization hook
053     *
054     * @param synchronization the hook
055     */
056    void removeSynchronization(Synchronization synchronization);
057
058    /**
059     * Checks if the passed synchronization hook is already part of this unit of work.
060     *
061     * @param synchronization the hook
062     * @return <tt>true</tt>, if the passed synchronization is part of this unit of work, else <tt>false</tt>
063     */
064    boolean containsSynchronization(Synchronization synchronization);
065
066    /**
067     * Handover all the registered synchronizations to the target {@link org.apache.camel.Exchange}.
068     * <p/>
069     * This is used when a route turns into asynchronous and the {@link org.apache.camel.Exchange} that
070     * is continued and routed in the async thread should do the on completion callbacks instead of the
071     * original synchronous thread.
072     *
073     * @param target the target exchange
074     */
075    void handoverSynchronization(Exchange target);
076
077    /**
078     * Handover all the registered synchronizations to the target {@link org.apache.camel.Exchange}.
079     * <p/>
080     * This is used when a route turns into asynchronous and the {@link org.apache.camel.Exchange} that
081     * is continued and routed in the async thread should do the on completion callbacks instead of the
082     * original synchronous thread.
083     *
084     * @param target the target exchange
085     * @param filter optional filter to only handover if filter returns <tt>true</tt>
086     */
087    void handoverSynchronization(Exchange target, Predicate<Synchronization> filter);
088
089    /**
090     * Invoked when this unit of work has been completed, whether it has failed or completed
091     *
092     * @param exchange the current exchange
093     */
094    void done(Exchange exchange);
095
096    /**
097     * Invoked when this unit of work is about to be routed by the given route.
098     *
099     * @param exchange the current exchange
100     * @param route    the route
101     */
102    void beforeRoute(Exchange exchange, Route route);
103
104    /**
105     * Invoked when this unit of work is done being routed by the given route.
106     *
107     * @param exchange the current exchange
108     * @param route    the route
109     */
110    void afterRoute(Exchange exchange, Route route);
111
112    /**
113     * Returns the unique ID of this unit of work, lazily creating one if it does not yet have one
114     *
115     * @return the unique ID
116     */
117    String getId();
118
119    /**
120     * Gets the original IN {@link Message} this Unit of Work was started with.
121     * <p/>
122     * The original message is only returned if the option {@link org.apache.camel.RuntimeConfiguration#isAllowUseOriginalMessage()}
123     * is enabled. If its disabled an <tt>IllegalStateException</tt> is thrown.
124     *
125     * @return the original IN {@link Message}, or <tt>null</tt> if using original message is disabled.
126     */
127    Message getOriginalInMessage();
128
129    /**
130     * Are we transacted?
131     *
132     * @return <tt>true</tt> if transacted, <tt>false</tt> otherwise
133     */
134    boolean isTransacted();
135
136    /**
137     * Are we already transacted by the given transaction key?
138     *
139     * @param key the transaction key
140     * @return <tt>true</tt> if already, <tt>false</tt> otherwise
141     */
142    boolean isTransactedBy(Object key);
143
144    /**
145     * Mark this UnitOfWork as being transacted by the given transaction key.
146     * <p/>
147     * When the transaction is completed then invoke the {@link #endTransactedBy(Object)} method using the same key.
148     *
149     * @param key the transaction key
150     */
151    void beginTransactedBy(Object key);
152
153    /**
154     * Mark this UnitOfWork as not transacted anymore by the given transaction definition.
155     *
156     * @param key the transaction key
157     */
158    void endTransactedBy(Object key);
159
160    /**
161     * Gets the {@link RouteContext} that this {@link UnitOfWork} currently is being routed through.
162     * <p/>
163     * Notice that an {@link Exchange} can be routed through multiple routes and thus the
164     * {@link org.apache.camel.spi.RouteContext} can change over time.
165     *
166     * @return the route context
167     * @see #pushRouteContext(RouteContext)
168     * @see #popRouteContext()
169     */
170    RouteContext getRouteContext();
171
172    /**
173     * Pushes the {@link RouteContext} that this {@link UnitOfWork} currently is being routed through.
174     * <p/>
175     * Notice that an {@link Exchange} can be routed through multiple routes and thus the
176     * {@link org.apache.camel.spi.RouteContext} can change over time.
177     *
178     * @param routeContext the route context
179     */
180    void pushRouteContext(RouteContext routeContext);
181
182    /**
183     * When finished being routed under the current {@link org.apache.camel.spi.RouteContext}
184     * it should be removed.
185     *
186     * @return the route context or <tt>null</tt> if none existed
187     */
188    RouteContext popRouteContext();
189
190    /**
191     * Strategy for optional work to be execute before processing
192     * <p/>
193     * For example the {@link org.apache.camel.impl.MDCUnitOfWork} leverages this
194     * to ensure MDC is handled correctly during routing exchanges using the
195     * asynchronous routing engine.
196     *
197     * @param processor the processor to be executed
198     * @param exchange  the current exchange
199     * @param callback  the callback
200     * @return the callback to be used (can return a wrapped callback)
201     */
202    AsyncCallback beforeProcess(Processor processor, Exchange exchange, AsyncCallback callback);
203
204    /**
205     * Strategy for optional work to be executed after the processing
206     *
207     * @param processor the processor executed
208     * @param exchange  the current exchange
209     * @param callback  the callback used
210     * @param doneSync  whether the process was done synchronously or asynchronously
211     */
212    void afterProcess(Processor processor, Exchange exchange, AsyncCallback callback, boolean doneSync);
213
214    /**
215     * Create a child unit of work, which is associated to this unit of work as its parent.
216     * <p/>
217     * This is often used when EIPs need to support {@link SubUnitOfWork}s. For example a splitter,
218     * where the sub messages of the splitter all participate in the same sub unit of work.
219     * That sub unit of work then decides whether the Splitter (in general) is failed or a
220     * processed successfully.
221     *
222     * @param childExchange the child exchange
223     * @return the created child unit of work
224     * @see SubUnitOfWork
225     * @see SubUnitOfWorkCallback
226     */
227    UnitOfWork createChildUnitOfWork(Exchange childExchange);
228
229    /**
230     * Sets the parent unit of work.
231     *
232     * @param parentUnitOfWork the parent
233     */
234    void setParentUnitOfWork(UnitOfWork parentUnitOfWork);
235
236    /**
237     * Gets the {@link SubUnitOfWorkCallback} if this unit of work participates in a sub unit of work.
238     *
239     * @return the callback, or <tt>null</tt> if this unit of work is not part of a sub unit of work.
240     * @see #beginSubUnitOfWork(org.apache.camel.Exchange)
241     */
242    SubUnitOfWorkCallback getSubUnitOfWorkCallback();
243
244    /**
245     * Begins a {@link SubUnitOfWork}, where sub (child) unit of works participate in a parent unit of work.
246     * The {@link SubUnitOfWork} will callback to the parent unit of work using {@link SubUnitOfWorkCallback}s.
247     *
248     * @param exchange the exchange
249     */
250    void beginSubUnitOfWork(Exchange exchange);
251
252    /**
253     * Ends a {@link SubUnitOfWork}.
254     * <p/>
255     * The {@link #beginSubUnitOfWork(org.apache.camel.Exchange)} must have been invoked
256     * prior to this operation.
257     *
258     * @param exchange the exchange
259     */
260    void endSubUnitOfWork(Exchange exchange);
261
262}