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    }