Permalink
Browse files

RIVER-416: Improved robustness of Levels serialization

git-svn-id: https://svn.apache.org/repos/asf/river/jtsk/trunk@1455692 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 5ae4701 commit 760f0c7b1320de32a01c5bff2bbb9e26868015a2 Dennis Reedy committed Mar 12, 2013
Showing with 95 additions and 48 deletions.
  1. +95 −48 src/com/sun/jini/logging/Levels.java
@@ -24,25 +24,27 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
+import java.io.ObjectStreamField;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.logging.Level;
/**
* Defines additional {@link Level} values. <p>
- * <p/>
+ *
* See the {@link LogManager} class for one way to use the <code>FAILED</code>
* and <code>HANDLED</code> logging levels in standard logging configuration
* files.
*
+ *
* @since 2.0
*/
public class Levels {
/**
* <code>FAILED</code> is a message level indicating that a facility has
* experienced a failure that it will reflect to its caller. <p>
- * <p/>
+ *
* <code>FAILED</code> messages are intended to provide users with
* information about failures produced by internal components in order to
* assist with debugging problems in systems with multiple components. This
@@ -54,38 +56,69 @@
* <code>HANDLED</code> is a message level indicating that a facility has
* detected a failure that it will take steps to handle without reflecting
* the failure to its caller. <p>
- * <p/>
+ *
* <code>HANDLED</code> messages are intended to provide users with
* information about failures detected by internal components in order to
* assist with debugging problems in systems with multiple components. This
* level is initialized to <code>550</code>.
*/
public static final Level HANDLED = createLevel("HANDLED", 550, null);
- /**
- * This class cannot be instantiated.
- */
+ /** This class cannot be instantiated. */
private Levels() {
- throw new AssertionError("This class cannot be instantiated");
+ throw new AssertionError("This class cannot be instantiated");
}
/**
* Defines a class that has the same data format as the Level class, to
* permit creating the serialized form of a Level instance.
*/
private static final class LevelData implements Serializable {
- private static final long serialVersionUID = -8176160795706313070L;
- private final String name;
- private final int value;
- private final String resourceBundleName;
- private final String localizedLevelName;
-
- LevelData(String name, int value, String resourceBundleName) {
- this.name = name;
- this.value = value;
- this.resourceBundleName = resourceBundleName;
- this.localizedLevelName = resourceBundleName == null ? name : null;
- }
+ /** Fields from {@link Level} that needs to be serialized. */
+ private static final ObjectStreamField[] serialPersistentFields =
+ ObjectStreamClass.lookup(Level.class).getFields();
+ private static final long serialVersionUID = -8176160795706313070L;
+ private transient final String name;
+ private transient final int value;
+ private transient final String resourceBundleName;
+
+ LevelData(String name, int value, String resourceBundleName) {
+ this.name = name;
+ this.value = value;
+ this.resourceBundleName = resourceBundleName;
+ }
+
+ /**
+ * Controls the writing of the actual fields to mimic those available
+ * in {@link Level}.
+ */
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException
+ {
+ ObjectOutputStream.PutField putFields = out.putFields();
+
+ for (int i = 0 ; i < serialPersistentFields.length ; i++) {
+ ObjectStreamField field = serialPersistentFields[i];
+
+ if (field.getName().equals("name")) {
+ putFields.put(field.getName(), name);
+ }
+ else if (field.getName().equals("resourceBundleName")) {
+ putFields.put(field.getName(), resourceBundleName);
+ }
+ else if (field.getName().equals("value")) {
+ putFields.put(field.getName(), value);
+ }
+
+ // if a field name is unknown it looks like the Level class
+ // evolved, but we are in no position to provide a meaningful
+ // value, so therefore don't provide a value as the putField
+ // object already has the default values set for all fields as
+ // returned by serialPersistentFields
+ }
+
+ out.writeFields();
+ }
}
/**
@@ -94,22 +127,30 @@ private Levels() {
* creating serialization data for a class when access to an appropriate
* constructor is not available.
*/
- private static final class ClassReplacingObjectOutputStream extends ObjectOutputStream {
- private final ObjectStreamClass from;
- private final ObjectStreamClass to;
-
- ClassReplacingObjectOutputStream(OutputStream out, Class from, Class to) throws IOException {
- super(out);
- this.from = ObjectStreamClass.lookup(from);
- this.to = ObjectStreamClass.lookup(to);
- }
-
- protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
- if (from.equals(desc)) {
- desc = to;
- }
- super.writeClassDescriptor(desc);
- }
+ private static final class ClassReplacingObjectOutputStream
+ extends ObjectOutputStream
+ {
+ private final ObjectStreamClass from;
+ private final ObjectStreamClass to;
+
+ ClassReplacingObjectOutputStream(OutputStream out,
+ Class from,
+ Class to)
+ throws IOException
+ {
+ super(out);
+ this.from = ObjectStreamClass.lookup(from);
+ this.to = ObjectStreamClass.lookup(to);
+ }
+
+ protected void writeClassDescriptor(ObjectStreamClass desc)
+ throws IOException
+ {
+ if (from.equals(desc)) {
+ desc = to;
+ }
+ super.writeClassDescriptor(desc);
+ }
}
/**
@@ -118,18 +159,24 @@ protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
* constructing the serialized form for an instance with the specified
* field values and deserializing it.
*/
- private static Level createLevel(String name, int value, String resourceBundleName) {
- try {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- ObjectOutputStream out = new ClassReplacingObjectOutputStream(bytes, LevelData.class, Level.class);
- out.writeObject(new LevelData(name, value, resourceBundleName));
- out.close();
- ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()));
- Level result = (Level) in.readObject();
- in.close();
- return result;
- } catch (Exception e) {
- throw new RuntimeException("Unexpected exception", e);
- }
+ private static Level createLevel(String name,
+ int value,
+ String resourceBundleName)
+ {
+ try {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ ObjectOutputStream out =
+ new ClassReplacingObjectOutputStream(
+ bytes, LevelData.class, Level.class);
+ out.writeObject(new LevelData(name, value, resourceBundleName));
+ out.close();
+ ObjectInputStream in = new ObjectInputStream(
+ new ByteArrayInputStream(bytes.toByteArray()));
+ Level result = (Level) in.readObject();
+ in.close();
+ return result;
+ } catch (Exception e) {
+ throw new RuntimeException("Unexpected exception", e);
+ }
}
}

0 comments on commit 760f0c7

Please sign in to comment.