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      */
writeObject(Object oldInstance, Encoder out)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      */
mutatesTo(Object oldInstance, Object newInstance)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      */
instantiate(Object oldInstance, Encoder out)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      */
initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out)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 }
217