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.Map;
020 import java.util.concurrent.ConcurrentHashMap;
021
022 import org.apache.camel.CamelContext;
023 import org.apache.camel.Endpoint;
024 import org.apache.camel.Exchange;
025 import org.apache.camel.ExchangePattern;
026 import org.apache.camel.ExchangeProperty;
027 import org.apache.camel.Message;
028 import org.apache.camel.RuntimeCamelException;
029 import org.apache.camel.spi.UnitOfWork;
030 import org.apache.camel.util.ExchangeHelper;
031 import org.apache.camel.util.UuidGenerator;
032 import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
033
034 /**
035 * A default implementation of {@link Exchange}
036 *
037 * @version $Revision: 752465 $
038 */
039 public class DefaultExchange implements Exchange {
040
041 private static final UuidGenerator DEFAULT_ID_GENERATOR = new UuidGenerator();
042 protected final CamelContext context;
043 private Map<String, Object> properties;
044 private Message in;
045 private Message out;
046 private Message fault;
047 private Exception exception;
048 private String exchangeId;
049 private UnitOfWork unitOfWork;
050 private ExchangePattern pattern;
051 private Endpoint fromEndpoint;
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.unitOfWork = parent.getUnitOfWork();
065 this.fromEndpoint = parent.getFromEndpoint();
066 }
067
068 public DefaultExchange(Endpoint fromEndpoint) {
069 this(fromEndpoint, ExchangePattern.InOnly);
070 }
071
072 public DefaultExchange(Endpoint fromEndpoint, ExchangePattern pattern) {
073 this.context = fromEndpoint.getCamelContext();
074 this.fromEndpoint = fromEndpoint;
075 this.pattern = pattern;
076 }
077
078 @Override
079 public String toString() {
080 return "Exchange[" + in + "]";
081 }
082
083 public Exchange copy() {
084 Exchange exchange = newInstance();
085 exchange.copyFrom(this);
086 return exchange;
087 }
088
089 public void copyFrom(Exchange exchange) {
090 if (exchange == this) {
091 return;
092 }
093 setProperties(safeCopy(exchange.getProperties()));
094
095 // this can cause strangeness if we copy, say, a FileMessage onto an FtpExchange with overloaded getExchange() methods etc.
096 safeCopy(getIn(), exchange, exchange.getIn());
097 Message copyOut = exchange.getOut(false);
098 if (copyOut != null) {
099 safeCopy(getOut(true), exchange, copyOut);
100 }
101 Message copyFault = exchange.getFault(false);
102 if (copyFault != null) {
103 safeCopy(getFault(true), exchange, copyFault);
104 }
105 setException(exchange.getException());
106
107 unitOfWork = exchange.getUnitOfWork();
108 pattern = exchange.getPattern();
109 setFromEndpoint(exchange.getFromEndpoint());
110 }
111
112 private static void safeCopy(Message message, Exchange exchange, Message that) {
113 if (message != null) {
114 message.copyFrom(that);
115 }
116 }
117
118 private static Map<String, Object> safeCopy(Map<String, Object> properties) {
119 if (properties == null) {
120 return null;
121 }
122 return new ConcurrentHashMap<String, Object>(properties);
123 }
124
125 public Exchange newInstance() {
126 return new DefaultExchange(this);
127 }
128
129 public CamelContext getContext() {
130 return context;
131 }
132
133 public Object getProperty(String name) {
134 if (properties != null) {
135 return properties.get(name);
136 }
137 return null;
138 }
139
140 public <T> T getProperty(String name, Class<T> type) {
141 Object value = getProperty(name);
142
143 // if the property is also a well known property in ExchangeProperty then validate that the
144 // value is of the same type
145 ExchangeProperty<?> property = ExchangeProperty.getByName(name);
146 if (property != null) {
147 validateExchangePropertyIsExpectedType(property, type, value);
148 }
149
150 return ExchangeHelper.convertToType(this, type, value);
151 }
152
153 @SuppressWarnings("unchecked")
154 public void setProperty(String name, Object value) {
155 ExchangeProperty<?> property = ExchangeProperty.getByName(name);
156
157 // if the property is also a well known property in ExchangeProperty then validate that the
158 // value is of the same type
159 if (property != null) {
160 Class type = value.getClass();
161 validateExchangePropertyIsExpectedType(property, type, value);
162 }
163 if (value != null) {
164 // avoid the NullPointException
165 getProperties().put(name, value);
166 } else {
167 // if the value is null , we just remove the key from the map
168 if (name != null) {
169 getProperties().remove(name);
170 }
171 }
172 }
173
174 private <T> void validateExchangePropertyIsExpectedType(ExchangeProperty<?> property, Class<T> type, Object value) {
175 if (value != null && property != null && !property.type().isAssignableFrom(type)) {
176 throw new RuntimeCamelException("Type cast exception while getting an "
177 + "Exchange Property value '" + value.toString() + "' on Exchange " + this
178 + " for a well known Exchange Property with these traits: " + property);
179 }
180 }
181
182 public Object removeProperty(String name) {
183 return getProperties().remove(name);
184 }
185
186 public Map<String, Object> getProperties() {
187 if (properties == null) {
188 properties = new ConcurrentHashMap<String, Object>();
189 }
190 return properties;
191 }
192
193 public void setProperties(Map<String, Object> properties) {
194 this.properties = properties;
195 }
196
197 public Message getIn() {
198 if (in == null) {
199 in = createInMessage();
200 configureMessage(in);
201 }
202 return in;
203 }
204
205 public void setIn(Message in) {
206 this.in = in;
207 configureMessage(in);
208 }
209
210 public Message getOut() {
211 return getOut(true);
212 }
213
214 public Message getOut(boolean lazyCreate) {
215 if (out == null && lazyCreate) {
216 out = createOutMessage();
217 configureMessage(out);
218 }
219 return out;
220 }
221
222 public void setOut(Message out) {
223 this.out = out;
224 configureMessage(out);
225 }
226
227 public Exception getException() {
228 return exception;
229 }
230
231 public void setException(Exception exception) {
232 this.exception = exception;
233 }
234
235 public ExchangePattern getPattern() {
236 return pattern;
237 }
238
239 public void setPattern(ExchangePattern pattern) {
240 this.pattern = pattern;
241 }
242
243 public Endpoint getFromEndpoint() {
244 return fromEndpoint;
245 }
246
247 public void setFromEndpoint(Endpoint fromEndpoint) {
248 this.fromEndpoint = fromEndpoint;
249 }
250
251 public void throwException() throws Exception {
252 if (exception == null) {
253 return;
254 }
255 if (exception instanceof RuntimeException) {
256 throw (RuntimeException)exception;
257 }
258 if (exception instanceof Exception) {
259 throw (Exception)exception;
260 }
261 throw wrapRuntimeCamelException(exception);
262 }
263
264 public Message getFault() {
265 return getFault(true);
266 }
267
268 public Message getFault(boolean lazyCreate) {
269 if (fault == null && lazyCreate) {
270 fault = createFaultMessage();
271 configureMessage(fault);
272 }
273 return fault;
274 }
275
276 public void setFault(Message fault) {
277 this.fault = fault;
278 configureMessage(fault);
279 }
280
281 public String getExchangeId() {
282 if (exchangeId == null) {
283 exchangeId = createExchangeId();
284 }
285 return exchangeId;
286 }
287
288 public void setExchangeId(String id) {
289 this.exchangeId = id;
290 }
291
292 public boolean isFailed() {
293 Message faultMessage = getFault(false);
294 if (faultMessage != null) {
295 Object faultBody = faultMessage.getBody();
296 if (faultBody != null) {
297 return true;
298 }
299 }
300 return getException() != null;
301 }
302
303 public boolean isTransacted() {
304 Boolean transacted = getProperty(TRANSACTED, Boolean.class);
305 return transacted != null && transacted;
306 }
307
308 public UnitOfWork getUnitOfWork() {
309 return unitOfWork;
310 }
311
312 public void setUnitOfWork(UnitOfWork unitOfWork) {
313 this.unitOfWork = unitOfWork;
314 }
315
316 /**
317 * Factory method used to lazily create the IN message
318 */
319 protected Message createInMessage() {
320 return new DefaultMessage();
321 }
322
323 /**
324 * Factory method to lazily create the OUT message
325 */
326 protected Message createOutMessage() {
327 return new DefaultMessage();
328 }
329
330 /**
331 * Factory method to lazily create the FAULT message
332 */
333 protected Message createFaultMessage() {
334 return new DefaultMessage();
335 }
336
337 /**
338 * Configures the message after it has been set on the exchange
339 */
340 protected void configureMessage(Message message) {
341 if (message instanceof MessageSupport) {
342 MessageSupport messageSupport = (MessageSupport)message;
343 messageSupport.setExchange(this);
344 }
345 }
346
347 protected String createExchangeId() {
348 String answer = in.createExchangeId();
349 if (answer == null) {
350 answer = DefaultExchange.DEFAULT_ID_GENERATOR.generateId();
351 }
352 return answer;
353 }
354
355 }