001: /*
002: * $RCSfile: SerializerFactory.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:57:54 $
010: * $State: Exp $
011: */
012: package javax.media.jai.remote;
013:
014: import java.awt.RenderingHints;
015: import java.io.Serializable;
016: import java.util.ArrayList;
017: import java.util.Hashtable;
018: import java.util.Iterator;
019: import java.util.Vector;
020: import com.sun.media.jai.rmi.SerializerImpl;
021: import com.sun.media.jai.rmi.InterfaceState;
022:
023: /**
024: * A utility class which provides factory methods for obtaining
025: * <code>Serializer</code> instances.
026: *
027: * <p> The <code>Serializer</code>s are maintained in a centralized repository
028: * which is organized based on the classes supported by the
029: * <code>Serializer</code>s and the order in which the <code>Serializer</code>s
030: * were registered. Convenience methods similar to those defined in the
031: * <code>Serializer</code> class are also provided. These enable
032: * functionality equivalent to a single <code>Serializer</code> which
033: * supports all the classes supported by the aggregate of all
034: * <code>Serializer</code>s resident in the repository.
035: *
036: * <p> By default <code>Serializer</code>s for the following classes
037: * are registered by JAI:
038: *
039: * <ul>
040: * <li><code>java.awt.RenderingHints</code>
041: * <br>(entries which are neither <code>Serializable</code> nor supported by
042: * <code>SerializerFactory</code> are omitted; support for specific
043: * <code>RenderingHints.Key</code> subclasses may be added by new
044: * <code>Serializer</code>s);</li>
045: * <li><code>java.awt.RenderingHints.Key</code>
046: * <br>(limited to <code>RenderingHints.Key</code>s defined in
047: * <code>java.awt.RenderingHints</code> and <code>javax.media.jai.JAI</code>);
048: * </li>
049: * <li><code>java.awt.Shape</code>;</li>
050: * <li><code>java.awt.image.DataBufferByte</code>;</li>
051: * <li><code>java.awt.image.DataBufferShort</code>;</li>
052: * <li><code>java.awt.image.DataBufferUShort</code>;</li>
053: * <li><code>java.awt.image.DataBufferInt</code>;</li>
054: * <li><code>javax.media.jai.DataBufferFloat</code>;</li>
055: * <li><code>javax.media.jai.DataBufferDouble</code>;</li>
056: * <li><code>java.awt.image.ComponentSampleModel</code>;</li>
057: * <li><code>java.awt.image.BandedSampleModel</code>;</li>
058: * <li><code>java.awt.image.PixelInterleavedSampleModel</code>;</li>
059: * <li><code>java.awt.image.SinglePixelPackedSampleModel</code>;</li>
060: * <li><code>java.awt.image.MultiPixelPackedSampleModel</code>;</li>
061: * <li><code>javax.media.jai.ComponentSampleModelJAI</code>;</li>
062: * <li><code>java.awt.image.Raster</code>
063: * <br>(limited to <code>Raster</code>s which have a <code>DataBuffer</code>
064: * and <code>SampleModel</code> supported by a <code>Serializer</code>);</li>
065: * <li><code>java.awt.image.WritableRaster</code>
066: * <br>(limited to <code>WritableRaster</code>s which have a
067: * <code>DataBuffer</code> and <code>SampleModel</code> supported by a
068: * <code>Serializer</code>);</li>
069: * <li><code>java.awt.image.ComponentColorModel</code>;</li>
070: * <li><code>java.awt.image.IndexColorModel</code>;</li>
071: * <li><code>java.awt.image.DirectColorModel</code>;</li>
072: * <li><code>javax.media.jai.FloatColorModel</code>;</li>
073: * <li><code>java.awt.image.renderable.RenderContext</code>;</li>
074: * <br>(constrained by the aforementioned limitations of
075: * the <code>RenderingHints</code> <code>Serializer</code>);</li>
076: * <li><code>java.awt.image.RenderedImage</code>
077: * <br>(limited to <code>RenderedImage</code>s which have <code>Raster</code>s
078: * and a <code>ColorModel</code> supported by a <code>Serializer</code>);</li>
079: * <li><code>java.awt.image.WritableRenderedImage</code>
080: * <br>(limited to <code>WritableRenderedImage</code>s which have
081: * <code>Raster</code>s and a <code>ColorModel</code> supported by a
082: * <code>Serializer</code>);</li>
083: * <li><code>java.io.Serializable</code>;</li>
084: * <li><code>java.util.HashSet</code>
085: * <br>(elements which are neither <code>Serializable</code> nor supported by
086: * <code>SerializerFactory</code> are omitted);</li>
087: * <li><code>java.util.Hashtable</code>
088: * <br>(entries which are neither <code>Serializable</code> nor supported by
089: * <code>SerializerFactory</code> are omitted);</li>
090: * <li><code>java.util.Vector</code>
091: * <br>(elements which are neither <code>Serializable</code> nor supported by
092: * <code>SerializerFactory</code> are omitted);</li>
093: * </ul>
094: *
095: * @see SerializableState
096: * @see Serializer
097: * @see java.io.Serializable
098: *
099: * @since JAI 1.1
100: */
101: public final class SerializerFactory {
102:
103: /**
104: * <code>Serializer</code> hashed by supported <code>Class</code>.
105: * The value is a <code>Serializer</code> if there is only one for the
106: * given <code>Class</code> or a <code>Vector</code> if there are more.
107: */
108: private static Hashtable repository = new Hashtable();
109:
110: /**
111: * Singleton instance of <code>Serializer</code> for use with already
112: * <code>Serializable</code> classes.
113: */
114: private static Serializer serializableSerializer = new SerSerializer();
115:
116: static final SerializableState NULL_STATE = new SerializableState() {
117: public Class getObjectClass() {
118: return Object.class;
119: }
120:
121: public Object getObject() {
122: return null;
123: }
124: };
125:
126: static {
127: // Load all <code>Serializer</code>s defined in com.sun.media.jai.rmi.
128: SerializerImpl.registerSerializers();
129: }
130:
131: protected SerializerFactory() {
132: }
133:
134: /**
135: * Adds a <code>Serializer</code> to the repository.
136: *
137: * @param s The <code>Serializer</code>s to be added to the repository.
138: * @exception IllegalArgumentException if <code>s</code> is
139: * <code>null</code>
140: */
141: public static synchronized void registerSerializer(Serializer s) {
142: if (s == null) {
143: throw new IllegalArgumentException(JaiI18N
144: .getString("Generic0"));
145: }
146:
147: Class c = s.getSupportedClass();
148:
149: if (repository.containsKey(c)) {
150: Object value = repository.get(c);
151: if (value instanceof Vector) {
152: ((Vector) value).add(0, s);
153: } else {
154: Vector v = new Vector(2);
155: v.add(0, s);
156: v.add(1, value);
157: repository.put(c, v);
158: }
159: } else {
160: repository.put(c, s);
161: }
162: }
163:
164: /**
165: * Removes a <code>Serializer</code> from the repository.
166: *
167: * @param s The <code>Serializer</code>s to be removed from the repository.
168: * @exception IllegalArgumentException if <code>s</code> is
169: * <code>null</code>
170: */
171: public static synchronized void unregisterSerializer(Serializer s) {
172: if (s == null) {
173: throw new IllegalArgumentException(JaiI18N
174: .getString("Generic0"));
175: }
176:
177: Class c = s.getSupportedClass();
178: Object value = repository.get(c);
179: if (value != null) {
180: if (value instanceof Vector) {
181: Vector v = (Vector) value;
182: v.remove(s);
183: if (v.size() == 1) {
184: repository.put(c, v.get(0));
185: }
186: } else {
187: repository.remove(c);
188: }
189: }
190: }
191:
192: /**
193: * Retrieves an array of all <code>Serializer</code>s currently
194: * resident in the repository which directly support the specified
195: * <code>Class</code>. <code>Serializer</code>s which support
196: * a superclass of the specified class and permit subclass
197: * serialization will not be included.
198: *
199: * @param c The class for which <code>Serializer</code>s will be
200: * retrieved.
201: * @exception IllegalArgumentException if <code>c</code> is
202: * <code>null</code>.
203: */
204: public static synchronized Serializer[] getSerializers(Class c) {
205: if (c == null) {
206: throw new IllegalArgumentException(JaiI18N
207: .getString("Generic0"));
208: }
209: Object value = repository.get(c);
210: Serializer[] result = null;
211: if (value == null && Serializable.class.isAssignableFrom(c)) {
212: result = new Serializer[] { serializableSerializer };
213: } else if (value instanceof Vector) {
214: result = (Serializer[]) ((Vector) value)
215: .toArray(new Serializer[0]);
216: } else if (value != null) {
217: result = new Serializer[] { (Serializer) value };
218: }
219: return result;
220: }
221:
222: /**
223: * Retrieves a <code>Serializer</code> for a given class <code>c</code>.
224: * If more than one <code>Serializer</code> is available for the class
225: * then the most recently registered <code>Serializer</code> will be
226: * returned. If no registered <code>Serializer</code> exists which
227: * directly supports the specified class, i.e., one for which the
228: * <code>getSupportedClass()</code> returns a value equal to the
229: * specified class, then a <code>Serializer</code> may be returned
230: * which is actually registered against a superclass but permits
231: * subclass serialization.
232: *
233: * @param c The class for which <code>Serializer</code>s will be
234: * retrieved.
235: * @return A <code>Serializer</code> which supports the specified class.
236: * or <code>null</code> if none is available.
237: * @exception IllegalArgumentException if <code>c</code> is
238: * <code>null</code>.
239: *
240: * @see java.awt.image.BandedSampleModel
241: * @see java.awt.image.ComponentSampleModel
242: */
243: public static synchronized Serializer getSerializer(Class c) {
244: if (c == null) {
245: throw new IllegalArgumentException(JaiI18N
246: .getString("Generic0"));
247: }
248:
249: // Get the value from the repository.
250: Object value = repository.get(c);
251:
252: // If null, attempt to find a superclass Serializer.
253: if (value == null) {
254: Class theClass = c;
255: while (theClass != java.lang.Object.class) {
256: Class theSuperclass = theClass.getSuperclass();
257: if (isSupportedClass(theSuperclass)) {
258: Serializer s = getSerializer(theSuperclass);
259: if (s.permitsSubclasses()) {
260: value = s;
261: break;
262: }
263: }
264: theClass = theSuperclass;
265: }
266: }
267:
268: if (value == null && Serializable.class.isAssignableFrom(c)) {
269: value = serializableSerializer;
270: }
271:
272: // Return the highest priority Serializer or null.
273: return value instanceof Vector ? (Serializer) ((Vector) value)
274: .get(0) : (Serializer) value;
275: }
276:
277: /**
278: * Whether there is currently resident in the repository a
279: * <code>Serializer</code> the <code>getSupportedClass()</code>
280: * method of which returns a value equal to the parameter supplied
281: * to this method according to <code>equals()</code>.
282: *
283: * @param c The class to be tested for compatibility.
284: * @return Whether the specified class is directly supported.
285: * @exception IllegalArgumentException if <code>c</code> is
286: * <code>null</code>
287: */
288: public static boolean isSupportedClass(Class c) {
289: if (c == null) {
290: throw new IllegalArgumentException(JaiI18N
291: .getString("Generic0"));
292: } else if (Serializable.class.isAssignableFrom(c)) {
293: return true;
294: }
295: return repository.containsKey(c);
296: }
297:
298: /**
299: * Returns an array listing all classes and interfaces on which the
300: * <code>isSupportedClass()</code> method of this class may be invoked
301: * and return <code>true</code>.
302: *
303: * @return An array of all supported classes and interfaces.
304: */
305: public static Class[] getSupportedClasses() {
306: Class[] classes = new Class[repository.size() + 1];
307: repository.keySet().toArray(classes);
308: classes[classes.length - 1] = Serializable.class;
309: return classes;
310: }
311:
312: /**
313: * Determines the <code>Class</code> of which the deserialized form of the
314: * supplied <code>Class</code> will be an instance. Specifically, this
315: * method returns the <code>Class</code> of the <code>Object</code>
316: * returned by invoking <code>getObject()</code> on the
317: * <code>SerializableState</code> returned by <code>getState()</code>
318: * after the state object has been serialized and deserialized. The
319: * returned value will equal the supplied argument unless there is no
320: * <code>Serializer</code> explicitly registered for this class but there
321: * is a <code>Serializer</code> registered for a superclass with a
322: * <code>permitsSubclasses()</code> method that returns
323: * <code>true</code>.
324: *
325: * @param The <code>Class</code> for which the deserialized class type is
326: * requested.
327: * @return The deserialized <code>Class</code> or <code>null</code>.
328: * @exception IllegalArgumentException if <code>c</code> is
329: * <code>null</code>
330: */
331: public static Class getDeserializedClass(Class c) {
332: if (c == null) {
333: throw new IllegalArgumentException(JaiI18N
334: .getString("Generic0"));
335: }
336:
337: Class deserializedClass = null;
338:
339: // Try to find a superclass Serializer.
340: if (isSupportedClass(c)) {
341: deserializedClass = c;
342: } else {
343: Class theClass = c;
344: while (theClass != java.lang.Object.class) {
345: Class theSuperclass = theClass.getSuperclass();
346: if (isSupportedClass(theSuperclass)) {
347: Serializer s = getSerializer(theSuperclass);
348: if (s.permitsSubclasses()) {
349: deserializedClass = theSuperclass;
350: break;
351: }
352: }
353: theClass = theSuperclass;
354: }
355: }
356:
357: return deserializedClass;
358: }
359:
360: /**
361: * Converts an object into a state-preserving object which may
362: * be serialized. If the class of the object parameter is supported
363: * explicitly, i.e., <code>isSupportedClass(o.getClass())</code>
364: * returns <code>true</code>, then the object will be converted into
365: * a form which may be deserialized into an instance of the same class.
366: * If the class is not supported explicitly but implements one or
367: * more supported interfaces, then it will be converted into a
368: * form which may be deserialized into an instance of an unspecified
369: * class which implements all interfaces which are both implemented by
370: * the class of the object and supported by some <code>Serializer</code>
371: * currently resident in the repository. If the object is
372: * <code>null</code>, the returned <code>SerializableState</code> will
373: * return <code>null</code> from its <code>getObject()</code> method
374: * and <code>java.lang.Object.class</code> from its
375: * <code>getObjectClass()</code> method.
376: *
377: * @param o The object to be converted into a serializable form.
378: * @param h Configuration parameters the exact nature of which is
379: * <code>Serializer</code>-dependent. If <code>null</code>,
380: * reasonable default settings should be used.
381: * @return A serializable form of the supplied object.
382: * @exception IllegalArgumentException if <code>o</code> is
383: * non-<code>null</code> and either
384: * <code>isSupportedClass(o.getClass())</code> returns
385: * <code>false</code>, or <code>o</code>
386: * is not an instance of a class supported by a
387: * <code>Serializer</code> in the repository or which
388: * implements at least one interface supported by some
389: * <code>Serializer</code>s in the repository.
390: */
391: public static SerializableState getState(Object o, RenderingHints h) {
392: if (o == null) {
393: return NULL_STATE;
394: }
395:
396: Class c = o.getClass();
397: SerializableState state = null;
398: if (isSupportedClass(c)) {
399: // Found an explicit Serializer.
400: Serializer s = getSerializer(c);
401: state = s.getState(o, h);
402: } else {
403: // Try to find a superclass Serializer.
404: Class theClass = c;
405: while (theClass != java.lang.Object.class) {
406: Class theSuperclass = theClass.getSuperclass();
407: if (isSupportedClass(theSuperclass)) {
408: Serializer s = getSerializer(theSuperclass);
409: if (s.permitsSubclasses()) {
410: state = s.getState(o, h);
411: break;
412: }
413: }
414: theClass = theSuperclass;
415: }
416:
417: if (state == null) {
418:
419: // Try an interface Serializer.
420: Class[] interfaces = getInterfaces(c);
421: Vector serializers = null;
422: int numInterfaces = (interfaces == null) ? 0
423: : interfaces.length;
424: for (int i = 0; i < numInterfaces; i++) {
425: Class iface = interfaces[i];
426: if (isSupportedClass(iface)) {
427: if (serializers == null) {
428: serializers = new Vector();
429: }
430: serializers.add(getSerializer(iface));
431: }
432: }
433:
434: int numSupportedInterfaces = serializers == null ? 0
435: : serializers.size();
436: if (numSupportedInterfaces == 0) {
437: throw new IllegalArgumentException(JaiI18N
438: .getString("SerializerFactory1"));
439: } else if (numSupportedInterfaces == 1) {
440: state = ((Serializer) serializers.get(0)).getState(
441: o, h);
442: } else {
443: Serializer[] sArray = (Serializer[]) serializers
444: .toArray(new Serializer[0]);
445: state = new InterfaceState(o, sArray, h);
446: }
447: }
448: }
449:
450: return state;
451: }
452:
453: /**
454: * Retrieve the interfaces implemented by the specified class and all
455: * its superclasses.
456: */
457: private static Class[] getInterfaces(Class c) {
458: if (c == null) {
459: throw new IllegalArgumentException(JaiI18N
460: .getString("Generic0"));
461: }
462:
463: ArrayList interfaces = new ArrayList();
464: Class laClasse = c;
465: while (!(laClasse == java.lang.Object.class)) {
466: Class[] iFaces = laClasse.getInterfaces();
467: if (iFaces != null) {
468: for (int i = 0; i < iFaces.length; i++) {
469: interfaces.add(iFaces[i]);
470: }
471: }
472: laClasse = laClasse.getSuperclass();
473: }
474:
475: return interfaces.size() == 0 ? null : (Class[]) interfaces
476: .toArray(new Class[interfaces.size()]);
477: }
478:
479: /**
480: * A convenience wrapper around
481: * <code>getState(Object o, RenderingHints h)</code> with
482: * the <code>RenderingHints</code> parameter <code>h</code> set
483: * to <code>null</code>.
484: */
485: public static final SerializableState getState(Object o) {
486: return getState(o, null);
487: }
488: }
489:
490: /**
491: * A <code>Serializer</code> for <code>Serializable</code> objects.
492: */
493: class SerSerializer implements Serializer {
494: SerSerializer() {
495: }
496:
497: public Class getSupportedClass() {
498: return Serializable.class;
499: }
500:
501: public boolean permitsSubclasses() {
502: return true;
503: }
504:
505: public SerializableState getState(Object o, RenderingHints h) {
506: if (o == null) {
507: return SerializerFactory.NULL_STATE;
508: } else if (!(o instanceof Serializable)) {
509: throw new IllegalArgumentException(JaiI18N
510: .getString("SerializerFactory2"));
511: }
512: return new SerState((Serializable) o);
513: }
514: }
515:
516: /**
517: * <code>SerializableState</code> which simply wraps an object that is
518: * already an instance of <code>Serializable</code>.
519: */
520: class SerState implements SerializableState {
521: private Serializable object;
522:
523: SerState(Serializable object) {
524: if (object == null) {
525: throw new IllegalArgumentException(JaiI18N
526: .getString("Generic0"));
527: }
528: this .object = object;
529: }
530:
531: public Class getObjectClass() {
532: return object.getClass();
533: }
534:
535: public Object getObject() {
536: return object;
537: }
538: }
|