1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.beans;
  26 
  27 /**
  28  * The PersistenceDelegate class takes the responsibility
  29  * for expressing the state of an instance of a given class
  30  * in terms of the methods in the class's public API. Instead
  31  * of associating the responsibility of persistence with
  32  * the class itself as is done, for example, by the
  33  * {@code readObject} and {@code writeObject}
  34  * methods used by the {@code ObjectOutputStream}, streams like
  35  * the {@code XMLEncoder} which
  36  * use this delegation model can have their behavior controlled
  37  * independently of the classes themselves. Normally, the class
  38  * is the best place to put such information and conventions
  39  * can easily be expressed in this delegation scheme to do just that.
  40  * Sometimes however, it is the case that a minor problem
  41  * in a single class prevents an entire object graph from
  42  * being written and this can leave the application
  43  * developer with no recourse but to attempt to shadow
  44  * the problematic classes locally or use alternative
  45  * persistence techniques. In situations like these, the
  46  * delegation model gives a relatively clean mechanism for
  47  * the application developer to intervene in all parts of the
  48  * serialization process without requiring that modifications
  49  * be made to the implementation of classes which are not part
  50  * of the application itself.
  51  * <p>
  52  * In addition to using a delegation model, this persistence
  53  * scheme differs from traditional serialization schemes
  54  * in requiring an analog of the {@code writeObject}
  55  * method without a corresponding {@code readObject}
  56  * method. The {@code writeObject} analog encodes each
  57  * instance in terms of its public API and there is no need to
  58  * define a {@code readObject} analog
  59  * since the procedure for reading the serialized form
  60  * is defined by the semantics of method invocation as laid
  61  * out in the Java Language Specification.
  62  * Breaking the dependency between {@code writeObject}
  63  * and {@code readObject} implementations, which may
  64  * change from version to version, is the key factor
  65  * in making the archives produced by this technique immune
  66  * to changes in the private implementations of the classes
  67  * to which they refer.
  68  * <p>
  69  * A persistence delegate, may take control of all
  70  * aspects of the persistence of an object including:
  71  * <ul>
  72  * <li>
  73  * Deciding whether or not an instance can be mutated
  74  * into another instance of the same class.
  75  * <li>
  76  * Instantiating the object, either by calling a
  77  * public constructor or a public factory method.
  78  * <li>
  79  * Performing the initialization of the object.
  80  * </ul>
  81  * @see XMLEncoder
  82  *
  83  * @since 1.4
  84  *
  85  * @author Philip Milne
  86  */
  87 
  88 public abstract class PersistenceDelegate {
  89 
  90     /**
  91      * The {@code writeObject} is a single entry point to the persistence
  92      * and is used by an {@code Encoder} in the traditional
  93      * mode of delegation. Although this method is not final,
  94      * it should not need to be subclassed under normal circumstances.
  95      * <p>
  96      * This implementation first checks to see if the stream
  97      * has already encountered this object. Next the
  98      * {@code mutatesTo} method is called to see if
  99      * that candidate returned from the stream can
 100      * be mutated into an accurate copy of {@code oldInstance}.
 101      * If it can, the {@code initialize} method is called to
 102      * perform the initialization. If not, the candidate is removed
 103      * from the stream, and the {@code instantiate} method
 104      * is called to create a new candidate for this object.
 105      *
 106      * @param oldInstance The instance that will be created by this expression.
 107      * @param out The stream to which this expression will be written.
 108      *
 109      * @throws NullPointerException if {@code out} is {@code null}
 110      */
 111     public void writeObject(Object oldInstance, Encoder out) {
 112         Object newInstance = out.get(oldInstance);
 113         if (!mutatesTo(oldInstance, newInstance)) {
 114             out.remove(oldInstance);
 115             out.writeExpression(instantiate(oldInstance, out));
 116         }
 117         else {
 118             initialize(oldInstance.getClass(), oldInstance, newInstance, out);
 119         }
 120     }
 121 
 122     /**
 123      * Returns true if an <em>equivalent</em> copy of {@code oldInstance} may be
 124      * created by applying a series of statements to {@code newInstance}.
 125      * In the specification of this method, we mean by equivalent that the modified instance
 126      * is indistinguishable from {@code oldInstance} in the behavior
 127      * of the relevant methods in its public API. [Note: we use the
 128      * phrase <em>relevant</em> methods rather than <em>all</em> methods
 129      * here only because, to be strictly correct, methods like {@code hashCode}
 130      * and {@code toString} prevent most classes from producing truly
 131      * indistinguishable copies of their instances].
 132      * <p>
 133      * The default behavior returns {@code true}
 134      * if the classes of the two instances are the same.
 135      *
 136      * @param oldInstance The instance to be copied.
 137      * @param newInstance The instance that is to be modified.
 138      * @return True if an equivalent copy of {@code newInstance} may be
 139      *         created by applying a series of mutations to {@code oldInstance}.
 140      */
 141     protected boolean mutatesTo(Object oldInstance, Object newInstance) {
 142         return (newInstance != null && oldInstance != null &&
 143                 oldInstance.getClass() == newInstance.getClass());
 144     }
 145 
 146     /**
 147      * Returns an expression whose value is {@code oldInstance}.
 148      * This method is used to characterize the constructor
 149      * or factory method that should be used to create the given object.
 150      * For example, the {@code instantiate} method of the persistence
 151      * delegate for the {@code Field} class could be defined as follows:
 152      * <pre>
 153      * Field f = (Field)oldInstance;
 154      * return new Expression(f, f.getDeclaringClass(), "getField", new Object[]{f.getName()});
 155      * </pre>
 156      * Note that we declare the value of the returned expression so that
 157      * the value of the expression (as returned by {@code getValue})
 158      * will be identical to {@code oldInstance}.
 159      *
 160      * @param oldInstance The instance that will be created by this expression.
 161      * @param out The stream to which this expression will be written.
 162      * @return An expression whose value is {@code oldInstance}.
 163      *
 164      * @throws NullPointerException if {@code out} is {@code null}
 165      *                              and this value is used in the method
 166      */
 167     protected abstract Expression instantiate(Object oldInstance, Encoder out);
 168 
 169     /**
 170      * Produce a series of statements with side effects on {@code newInstance}
 171      * so that the new instance becomes <em>equivalent</em> to {@code oldInstance}.
 172      * In the specification of this method, we mean by equivalent that, after the method
 173      * returns, the modified instance is indistinguishable from
 174      * {@code newInstance} in the behavior of all methods in its
 175      * public API.
 176      * <p>
 177      * The implementation typically achieves this goal by producing a series of
 178      * "what happened" statements involving the {@code oldInstance}
 179      * and its publicly available state. These statements are sent
 180      * to the output stream using its {@code writeExpression}
 181      * method which returns an expression involving elements in
 182      * a cloned environment simulating the state of an input stream during
 183      * reading. Each statement returned will have had all instances
 184      * the old environment replaced with objects which exist in the new
 185      * one. In particular, references to the target of these statements,
 186      * which start out as references to {@code oldInstance} are returned
 187      * as references to the {@code newInstance} instead.
 188      * Executing these statements effects an incremental
 189      * alignment of the state of the two objects as a series of
 190      * modifications to the objects in the new environment.
 191      * By the time the initialize method returns it should be impossible
 192      * to tell the two instances apart by using their public APIs.
 193      * Most importantly, the sequence of steps that were used to make
 194      * these objects appear equivalent will have been recorded
 195      * by the output stream and will form the actual output when
 196      * the stream is flushed.
 197      * <p>
 198      * The default implementation, calls the {@code initialize}
 199      * method of the type's superclass.
 200      *
 201      * @param type the type of the instances
 202      * @param oldInstance The instance to be copied.
 203      * @param newInstance The instance that is to be modified.
 204      * @param out The stream to which any initialization statements should be written.
 205      *
 206      * @throws NullPointerException if {@code out} is {@code null}
 207      */
 208     protected void initialize(Class<?> type,
 209                               Object oldInstance, Object newInstance,
 210                               Encoder out)
 211     {
 212         Class<?> superType = type.getSuperclass();
 213         PersistenceDelegate info = out.getPersistenceDelegate(superType);
 214         info.initialize(superType, oldInstance, newInstance, out);
 215     }
 216 }