Author: david.lloyd(a)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);
}