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 */
017 package org.apache.camel.impl;
018
019 import java.util.ArrayList;
020 import java.util.List;
021 import java.util.Map;
022 import java.util.concurrent.ConcurrentHashMap;
023
024 import org.apache.camel.CamelContext;
025 import org.apache.camel.Endpoint;
026 import org.apache.camel.Exchange;
027 import org.apache.camel.ExchangePattern;
028 import org.apache.camel.Message;
029 import org.apache.camel.spi.Synchronization;
030 import org.apache.camel.spi.UnitOfWork;
031 import org.apache.camel.util.ExchangeHelper;
032 import org.apache.camel.util.ObjectHelper;
033 import org.apache.camel.util.UuidGenerator;
034
035 /**
036 * A default implementation of {@link Exchange}
037 *
038 * @version $Revision: 893110 $
039 */
040 public final class DefaultExchange implements Exchange {
041
042 protected final CamelContext context;
043 private Map<String, Object> properties;
044 private Message in;
045 private Message out;
046 private Exception exception;
047 private String exchangeId;
048 private UnitOfWork unitOfWork;
049 private ExchangePattern pattern;
050 private Endpoint fromEndpoint;
051 private List<Synchronization> onCompletions;
052
053 public DefaultExchange(CamelContext context) {
054 this(context, ExchangePattern.InOnly);
055 }
056
057 public DefaultExchange(CamelContext context, ExchangePattern pattern) {
058 this.context = context;
059 this.pattern = pattern;
060 }
061
062 public DefaultExchange(Exchange parent) {
063 this(parent.getContext(), parent.getPattern());
064 this.fromEndpoint = parent.getFromEndpoint();
065 this.unitOfWork = parent.getUnitOfWork();
066 }
067
068 public DefaultExchange(Endpoint fromEndpoint) {
069 this(fromEndpoint, ExchangePattern.InOnly);
070 }
071
072 public DefaultExchange(Endpoint fromEndpoint, ExchangePattern pattern) {
073 this(fromEndpoint.getCamelContext(), pattern);
074 this.fromEndpoint = fromEndpoint;
075 }
076
077 @Override
078 public String toString() {
079 return "Exchange[" + in + "]";
080 }
081
082 public Exchange copy() {
083 DefaultExchange exchange = new DefaultExchange(this);
084
085 exchange.setProperties(safeCopy(getProperties()));
086 safeCopy(exchange.getIn(), getIn());
087 if (hasOut()) {
088 safeCopy(exchange.getOut(), getOut());
089 }
090 exchange.setException(getException());
091 return exchange;
092 }
093
094 private static void safeCopy(Message message, Message that) {
095 if (message != null) {
096 message.copyFrom(that);
097 }
098 }
099
100 private static Map<String, Object> safeCopy(Map<String, Object> properties) {
101 if (properties == null) {
102 return null;
103 }
104 return new ConcurrentHashMap<String, Object>(properties);
105 }
106
107 public CamelContext getContext() {
108 return context;
109 }
110
111 public Object getProperty(String name) {
112 if (properties != null) {
113 return properties.get(name);
114 }
115 return null;
116 }
117
118 public Object getProperty(String name, Object defaultValue) {
119 Object answer = null;
120 if (properties != null) {
121 answer = properties.get(name);
122 }
123 return answer != null ? answer : defaultValue;
124 }
125
126 public <T> T getProperty(String name, Class<T> type) {
127 Object value = getProperty(name);
128
129 // eager same instance type test to avoid the overhead of invoking the type converter
130 // if already same type
131 if (type.isInstance(value)) {
132 return type.cast(value);
133 }
134
135 return ExchangeHelper.convertToType(this, type, value);
136 }
137
138 public <T> T getProperty(String name, Object defaultValue, Class<T> type) {
139 Object value = getProperty(name, defaultValue);
140
141 // eager same instance type test to avoid the overhead of invoking the type converter
142 // if already same type
143 if (type.isInstance(value)) {
144 return type.cast(value);
145 }
146
147 return ExchangeHelper.convertToType(this, type, value);
148 }
149
150 public void setProperty(String name, Object value) {
151 if (value != null) {
152 // avoid the NullPointException
153 getProperties().put(name, value);
154 } else {
155 // if the value is null, we just remove the key from the map
156 if (name != null) {
157 getProperties().remove(name);
158 }
159 }
160 }
161
162 public Object removeProperty(String name) {
163 return getProperties().remove(name);
164 }
165
166 public Map<String, Object> getProperties() {
167 if (properties == null) {
168 properties = new ConcurrentHashMap<String, Object>();
169 }
170 return properties;
171 }
172
173 public boolean hasProperties() {
174 return properties != null && !properties.isEmpty();
175 }
176
177 public void setProperties(Map<String, Object> properties) {
178 this.properties = properties;
179 }
180
181 public Message getIn() {
182 if (in == null) {
183 in = new DefaultMessage();
184 configureMessage(in);
185 }
186 return in;
187 }
188
189 public <T> T getIn(Class<T> type) {
190 Message in = getIn();
191
192 // eager same instance type test to avoid the overhead of invoking the type converter
193 // if already same type
194 if (type.isInstance(in)) {
195 return type.cast(in);
196 }
197
198 // fallback to use type converter
199 return context.getTypeConverter().convertTo(type, in);
200 }
201
202 public void setIn(Message in) {
203 this.in = in;
204 configureMessage(in);
205 }
206
207 public Message getOut() {
208 // lazy create
209 if (out == null) {
210 out = (in != null && in instanceof MessageSupport)
211 ? ((MessageSupport)in).newInstance() : new DefaultMessage();
212 configureMessage(out);
213 }
214 return out;
215 }
216
217 public <T> T getOut(Class<T> type) {
218 if (!hasOut()) {
219 return null;
220 }
221
222 Message out = getOut();
223
224 // eager same instance type test to avoid the overhead of invoking the type converter
225 // if already same type
226 if (type.isInstance(out)) {
227 return type.cast(out);
228 }
229
230 // fallback to use type converter
231 return context.getTypeConverter().convertTo(type, out);
232 }
233
234 public boolean hasOut() {
235 return out != null;
236 }
237
238 public void setOut(Message out) {
239 this.out = out;
240 configureMessage(out);
241 }
242
243 public Exception getException() {
244 return exception;
245 }
246
247 public <T> T getException(Class<T> type) {
248 return ObjectHelper.getException(type, exception);
249 }
250
251 public void setException(Exception exception) {
252 this.exception = exception;
253 }
254
255 public ExchangePattern getPattern() {
256 return pattern;
257 }
258
259 public void setPattern(ExchangePattern pattern) {
260 this.pattern = pattern;
261 }
262
263 public Endpoint getFromEndpoint() {
264 return fromEndpoint;
265 }
266
267 public void setFromEndpoint(Endpoint fromEndpoint) {
268 this.fromEndpoint = fromEndpoint;
269 }
270
271 public String getExchangeId() {
272 if (exchangeId == null) {
273 exchangeId = createExchangeId();
274 }
275 return exchangeId;
276 }
277
278 public void setExchangeId(String id) {
279 this.exchangeId = id;
280 }
281
282 public boolean isFailed() {
283 return (hasOut() && getOut().isFault()) || getException() != null;
284 }
285
286 public boolean isTransacted() {
287 return Boolean.TRUE.equals(getProperty(Exchange.TRANSACTED));
288 }
289
290 public boolean isRollbackOnly() {
291 return Boolean.TRUE.equals(getProperty(Exchange.ROLLBACK_ONLY)) || Boolean.TRUE.equals(getProperty(Exchange.ROLLBACK_ONLY_LAST));
292 }
293
294 public UnitOfWork getUnitOfWork() {
295 return unitOfWork;
296 }
297
298 public void setUnitOfWork(UnitOfWork unitOfWork) {
299 this.unitOfWork = unitOfWork;
300 if (this.onCompletions != null) {
301 // now an unit of work has been assigned so add the on completions
302 // we might have registered already
303 for (Synchronization onCompletion : this.onCompletions) {
304 this.unitOfWork.addSynchronization(onCompletion);
305 }
306 // cleanup the temporary on completion list as they now have been registered
307 // on the unit of work
308 this.onCompletions.clear();
309 this.onCompletions = null;
310 }
311 }
312
313 public void addOnCompletion(Synchronization onCompletion) {
314 if (this.unitOfWork == null) {
315 // unit of work not yet registered so we store the on completion temporary
316 // until the unit of work is assigned to this exchange by the UnitOfWorkProcessor
317 if (this.onCompletions == null) {
318 this.onCompletions = new ArrayList<Synchronization>();
319 }
320 this.onCompletions.add(onCompletion);
321 } else {
322 this.getUnitOfWork().addSynchronization(onCompletion);
323 }
324 }
325
326 /**
327 * Configures the message after it has been set on the exchange
328 */
329 protected void configureMessage(Message message) {
330 if (message instanceof MessageSupport) {
331 MessageSupport messageSupport = (MessageSupport)message;
332 messageSupport.setExchange(this);
333 }
334 }
335
336 protected String createExchangeId() {
337 String answer = null;
338 if (in != null) {
339 answer = in.createExchangeId();
340 }
341 if (answer == null) {
342 answer = UuidGenerator.get().generateUuid();
343 }
344 return answer;
345 }
346 }