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