1 /* 2 * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com 3 * The software in this package is published under the terms of the CPAL v1.0 4 * license, a copy of which has been included with this distribution in the 5 * LICENSE.txt file. 6 */ 7 package org.mule.api; 8 9 import org.mule.api.config.MuleProperties; 10 11 import org.apache.commons.lang.BooleanUtils; 12 13 14 /** 15 * Interface implemented by message-related objects that avoid exposing mutable data to multiple threads 16 * by providing immutable copies. This interface is optional - it is an implementation detail that is 17 * tested for dynamically and used only if available. 18 * 19 * <p>To avoid "scribbling" where several threads change state within in a single method (typically 20 * in inconsistent ways, causing subtle and intermittent errors) we use the following access policy for 21 * message related objects:</p> 22 * 23 * <ul> 24 * 25 * <li>A new object is "unbound" and "mutable".</li> 26 * 27 * <li>An object is "bound" to the first thread that calls the object after it is created.</li> 28 * 29 * <li>A "mutable" object can be modified only by the thread to which it is bound.</li> 30 * 31 * <li>An object is "sealed" (no longer "mutable") when it is accessed by a thread other than the 32 * thread to which it is "bound". It is an error to attempt to change a "sealed" object.</li> 33 * 34 * </ul> 35 * 36 * <p>In practice this means that objects are initially mutable, but become immutable once they are 37 * shared.</p> 38 */ 39 public interface ThreadSafeAccess 40 { 41 boolean WRITE = true; 42 boolean READ = false; 43 44 /** 45 * This method may be called before data in the object are accessed. It should verify that the 46 * access policy is followed correctly (if not, a runtime exception may be thrown). 47 * 48 * @param write True if the access will mutate values. 49 */ 50 void assertAccess(boolean write); 51 52 /** 53 * This method should ONLY be used in the construction of composite ThreadSafeAccess instances. 54 * For example, a ThreadSafeAccess MuleEvent contains a ThreadSafeAccess MuleMessage. During 55 * the construction of the event, the message may be bound to the contructing thread. 56 * Calling this method releases that binding so that the event as a whole can be passed to a new 57 * thread unbound. 58 */ 59 void resetAccessControl(); 60 61 /** 62 * @return A new instance of the implementing class, unbound to any thread and mutable. 63 */ 64 ThreadSafeAccess newThreadCopy(); 65 66 /** 67 * This helper class can be used by code implementing this interface to determine whether 68 * the thread safety of a message should be enforced or not. 69 */ 70 class AccessControl 71 { 72 private static boolean assertMessageAccess = true; 73 private static boolean failOnMessageScribbling = true; 74 75 static 76 { 77 String propertyValue = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "message.assertAccess"); 78 if (propertyValue != null) 79 { 80 assertMessageAccess = BooleanUtils.toBoolean(propertyValue); 81 } 82 83 propertyValue = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "disable.threadsafemessages"); 84 if (propertyValue != null) 85 { 86 failOnMessageScribbling = !BooleanUtils.toBoolean(propertyValue); 87 } 88 } 89 90 public static boolean isAssertMessageAccess() 91 { 92 return assertMessageAccess; 93 } 94 95 public static void setAssertMessageAccess(boolean flag) 96 { 97 assertMessageAccess = flag; 98 } 99 100 /** 101 * Should we fail when we detect "message scribbling"? 102 * (see AbstractMessageAdapter#checkMutable()) 103 */ 104 public static boolean isFailOnMessageScribbling() 105 { 106 return failOnMessageScribbling; 107 } 108 109 public static void setFailOnMessageScribbling(boolean flag) 110 { 111 failOnMessageScribbling = flag; 112 } 113 } 114 115 }