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 import java.util.concurrent.ConcurrentHashMap; 022 023 import org.apache.camel.CamelContext; 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.UuidGenerator; 031 032 /** 033 * A default implementation of {@link Exchange} 034 * 035 * @version $Revision: 46968 $ 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 { // if the value is null , we just remove the key from the map 163 if (name != null) { 164 getProperties().remove(name); 165 } 166 } 167 } 168 169 private <T> void validateExchangePropertyIsExpectedType(ExchangeProperty<?> property, Class<T> type, Object value) { 170 if (value != null && property != null && !property.type().isAssignableFrom(type)) { 171 throw new RuntimeCamelException("Type cast exception while getting an " 172 + "Exchange Property value '" + value.toString() 173 + "' on Exchange " + this 174 + " for a well known Exchange Property with these traits: " + property); 175 } 176 } 177 178 public Object removeProperty(String name) { 179 return getProperties().remove(name); 180 } 181 182 public Map<String, Object> getProperties() { 183 if (properties == null) { 184 properties = new ConcurrentHashMap<String, Object>(); 185 } 186 return properties; 187 } 188 189 public void setProperties(Map<String, Object> properties) { 190 this.properties = properties; 191 } 192 193 public Message getIn() { 194 if (in == null) { 195 in = createInMessage(); 196 configureMessage(in); 197 } 198 return in; 199 } 200 201 public void setIn(Message in) { 202 this.in = in; 203 configureMessage(in); 204 } 205 206 public Message getOut() { 207 return getOut(true); 208 } 209 210 public Message getOut(boolean lazyCreate) { 211 if (out == null && lazyCreate) { 212 out = createOutMessage(); 213 configureMessage(out); 214 } 215 return out; 216 } 217 218 public void setOut(Message out) { 219 this.out = out; 220 configureMessage(out); 221 } 222 223 public Throwable getException() { 224 return exception; 225 } 226 227 public void setException(Throwable exception) { 228 this.exception = exception; 229 } 230 231 public ExchangePattern getPattern() { 232 return pattern; 233 } 234 235 public void setPattern(ExchangePattern pattern) { 236 this.pattern = pattern; 237 } 238 239 public void throwException() throws Exception { 240 if (exception == null) { 241 return; 242 } 243 if (exception instanceof RuntimeException) { 244 throw (RuntimeException)exception; 245 } 246 if (exception instanceof Exception) { 247 throw (Exception)exception; 248 } 249 throw new RuntimeCamelException(exception); 250 } 251 252 public Message getFault() { 253 return getFault(true); 254 } 255 256 public Message getFault(boolean lazyCreate) { 257 if (fault == null && lazyCreate) { 258 fault = createFaultMessage(); 259 configureMessage(fault); 260 } 261 return fault; 262 } 263 264 public void setFault(Message fault) { 265 this.fault = fault; 266 configureMessage(fault); 267 } 268 269 public String getExchangeId() { 270 if (exchangeId == null) { 271 exchangeId = DefaultExchange.DEFAULT_ID_GENERATOR.generateId(); 272 } 273 return exchangeId; 274 } 275 276 public void setExchangeId(String id) { 277 this.exchangeId = id; 278 } 279 280 public boolean isFailed() { 281 Message faultMessage = getFault(false); 282 if (faultMessage != null) { 283 Object faultBody = faultMessage.getBody(); 284 if (faultBody != null) { 285 return true; 286 } 287 } 288 return getException() != null; 289 } 290 291 public boolean isTransacted() { 292 ExchangeProperty<?> property = ExchangeProperty.get("transacted"); 293 return property != null && property.get(this) == Boolean.TRUE; 294 } 295 296 public UnitOfWork getUnitOfWork() { 297 return unitOfWork; 298 } 299 300 public void setUnitOfWork(UnitOfWork unitOfWork) { 301 this.unitOfWork = unitOfWork; 302 } 303 304 /** 305 * Factory method used to lazily create the IN message 306 */ 307 protected Message createInMessage() { 308 return new DefaultMessage(); 309 } 310 311 /** 312 * Factory method to lazily create the OUT message 313 */ 314 protected Message createOutMessage() { 315 return new DefaultMessage(); 316 } 317 318 /** 319 * Factory method to lazily create the FAULT message 320 */ 321 protected Message createFaultMessage() { 322 return new DefaultMessage(); 323 } 324 325 /** 326 * Configures the message after it has been set on the exchange 327 */ 328 protected void configureMessage(Message message) { 329 if (message instanceof MessageSupport) { 330 MessageSupport messageSupport = (MessageSupport)message; 331 messageSupport.setExchange(this); 332 } 333 } 334 335 }