]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/util/Freezable.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / util / Freezable.java
1 /*\r
2  ******************************************************************************\r
3  * Copyright (C) 200-2009, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                               *\r
5  ******************************************************************************\r
6 */\r
7 package com.ibm.icu.util;\r
8 \r
9 /**\r
10  * Provides a flexible mechanism for controlling access, without requiring that\r
11  * a class be immutable. Once locked, an object can never be unlocked, so it is\r
12  * thread-safe from that point onward. The implementation of both methods must\r
13  * be synchronized. Once the object has been locked, it must guarantee that no\r
14  * changes can be made to it. Any attempt to alter it must raise an\r
15  * UnsupportedOperationException exception. This means that when the object\r
16  * returns internal objects, or if anyone has references to those internal\r
17  * objects, that those internal objects must either be immutable, or must also\r
18  * raise exceptions if any attempt to modify them is made. Of course, the object\r
19  * can return clones of internal objects, since those are safe.\r
20  * <h2>Background</h2>\r
21  * <p>\r
22  * There are often times when you need objects to be objects 'safe', so that\r
23  * they can't be modified. Examples are when objects need to be thread-safe, or\r
24  * in writing robust code, or in caches. If you are only creating your own\r
25  * objects, you can guarantee this, of course -- but only if you don't make a\r
26  * mistake. If you have objects handed into you, or are creating objects using\r
27  * others handed into you, it is a different story. It all comes down to whether\r
28  * you want to take the Blanche Dubois approach (&quot;depend on the kindness of\r
29  * strangers&quot;) or the Andy Grove approach (&quot;Only the Paranoid\r
30  * Survive&quot;).\r
31  * </p>\r
32  * <p>\r
33  * For example, suppose we have a simple class:\r
34  * </p>\r
35  * \r
36  * <pre>\r
37  * public class A {\r
38  *      protected Collection b;\r
39  * \r
40  *      protected Collection c;\r
41  * \r
42  *      public Collection get_b() {\r
43  *              return b;\r
44  *      }\r
45  * \r
46  *      public Collection get_c() {\r
47  *              return c;\r
48  *      }\r
49  * \r
50  *      public A(Collection new_b, Collection new_c) {\r
51  *              b = new_b;\r
52  *              c = new_c;\r
53  *      }\r
54  * }\r
55  * </pre>\r
56  * \r
57  * <p>\r
58  * Since the class doesn't have any setters, someone might think that it is\r
59  * immutable. You know where this is leading, of course; this class is unsafe in\r
60  * a number of ways. The following illustrates that.\r
61  * </p>\r
62  * \r
63  * <pre>\r
64  *  public test1(SupposedlyImmutableClass x, SafeStorage y) {\r
65  *    // unsafe getter\r
66  *    A a = x.getA();\r
67  *    Collection col = a.get_b();\r
68  *    col.add(something); // a has now been changed, and x too\r
69  *\r
70  *    // unsafe constructor\r
71  *    a = new A(col, col);\r
72  *    y.store(a);\r
73  *    col.add(something); // a has now been changed, and y too\r
74  *  }\r
75  * </pre>\r
76  * \r
77  * <p>\r
78  * There are a few different techniques for having safe classes.\r
79  * </p>\r
80  * <ol>\r
81  * <li>Const objects. In C++, you can declare parameters const.</li>\r
82  * <li>Immutable wrappers. For example, you can put a collection in an\r
83  * immutable wrapper.</li>\r
84  * <li>Always-Immutable objects. Java uses this approach, with a few\r
85  * variations. Examples:\r
86  * <ol>\r
87  * <li>Simple. Once a Color is created (eg from R, G, and B integers) it is\r
88  * immutable.</li>\r
89  * <li>Builder Class. There is a separate 'builder' class. For example,\r
90  * modifiable Strings are created using StringBuffer (which doesn't have the\r
91  * full String API available). Once you want an immutable form, you create one\r
92  * with toString().</li>\r
93  * <li>Primitives. These are always safe, since they are copied on input/output\r
94  * from methods.</li>\r
95  * </ol>\r
96  * </li>\r
97  * <li>Cloning. Where you need an object to be safe, you clone it.</li>\r
98  * </ol>\r
99  * <p>\r
100  * There are advantages and disadvantages of each of these.\r
101  * </p>\r
102  * <ol>\r
103  * <li>Const provides a certain level of protection, but since const can be and\r
104  * is often cast away, it only protects against most inadvertent mistakes. It\r
105  * also offers no threading protection, since anyone who has a pointer to the\r
106  * (unconst) object in another thread can mess you up.</li>\r
107  * <li>Immutable wrappers are safer than const in that the constness can't be\r
108  * cast away. But other than that they have all the same problems: not safe if\r
109  * someone else keeps hold of the original object, or if any of the objects\r
110  * returned by the class are mutable.</li>\r
111  * <li>Always-Immutable Objects are safe, but usage can require excessive\r
112  * object creation.</li>\r
113  * <li>Cloning is only safe if the object truly has a 'safe' clone; defined as\r
114  * one that <i>ensures that no change to the clone affects the original</i>.\r
115  * Unfortunately, many objects don't have a 'safe' clone, and always cloning can\r
116  * require excessive object creation.</li>\r
117  * </ol>\r
118  * <h2>Freezable Model</h2>\r
119  * <p>\r
120  * The <code>Freezable</code> model supplements these choices by giving you\r
121  * the ability to build up an object by calling various methods, then when it is\r
122  * in a final state, you can <i>make</i> it immutable. Once immutable, an\r
123  * object cannot <i>ever </i>be modified, and is completely thread-safe: that\r
124  * is, multiple threads can have references to it without any synchronization.\r
125  * If someone needs a mutable version of an object, they can use\r
126  * <code>cloneAsThawed()</code>, and modify the copy. This provides a simple,\r
127  * effective mechanism for safe classes in circumstances where the alternatives\r
128  * are insufficient or clumsy. (If an object is shared before it is immutable,\r
129  * then it is the responsibility of each thread to mutex its usage (as with\r
130  * other objects).)\r
131  * </p>\r
132  * <p>\r
133  * Here is what needs to be done to implement this interface, depending on the\r
134  * type of the object.\r
135  * </p>\r
136  * <h3><b>Immutable Objects</b></h3>\r
137  * <p>\r
138  * These are the easiest. You just use the interface to reflect that, by adding\r
139  * the following:\r
140  * </p>\r
141  * \r
142  * <pre>\r
143  *  public class A implements Freezable<A> {\r
144  *   ...\r
145  *   public final boolean isFrozen() {return true;}\r
146  *   public final A freeze() {return this;}\r
147  *   public final A cloneAsThawed() { return this; }\r
148  *   }\r
149  * </pre>\r
150  * \r
151  * <p>\r
152  * These can be final methods because subclasses of immutable objects must\r
153  * themselves be immutable. (Note: <code>freeze</code> is returning\r
154  * <code>this</code> for chaining.)\r
155  * </p>\r
156  * <h3><b>Mutable Objects</b></h3>\r
157  * <p>\r
158  * Add a protected 'flagging' field:\r
159  * </p>\r
160  * \r
161  * <pre>\r
162  * protected boolean immutable;\r
163  * </pre>\r
164  * \r
165  * <p>\r
166  * Add the following methods:\r
167  * </p>\r
168  * \r
169  * <pre>\r
170  * public final boolean isFrozen() {\r
171  *      return frozen;\r
172  * };\r
173  * \r
174  * public A freeze() {\r
175  *      frozen = true;\r
176  *      return this;\r
177  * }\r
178  * </pre>\r
179  * \r
180  * <p>\r
181  * Add a <code>cloneAsThawed()</code> method following the normal pattern for\r
182  * <code>clone()</code>, except that <code>frozen=false</code> in the new\r
183  * clone.\r
184  * </p>\r
185  * <p>\r
186  * Then take the setters (that is, any method that can change the internal state\r
187  * of the object), and add the following as the first statement:\r
188  * </p>\r
189  * \r
190  * <pre>\r
191  * if (isFrozen()) {\r
192  *      throw new UnsupportedOperationException(&quot;Attempt to modify frozen object&quot;);\r
193  * }\r
194  * </pre>\r
195  * \r
196  * <h4><b>Subclassing</b></h4>\r
197  * <p>\r
198  * Any subclass of a <code>Freezable</code> will just use its superclass's\r
199  * flagging field. It must override <code>freeze()</code> and\r
200  * <code>cloneAsThawed()</code> to call the superclass, but normally does not\r
201  * override <code>isFrozen()</code>. It must then just pay attention to its\r
202  * own getters, setters and fields.\r
203  * </p>\r
204  * <h4><b>Internal Caches</b></h4>\r
205  * <p>\r
206  * Internal caches are cases where the object is logically unmodified, but\r
207  * internal state of the object changes. For example, there are const C++\r
208  * functions that cast away the const on the &quot;this&quot; pointer in order\r
209  * to modify an object cache. These cases are handled by mutexing the internal\r
210  * cache to ensure thread-safety. For example, suppose that UnicodeSet had an\r
211  * internal marker to the last code point accessed. In this case, the field is\r
212  * not externally visible, so the only thing you need to do is to synchronize\r
213  * the field for thread safety.\r
214  * </p>\r
215  * <h4>Unsafe Internal Access</h4>\r
216  * <p>\r
217  * Internal fields are called <i>safe</i> if they are either\r
218  * <code>frozen</code> or immutable (such as String or primitives). If you've\r
219  * never allowed internal access to these, then you are all done. For example,\r
220  * converting UnicodeSet to be <code>Freezable</code> is just accomplished\r
221  * with the above steps. But remember that you <i><b>have</b></i> allowed\r
222  * access to unsafe internals if you have any code like the following, in a\r
223  * getter, setter, or constructor:\r
224  * </p>\r
225  * \r
226  * <pre>\r
227  * Collection getStuff() {\r
228  *      return stuff;\r
229  * } // caller could keep reference &amp; modify\r
230  * \r
231  * void setStuff(Collection x) {\r
232  *      stuff = x;\r
233  * } // caller could keep reference &amp; modify\r
234  * \r
235  * MyClass(Collection x) {\r
236  *      stuff = x;\r
237  * } // caller could keep reference &amp; modify\r
238  * </pre>\r
239  * \r
240  * <p>\r
241  * These also illustrated in the code sample in <b>Background</b> above.\r
242  * </p>\r
243  * <p>\r
244  * To deal with unsafe internals, the simplest course of action is to do the\r
245  * work in the <code>freeze()</code> function. Just make all of your internal\r
246  * fields frozen, and set the frozen flag. Any subsequent getter/setter will\r
247  * work properly. Here is an example:\r
248  * </p>\r
249  * \r
250  * <pre>\r
251  * public A freeze() {\r
252  *      if (!frozen) {\r
253  *              foo.freeze();\r
254  *              frozen = true;\r
255  *      }\r
256  *      return this;\r
257  * }\r
258  * </pre>\r
259  * \r
260  * <p>\r
261  * If the field is a <code>Collection</code> or <code>Map</code>, then to\r
262  * make it frozen you have two choices. If you have never allowed access to the\r
263  * collection from outside your object, then just wrap it to prevent future\r
264  * modification.\r
265  * </p>\r
266  * \r
267  * <pre>\r
268  * zone_to_country = Collections.unmodifiableMap(zone_to_country);\r
269  * </pre>\r
270  * \r
271  * <p>\r
272  * If you have <i>ever</i> allowed access, then do a <code>clone()</code>\r
273  * before wrapping it.\r
274  * </p>\r
275  * \r
276  * <pre>\r
277  * zone_to_country = Collections.unmodifiableMap(zone_to_country.clone());\r
278  * </pre>\r
279  * \r
280  * <p>\r
281  * If a collection <i>(or any other container of objects)</i> itself can\r
282  * contain mutable objects, then for a safe clone you need to recurse through it\r
283  * to make the entire collection immutable. The recursing code should pick the\r
284  * most specific collection available, to avoid the necessity of later\r
285  * downcasing.\r
286  * </p>\r
287  * <blockquote>\r
288  * <p>\r
289  * <b>Note: </b>An annoying flaw in Java is that the generic collections, like\r
290  * <code>Map</code> or <code>Set</code>, don't have a <code>clone()</code>\r
291  * operation. When you don't know the type of the collection, the simplest\r
292  * course is to just create a new collection:\r
293  * </p>\r
294  * \r
295  * <pre>\r
296  * zone_to_country = Collections.unmodifiableMap(new HashMap(zone_to_country));\r
297  * </pre>\r
298  * \r
299  * </blockquote>\r
300  * @stable ICU 3.8\r
301  */\r
302 public interface Freezable<T> extends Cloneable {\r
303     /**\r
304      * Determines whether the object has been locked or not.\r
305      * @stable ICU 3.8\r
306      */\r
307     public boolean isFrozen();\r
308 \r
309     /**\r
310      * Locks the object.\r
311      * @return the object itself.\r
312      * @stable ICU 3.8\r
313      */\r
314     public T freeze();\r
315 \r
316     /**\r
317      * Provides for the clone operation. Any clone is initially unlocked.\r
318      * @stable ICU 3.8\r
319      */\r
320     public T cloneAsThawed();\r
321 }\r