/* GENERATED SOURCE. DO NOT MODIFY. */ // © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ****************************************************************************** * Copyright (C) 2005-2016, International Business Machines Corporation and * * others. All Rights Reserved. * ****************************************************************************** */ package android.icu.util; /** * Provides a flexible mechanism for controlling access, without requiring that * a class be immutable. Once frozen, an object can never be unfrozen, so it is * thread-safe from that point onward. Once the object has been frozen, * it must guarantee that no changes can be made to it. Any attempt to alter * it must raise an UnsupportedOperationException exception. This means that when * the object returns internal objects, or if anyone has references to those internal * objects, that those internal objects must either be immutable, or must also * raise exceptions if any attempt to modify them is made. Of course, the object * can return clones of internal objects, since those are safe. *
* There are often times when you need objects to be objects 'safe', so that * they can't be modified. Examples are when objects need to be thread-safe, or * in writing robust code, or in caches. If you are only creating your own * objects, you can guarantee this, of course -- but only if you don't make a * mistake. If you have objects handed into you, or are creating objects using * others handed into you, it is a different story. It all comes down to whether * you want to take the Blanche Dubois approach ("depend on the kindness of * strangers") or the Andy Grove approach ("Only the Paranoid * Survive"). *
** For example, suppose we have a simple class: *
* *
* public class A {
* protected Collection b;
*
* protected Collection c;
*
* public Collection get_b() {
* return b;
* }
*
* public Collection get_c() {
* return c;
* }
*
* public A(Collection new_b, Collection new_c) {
* b = new_b;
* c = new_c;
* }
* }
*
*
* * Since the class doesn't have any setters, someone might think that it is * immutable. You know where this is leading, of course; this class is unsafe in * a number of ways. The following illustrates that. *
* *
* public test1(SupposedlyImmutableClass x, SafeStorage y) {
* // unsafe getter
* A a = x.getA();
* Collection col = a.get_b();
* col.add(something); // a has now been changed, and x too
*
* // unsafe constructor
* a = new A(col, col);
* y.store(a);
* col.add(something); // a has now been changed, and y too
* }
*
*
* * There are a few different techniques for having safe classes. *
** There are advantages and disadvantages of each of these. *
*
* The Freezable model supplements these choices by giving you
* the ability to build up an object by calling various methods, then when it is
* in a final state, you can make it immutable. Once immutable, an
* object cannot ever be modified, and is completely thread-safe: that
* is, multiple threads can have references to it without any synchronization.
* If someone needs a mutable version of an object, they can use
* cloneAsThawed(), and modify the copy. This provides a simple,
* effective mechanism for safe classes in circumstances where the alternatives
* are insufficient or clumsy. (If an object is shared before it is immutable,
* then it is the responsibility of each thread to mutex its usage (as with
* other objects).)
*
* Here is what needs to be done to implement this interface, depending on the * type of the object. *
** These are the easiest. You just use the interface to reflect that, by adding * the following: *
* *
* public class A implements Freezable<A> {
* ...
* public final boolean isFrozen() {return true;}
* public final A freeze() {return this;}
* public final A cloneAsThawed() { return this; }
* }
*
*
*
* These can be final methods because subclasses of immutable objects must
* themselves be immutable. (Note: freeze is returning
* this for chaining.)
*
* Add a protected 'flagging' field: *
* ** protected volatile boolean frozen; // WARNING: must be volatile ** *
* Add the following methods: *
* *
* public final boolean isFrozen() {
* return frozen;
* };
*
* public A freeze() {
* frozen = true; // WARNING: must be final statement before return
* return this;
* }
*
*
*
* Add a cloneAsThawed() method following the normal pattern for
* clone(), except that frozen=false in the new
* clone.
*
* Then take the setters (that is, any method that can change the internal state * of the object), and add the following as the first statement: *
* *
* if (isFrozen()) {
* throw new UnsupportedOperationException("Attempt to modify frozen object");
* }
*
*
*
* Any subclass of a Freezable will just use its superclass's
* flagging field. It must override freeze() and
* cloneAsThawed() to call the superclass, but normally does not
* override isFrozen(). It must then just pay attention to its
* own getters, setters and fields.
*
* Internal caches are cases where the object is logically unmodified, but * internal state of the object changes. For example, there are const C++ * functions that cast away the const on the "this" pointer in order * to modify an object cache. These cases are handled by mutexing the internal * cache to ensure thread-safety. For example, suppose that UnicodeSet had an * internal marker to the last code point accessed. In this case, the field is * not externally visible, so the only thing you need to do is to synchronize * the field for thread safety. *
*
* Internal fields are called safe if they are either
* frozen or immutable (such as String or primitives). If you've
* never allowed internal access to these, then you are all done. For example,
* converting UnicodeSet to be Freezable is just accomplished
* with the above steps. But remember that you have allowed
* access to unsafe internals if you have any code like the following, in a
* getter, setter, or constructor:
*
* Collection getStuff() {
* return stuff;
* } // caller could keep reference & modify
*
* void setStuff(Collection x) {
* stuff = x;
* } // caller could keep reference & modify
*
* MyClass(Collection x) {
* stuff = x;
* } // caller could keep reference & modify
*
*
* * These also illustrated in the code sample in Background above. *
*
* To deal with unsafe internals, the simplest course of action is to do the
* work in the freeze() function. Just make all of your internal
* fields frozen, and set the frozen flag. Any subsequent getter/setter will
* work properly. Here is an example:
*
Warning! The 'frozen' boolean MUST be volatile, and must be set as the last statement * in the method.
*
* public A freeze() {
* if (!frozen) {
* foo.freeze();
* frozen = true;
* }
* return this;
* }
*
*
*
* If the field is a Collection or Map, then to
* make it frozen you have two choices. If you have never allowed access to the
* collection from outside your object, then just wrap it to prevent future
* modification.
*
* zone_to_country = Collections.unmodifiableMap(zone_to_country); ** *
* If you have ever allowed access, then do a clone()
* before wrapping it.
*
* zone_to_country = Collections.unmodifiableMap(zone_to_country.clone()); ** *
* If a collection (or any other container of objects) itself can * contain mutable objects, then for a safe clone you need to recurse through it * to make the entire collection immutable. The recursing code should pick the * most specific collection available, to avoid the necessity of later * downcasing. *
***/ public interface Freezable* Note: An annoying flaw in Java is that the generic collections, like *
* *MaporSet, don't have aclone()* operation. When you don't know the type of the collection, the simplest * course is to just create a new collection: ** zone_to_country = Collections.unmodifiableMap(new HashMap(zone_to_country)); ** *