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 }