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