Hi Jukka,
I have some more adaptions for the JCR-RMI value implementation: StatefullValueAdapter needs read/writeObject as does BinaryValue. On the other hand SerialValue does not need it.
How about renaming StatefullValue* ? At least the double-l should be changed to single-l.
Regards Felix
Index: src/java/org/apache/jackrabbit/value/StatefullValueAdapter.java
===================================================================
--- src/java/org/apache/jackrabbit/value/StatefullValueAdapter.java
(revision 169423)
+++ src/java/org/apache/jackrabbit/value/StatefullValueAdapter.java
(working copy)
@@ -16,24 +16,47 @@
*/
package org.apache.jackrabbit.value;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.util.Calendar;
+import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
/**
- * The <code>StatefullValueAdapter</code> class
+ * The <code>StatefullValueAdapter</code> class implements the committed value
+ * state for some JCR <code>Value</code> as a part of the State design pattern
+ * (Gof) used by this package.
+ * <p>
+ * This class implements [EMAIL PROTECTED] #readObject(ObjectInputStream)} and
+ * [EMAIL PROTECTED] #writeObject(ObjectOutputStream)} overwriting the default
behaviour.
+ * The reason for this is, that we cannot guarantee delegatee value to be
+ * serializable in which case the [EMAIL PROTECTED]
#writeObject(ObjectOutputStream)}
+ * must first create a serializable value. The
+ * [EMAIL PROTECTED] #readObject(ObjectInputStream)} method is here just to
guarantee
+ * symetric implementation.
+ *
+ * @version $Revision$, $Date$
+ * @author Felix Meschberger
+ * @since 0.16.4.1
*
- * @version $Revision$, $Date$
- * @author fmeschbe
- * @since
+ * @see SerialValue
*/
final class StatefullValueAdapter implements StatefullValue {
- private final Value delegatee;
+ /** The delegatee value. */
+ private Value delegatee;
+ /**
+ * Creates an instance adapting the given JCR <code>Value</code> to the
+ * State design pattern.
+ *
+ * @param delegatee The JCR <code>Value</code> providing the value date.
+ */
StatefullValueAdapter(Value delegatee) {
this.delegatee = delegatee;
}
@@ -72,4 +95,94 @@
public int getType() {
return delegatee.getType();
}
+
+ /**
+ * Writes the delegate value to the given <code>ObjectOutputStream</code>.
+ * If the delegatee is [EMAIL PROTECTED] SerialValue} it is directly
written. Otherwise
+ * the [EMAIL PROTECTED] SerialValueFactory} is asked to create a [EMAIL
PROTECTED] StatefullValue}
+ * from the delegatee, which is then written. The newly created
+ * [EMAIL PROTECTED] StatefullValue} value also replaces the original
delegatee
+ * internally.
+ *
+ * @param out The destination to write the delegatee to.
+ *
+ * @throws IOException If an error occurrs writing the value or if an
+ * error occurrs creating the [EMAIL PROTECTED] StatefullValue} from
the
+ * delegatee.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ // if the delegatee value is a StatefullValue or SerialValue,
serialize it
+ if (delegatee instanceof StatefullValue ||
+ delegatee instanceof SerialValue) {
+ out.writeObject(delegatee);
+ return;
+ }
+
+ // otherwise create a SerialValue from the delegatee value to send
+ try {
+ SerialValueFactory factory = SerialValueFactory.getInstance();
+ Value toSend;
+ switch (getType()) {
+ case PropertyType.BINARY:
+ toSend = factory.createBinaryValue(getStream());
+ break;
+ case PropertyType.BOOLEAN:
+ toSend = factory.createBooleanValue(getBoolean());
+ break;
+ case PropertyType.DATE:
+ toSend = factory.createDateValue(getDate());
+ break;
+ case PropertyType.DOUBLE:
+ toSend = factory.createDoubleValue(getDouble());
+ break;
+ case PropertyType.LONG:
+ toSend = factory.createLongValue(getLong());
+ break;
+ case PropertyType.NAME:
+ toSend = factory.createNameValue(getString());
+ break;
+ case PropertyType.PATH:
+ toSend = factory.createPathValue(getString());
+ break;
+ case PropertyType.REFERENCE:
+ toSend = factory.createReferenceValue(getString());
+ break;
+ case PropertyType.STRING:
+ toSend = factory.createStringValue(getString());
+ break;
+ default:
+ throw new IOException("Unknown value type");
+ }
+
+ // replace the delegatee with the new one
+ delegatee = toSend;
+
+ // and finally send the serial value instance
+ out.writeObject(toSend);
+ } catch (RepositoryException ex) {
+ throw new IOException(ex.getMessage());
+ }
+ }
+
+ /**
+ * Reads an reconstructs the delegatee from the given
+ * <code>ObjectInputStream</code>. The value read will either be an
+ * instance of [EMAIL PROTECTED] SerialValue} or a [EMAIL PROTECTED]
StatefullValue} depending
+ * on the original delegatee written.
+ *
+ * @param in The <code>ObjectInputStream</code> from which to read the
+ * delegatee.
+ *
+ * @throws IOException If an error occurrs reading from the
+ * <code>ObjectInputStream</code> or if the runtime class of the
+ * value to be read cannot be found.
+ */
+ private void readObject(ObjectInputStream in) throws IOException {
+ try {
+ delegatee = (Value) in.readObject();
+ } catch (ClassNotFoundException cnfe) {
+ throw new IOException("Cannot load value object class: " +
+ cnfe.getMessage());
+ }
+ }
}
Index: src/java/org/apache/jackrabbit/value/SerialValue.java
===================================================================
--- src/java/org/apache/jackrabbit/value/SerialValue.java (revision
169423)
+++ src/java/org/apache/jackrabbit/value/SerialValue.java (working copy)
@@ -16,16 +16,10 @@
*/
package org.apache.jackrabbit.value;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Calendar;
-import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
@@ -35,8 +29,9 @@
* part of the State design pattern (GoF) used for managing the JCR Value
* states.
* <p>
- * Instances of this class are issued by the [EMAIL PROTECTED]
org.apache.jackrabbit.value.SerialValueFactory}
- * and are <code>Serializable</code>.
+ * Instances of this class are issued by the
+ * [EMAIL PROTECTED] org.apache.jackrabbit.value.SerialValueFactory} and are
+ * <code>Serializable</code>.
*
* @see org.apache.jackrabbit.value.SerialValueFactory
*/
@@ -188,117 +183,4 @@
public int getType() {
return type;
}
-
- //---------- Serializable interface support
--------------------------------
-
- /**
- * Serializes the underlying Value object. Instead of using
- * the normal serialization mechanism, the essential state
- * of the Value object is extracted and written to the serialization
- * stream as a type-value pair.
- *
- * @param out the serialization stream
- * @throws IOException on IO errors
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- try {
- // write real type
- out.writeInt(type);
-
- switch (type) {
- case PropertyType.BINARY:
- InputStream data = value.getStream();
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- byte[] bytes = new byte[4096];
- for (int n = data.read(bytes); n != -1; n = data
- .read(bytes)) {
- buffer.write(bytes, 0, n);
- }
- out.writeInt(buffer.size());
- buffer.writeTo(out);
- break;
- case PropertyType.BOOLEAN:
- out.writeBoolean(value.getBoolean());
- break;
- case PropertyType.DATE:
- out.writeObject(value.getDate());
- break;
- case PropertyType.DOUBLE:
- out.writeDouble(value.getDouble());
- break;
- case PropertyType.LONG:
- out.writeLong(value.getLong());
- break;
- case PropertyType.NAME:
- case PropertyType.PATH:
- case PropertyType.REFERENCE:
- case PropertyType.STRING:
- out.writeUTF(value.getString());
- break;
- default:
- throw new IOException("Unknown value type");
- }
- } catch (RepositoryException ex) {
- throw new IOException(ex.getMessage());
- }
- }
-
- /**
- * Deserializes the underlying Value object. A new Value object
- * is created based on the type and state data read fro the
- * serialization stream.
- *
- * @param in the serialization stream
- * @throws IOException on IO errors
- */
- private void readObject(ObjectInputStream in) throws IOException {
- try {
- SerialValueFactory factory = SerialValueFactory.getInstance();
- StatefullValue realValue;
- int type = in.readInt();
- switch (type) {
- case PropertyType.BINARY:
- byte[] bytes = new byte[in.readInt()];
- in.readFully(bytes);
- ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
- realValue = factory.createBinaryValue(bin);
- break;
- case PropertyType.BOOLEAN:
- realValue = factory.createBooleanValue(in.readBoolean());
- break;
- case PropertyType.DATE:
- realValue = factory.createDateValue((Calendar)
in.readObject());
- break;
- case PropertyType.DOUBLE:
- realValue = factory.createDoubleValue(in.readDouble());
- break;
- case PropertyType.LONG:
- realValue = factory.createLongValue(in.readLong());
- break;
- case PropertyType.NAME:
- realValue = factory.createNameValue(in.readUTF());
- break;
- case PropertyType.PATH:
- realValue = factory.createPathValue(in.readUTF());
- break;
- case PropertyType.REFERENCE:
- realValue = factory.createReferenceValue(in.readUTF());
- break;
- case PropertyType.STRING:
- realValue = factory.createStringValue(in.readUTF());
- break;
- default:
- throw new IllegalStateException("Illegal serial value
type");
- }
-
- // now we set the fields
- this.type = type;
- this.value = new InitialValue(this, realValue);
-
- } catch (ValueFormatException vfe) {
- throw new IOException(vfe.getMessage());
- } catch (ClassNotFoundException ex) {
- throw new IOException(ex.getMessage());
- }
- }
}
Index: src/java/org/apache/jackrabbit/value/BinaryValue.java
===================================================================
--- src/java/org/apache/jackrabbit/value/BinaryValue.java (revision
169423)
+++ src/java/org/apache/jackrabbit/value/BinaryValue.java (working copy)
@@ -17,7 +17,11 @@
package org.apache.jackrabbit.value;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
@@ -33,6 +37,10 @@
* created through the [EMAIL PROTECTED] #getStream()} method but does not
close the
* stream. It is the sole responsibility of the user of this value to close the
* stream if not needed anymore to prevent memory loss.
+ * <p>
+ * This class implements [EMAIL PROTECTED] #readObject(ObjectInputStream)} and
+ * [EMAIL PROTECTED] #writeObject(ObjectOutputStream)} methods to
(de-)serialize the
+ * data.
*
* @version $Revision$, $Date$
* @author Jukka Zitting
@@ -43,7 +51,7 @@
public class BinaryValue implements StatefullValue {
/** The <code>InputStream</code> providing the value */
- private final InputStream stream;
+ private InputStream stream;
/**
* Creates an instance on the given <code>InputStream</code>. This exact
@@ -157,4 +165,50 @@
public boolean getBoolean() {
throw new IllegalStateException("Stream already retrieved");
}
+
+ /**
+ * Writes the contents of the underlying stream to the
+ * <code>ObjectOutputStream</code> by first copying to an internal byte
+ * array.
+ *
+ * @param out The <code>ObjectOutputStream</code> to where the binary
+ * data is copied.
+ *
+ * @throws IOException If an error occurrs writing the binary data.
+ * @throws OutOfMemoryError If not enouhg memory is available to store the
+ * binary data in the internal byte array.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ // read the input into a byte array - limited by memory available !!
+ ByteArrayOutputStream bos =
+ new ByteArrayOutputStream(stream.available());
+ byte[] buf = new byte[2048];
+ int rd = 0;
+ while ((rd = stream.read(buf)) >= 0) {
+ bos.write(buf, 0, rd);
+ }
+
+ // stream the data to the object output
+ out.writeInt(bos.size());
+ out.write(bos.toByteArray());
+ }
+
+ /**
+ * Reads the binary data from the <code>ObjectInputStream</code> into an
+ * internal byte array, which is then provided through a
+ * <code>ByteArrayInputStream</code>.
+ *
+ * @param in The <code>ObjectInputStream</code> from where to get the
+ * binary data.
+ *
+ * @throws IOException If an error occurrs reading the binary data.
+ * @throws OutOfMemoryError If not enouhg memory is available to store the
+ * binary data in the internal byte array.
+ */
+ private void readObject(ObjectInputStream in) throws IOException {
+ int size = in.readInt();
+ byte[] buf = new byte[size];
+ in.readFully(buf);
+ stream = new ByteArrayInputStream(buf);
+ }
}
\ No newline at end of file
