001: /*
002: * $RCSfile: RenderingHintsProxy.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:53 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.rmi;
013:
014: import java.awt.RenderingHints;
015: import java.io.IOException;
016: import java.io.NotSerializableException;
017: import java.io.ObjectInputStream;
018: import java.io.ObjectOutputStream;
019: import java.io.Serializable;
020: import java.lang.ref.SoftReference;
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Modifier;
023: import java.util.Enumeration;
024: import java.util.Hashtable;
025: import java.util.Iterator;
026: import java.util.Set;
027: import java.util.Vector;
028: import javax.media.jai.JAI;
029: import javax.media.jai.OperationRegistry;
030:
031: /**
032: * This class is a serializable proxy for a RenderingHints object from which
033: * the RenderingHints object may be reconstituted.
034: *
035: *
036: * @since EA3
037: */
038: public class RenderingHintsProxy implements Serializable {
039: /** The RenderingHints object. */
040: private transient RenderingHints hints;
041:
042: /**
043: * The classes wherein all possible relevant public static
044: * RenderingHints.Key objects are defined. Classes which contain
045: * declarations of such keys should be added to this array.
046: */
047: private static final Class[] KEY_CLASSES = { RenderingHints.class,
048: JAI.class };
049:
050: /**
051: * Instances of keys which should not be serialized. Objects which
052: * represent such keys should be added to this array. Presumably such
053: * objects would be static and final members of one of the classes
054: * in the KEY_CLASSES array.
055: */
056: private static final Object[] SUPPRESSED_KEYS = {
057: JAI.KEY_OPERATION_REGISTRY, JAI.KEY_TILE_CACHE,
058: JAI.KEY_RETRY_INTERVAL, JAI.KEY_NUM_RETRIES,
059: JAI.KEY_NEGOTIATION_PREFERENCES };
060:
061: /** A SoftReference to a Vector of keys which are to be suppressed. */
062: private static SoftReference suppressedKeyReference = null;
063:
064: /**
065: * A SoftReference to a Hashtable containing serializable versions of
066: * all public static fields in the classes in the KEY_CLASSES array.
067: */
068: private static SoftReference hintTableReference = null;
069:
070: /**
071: * Constructs a <code>RenderingHintsProxy</code> from a
072: * <code>RenderingHints</code> object.
073: *
074: * @param source The <code>RenderingHints</code> object to be serialized.
075: */
076: public RenderingHintsProxy(RenderingHints source) {
077: hints = source;
078: }
079:
080: /** An inner class representing either a hint key or a hint value. */
081: private static class HintElement implements Serializable {
082: /** The class represents a serializable object. */
083: private static final int TYPE_OBJECT = 1;
084:
085: /** The class represents an element by class and field name. */
086: private static final int TYPE_FIELD = 2;
087:
088: /** The type of the element representation. */
089: private int type;
090:
091: /** The element itself. */
092: private Object obj;
093:
094: /** The name of the class of the element (type == TYPE_FIELD only). */
095: private String className;
096:
097: /** The name of the field of the element (type == TYPE_FIELD only). */
098: private String fieldName;
099:
100: /** Constructs a HintElement representing a serializable object. */
101: public HintElement(Object obj) throws NotSerializableException {
102: if (!(obj instanceof Serializable)) {
103: throw new NotSerializableException();
104: }
105: type = TYPE_OBJECT;
106: this .obj = obj;
107: }
108:
109: /** Constructs a HintElement representing a public static field. */
110: public HintElement(Class cls, Field fld) {
111: type = TYPE_FIELD;
112: this .className = cls.getName();
113: this .fieldName = fld.getName();
114: }
115:
116: /** Retrieves the element value. Returns null on error. */
117: public Object getObject() {
118: Object elt = null;
119:
120: if (type == TYPE_OBJECT) {
121: elt = obj;
122: } else if (type == TYPE_FIELD) {
123: try {
124: Class cls = Class.forName(className);
125: Field fld = cls.getField(fieldName);
126: elt = fld.get(null);
127: } catch (Exception e) {
128: // Do nothing.
129: }
130: }
131:
132: return elt;
133: }
134: }
135:
136: /**
137: * Retrieves the associated <code>RenderingHints</code> object.
138: * @return The (perhaps reconstructed) <code>RenderingHints</code>
139: * object.
140: */
141: public RenderingHints getRenderingHints() {
142: return hints;
143: }
144:
145: /** Returns a Vector of keys which should not be serialized or null. */
146: private static synchronized Vector getSuppressedKeys() {
147: Vector suppressedKeys = null;
148:
149: if (SUPPRESSED_KEYS != null) {
150: // Initialize the Vector to the SoftReference's referent or null.
151: suppressedKeys = suppressedKeyReference != null ? (Vector) suppressedKeyReference
152: .get()
153: : null;
154:
155: if (suppressedKeys == null) {
156: // Cache the number of suppressed keys.
157: int numSuppressedKeys = SUPPRESSED_KEYS.length;
158:
159: // Load the Vector with the suppressed key objects.
160: suppressedKeys = new Vector(numSuppressedKeys);
161: for (int i = 0; i < numSuppressedKeys; i++) {
162: suppressedKeys.add(SUPPRESSED_KEYS[i]);
163: }
164:
165: // Cache the Vector of suppressed keys.
166: suppressedKeyReference = new SoftReference(
167: suppressedKeys);
168: }
169: }
170:
171: return suppressedKeys;
172: }
173:
174: /**
175: * Returns a Hashtable wherein the keys are instances of
176: * RenderingHints.Key and the values are HintElements.
177: */
178: private static synchronized Hashtable getHintTable() {
179: // Initialize the table to the SoftReference's referent or null.
180: Hashtable table = hintTableReference != null ? (Hashtable) hintTableReference
181: .get()
182: : null;
183:
184: if (table == null) {
185: // Allocate a table for the field values.
186: table = new Hashtable();
187:
188: for (int i = 0; i < KEY_CLASSES.length; i++) {
189: // Cache the class.
190: Class cls = KEY_CLASSES[i];
191:
192: // Retrieve the fields for this class.
193: Field[] fields = cls.getFields();
194:
195: // Load the table with the values of all
196: // fields with public and static modifiers.
197: for (int j = 0; j < fields.length; j++) {
198: Field fld = fields[j];
199: int modifiers = fld.getModifiers();
200: if (Modifier.isPublic(modifiers)
201: && Modifier.isStatic(modifiers)) {
202: try {
203: Object fieldValue = fld.get(null);
204: table.put(fieldValue, new HintElement(cls,
205: fld));
206: } catch (Exception e) {
207: // Ignore exception.
208: }
209: }
210: }
211: }
212:
213: // Cache the table.
214: hintTableReference = new SoftReference(table);
215: }
216:
217: return table;
218: }
219:
220: /*
221: * The RenderingHints are serialized by creating a Hashtable of key/value
222: * pairs wherein the keys are instances of the inner class HintElement and
223: * the values are also instances of HintElement or of seriailizable
224: * classes.
225: */
226:
227: /**
228: * Serialize the RenderingHintsProxy.
229: */
230: private void writeObject(ObjectOutputStream out) throws IOException {
231: // -- Create a serializable form of the RenderingHints object. --
232:
233: // Create an empty Hashtable.
234: Hashtable table = new Hashtable();
235:
236: // If there are hints, add them to the table.
237: if (hints != null && !hints.isEmpty()) {
238: // Get a view of the hints' keys.
239: Set keySet = hints.keySet();
240:
241: // Proceed if the key set is non-empty.
242: if (!keySet.isEmpty()) {
243: // Get an iterator for the key set.
244: Iterator keyIterator = keySet.iterator();
245:
246: // Get the cached hint table.
247: Hashtable hintTable = getHintTable();
248:
249: // Get the suppressed key Vector.
250: Vector suppressedKeys = getSuppressedKeys();
251:
252: // Loop over the keys.
253: while (keyIterator.hasNext()) {
254: // Get the next key.
255: Object key = keyIterator.next();
256:
257: // Skip this element if the key is suppressed.
258: if (suppressedKeys != null
259: && suppressedKeys.indexOf(key) != -1) {
260: continue;
261: }
262:
263: // Get the field of the key.
264: HintElement keyElement = (HintElement) hintTable
265: .get(key);
266:
267: // If the key was not in the table it is not a public
268: // static field in one of the KEY_CLASSES so skip it.
269: if (keyElement == null) {
270: continue;
271: }
272:
273: // Get the next value.
274: Object value = hints.get(key);
275:
276: // Pack the key/value pair in a Hashtable entry.
277: HintElement valueElement = null;
278: try {
279: // Try to create a HintElement from the value directly.
280: valueElement = new HintElement(value);
281: } catch (NotSerializableException nse) {
282: // The value is not serializable so try to get a
283: // HintElement from the table in case the value is
284: // a public static field in one of the KEY_CLASSES.
285: valueElement = (HintElement) hintTable
286: .get(value);
287: }
288:
289: // If the value element is valid add it and its key.
290: if (valueElement != null) {
291: table.put(keyElement, valueElement);
292: }
293: }
294: }
295: }
296:
297: // Write serialized form to the stream.
298: out.writeObject(table);
299: }
300:
301: /**
302: * Deserialize the RenderingHintsProxy.
303: */
304: private void readObject(ObjectInputStream in) throws IOException,
305: ClassNotFoundException {
306: // Read serialized form from the stream.
307: Hashtable table = (Hashtable) in.readObject();
308:
309: // Create an empty RenderingHints object.
310: hints = new RenderingHints(null);
311:
312: // If the table is empty just return.
313: if (table.isEmpty()) {
314: return;
315: }
316:
317: // -- Restore the transient RenderingHints object. --
318:
319: // Get an enumeration of the table keys.
320: Enumeration keys = table.keys();
321:
322: // Loop over the table keys.
323: while (keys.hasMoreElements()) {
324: // Get the next key element.
325: HintElement keyElement = (HintElement) keys.nextElement();
326:
327: // Get the key object corresponding to this key element.
328: Object key = keyElement.getObject();
329:
330: // Get the value element.
331: HintElement valueElement = (HintElement) table
332: .get(keyElement);
333:
334: // Get the value object corresponding to this value element.
335: Object value = valueElement.getObject();
336:
337: // Add an entry to the hints.
338: hints.put(key, value);
339: }
340: }
341: }
|