[jboss-remoting-commits] JBoss Remoting SVN: r5498 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3.

jboss-remoting-commits at lists.jboss.org jboss-remoting-commits at lists.jboss.org
Wed Sep 16 12:36:28 EDT 2009


Author: david.lloyd at jboss.com
Date: 2009-09-16 12:36:27 -0400 (Wed, 16 Sep 2009)
New Revision: 5498

Modified:
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Option.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/OptionMap.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java
Log:
Make options and option maps serializable

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Option.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Option.java	2009-09-16 16:09:24 UTC (rev 5497)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Option.java	2009-09-16 16:36:27 UTC (rev 5498)
@@ -23,18 +23,27 @@
 package org.jboss.remoting3;
 
 import java.util.Collection;
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 
 /**
- * A strongly-typed option to configure an aspect of a service.  Options are immutable and use identity comparisons
- * and hash codes, and they are not serializable.
+ * A strongly-typed option to configure an aspect of a service or connection.  Options are immutable and use identity comparisons
+ * and hash codes.  Options should always be declared as {@code public static final} members in order to support serialization.
  *
  * @param <T> the option value type
  */
-public abstract class Option<T> {
+public abstract class Option<T> implements Serializable {
 
+    private static final long serialVersionUID = -1564427329140182760L;
+
+    private final Class<?> declClass;
     private final String name;
 
-    Option(final String name) {
+    Option(final Class<?> declClass, final String name) {
+        this.declClass = declClass;
         if (name == null) {
             throw new NullPointerException("name is null");
         }
@@ -45,39 +54,40 @@
      * Create an option with a simple type.  The class object given <b>must</b> represent some immutable type, otherwise
      * unexpected behavior may result.
      *
-     * @param name the name of this option
+     * @param declClass the declaring class of the option
+     * @param name the (field) name of this option
      * @param type the class of the value associated with this option
-     * @param <T> the type of the value associated with this option
      * @return the option instance
      */
-    public static <T> Option<T> simple(final String name, final Class<T> type) {
-        return new SingleOption<T>(name, type);
+    public static <T> Option<T> simple(final Class<?> declClass, final String name, final Class<T> type) {
+        return new SingleOption<T>(declClass, name, type);
     }
 
     /**
      * Create an option with a sequence type.  The class object given <b>must</b> represent some immutable type, otherwise
      * unexpected behavior may result.
      *
-     * @param name the name of this option
+     * @param declClass the declaring class of the option
+     * @param name the (field) name of this option
      * @param elementType the class of the sequence element value associated with this option
-     * @param <T> the type of the sequence element value associated with this option
      * @return the option instance
      */
-    public static <T> Option<Sequence<T>> sequence(final String name, final Class<T> elementType) {
-        return new SequenceOption<T>(name, elementType);
+    public static <T> Option<Sequence<T>> sequence(final Class<?> declClass, final String name, final Class<T> elementType) {
+        return new SequenceOption<T>(declClass, name, elementType);
     }
 
     /**
      * Create an option with a flag set type.  The class object given <b>must</b> represent some immutable type, otherwise
      * unexpected behavior may result.
      *
-     * @param name the name of this option
+     * @param declClass the declaring class of the option
+     * @param name the (field) name of this option
      * @param elementType the class of the flag values associated with this option
      * @param <T> the type of the flag values associated with this option
      * @return the option instance
      */
-    public static <T extends Enum<T>> Option<FlagSet<T>> flags(final String name, final Class<T> elementType) {
-        return new FlagsOption<T>(name, elementType);
+    public static <T extends Enum<T>> Option<FlagSet<T>> flags(final Class<?> declClass, final String name, final Class<T> elementType) {
+        return new FlagsOption<T>(declClass, name, elementType);
     }
 
     /**
@@ -90,6 +100,15 @@
     }
 
     /**
+     * Get a human-readible string representation of this object.
+     *
+     * @return the string representation
+     */
+    public String toString() {
+        return super.toString() + " (" + declClass.getName() + "#" + name + ")";
+    }
+
+    /**
      * Return the given object as the type of this option.  If the cast could not be completed, an exception is thrown.
      *
      * @param o the object to cast
@@ -97,14 +116,40 @@
      * @throws ClassCastException if the object is not of a compatible type
      */
     public abstract T cast(Object o) throws ClassCastException;
+
+    /**
+     * Resolve this instance for serialization.
+     *
+     * @return the resolved object
+     * @throws ObjectStreamException if the object could not be resolved
+     */
+    protected final Object readResolve() throws ObjectStreamException {
+        try {
+            final Field field = declClass.getField(name);
+            final int modifiers = field.getModifiers();
+            if (! Modifier.isProtected(modifiers)) {
+                throw new InvalidObjectException("Invalid Option instance (the field is not public)");
+            }
+            if (! Modifier.isStatic(modifiers)) {
+                throw new InvalidObjectException("Invalid Option instance (the field is not static)");
+            }
+            return field.get(null);
+        } catch (NoSuchFieldException e) {
+            throw new InvalidObjectException("Invalid Option instance (no matching field)");
+        } catch (IllegalAccessException e) {
+            throw new InvalidObjectException("Invalid Option instance (Illegal access on field get)");
+        }
+    }
 }
 
 final class SingleOption<T> extends Option<T> {
 
-    private final Class<T> type;
+    private static final long serialVersionUID = 2449094406108952764L;
 
-    SingleOption(final String name, final Class<T> type) {
-        super(name);
+    private transient final Class<T> type;
+
+    SingleOption(final Class<?> declClass, final String name, final Class<T> type) {
+        super(declClass, name);
         this.type = type;
     }
 
@@ -114,10 +159,13 @@
 }
 
 final class SequenceOption<T> extends Option<Sequence<T>> {
-    private final Class<T> elementType;
 
-    SequenceOption(final String name, final Class<T> elementType) {
-        super(name);
+    private static final long serialVersionUID = -4328676629293125136L;
+
+    private transient final Class<T> elementType;
+
+    SequenceOption(final Class<?> declClass, final String name, final Class<T> elementType) {
+        super(declClass, name);
         this.elementType = elementType;
     }
 
@@ -136,10 +184,12 @@
 
 final class FlagsOption<T extends Enum<T>> extends Option<FlagSet<T>> {
 
-    private final Class<T> elementType;
+    private static final long serialVersionUID = -5487268452958691541L;
 
-    FlagsOption(final String name, final Class<T> elementType) {
-        super(name);
+    private transient final Class<T> elementType;
+
+    FlagsOption(final Class<?> declClass, final String name, final Class<T> elementType) {
+        super(declClass, name);
         this.elementType = elementType;
     }
 

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/OptionMap.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/OptionMap.java	2009-09-16 16:09:24 UTC (rev 5497)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/OptionMap.java	2009-09-16 16:36:27 UTC (rev 5498)
@@ -28,12 +28,15 @@
 import java.util.Map;
 import java.util.Collections;
 import java.util.IdentityHashMap;
+import java.io.Serializable;
 
 /**
  * An immutable map of options to option values.  No {@code null} keys or values are permitted.
  */
-public final class OptionMap implements Iterable<Option<?>> {
+public final class OptionMap implements Iterable<Option<?>>, Serializable {
 
+    private static final long serialVersionUID = 3632842565346928132L;
+
     private final Map<Option<?>, Object> value;
 
     private OptionMap(final Map<Option<?>, Object> value) {

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java	2009-09-16 16:09:24 UTC (rev 5497)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java	2009-09-16 16:36:27 UTC (rev 5498)
@@ -34,45 +34,45 @@
      * Request that the marshalling layer require the use of one of the listed marshalling protocols, in order of decreasing preference.  If
      * not specified, use a default value.  The marshaller {@code "default"} can be specified explicitly for this default value.
      */
-    public static final Option<Sequence<String>> MARSHALLING_PROTOCOLS = Option.sequence("jboss.remoting3.marshalling.protocols", String.class);
+    public static final Option<Sequence<String>> MARSHALLING_PROTOCOLS = Option.sequence(Options.class, "MARSHALLING_PROTOCOLS", String.class);
 
     /**
      * Request that the marshalling layer require the presense of one of the listed user-defined class tables, in order of decreasing preference.  If
      * not specified, no user class table should be used.
      */
-    public static final Option<Sequence<String>> MARSHALLING_CLASS_TABLES = Option.sequence("jboss.remoting3.marshalling.classTables", String.class);
+    public static final Option<Sequence<String>> MARSHALLING_CLASS_TABLES = Option.sequence(Options.class, "MARSHALLING_CLASS_TABLES", String.class);
 
     /**
      * Request that the marshalling layer require the presense of one of the listed user-defined object tables, in order of decreasing preference.  If
      * not specified, no user object table should be used.
      */
-    public static final Option<Sequence<String>> MARSHALLING_OBJECT_TABLES = Option.sequence("jboss.remoting3.marshalling.objectTables", String.class);
+    public static final Option<Sequence<String>> MARSHALLING_OBJECT_TABLES = Option.sequence(Options.class, "MARSHALLING_OBJECT_TABLES", String.class);
 
     /**
      * Request that the marshalling layer require the presense of one of the listed class resolvers, in order of decreasing preference.  If
      * not specified, classes are resolved on the remote side using a default strategy.
      */
-    public static final Option<Sequence<String>> MARSHALLING_CLASS_RESOLVERS = Option.sequence("jboss.remoting3.marshalling.classResolvers", String.class);
+    public static final Option<Sequence<String>> MARSHALLING_CLASS_RESOLVERS = Option.sequence(Options.class, "MARSHALLING_CLASS_RESOLVERS", String.class);
 
     /**
      * Request that the marshalling layer require the presense of one of the listed object resolvers, in order of decreasing preference.  If
      * not specified, no object substitution will take place.
      */
-    public static final Option<Sequence<String>> MARSHALLING_OBJECT_RESOLVERS = Option.sequence("jboss.remoting3.marshalling.objectResolvers", String.class);
+    public static final Option<Sequence<String>> MARSHALLING_OBJECT_RESOLVERS = Option.sequence(Options.class, "MARSHALLING_OBJECT_RESOLVERS", String.class);
 
     /**
      * Request that the marshalling layer require the presense of one of the listed user-defined externalizer factories, in order of decreasing preference.  If
      * not specified, no user externalizer factory should be used.
      */
-    public static final Option<Sequence<String>> MARSHALLING_EXTERNALIZER_FACTORIES = Option.sequence("jboss.remoting3.marshalling.externalizerFactories", String.class);
+    public static final Option<Sequence<String>> MARSHALLING_EXTERNALIZER_FACTORIES = Option.sequence(Options.class, "MARSHALLING_EXTERNALIZER_FACTORIES", String.class);
 
     /**
      * Specify a metric which is a hint that describes the relative desirability of this service.
      */
-    public static final Option<Integer> METRIC = Option.simple("jboss.remoting3.metric", Integer.class);
+    public static final Option<Integer> METRIC = Option.simple(Options.class, "METRIC", Integer.class);
 
     /**
      * Specify that the registered service should or should not be visible remotely.  If not specified, defaults to {@code true}.
      */
-    public static final Option<Boolean> REMOTELY_VISIBLE = Option.simple("jboss.remoting3.remotelyVisible", Boolean.class);
+    public static final Option<Boolean> REMOTELY_VISIBLE = Option.simple(Options.class, "REMOTELY_VISIBLE", Boolean.class);
 }



More information about the jboss-remoting-commits mailing list