1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers;
12
13 import org.mule.MuleManager;
14 import org.mule.MuleRuntimeException;
15 import org.mule.config.MuleProperties;
16 import org.mule.config.i18n.CoreMessages;
17 import org.mule.impl.ThreadSafeAccess;
18 import org.mule.umo.UMOExceptionPayload;
19 import org.mule.umo.provider.UMOMessageAdapter;
20 import org.mule.umo.transformer.TransformerException;
21 import org.mule.util.MapUtils;
22 import org.mule.util.StringUtils;
23 import org.mule.util.UUID;
24
25 import java.io.Serializable;
26 import java.io.UnsupportedEncodingException;
27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.Set;
31
32 import javax.activation.DataHandler;
33
34 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
35 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
36 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
37 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicReference;
38 import org.apache.commons.lang.SerializationUtils;
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41
42
43
44
45
46
47 public abstract class AbstractMessageAdapter implements UMOMessageAdapter, ThreadSafeAccess
48 {
49
50
51
52
53 protected transient Log logger = LogFactory.getLog(getClass());
54
55 protected ConcurrentMap properties = new ConcurrentHashMap();
56 protected ConcurrentMap attachments = new ConcurrentHashMap();
57 protected String encoding = MuleManager.getConfiguration().getEncoding();
58
59
60
61
62
63 public static final boolean DEFAULT_FAILFAST = false;
64
65 protected UMOExceptionPayload exceptionPayload;
66 protected String id = UUID.getUUID();
67
68
69
70 private transient AtomicReference ownerThread = null;
71 private transient AtomicBoolean mutable = null;
72 public static final boolean WRITE = true;
73 public static final boolean READ = false;
74
75 protected AbstractMessageAdapter()
76 {
77
78 }
79
80 protected AbstractMessageAdapter(UMOMessageAdapter template)
81 {
82 if (null != template)
83 {
84 Iterator propertyNames = template.getPropertyNames().iterator();
85 while (propertyNames.hasNext())
86 {
87 String key = (String) propertyNames.next();
88 try
89 {
90 setProperty(key, template.getProperty(key));
91 }
92 catch (Exception e)
93 {
94 throw new MuleRuntimeException(CoreMessages.failedToReadPayload(), e);
95 }
96 }
97 Iterator attachmentNames = template.getAttachmentNames().iterator();
98 while (attachmentNames.hasNext())
99 {
100 String key = (String) attachmentNames.next();
101 try
102 {
103 addAttachment(key, template.getAttachment(key));
104 }
105 catch (Exception e)
106 {
107 throw new MuleRuntimeException(CoreMessages.failedToReadPayload(), e);
108 }
109 }
110 encoding = template.getEncoding();
111 exceptionPayload = template.getExceptionPayload();
112 id = template.getUniqueId();
113 }
114 }
115
116 public String toString()
117 {
118 assertAccess(READ);
119 StringBuffer buf = new StringBuffer(120);
120 buf.append(getClass().getName());
121 buf.append("/" + super.toString());
122 buf.append('{');
123 buf.append("id=").append(getUniqueId());
124 buf.append(", payload=").append(getPayload().getClass().getName());
125 buf.append(", correlationId=").append(getCorrelationId());
126 buf.append(", correlationGroup=").append(getCorrelationGroupSize());
127 buf.append(", correlationSeq=").append(getCorrelationSequence());
128 buf.append(", encoding=").append(getEncoding());
129 buf.append(", exceptionPayload=").append(exceptionPayload);
130 buf.append(", properties=").append(MapUtils.toString(properties, true));
131 buf.append('}');
132 return buf.toString();
133 }
134
135 public void addProperties(Map props)
136 {
137 assertAccess(WRITE);
138 if (props != null)
139 {
140 synchronized (props)
141 {
142 for (Iterator iter = props.entrySet().iterator(); iter.hasNext();)
143 {
144 Map.Entry entry = (Map.Entry) iter.next();
145 setProperty((String) entry.getKey(), entry.getValue());
146 }
147 }
148 }
149 }
150
151 public void clearProperties()
152 {
153 assertAccess(WRITE);
154 properties.clear();
155 }
156
157
158
159
160
161
162 public Object removeProperty(String key)
163 {
164 assertAccess(WRITE);
165 return properties.remove(key);
166 }
167
168
169
170
171
172
173 public Object getProperty(String key)
174 {
175 assertAccess(READ);
176 return properties.get(key);
177 }
178
179
180
181
182
183
184 public Set getPropertyNames()
185 {
186 assertAccess(READ);
187 return Collections.unmodifiableSet(properties.keySet());
188 }
189
190
191
192
193
194
195
196 public void setProperty(String key, Object value)
197 {
198 assertAccess(WRITE);
199 if (key != null)
200 {
201 if (value != null)
202 {
203 properties.put(key, value);
204 }
205 else
206 {
207 logger.warn("setProperty(key, value) called with null value; removing key: " + key
208 + "; please report the following stack trace to dev@mule.codehaus.org.",
209 new Throwable());
210 properties.remove(key);
211 }
212 }
213 else
214 {
215 logger.warn("setProperty(key, value) ignored because of null key for object: " + value
216 + "; please report the following stack trace to dev@mule.codehaus.org.",
217 new Throwable());
218 }
219 }
220
221 public String getUniqueId()
222 {
223 assertAccess(READ);
224 return id;
225 }
226
227 public Object getProperty(String name, Object defaultValue)
228 {
229 assertAccess(READ);
230 return MapUtils.getObject(properties, name, defaultValue);
231 }
232
233 public int getIntProperty(String name, int defaultValue)
234 {
235 assertAccess(READ);
236 return MapUtils.getIntValue(properties, name, defaultValue);
237 }
238
239 public long getLongProperty(String name, long defaultValue)
240 {
241 assertAccess(READ);
242 return MapUtils.getLongValue(properties, name, defaultValue);
243 }
244
245 public double getDoubleProperty(String name, double defaultValue)
246 {
247 assertAccess(READ);
248 return MapUtils.getDoubleValue(properties, name, defaultValue);
249 }
250
251 public boolean getBooleanProperty(String name, boolean defaultValue)
252 {
253 assertAccess(READ);
254 return MapUtils.getBooleanValue(properties, name, defaultValue);
255 }
256
257 public String getStringProperty(String name, String defaultValue)
258 {
259 assertAccess(READ);
260 return MapUtils.getString(properties, name, defaultValue);
261 }
262
263 public void setBooleanProperty(String name, boolean value)
264 {
265 assertAccess(WRITE);
266 setProperty(name, Boolean.valueOf(value));
267 }
268
269 public void setIntProperty(String name, int value)
270 {
271 assertAccess(WRITE);
272 setProperty(name, new Integer(value));
273 }
274
275 public void setLongProperty(String name, long value)
276 {
277 assertAccess(WRITE);
278 setProperty(name, new Long(value));
279 }
280
281 public void setDoubleProperty(String name, double value)
282 {
283 assertAccess(WRITE);
284 setProperty(name, new Double(value));
285 }
286
287 public void setStringProperty(String name, String value)
288 {
289 assertAccess(WRITE);
290 setProperty(name, value);
291 }
292
293 public Object getReplyTo()
294 {
295 assertAccess(READ);
296 return getProperty(MuleProperties.MULE_REPLY_TO_PROPERTY);
297 }
298
299 public void setReplyTo(Object replyTo)
300 {
301 assertAccess(WRITE);
302 if (replyTo != null)
303 {
304 setProperty(MuleProperties.MULE_REPLY_TO_PROPERTY, replyTo);
305 }
306 else
307 {
308 removeProperty(MuleProperties.MULE_REPLY_TO_PROPERTY);
309 }
310 }
311
312 public String getCorrelationId()
313 {
314 assertAccess(READ);
315 return (String) getProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY);
316 }
317
318 public void setCorrelationId(String correlationId)
319 {
320 assertAccess(WRITE);
321 if (StringUtils.isNotBlank(correlationId))
322 {
323 setProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY, correlationId);
324 }
325 else
326 {
327 removeProperty(MuleProperties.MULE_CORRELATION_ID_PROPERTY);
328 }
329 }
330
331
332
333
334
335
336
337 public int getCorrelationSequence()
338 {
339 assertAccess(READ);
340 return getIntProperty(MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY, -1);
341 }
342
343
344
345
346
347
348
349 public void setCorrelationSequence(int sequence)
350 {
351 assertAccess(WRITE);
352 setIntProperty(MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY, sequence);
353 }
354
355
356
357
358
359
360 public int getCorrelationGroupSize()
361 {
362 assertAccess(READ);
363 return getIntProperty(MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY, -1);
364 }
365
366
367
368
369
370
371 public void setCorrelationGroupSize(int size)
372 {
373 assertAccess(WRITE);
374 setIntProperty(MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY, size);
375 }
376
377 public UMOExceptionPayload getExceptionPayload()
378 {
379 assertAccess(READ);
380 return exceptionPayload;
381 }
382
383 public void setExceptionPayload(UMOExceptionPayload payload)
384 {
385 assertAccess(WRITE);
386 exceptionPayload = payload;
387 }
388
389 public void addAttachment(String name, DataHandler dataHandler) throws Exception
390 {
391 assertAccess(WRITE);
392 attachments.put(name, dataHandler);
393 }
394
395 public void removeAttachment(String name) throws Exception
396 {
397 assertAccess(WRITE);
398 attachments.remove(name);
399 }
400
401 public DataHandler getAttachment(String name)
402 {
403 assertAccess(READ);
404 return (DataHandler) attachments.get(name);
405 }
406
407 public Set getAttachmentNames()
408 {
409 assertAccess(READ);
410 return Collections.unmodifiableSet(attachments.keySet());
411 }
412
413 public String getEncoding()
414 {
415 assertAccess(READ);
416 return encoding;
417 }
418
419
420
421
422
423
424 public void setEncoding(String encoding)
425 {
426 assertAccess(WRITE);
427 this.encoding = encoding;
428 }
429
430
431
432
433
434
435
436
437 public final String getPayloadAsString() throws Exception
438 {
439 assertAccess(READ);
440 return getPayloadAsString(getEncoding());
441 }
442
443 protected byte[] convertToBytes(Object object) throws TransformerException, UnsupportedEncodingException
444 {
445 assertAccess(READ);
446 if (object instanceof String)
447 {
448 return object.toString().getBytes(getEncoding());
449 }
450
451 if (object instanceof byte[])
452 {
453 return (byte[]) object;
454 }
455 else if (object instanceof Serializable)
456 {
457 try
458 {
459 return SerializationUtils.serialize((Serializable) object);
460 }
461 catch (Exception e)
462 {
463 throw new TransformerException(
464 CoreMessages.transformFailed(object.getClass().getName(), "byte[]"), e);
465 }
466 }
467 else
468 {
469 throw new TransformerException(
470 CoreMessages.transformOnObjectNotOfSpecifiedType(object.getClass().getName(),
471 "byte[] or " + Serializable.class.getName()));
472 }
473 }
474
475
476
477
478
479
480
481
482 public void assertAccess(boolean write)
483 {
484 initAccessControl();
485 setOwner();
486 checkMutable(write);
487 }
488
489 private void setOwner()
490 {
491 if (null == ownerThread.get())
492 {
493 ownerThread.compareAndSet(null, Thread.currentThread());
494 }
495 }
496
497 private void checkMutable(boolean write)
498 {
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519 Thread currentThread = Thread.currentThread();
520 if (currentThread.equals(ownerThread.get()))
521 {
522 if (write && !mutable.get())
523 {
524 if (isDisabled())
525 {
526 logger.warn("Writing to immutable message (exception disabled)");
527 }
528 else
529 {
530 throw newException("Cannot write to immutable message");
531 }
532 }
533 }
534 else
535 {
536 if (write)
537 {
538 if (isDisabled())
539 {
540 logger.warn("Non-owner writing to message (exception disabled)");
541 }
542 else
543 {
544 throw newException("Only owner thread can write to message: "
545 + ownerThread.get() + "/" + Thread.currentThread());
546 }
547 }
548 else
549 {
550
551 mutable.set(false);
552 }
553 }
554 }
555
556 protected IllegalStateException newException(String message)
557 {
558 IllegalStateException exception = new IllegalStateException(message);
559 logger.warn("Message access violation", exception);
560 return exception;
561 }
562
563 protected boolean isDisabled()
564 {
565 return org.apache.commons.collections.MapUtils.getBooleanValue(System.getProperties(),
566 MuleProperties.MULE_THREAD_UNSAFE_MESSAGES_PROPERTY, !DEFAULT_FAILFAST);
567 }
568
569 private synchronized void initAccessControl()
570 {
571 if (null == ownerThread)
572 {
573 ownerThread = new AtomicReference();
574 }
575 if (null == mutable)
576 {
577 mutable = new AtomicBoolean(true);
578 }
579 }
580
581 public synchronized void resetAccessControl()
582 {
583 assertAccess(WRITE);
584 ownerThread.set(null);
585 mutable.set(true);
586 }
587
588
589
590
591
592
593
594
595 public ThreadSafeAccess newThreadCopy()
596 {
597 if (logger.isInfoEnabled())
598 {
599 logger.info("The newThreadCopy method in AbstractMessageAdapter is being used directly. "
600 + "This code may be susceptible to 'scribbling' issues with messages. "
601 + "Please consider implementing the ThreadSafeAccess interface in the message adapter.");
602 }
603 return this;
604 }
605
606 }