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