001 /*
002 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package java.beans;
026
027 /**
028 * The PersistenceDelegate class takes the responsibility
029 * for expressing the state of an instance of a given class
030 * in terms of the methods in the class's public API. Instead
031 * of associating the responsibility of persistence with
032 * the class itself as is done, for example, by the
033 * <code>readObject</code> and <code>writeObject</code>
034 * methods used by the <code>ObjectOutputStream</code>, streams like
035 * the <code>XMLEncoder</code> which
036 * use this delegation model can have their behavior controlled
037 * independently of the classes themselves. Normally, the class
038 * is the best place to put such information and conventions
039 * can easily be expressed in this delegation scheme to do just that.
040 * Sometimes however, it is the case that a minor problem
041 * in a single class prevents an entire object graph from
042 * being written and this can leave the application
043 * developer with no recourse but to attempt to shadow
044 * the problematic classes locally or use alternative
045 * persistence techniques. In situations like these, the
046 * delegation model gives a relatively clean mechanism for
047 * the application developer to intervene in all parts of the
048 * serialization process without requiring that modifications
049 * be made to the implementation of classes which are not part
050 * of the application itself.
051 * <p>
052 * In addition to using a delegation model, this persistence
053 * scheme differs from traditional serialization schemes
054 * in requiring an analog of the <code>writeObject</code>
055 * method without a corresponding <code>readObject</code>
056 * method. The <code>writeObject</code> analog encodes each
057 * instance in terms of its public API and there is no need to
058 * define a <code>readObject</code> analog
059 * since the procedure for reading the serialized form
060 * is defined by the semantics of method invocation as laid
061 * out in the Java Language Specification.
062 * Breaking the dependency between <code>writeObject</code>
063 * and <code>readObject</code> implementations, which may
064 * change from version to version, is the key factor
065 * in making the archives produced by this technique immune
066 * to changes in the private implementations of the classes
067 * to which they refer.
068 * <p>
069 * A persistence delegate, may take control of all
070 * aspects of the persistence of an object including:
071 * <ul>
072 * <li>
073 * Deciding whether or not an instance can be mutated
074 * into another instance of the same class.
075 * <li>
076 * Instantiating the object, either by calling a
077 * public constructor or a public factory method.
078 * <li>
079 * Performing the initialization of the object.
080 * </ul>
081 * @see XMLEncoder
082 *
083 * @since 1.4
084 *
085 * @version 1.19 05/05/07
086 * @author Philip Milne
087 */
088
089 public abstract class PersistenceDelegate {
090
091 /**
092 * The <code>writeObject</code> is a single entry point to the persistence
093 * and is used by a <code>Encoder</code> in the traditional
094 * mode of delegation. Although this method is not final,
095 * it should not need to be subclassed under normal circumstances.
096 * <p>
097 * This implementation first checks to see if the stream
098 * has already encountered this object. Next the
099 * <code>mutatesTo</code> method is called to see if
100 * that candidate returned from the stream can
101 * be mutated into an accurate copy of <code>oldInstance</code>.
102 * If it can, the <code>initialize</code> method is called to
103 * perform the initialization. If not, the candidate is removed
104 * from the stream, and the <code>instantiate</code> method
105 * is called to create a new candidate for this object.
106 *
107 * @param oldInstance The instance that will be created by this expression.
108 * @param out The stream to which this expression will be written.
109 */
110 public void writeObject(Object oldInstance, Encoder out) {
111 Object newInstance = out.get(oldInstance);
112 if (!mutatesTo(oldInstance, newInstance)) {
113 out.remove(oldInstance);
114 out.writeExpression(instantiate(oldInstance, out));
115 } else {
116 initialize(oldInstance.getClass(), oldInstance,
117 newInstance, out);
118 }
119 }
120
121 /**
122 * Returns true if an <em>equivalent</em> copy of <code>oldInstance</code> may be
123 * created by applying a series of statements to <code>newInstance</code>.
124 * In the specification of this method, we mean by equivalent that the modified instance
125 * is indistinguishable from <code>oldInstance</code> in the behavior
126 * of the relevant methods in its public API. [Note: we use the
127 * phrase <em>relevant</em> methods rather than <em>all</em> methods
128 * here only because, to be strictly correct, methods like <code>hashCode</code>
129 * and <code>toString</code> prevent most classes from producing truly
130 * indistinguishable copies of their instances].
131 * <p>
132 * The default behavior returns <code>true</code>
133 * if the classes of the two instances are the same.
134 *
135 * @param oldInstance The instance to be copied.
136 * @param newInstance The instance that is to be modified.
137 * @return True if an equivalent copy of <code>newInstance</code> may be
138 * created by applying a series of mutations to <code>oldInstance</code>.
139 */
140 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
141 return (newInstance != null && oldInstance != null && oldInstance
142 .getClass() == newInstance.getClass());
143 }
144
145 /**
146 * Returns an expression whose value is <code>oldInstance</code>.
147 * This method is used to characterize the constructor
148 * or factory method that should be used to create the given object.
149 * For example, the <code>instantiate</code> method of the persistence
150 * delegate for the <code>Field</code> class could be defined as follows:
151 * <pre>
152 * Field f = (Field)oldInstance;
153 * return new Expression(f, f.getDeclaringClass(), "getField", new Object[]{f.getName()});
154 * </pre>
155 * Note that we declare the value of the returned expression so that
156 * the value of the expression (as returned by <code>getValue</code>)
157 * will be identical to <code>oldInstance</code>.
158 *
159 * @param oldInstance The instance that will be created by this expression.
160 * @param out The stream to which this expression will be written.
161 * @return An expression whose value is <code>oldInstance</code>.
162 */
163 protected abstract Expression instantiate(Object oldInstance,
164 Encoder out);
165
166 /**
167 * Produce a series of statements with side effects on <code>newInstance</code>
168 * so that the new instance becomes <em>equivalent</em> to <code>oldInstance</code>.
169 * In the specification of this method, we mean by equivalent that, after the method
170 * returns, the modified instance is indistinguishable from
171 * <code>newInstance</code> in the behavior of all methods in its
172 * public API.
173 * <p>
174 * The implementation typically achieves this goal by producing a series of
175 * "what happened" statements involving the <code>oldInstance</code>
176 * and its publicly available state. These statements are sent
177 * to the output stream using its <code>writeExpression</code>
178 * method which returns an expression involving elements in
179 * a cloned environment simulating the state of an input stream during
180 * reading. Each statement returned will have had all instances
181 * the old environment replaced with objects which exist in the new
182 * one. In particular, references to the target of these statements,
183 * which start out as references to <code>oldInstance</code> are returned
184 * as references to the <code>newInstance</code> instead.
185 * Executing these statements effects an incremental
186 * alignment of the state of the two objects as a series of
187 * modifications to the objects in the new environment.
188 * By the time the initialize method returns it should be impossible
189 * to tell the two instances apart by using their public APIs.
190 * Most importantly, the sequence of steps that were used to make
191 * these objects appear equivalent will have been recorded
192 * by the output stream and will form the actual output when
193 * the stream is flushed.
194 * <p>
195 * The default implementation, calls the <code>initialize</code>
196 * method of the type's superclass.
197 *
198 * @param oldInstance The instance to be copied.
199 * @param newInstance The instance that is to be modified.
200 * @param out The stream to which any initialization statements should be written.
201 */
202 protected void initialize(Class<?> type, Object oldInstance,
203 Object newInstance, Encoder out) {
204 Class super Type = type.getSuperclass();
205 PersistenceDelegate info = out
206 .getPersistenceDelegate(superType);
207 info.initialize(superType, oldInstance, newInstance, out);
208 }
209 }
|