Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BinaryValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BinaryValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BinaryValue.java	(working copy)
@@ -16,36 +16,22 @@
  */
 package org.apache.jackrabbit.value;
 
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
+import java.util.Calendar;
 
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+
 /**
  * A <code>BinaryValue</code> provides an implementation
  * of the <code>Value</code> interface representing a binary value.
  */
-public class BinaryValue extends BaseValue {
+public class BinaryValue implements Value {
 
-    public static final int TYPE = PropertyType.BINARY;
-
-    // those fields are mutually exclusive, i.e. only one can be non-null
-    private byte[] streamData = null;
-    private String text = null;
-
     /**
-     * Constructs a <code>BinaryValue</code> object based on a string.
-     *
-     * @param text the string this <code>BinaryValue</code> should represent
+     * The binary value.
      */
-    public BinaryValue(String text) {
-        super(TYPE);
-        this.text = text;
-    }
+    private final InputStream stream;
 
     /**
      * Constructs a <code>BinaryValue</code> object based on a stream.
@@ -53,141 +39,77 @@
      * @param stream the stream this <code>BinaryValue</code> should represent
      */
     public BinaryValue(InputStream stream) {
-        super(TYPE);
         this.stream = stream;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Constructs a <code>BinaryValue</code> object based on a stream.
+     * Returns {@link PropertyType#BINARY}.
      *
-     * @param data the stream this <code>BinaryValue</code> should represent
+     * @return {@link PropertType#BINARY}
      */
-    public BinaryValue(byte[] data) {
-        super(TYPE);
-        streamData = data;
+    public int getType() {
+        return PropertyType.BINARY;
     }
 
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>BinaryValue</code> object that
-     * represents the same value as this object.
+     * Returns the binary value.
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return binary value
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof BinaryValue) {
-            BinaryValue other = (BinaryValue) obj;
-            if (text == other.text && stream == other.stream
-                    && streamData == other.streamData) {
-                return true;
-            }
-            // stream, streamData and text are mutually exclusive,
-            // i.e. only one of them can be non-null
-            if (stream != null) {
-                return stream.equals(other.stream);
-            } else if (streamData != null) {
-                return streamData.equals(other.streamData);
-            } else {
-                return text.equals(other.text);
-            }
-        }
-        return false;
+    public InputStream getStream() {
+        return stream;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Throws an {@link IllegalStateException}.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return nothing
+     * @throws IllegalStateException always thrown
      */
-    public int hashCode() {
-        return 0;
+    public boolean getBoolean() throws IllegalStateException {
+        throw new IllegalStateException("Illegal value state");
     }
 
-    //------------------------------------------------------------< BaseValue >
     /**
-     * Gets the string representation of this binary value.
+     * Throws an {@link IllegalStateException}.
      *
-     * @return string representation of this binary value.
-     *
-     * @throws javax.jcr.ValueFormatException
-     * @throws javax.jcr.RepositoryException  if another error occurs
+     * @return nothing
+     * @throws IllegalStateException always thrown
      */
-    public String getInternalString()
-            throws ValueFormatException, RepositoryException {
-        // build text value if necessary
-        if (streamData != null) {
-            try {
-                text = new String(streamData, DEFAULT_ENCODING);
-            } catch (UnsupportedEncodingException e) {
-                throw new RepositoryException(DEFAULT_ENCODING
-                        + " not supported on this platform", e);
-            }
-            streamData = null;
-        } else if (stream != null) {
-            try {
-                ByteArrayOutputStream out = new ByteArrayOutputStream();
-                byte[] buffer = new byte[8192];
-                int read;
-                while ((read = stream.read(buffer)) > 0) {
-                    out.write(buffer, 0, read);
-                }
-                byte[] data = out.toByteArray();
-                text = new String(data, DEFAULT_ENCODING);
-            } catch (UnsupportedEncodingException e) {
-                throw new RepositoryException(DEFAULT_ENCODING
-                        + " not supported on this platform", e);
-            } catch (IOException e) {
-                throw new RepositoryException("conversion from stream to string failed", e);
-            } finally {
-                try {
-                    if (stream != null) {
-                        stream.close();
-                    }
-                } catch (IOException e) {
-                    // ignore
-                }
-            }
-            stream = null;
-        }
+    public Calendar getDate() throws IllegalStateException {
+        throw new IllegalStateException("Illegal value state");
+    }
 
-        if (text != null) {
-            return text;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    /**
+     * Throws an {@link IllegalStateException}.
+     *
+     * @return nothing
+     * @throws IllegalStateException always thrown
+     */
+    public double getDouble() throws IllegalStateException {
+        throw new IllegalStateException("Illegal value state");
     }
 
-    //----------------------------------------------------------------< Value >
     /**
-     * {@inheritDoc}
+     * Throws an {@link IllegalStateException}.
+     *
+     * @return nothing
+     * @throws IllegalStateException always thrown
      */
-    public InputStream getStream()
-            throws IllegalStateException, RepositoryException {
-        setStreamConsumed();
+    public long getLong() throws IllegalStateException {
+        throw new IllegalStateException("Illegal value state");
+    }
 
-        // build stream value if necessary
-        if (streamData != null) {
-            stream = new ByteArrayInputStream(streamData);
-            streamData = null;
-        } else if (text != null) {
-            try {
-                stream = new ByteArrayInputStream(text.getBytes(DEFAULT_ENCODING));
-            } catch (UnsupportedEncodingException e) {
-                throw new RepositoryException(DEFAULT_ENCODING
-                        + " not supported on this platform", e);
-            }
-            text = null;
-        }
-
-        return super.getStream();
+    /**
+     * Throws an {@link IllegalStateException}.
+     *
+     * @return nothing
+     * @throws IllegalStateException always thrown
+     */
+    public String getString() throws IllegalStateException {
+        throw new IllegalStateException("Illegal value state");
     }
+
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/StringValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/StringValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/StringValue.java	(working copy)
@@ -16,17 +16,22 @@
  */
 package org.apache.jackrabbit.value;
 
+import java.util.Calendar;
+
 import javax.jcr.PropertyType;
 import javax.jcr.ValueFormatException;
 
+import org.apache.jackrabbit.util.ISO8601;
+
 /**
  * A <code>StringValue</code> provides an implementation
  * of the <code>Value</code> interface representing a string value.
  */
 public class StringValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.STRING;
-
+    /**
+     * The string value.
+     */
     private final String text;
 
     /**
@@ -35,56 +40,79 @@
      * @param text the string this <code>StringValue</code> should represent
      */
     public StringValue(String text) {
-        super(TYPE);
         this.text = text;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>StringValue</code> object that
-     * represents the same value as this object.
+     * Returns {@link PropertyType#STRING}.
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return {@link PropertyType#STRING}
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof StringValue) {
-            StringValue other = (StringValue) obj;
-            if (text == other.text) {
-                return true;
-            } else if (text != null && other.text != null) {
-                return text.equals(other.text);
-            }
-        }
-        return false;
+    public int getType() {
+        return PropertyType.STRING;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the string value as a boolean.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return boolean value
      */
-    public int hashCode() {
-        return 0;
+    public boolean getBoolean() {
+        return Boolean.valueOf(text).booleanValue();
     }
 
-    //------------------------------------------------------------< BaseValue >
     /**
-     * {@inheritDoc}
+     * Returns the string value as a date ({@link ISO8601} formatting}.
+     *
+     * @return date value
+     * @throws ValueFormatException if value conversion failed
      */
-    protected String getInternalString() throws ValueFormatException {
-        if (text != null) {
-            return text;
+    public Calendar getDate() throws ValueFormatException {
+        Calendar date = ISO8601.parse(text);
+        if (date != null) {
+            return date;
         } else {
-            throw new ValueFormatException("empty value");
+            throw new ValueFormatException("Not a date: " + text);
         }
     }
+
+    /**
+     * Returns the string value as a double.
+     *
+     * @return double value
+     * @throws ValueFormatException if value conversion failed
+     */
+    public double getDouble() throws ValueFormatException {
+        try {
+            return Double.parseDouble(text);
+        } catch (NumberFormatException e) {
+            throw new ValueFormatException("Not a double: " + text, e);
+        }
+    }
+
+    /**
+     * Returns the string value as a long.
+     *
+     * @return long value
+     * @throws ValueFormatException if value conversion failed
+     */
+    public long getLong() throws ValueFormatException {
+        try {
+            return Long.parseLong(text);
+        } catch (NumberFormatException e) {
+            throw new ValueFormatException("Not a long: " + text, e);
+        }
+    }
+
+    /**
+     * Returns the string value.
+     *
+     * @return string value
+     */
+    public String getString() {
+        return text;
+    }
+
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java	(working copy)
@@ -22,7 +22,17 @@
 import javax.jcr.ValueFactory;
 import javax.jcr.ValueFormatException;
 import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.name.IllegalNameException;
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.name.NameFormat;
+import org.apache.jackrabbit.name.PathFormat;
+import org.apache.jackrabbit.util.ISO8601;
+import org.apache.jackrabbit.uuid.UUID;
+
+import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.util.Calendar;
 
 /**
@@ -53,49 +63,49 @@
      * {@inheritDoc}
      */
     public Value createValue(boolean value) {
-        return new BooleanValue(value);
+        return new GenericValue(new BooleanValue(value));
     }
 
     /**
      * {@inheritDoc}
      */
     public Value createValue(Calendar value) {
-        return new DateValue(value);
+        return new GenericValue(new DateValue(value));
     }
 
     /**
      * {@inheritDoc}
      */
     public Value createValue(double value) {
-        return new DoubleValue(value);
+        return new GenericValue(new DoubleValue(value));
     }
 
     /**
      * {@inheritDoc}
      */
     public Value createValue(InputStream value) {
-        return new BinaryValue(value);
+        return new GenericValue(new BinaryValue(value));
     }
 
     /**
      * {@inheritDoc}
      */
     public Value createValue(long value) {
-        return new LongValue(value);
+        return new GenericValue(new LongValue(value));
     }
 
     /**
      * {@inheritDoc}
      */
     public Value createValue(Node value) throws RepositoryException {
-        return new ReferenceValue(value);
+        return new GenericValue(new ReferenceValue(value.getUUID()));
     }
 
     /**
      * {@inheritDoc}
      */
     public Value createValue(String value) {
-        return new StringValue(value);
+        return new GenericValue(new StringValue(value));
     }
 
     /**
@@ -109,32 +119,65 @@
                 val = new StringValue(value);
                 break;
             case PropertyType.BOOLEAN:
-                val = BooleanValue.valueOf(value);
+                val = new BooleanValue(Boolean.valueOf(value).booleanValue());
                 break;
             case PropertyType.DOUBLE:
-                val = DoubleValue.valueOf(value);
+                try {
+                    val = new DoubleValue(Double.parseDouble(value));
+                } catch (NumberFormatException e) {
+                    throw new ValueFormatException("Not a double: " + value, e);
+                }
                 break;
             case PropertyType.LONG:
-                val = LongValue.valueOf(value);
+                try {
+                    val = new LongValue(Long.parseLong(value));
+                } catch (NumberFormatException e) {
+                    throw new ValueFormatException("Not a long: " + value, e);
+                }
                 break;
             case PropertyType.DATE:
-                val = DateValue.valueOf(value);
+                Calendar cal = ISO8601.parse(value);
+                if (cal != null) {
+                    val = new DateValue(cal);
+                } else {
+                    throw new ValueFormatException("Not a date: " + value);
+                }
                 break;
             case PropertyType.NAME:
-                val = NameValue.valueOf(value);
+                try {
+                    NameFormat.checkFormat(value);
+                } catch (IllegalNameException e) {
+                    throw new ValueFormatException("Not a name: " + value, e);
+                }
+                val = new NameValue(value);
                 break;
             case PropertyType.PATH:
-                val = PathValue.valueOf(value);
+                try {
+                    PathFormat.checkFormat(value);
+                } catch (MalformedPathException e) {
+                    throw new ValueFormatException("Not a path: " + value, e);
+                }
+                val = new PathValue(value);
                 break;
             case PropertyType.REFERENCE:
-                val = ReferenceValue.valueOf(value);
+                try {
+                    UUID.fromString(value);
+                } catch (IllegalArgumentException e) {
+                    throw new ValueFormatException("Not a UUID: " + value, e);
+                }
+                val = new ReferenceValue(value);
                 break;
             case PropertyType.BINARY:
-                val = new BinaryValue(value);
+                try {
+                    val = new BinaryValue(
+                            new ByteArrayInputStream(value.getBytes("UTF-8")));
+                } catch (UnsupportedEncodingException e) {
+                    throw new ValueFormatException("UTF-8 not supported", e);
+                }
                 break;
             default:
                 throw new IllegalArgumentException("Invalid type constant: " + type);
         }
-        return val;
+        return new GenericValue(val);
     }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DoubleValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DoubleValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DoubleValue.java	(working copy)
@@ -16,31 +16,20 @@
  */
 package org.apache.jackrabbit.value;
 
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
 import java.util.Calendar;
-import java.util.Date;
 
+import javax.jcr.PropertyType;
+
 /**
  * A <code>DoubleValue</code> provides an implementation
  * of the <code>Value</code> interface representing a double value.
  */
 public class DoubleValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.DOUBLE;
-
-    private final Double dblNumber;
-
     /**
-     * Constructs a <code>DoubleValue</code> object representing a double.
-     *
-     * @param dblNumber the double this <code>DoubleValue</code> should represent
+     * The double value.
      */
-    public DoubleValue(Double dblNumber) {
-        super(TYPE);
-        this.dblNumber = dblNumber;
-    }
+    private final double value;
 
     /**
      * Constructs a <code>DoubleValue</code> object representing a double.
@@ -48,134 +37,56 @@
      * @param dbl the double this <code>DoubleValue</code> should represent
      */
     public DoubleValue(double dbl) {
-        super(TYPE);
-        this.dblNumber = new Double(dbl);
+        this.value = dbl;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Returns a new <code>DoubleValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
+     * Returns {@link PropertyType#DOUBLE}.
      *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>DoubleValue</code> representing the
-     *         the specified value.
-     * @throws javax.jcr.ValueFormatException If the <code>String</code> does not
-     *                                        contain a parsable <code>double</code>.
+     * @return {@link PropertyType#DOUBLE}
      */
-    public static DoubleValue valueOf(String s) throws ValueFormatException {
-        try {
-            return new DoubleValue(Double.parseDouble(s));
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("invalid format", e);
-        }
+    public int getType() {
+        return PropertyType.DOUBLE;
     }
 
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>DoubleValue</code> object that
-     * represents the same value as this object.
+     * Returns the double value as a date (milliseconds since the epoch).
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return date value
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof DoubleValue) {
-            DoubleValue other = (DoubleValue) obj;
-            if (dblNumber == other.dblNumber) {
-                return true;
-            } else if (dblNumber != null && other.dblNumber != null) {
-                return dblNumber.equals(other.dblNumber);
-            }
-        }
-        return false;
+    public Calendar getDate() {
+        Calendar date = Calendar.getInstance();
+        date.setTimeInMillis((long) value);
+        return date;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the double value as a long.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return long value
      */
-    public int hashCode() {
-        return 0;
+    public long getLong() {
+        return (long) value;
     }
 
-    //------------------------------------------------------------< BaseValue >
     /**
-     * {@inheritDoc}
+     * Returns the double value.
+     *
+     * @return double value
      */
-    protected String getInternalString() throws ValueFormatException {
-        if (dblNumber != null) {
-            return dblNumber.toString();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    public double getDouble() {
+        return value;
     }
 
-    //----------------------------------------------------------------< Value >
     /**
-     * {@inheritDoc}
+     * Returns the double value as a string.
+     *
+     * @return string value
      */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (dblNumber != null) {
-            // loosing timezone information...
-            Calendar cal = Calendar.getInstance();
-            cal.setTime(new Date(dblNumber.longValue()));
-            return cal;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    public String getString() {
+        return Double.toString(value);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (dblNumber != null) {
-            return dblNumber.longValue();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to boolean failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (dblNumber != null) {
-            return dblNumber.doubleValue();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BaseValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BaseValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BaseValue.java	(working copy)
@@ -16,194 +16,86 @@
  */
 package org.apache.jackrabbit.value;
 
-import org.apache.jackrabbit.util.ISO8601;
-
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
-import java.io.ByteArrayInputStream;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Calendar;
 
 /**
- * This class is the superclass of the type-specific
- * classes implementing the <code>Value</code> interfaces.
- *
- * @see javax.jcr.Value
- * @see StringValue
- * @see LongValue
- * @see DoubleValue
- * @see BooleanValue
- * @see DateValue
- * @see BinaryValue
- * @see NameValue
- * @see PathValue
- * @see ReferenceValue
+ * Abstract base class for committed non-binary values. This class throws
+ * an {@link IllegalStateException} from {@link #getStream()} and defaults
+ * to throwing a {@link ValueFormatException} from the other value getters.
+ * Subclasses should implement {@link Value#getType()} and the non-binary
+ * value getters for which a value conversion is defined.
  */
 public abstract class BaseValue implements Value {
 
-    protected static final String DEFAULT_ENCODING = "UTF-8";
+    //----------------------------------------------------------------< Value >
 
-    private static final short STATE_UNDEFINED = 0;
-    private static final short STATE_VALUE_CONSUMED = 1;
-    private static final short STATE_STREAM_CONSUMED = 2;
-
-    private short state = STATE_UNDEFINED;
-
-    protected final int type;
-
-    protected InputStream stream = null;
-
     /**
-     * Package-private default constructor.
+     * Throws a {@link ValueFormatException}, unless overridden by a subclass.
      *
-     * @param type The type of this value.
+     * @return nothing
+     * @throws ValueFormatException always thrown, unless overridden
      */
-    BaseValue(int type) {
-        this.type = type;
+    public Calendar getDate() throws ValueFormatException {
+        throw new ValueFormatException("Invalid date format: " + this);
     }
 
     /**
-     * Checks if the non-stream value of this instance has already been
-     * consumed (if any getter methods except <code>{@link #getStream()}</code> and
-     * <code>{@link #getType()}</code> have been previously called at least once) and
-     * sets the state to <code>STATE_STREAM_CONSUMED</code>.
+     * Throws a {@link ValueFormatException}, unless overridden by a subclass.
      *
-     * @throws IllegalStateException if any getter methods other than
-     *                               <code>getStream()</code> and
-     *                               <code>getType()</code> have been
-     *                               previously called at least once.
+     * @return nothing
+     * @throws ValueFormatException always thrown, unless overridden
      */
-    protected void setStreamConsumed() throws IllegalStateException {
-        if (state == STATE_VALUE_CONSUMED) {
-            throw new IllegalStateException("non-stream value has already been consumed");
-        }
-        state = STATE_STREAM_CONSUMED;
+    public long getLong() throws ValueFormatException {
+        throw new ValueFormatException("Invalid long format: " + this);
     }
 
     /**
-     * Checks if the stream value of this instance has already been
-     * consumed (if {@link #getStream()} has been previously called
-     * at least once) and sets the state to <code>STATE_VALUE_CONSUMED</code>.
+     * Throws a {@link ValueFormatException}, unless overridden by a subclass.
      *
-     * @throws IllegalStateException if <code>getStream()</code> has been
-     *                               previously called at least once.
+     * @return nothing
+     * @throws ValueFormatException always thrown, unless overridden
      */
-    protected void setValueConsumed() throws IllegalStateException {
-        if (state == STATE_STREAM_CONSUMED) {
-            throw new IllegalStateException("stream value has already been consumed");
-        }
-        state = STATE_VALUE_CONSUMED;
+    public boolean getBoolean() throws ValueFormatException {
+        throw new ValueFormatException("Invalid boolean format: " + this);
     }
 
     /**
-     * Returns the internal string representation of this value without modifying
-     * the value state.
-     *
-     * @return the internal string representation
-     * @throws javax.jcr.ValueFormatException if the value can not be represented as a
-     *                              <code>String</code> or if the value is
-     *                              <code>null</code>.
-     * @throws javax.jcr.RepositoryException  if another error occurs.
-     */
-    protected abstract String getInternalString()
-            throws ValueFormatException, RepositoryException;
-
-    //----------------------------------------------------------------< Value >
-    /**
      * {@inheritDoc}
      */
-    public int getType() {
-        return type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
+    public double getDouble()
             throws ValueFormatException, IllegalStateException,
             RepositoryException {
-        setValueConsumed();
-
-        Calendar cal = ISO8601.parse(getInternalString());
-        if (cal == null) {
-            throw new ValueFormatException("not a valid date format");
-        } else {
-            return cal;
-        }
+        throw new ValueFormatException("Invalid double format: " + this);
     }
 
     /**
-     * {@inheritDoc}
+     * Throws an {@link IllegalStateException}.
+     *
+     * @return nothing
+     * @throws IllegalStateException always thrown
      */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        try {
-            return Long.parseLong(getInternalString());
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("conversion to long failed", e);
-        }
+    public InputStream getStream() throws IllegalStateException {
+        throw new IllegalStateException("Illegal value state");
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
+    //--------------------------------------------------------------< Object >
 
-        return Boolean.valueOf(getInternalString()).booleanValue();
-    }
-
     /**
-     * {@inheritDoc}
+     * Returns the string representation of this value.
+     *
+     * @return return value of {@link Value#getString()},
+     *         or <code>&lt;value&gt;</code> if the method fails
      */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
+    public String toString() {
         try {
-            return Double.parseDouble(getInternalString());
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("conversion to double failed", e);
+            return getString();
+        } catch (RepositoryException e) {
+            return "<value>";
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public InputStream getStream()
-            throws IllegalStateException, RepositoryException {
-        setStreamConsumed();
-
-        if (stream != null) {
-            return stream;
-        }
-
-        try {
-            // convert via string
-            stream = new ByteArrayInputStream(getInternalString().getBytes(DEFAULT_ENCODING));
-            return stream;
-        } catch (UnsupportedEncodingException e) {
-            throw new RepositoryException(DEFAULT_ENCODING
-                    + " not supported on this platform", e);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getString()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        return getInternalString();
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/PathValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/PathValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/PathValue.java	(working copy)
@@ -16,13 +16,7 @@
  */
 package org.apache.jackrabbit.value;
 
-import org.apache.jackrabbit.name.MalformedPathException;
-import org.apache.jackrabbit.name.PathFormat;
-
 import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import java.util.Calendar;
 
 /**
  * A <code>PathValue</code> provides an implementation
@@ -31,139 +25,40 @@
  */
 public class PathValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.PATH;
-
-    private final String path;
-
     /**
-     * Returns a new <code>PathValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
-     * <p/>
-     * The specified <code>String</code> must be a valid absolute or relative
-     * path.
-     *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>PathValue</code> representing the
-     *         the specified value.
-     * @throws javax.jcr.ValueFormatException If the <code>String</code> is not a valid
-     *                              absolute or relative path.
+     * The path value.
      */
-    public static PathValue valueOf(String s) throws ValueFormatException {
-        if (s != null) {
-            try {
-                PathFormat.checkFormat(s);
-            } catch (MalformedPathException mpe) {
-                throw new ValueFormatException(mpe.getMessage());
-            }
-            return new PathValue(s);
-        } else {
-            throw new ValueFormatException("not a valid path format");
-        }
-    }
+    private final String path;
 
     /**
      * Protected constructor creating a <code>PathValue</code> object
      * without validating the path.
      *
      * @param path the path this <code>PathValue</code> should represent
-     * @see #valueOf
      */
     protected PathValue(String path) {
-        super(TYPE);
         this.path = path;
     }
 
-    /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>PathValue</code> object that
-     * represents the same value as this object.
-     *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
-     */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof PathValue) {
-            PathValue other = (PathValue) obj;
-            if (path == other.path) {
-                return true;
-            } else if (path != null && other.path != null) {
-                return path.equals(other.path);
-            }
-        }
-        return false;
-    }
 
-    /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
-     *
-     * @return always zero
-     * @see Object#hashCode()
-     */
-    public int hashCode() {
-        return 0;
-    }
-
-    //------------------------------------------------------------< BaseValue >
-    /**
-     * {@inheritDoc}
-     */
-    protected String getInternalString() throws ValueFormatException {
-        if (path != null) {
-            return path;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
     //----------------------------------------------------------------< Value >
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
 
-        throw new ValueFormatException("conversion to date failed: inconvertible types");
-    }
-
     /**
-     * {@inheritDoc}
+     * Returns {@link PropertyType#PATH}.
+     *
+     * @return {@link PropertyType#PATH}
      */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to long failed: inconvertible types");
+    public int getType() {
+        return PropertyType.PATH;
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the path value.
+     *
+     * @return path value
      */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to boolean failed: inconvertible types");
+    public String getString() {
+        return path;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to double failed: inconvertible types");
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/GenericValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/GenericValue.java	(revision 0)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/GenericValue.java	(revision 0)
@@ -0,0 +1,528 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.value;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.util.Calendar;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+/**
+ * Generic value implementation. This class uses the State design pattern
+ * to implement the full value state mechanism specified by JSR 170. This
+ * class also implements the correct {@link Object#equals(Object)} semantics.
+ * <p>
+ * The internal value representation and the value conversion rules are
+ * delegated to the associated committed value state.
+ */
+class GenericValue implements Value {
+
+    /**
+     * UTF-8 character encoding.
+     */
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+
+    /**
+     * Value type. The type of the generic value does not change even if
+     * the value state changes from binary to non-binary or vice versa.
+     */
+    private final int type;
+
+    /**
+     * Value state. The value state is initially set to an instance of
+     * the {@link InitialBinaryValue} or {@link InitialScalarValue} class,
+     * and changed to a direct reference to an underlying committed value
+     * state when the first value getter is called. The value state is not
+     * changed after the first getter invocation.
+     */
+    private Value value;
+
+    /**
+     * Creates a generic value. The given value factory is used if value
+     * state conversions are needed. The value factory must create value
+     * instances that are already in the committed state.
+     *
+     * @param committed committed value state
+     */
+    GenericValue(Value committed) {
+        this.type = committed.getType();
+        if (type == PropertyType.BINARY) {
+            this.value = new InitialBinaryValue(committed);
+        } else {
+            this.value = new InitialScalarValue(committed);
+        }
+    }
+
+    //---------------------------------------------------------------< Value >
+
+    /**
+     * Returns the value type. The type never changes even if the underlying
+     * value state may change.
+     *
+     * @return value type
+     * @see PropertyType
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Returns the boolean value. Commits the value state to non-binary if this
+     * is the first value getter call.
+     *
+     * @return boolean value
+     * @throws IllegalStateException if the value is in committed binary state
+     * @throws RepositoryException if value access or conversion fails
+     */
+    public boolean getBoolean()
+            throws IllegalStateException, RepositoryException {
+        return value.getBoolean();
+    }
+
+    /**
+     * Returns the date value. Commits the value state to non-binary if this
+     * is the first value getter call.
+     *
+     * @return date value
+     * @throws IllegalStateException if the value is in committed binary state
+     * @throws RepositoryException if value access or conversion fails
+     */
+    public Calendar getDate()
+            throws IllegalStateException, RepositoryException {
+        return value.getDate();
+    }
+
+    /**
+     * Returns the double value. Commits the value state to non-binary if this
+     * is the first value getter call.
+     *
+     * @return double value
+     * @throws IllegalStateException if the value is in committed binary state
+     * @throws RepositoryException if value access or conversion fails
+     */
+    public double getDouble()
+            throws IllegalStateException, RepositoryException {
+        return value.getDouble();
+    }
+
+    /**
+     * Returns the long value. Commits the value state to non-binary if this
+     * is the first value getter call.
+     *
+     * @return long value
+     * @throws IllegalStateException if the value is in committed binary state
+     * @throws RepositoryException if value access or conversion fails
+     */
+    public long getLong()
+            throws IllegalStateException, RepositoryException {
+        return value.getLong();
+    }
+
+    /**
+     * Returns the binary value. Commits the value state to binary if this
+     * is the first value getter call.
+     *
+     * @return long value
+     * @throws IllegalStateException
+     *             if the value is in committed non-binary state
+     * @throws RepositoryException if value access or conversion fails
+     */
+    public InputStream getStream()
+            throws IllegalStateException, RepositoryException {
+        return value.getStream();
+    }
+
+    /**
+     * Returns the string value. Commits the value state to non-binary if this
+     * is the first value getter call.
+     *
+     * @return string value
+     * @throws IllegalStateException if the value is in committed binary state
+     * @throws RepositoryException if value access or conversion fails
+     */
+    public String getString()
+            throws IllegalStateException, RepositoryException {
+        return value.getString();
+    }
+
+    //--------------------------------------------------------------< Object >
+
+    /**
+     * Compares two values for equality. Implements the exact equality
+     * semantics specified by JSR 170, i.e. values are equal if and only if
+     * their types and string representations are equal.
+     * <p>
+     * Returns <code>false</code> if either this or the other value is in
+     * committed binary state (in which case the string representation is
+     * not available) or if one of the string value getters fails.
+     * <p>
+     * Note that this method may change the underlying value state!
+     *
+     * @param other other object
+     * @return <code>true</code> if the values are equal,
+     *         <code>false</code> otherwise
+     */
+    public boolean equals(Object other) {
+        try {
+            return (other instanceof Value)
+                && getType() == ((Value) other).getType()
+                && getString().equals(((Value) other).getString());
+        } catch (IllegalStateException e) {
+            return false;
+        } catch (RepositoryException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the hash code of this value. The hash code is computed based
+     * on the value type and string representation to be consistent with the
+     * {@link #equals(Object)} implementation.
+     * <p>
+     * Returns <code>0</code> if this value is in commmitted binary state
+     * (in which case the string representation is not available) or if the
+     * string value getter fails.
+     * <p>
+     * Note that this method may change the underlying value state!
+     *
+     * @return hash code
+     */
+    public int hashCode() {
+        try {
+            int code = 17;
+            code = 37 * code + getType();
+            code = 37 * code + getString().hashCode();
+            return code;
+        } catch (IllegalStateException e) {
+            return 0;
+        } catch (RepositoryException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns a string representation (not necessarily {@link #getString()})
+     * of the underlying value. Does <em>not</em> change the value state.
+     *
+     * @return string representation of the value
+     */
+    public String toString() {
+        return value.toString();
+    }
+
+    //--------------------------------------------------< InitialBinaryValue >
+
+    /**
+     * Initial state of a binary value. The task of this class is to intercept
+     * the first binary or non-binary value getter method and to change the
+     * state of the containing generic value accordingly.
+     */
+    private class InitialBinaryValue implements Value {
+
+        /**
+         * Underlying committed value state.
+         */
+        private final Value committed;
+
+        /**
+         * Creates an initial binary value state.
+         *
+         * @param committed underlying committed binary value state
+         */
+        public InitialBinaryValue(Value committed) {
+            this.committed = committed;
+        }
+
+        /**
+         * Converts the {@link #committed underlying binary value} to a string
+         * by reading it as a {@link #UTF8 UTF-8} stream.
+         *
+         * @return string contents of the stream
+         * @throws RepositoryException if the stream could not be read as UTF-8
+         */
+        private Value toStringValue() throws RepositoryException {
+            try {
+                Reader reader =
+                    new InputStreamReader(committed.getStream(), UTF8);
+                try {
+                    StringWriter writer = new StringWriter();
+                    char[] buffer = new char[1000];
+                    int n = reader.read(buffer);
+                    while (n != -1) {
+                        writer.write(buffer, 0, n);
+                        n = reader.read(buffer);
+                    }
+                    ValueFactory factory = ValueFactoryImpl.getInstance();
+                    return factory.createValue(writer.toString());
+                } finally {
+                    reader.close();
+                }
+            } catch (IOException e) {
+                throw new RepositoryException("Error reading binary value", e);
+            }
+        }
+
+        //-----------------------------------------------------------< Value >
+
+        /**
+         * Returns {@link PropertyType#BINARY}.
+         *
+         * @return {@link PropertyType#BINARY}
+         */
+        public int getType() {
+            return PropertyType.BINARY;
+        }
+
+        /**
+         * Converts the {@link #committed underlying binary value} to boolean by
+         * reading the stream as UTF-8 and using the
+         * {@link #factory associated value factory}. Sets the boolean value as
+         * the committed non-binary state of the containing generic value and
+         * restarts the method call.
+         *
+         * @return boolean value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public boolean getBoolean() throws RepositoryException {
+            value = toStringValue();
+            return value.getBoolean();
+        }
+
+        /**
+         * Converts the {@link #committed underlying binary value} to date by
+         * reading the stream as UTF-8 and using the
+         * {@link #factory associated value factory}. Sets the date value as
+         * the committed non-binary state of the containing generic value and
+         * restarts the method call.
+         *
+         * @return date value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public Calendar getDate() throws RepositoryException {
+            value = toStringValue();
+            return value.getDate();
+        }
+
+        /**
+         * Converts the {@link #committed underlying binary value} to double by
+         * reading the stream as UTF-8 and using the
+         * {@link #factory associated value factory}. Sets the double value as
+         * the committed non-binary state of the containing generic value and
+         * restarts the method call.
+         *
+         * @return double value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public double getDouble() throws RepositoryException {
+            value = toStringValue();
+            return value.getDouble();
+        }
+
+        /**
+         * Converts the {@link #committed underlying binary value} to long by
+         * reading the stream as UTF-8 and using the
+         * {@link #factory associated value factory}. Sets the long value as
+         * the committed non-binary state of the containing generic value and
+         * restarts the method call.
+         *
+         * @return long value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public long getLong() throws RepositoryException {
+            value = toStringValue();
+            return value.getLong();
+        }
+
+        /**
+         * Sets the {@link #committed underlying binary value} as the committed
+         * state of the containing generic value and restarts the method call.
+         *
+         * @return binary value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public InputStream getStream() throws RepositoryException {
+            value = committed;
+            return value.getStream();
+        }
+
+        /**
+         * Converts the {@link #committed underlying binary value} to string by
+         * reading the stream as UTF-8 and using the
+         * {@link #factory associated value factory}. Sets the string value as
+         * the committed non-binary state of the containing generic value and
+         * restarts the method call.
+         *
+         * @return string value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public String getString() throws RepositoryException {
+            value = toStringValue();
+            return value.getString();
+        }
+
+        //----------------------------------------------------------< Object >
+
+        /**
+         * Returns "<code>&lt;binary&gt;</code>".
+         *
+         * @return "<code>&lt;binary&gt;</code>"
+         */
+        public String toString() {
+            return "<binary>";
+        }
+
+    }
+
+    //--------------------------------------------------< InitialScalarValue >
+
+    /**
+     * Initial state of a non-binary value. The task of this class is to
+     * intercept the first binary or non-binary value getter method and to
+     * change the state of the containing generic value accordingly.
+     */
+    private class InitialScalarValue implements Value {
+
+        /**
+         * Underlying committed value state.
+         */
+        private final Value committed;
+
+        /**
+         * Creates an initial scalar value state.
+         *
+         * @param value underlying committed scalar value state
+         */
+        public InitialScalarValue(Value value) {
+            this.committed = value;
+        }
+
+        //---------------------------------------------------------------< Value >
+
+        /**
+         * Returns the type of the {@link #committed underlying value}.
+         *
+         * @return value type
+         */
+        public int getType() {
+            return committed.getType();
+        }
+
+        /**
+         * Sets the {@link #committed underlying scalar value} as the committed
+         * non-binary state of the containing generic value and restarts the
+         * method call.
+         *
+         * @return boolean value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public boolean getBoolean() throws RepositoryException {
+            value = committed;
+            return value.getBoolean();
+        }
+
+        /**
+         * Sets the {@link #committed underlying scalar value} as the committed
+         * non-binary state of the containing generic value and restarts the
+         * method call.
+         *
+         * @return date value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public Calendar getDate() throws RepositoryException {
+            value = committed;
+            return value.getDate();
+        }
+
+        /**
+         * Sets the {@link #committed underlying scalar value} as the committed
+         * non-binary state of the containing generic value and restarts the
+         * method call.
+         *
+         * @return double value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public double getDouble() throws RepositoryException {
+            value = committed;
+            return value.getDouble();
+        }
+
+        /**
+         * Sets the {@link #committed underlying scalar value} as the committed
+         * non-binary state of the containing generic value and restarts the
+         * method call.
+         *
+         * @return long value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public long getLong() throws RepositoryException {
+            value = committed;
+            return value.getLong();
+        }
+
+        /**
+         * Converts the {@link #committed underlying scalar value} to binary
+         * using the string representation of the value and the
+         * {@link #factory associated value factory}. Sets the binary value as
+         * the committed state of the containing generic value and restarts the
+         * method call.
+         *
+         * @return binary value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public InputStream getStream() throws RepositoryException {
+            ValueFactory factory = ValueFactoryImpl.getInstance();
+            value = factory.createValue(
+                    committed.getString(), PropertyType.BINARY);
+            return value.getStream();
+        }
+
+        /**
+         * Sets the {@link #committed underlying scalar value} as the committed
+         * non-binary state of the containing generic value and restarts the
+         * method call.
+         *
+         * @return string value
+         * @throws RepositoryException if the value retrieval fails
+         */
+        public String getString() throws RepositoryException {
+            value = committed;
+            return value.getString();
+        }
+
+        //----------------------------------------------------------< Object >
+
+        /**
+         * Returns the string representation of the
+         * {@link #committed underlying value}.
+         *
+         * @return string representation of the value
+         */
+        public String toString() {
+            return committed.toString();
+        }
+
+    }
+
+}

Property changes on: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/GenericValue.java
___________________________________________________________________
Name: svn:eol-style
   + native

Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DateValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DateValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/DateValue.java	(working copy)
@@ -19,8 +19,6 @@
 import org.apache.jackrabbit.util.ISO8601;
 
 import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
 import java.util.Calendar;
 
 /**
@@ -29,8 +27,9 @@
  */
 public class DateValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.DATE;
-
+    /**
+     * The date value.
+     */
     private final Calendar date;
 
     /**
@@ -39,153 +38,54 @@
      * @param date the date this <code>DateValue</code> should represent
      */
     public DateValue(Calendar date) {
-        super(TYPE);
         this.date = date;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Returns a new <code>DateValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
-     * <p/>
-     * The specified <code>String</code> must be a ISO8601-compliant date/time
-     * string.
+     * Returns {@link PropertyType#DATE}.
      *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>DateValue</code> representing the
-     *         the specified value.
-     * @throws javax.jcr.ValueFormatException If the <code>String</code> is not a valid
-     *                              ISO8601-compliant date/time string.
-     * @see ISO8601
+     * @return {@link PropertyType#DATE}
      */
-    public static DateValue valueOf(String s) throws ValueFormatException {
-        Calendar cal = ISO8601.parse(s);
-        if (cal != null) {
-            return new DateValue(cal);
-        } else {
-            throw new ValueFormatException("not a valid date format");
-        }
+    public int getType() {
+        return PropertyType.DATE;
     }
 
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>DateValue</code> object that
-     * represents the same value as this object.
-     * <p>
-     * The value comparison is performed using the ISO 8601 string
-     * representation of the dates, since the native Calendar.equals()
-     * method may produce false negatives (see JSR-598).
-     * <p>
-     * Note that the comparison still returns false when comparing the
-     * same time in different time zones, but that seems to be the intent
-     * of JSR 170. Compare the Value.getDate().getTime() values if you need
-     * an exact time comparison in UTC. 
+     * Returns the date value.
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return date value
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof DateValue) {
-            DateValue other = (DateValue) obj;
-            if (date == other.date) {
-                return true;
-            } else if (date != null && other.date != null) {
-                return ISO8601.format(date).equals(ISO8601.format(other.date));
-            }
-        }
-        return false;
+    public Calendar getDate() {
+        return date;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the date value as a long (milliseconds since epoch).
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return long value
      */
-    public int hashCode() {
-        return 0;
+    public long getLong() {
+        return date.getTimeInMillis();
     }
 
-    //------------------------------------------------------------< BaseValue >
     /**
-     * {@inheritDoc}
+     * Returns the date value as a double (milliseconds since epoch).
+     *
+     * @return double value
      */
-    protected String getInternalString() throws ValueFormatException {
-        if (date != null) {
-            return ISO8601.format(date);
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    public double getDouble() {
+        return date.getTimeInMillis();
     }
 
-    //----------------------------------------------------------------< Value >
     /**
-     * {@inheritDoc}
+     * Returns the date value as a string ({@link ISO8601} formatted).
+     *
+     * @return string value
      */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (date != null) {
-            return date;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    public String getString() {
+        return ISO8601.format(date);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (date != null) {
-            return date.getTimeInMillis();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (date != null) {
-            throw new ValueFormatException("cannot convert date to boolean");
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (date != null) {
-            long ms = date.getTimeInMillis();
-            if (ms <= Double.MAX_VALUE) {
-                return ms;
-            }
-            throw new ValueFormatException("conversion from date to double failed: inconvertible types");
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ReferenceValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ReferenceValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ReferenceValue.java	(working copy)
@@ -16,14 +16,7 @@
  */
 package org.apache.jackrabbit.value;
 
-import org.apache.jackrabbit.uuid.UUID;
-
-import javax.jcr.Node;
 import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.ValueFormatException;
-import java.util.Calendar;
 
 /**
  * A <code>ReferenceValue</code> provides an implementation
@@ -32,54 +25,12 @@
  */
 public class ReferenceValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.REFERENCE;
-
-    private final String uuid;
-
     /**
-     * Constructs a <code>ReferenceValue</code> object representing the UUID of
-     * an existing node.
-     *
-     * @param target the node to be referenced
-     * @throws IllegalArgumentException If <code>target</code> is nonreferenceable.
-     * @throws javax.jcr.RepositoryException      If another error occurs.
+     * The reference value.
      */
-    public ReferenceValue(Node target) throws RepositoryException {
-        super(TYPE);
-        try {
-            this.uuid = target.getUUID();
-        } catch (UnsupportedRepositoryOperationException ure) {
-            throw new IllegalArgumentException("target is nonreferenceable.");
-        }
-    }
+    private final String uuid;
 
     /**
-     * Returns a new <code>ReferenceValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
-     * <p/>
-     * The specified <code>String</code> must denote the UUID of an existing
-     * node.
-     *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>ReferenceValue</code> representing the
-     *         the specified value.
-     * @throws javax.jcr.ValueFormatException If the <code>String</code> is not a valid
-     *                              not a valid UUID format.
-     */
-    public static ReferenceValue valueOf(String s) throws ValueFormatException {
-        if (s != null) {
-            try {
-                UUID.fromString(s);
-            } catch (IllegalArgumentException iae) {
-                throw new ValueFormatException("not a valid UUID format");
-            }
-            return new ReferenceValue(s);
-        } else {
-            throw new ValueFormatException("not a valid UUID format");
-        }
-    }
-
-    /**
      * Protected constructor creating a <code>ReferenceValue</code> object
      * without validating the UUID format.
      *
@@ -87,101 +38,27 @@
      * @see #valueOf
      */
     protected ReferenceValue(String uuid) {
-        super(TYPE);
         this.uuid = uuid;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>ReferenceValue</code> object that
-     * represents the same value as this object.
+     * Returns {@link PropertyType#REFERENCE}.
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return {@link PropertyType#REFERENCE}
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof ReferenceValue) {
-            ReferenceValue other = (ReferenceValue) obj;
-            if (uuid == other.uuid) {
-                return true;
-            } else if (uuid != null && other.uuid != null) {
-                return uuid.equals(other.uuid);
-            }
-        }
-        return false;
+    public int getType() {
+        return PropertyType.REFERENCE;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the reference value.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return reference value
      */
-    public int hashCode() {
-        return 0;
+    public String getString() {
+        return uuid;
     }
 
-    //------------------------------------------------------------< BaseValue >
-    /**
-     * {@inheritDoc}
-     */
-    protected String getInternalString() throws ValueFormatException {
-        if (uuid != null) {
-            return uuid;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    //----------------------------------------------------------------< Value >
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to date failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to long failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to boolean failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to double failed: inconvertible types");
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ValueHelper.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ValueHelper.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/ValueHelper.java	(working copy)
@@ -25,6 +25,8 @@
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
 import javax.jcr.ValueFactory;
+
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.Reader;
@@ -672,7 +674,8 @@
             // NOTE: for performance reasons the BinaryValue is created directly
             // from the byte-array. This is inconsistent with the other calls,
             // that delegate the value creation to the ValueFactory.
-            return new BinaryValue(baos.toByteArray());
+            InputStream stream = new ByteArrayInputStream(baos.toByteArray());
+            return new GenericValue(new BinaryValue(stream));
         } else {
             if (decodeBlanks) {
                 // decode encoded blanks in value
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BooleanValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BooleanValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/BooleanValue.java	(working copy)
@@ -17,9 +17,6 @@
 package org.apache.jackrabbit.value;
 
 import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import java.util.Calendar;
 
 /**
  * A <code>BooleanValue</code> provides an implementation
@@ -27,19 +24,10 @@
  */
 public class BooleanValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.BOOLEAN;
-
-    private final Boolean bool;
-
     /**
-     * Constructs a <code>BooleanValue</code> object representing a boolean.
-     *
-     * @param bool the boolean this <code>BooleanValue</code> should represent
+     * The boolean value.
      */
-    public BooleanValue(Boolean bool) {
-        super(TYPE);
-        this.bool = bool;
-    }
+    private final boolean value;
 
     /**
      * Constructs a <code>BooleanValue</code> object representing a boolean.
@@ -47,117 +35,36 @@
      * @param bool the boolean this <code>BooleanValue</code> should represent
      */
     public BooleanValue(boolean bool) {
-        super(TYPE);
-        this.bool = Boolean.valueOf(bool);
+        this.value = bool;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Returns a new <code>BooleanValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
+     * Returns {@link PropertyType#BOOLEAN}.
      *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>BooleanValue</code> representing the
-     *         the specified value.
+     * @return {@link PropertyType#BOOLEAN}
      */
-    public static BooleanValue valueOf(String s) {
-        return new BooleanValue(Boolean.valueOf(s));
+    public int getType() {
+        return PropertyType.BOOLEAN;
     }
 
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>BooleanValue</code> object that
-     * represents the same value as this object.
+     * Returns the boolean value.
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return boolean value
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof BooleanValue) {
-            BooleanValue other = (BooleanValue) obj;
-            if (bool == other.bool) {
-                return true;
-            } else if (bool != null && other.bool != null) {
-                return bool.equals(other.bool);
-            }
-        }
-        return false;
+    public boolean getBoolean() {
+        return value;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the boolean value as a string.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return string value
      */
-    public int hashCode() {
-        return 0;
+    public String getString() {
+        return Boolean.toString(value);
     }
 
-    //------------------------------------------------------------< BaseValue >
-    /**
-     * {@inheritDoc}
-     */
-    protected String getInternalString() throws ValueFormatException {
-        if (bool != null) {
-            return bool.toString();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    //----------------------------------------------------------------< Value >
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to date failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to long failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (bool != null) {
-            return bool.booleanValue();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to double failed: inconvertible types");
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/LongValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/LongValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/LongValue.java	(working copy)
@@ -16,31 +16,20 @@
  */
 package org.apache.jackrabbit.value;
 
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
 import java.util.Calendar;
-import java.util.Date;
 
+import javax.jcr.PropertyType;
+
 /**
  * A <code>LongValue</code> provides an implementation
  * of the <code>Value</code> interface representing a long value.
  */
 public class LongValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.LONG;
-
-    private final Long lNumber;
-
     /**
-     * Constructs a <code>LongValue</code> object representing a long.
-     *
-     * @param lNumber the long this <code>LongValue</code> should represent
+     * The long value.
      */
-    public LongValue(Long lNumber) {
-        super(TYPE);
-        this.lNumber = lNumber;
-    }
+    private final long value;
 
     /**
      * Constructs a <code>LongValue</code> object representing a long.
@@ -48,134 +37,56 @@
      * @param l the long this <code>LongValue</code> should represent
      */
     public LongValue(long l) {
-        super(TYPE);
-        this.lNumber = new Long(l);
+        this.value = l;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Returns a new <code>LongValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
+     * Returns {@link PropertyType#LONG}.
      *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>LongValue</code> representing the
-     *         the specified value.
-     * @throws javax.jcr.ValueFormatException If the <code>String</code> does not
-     *                                        contain a parsable <code>long</code>.
+     * @return {@link PropertyType#LONG}
      */
-    public static LongValue valueOf(String s) throws ValueFormatException {
-        try {
-            return new LongValue(Long.parseLong(s));
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("invalid format", e);
-        }
+    public int getType() {
+        return PropertyType.LONG;
     }
 
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>LongValue</code> object that
-     * represents the same value as this object.
+     * Returns the long value as a date (milliseconds since the epoch).
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return date value
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof LongValue) {
-            LongValue other = (LongValue) obj;
-            if (lNumber == other.lNumber) {
-                return true;
-            } else if (lNumber != null && other.lNumber != null) {
-                return lNumber.equals(other.lNumber);
-            }
-        }
-        return false;
+    public Calendar getDate() {
+        Calendar date = Calendar.getInstance();
+        date.setTimeInMillis(value);
+        return date;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the long value.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return long value
      */
-    public int hashCode() {
-        return 0;
+    public long getLong() {
+        return value;
     }
 
-    //------------------------------------------------------------< BaseValue >
     /**
-     * {@inheritDoc}
+     * Returns the long value as a double.
+     *
+     * @return double value
      */
-    protected String getInternalString() throws ValueFormatException {
-        if (lNumber != null) {
-            return lNumber.toString();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    public double getDouble() {
+        return value;
     }
 
-    //----------------------------------------------------------------< Value >
     /**
-     * {@inheritDoc}
+     * Returns the long value as a string.
+     *
+     * @return string value
      */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (lNumber != null) {
-            // loosing timezone information...
-            Calendar cal = Calendar.getInstance();
-            cal.setTime(new Date(lNumber.longValue()));
-            return cal;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
+    public String getString() {
+        return Long.toString(value);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (lNumber != null) {
-            return lNumber.longValue();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to boolean failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        if (lNumber != null) {
-            return lNumber.doubleValue();
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
 }
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/NameValue.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/NameValue.java	(revision 490503)
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/value/NameValue.java	(working copy)
@@ -16,13 +16,7 @@
  */
 package org.apache.jackrabbit.value;
 
-import org.apache.jackrabbit.name.NameFormat;
-import org.apache.jackrabbit.name.IllegalNameException;
-
 import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import java.util.Calendar;
 
 /**
  * A <code>NameValue</code> provides an implementation
@@ -31,138 +25,39 @@
  */
 public class NameValue extends BaseValue {
 
-    public static final int TYPE = PropertyType.NAME;
-
-    private final String name;
-
     /**
-     * Returns a new <code>NameValue</code> initialized to the value
-     * represented by the specified <code>String</code>.
-     * <p/>
-     * The specified <code>String</code> must be a valid JCR name.
-     *
-     * @param s the string to be parsed.
-     * @return a newly constructed <code>NameValue</code> representing the
-     *         the specified value.
-     * @throws javax.jcr.ValueFormatException If the <code>String</code> is not a valid
-     *                              name.
+     * The name value.
      */
-    public static NameValue valueOf(String s) throws ValueFormatException {
-        if (s != null) {
-            try {
-                NameFormat.checkFormat(s);
-            } catch (IllegalNameException ine) {
-                throw new ValueFormatException(ine.getMessage());
-            }
-            return new NameValue(s);
-        } else {
-            throw new ValueFormatException("not a valid name format");
-        }
-    }
+    private final String name;
 
     /**
      * Protected constructor creating a <code>NameValue</code> object
      * without validating the name.
      *
      * @param name the name this <code>NameValue</code> should represent
-     * @see #valueOf
      */
     protected NameValue(String name) {
-        super(TYPE);
         this.name = name;
     }
 
+    //----------------------------------------------------------------< Value >
+
     /**
-     * Indicates whether some other object is "equal to" this one.
-     * <p/>
-     * The result is <code>true</code> if and only if the argument is not
-     * <code>null</code> and is a <code>NameValue</code> object that
-     * represents the same value as this object.
+     * Returns {@link PropertyType#NAME}.
      *
-     * @param obj the reference object with which to compare.
-     * @return <code>true</code> if this object is the same as the obj
-     *         argument; <code>false</code> otherwise.
+     * @return {@link PropertyType#NAME}
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof NameValue) {
-            NameValue other = (NameValue) obj;
-            if (name == other.name) {
-                return true;
-            } else if (name != null && other.name != null) {
-                return name.equals(other.name);
-            }
-        }
-        return false;
+    public int getType() {
+        return PropertyType.NAME;
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * Returns the name value.
      *
-     * @return always zero
-     * @see Object#hashCode()
+     * @return name value
      */
-    public int hashCode() {
-        return 0;
+    public String getString() {
+        return name;
     }
 
-    //------------------------------------------------------------< BaseValue >
-    /**
-     * {@inheritDoc}
-     */
-    protected String getInternalString() throws ValueFormatException {
-        if (name != null) {
-            return name;
-        } else {
-            throw new ValueFormatException("empty value");
-        }
-    }
-
-    //----------------------------------------------------------------< Value >
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to date failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to long failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to boolean failed: inconvertible types");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        setValueConsumed();
-
-        throw new ValueFormatException("conversion to double failed: inconvertible types");
-    }
 }
Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/value/BinaryValueTest.java
===================================================================
--- jackrabbit-core/src/test/java/org/apache/jackrabbit/value/BinaryValueTest.java	(revision 490503)
+++ jackrabbit-core/src/test/java/org/apache/jackrabbit/value/BinaryValueTest.java	(working copy)
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.value;
-
-import java.io.ByteArrayInputStream;
-
-import org.apache.jackrabbit.test.AbstractJCRTest;
-
-/**
- * Test cases for binary values.
- */
-public class BinaryValueTest extends AbstractJCRTest {
-
-    private static final byte[] DATA = "abc".getBytes();
-
-    public void testBinaryValueEquals() throws Exception {
-        assertFalse(new BinaryValue(DATA).equals(null));
-        assertFalse(new BinaryValue(DATA).equals(new Object()));
-
-        assertTrue(new BinaryValue(DATA).equals(new BinaryValue(DATA)));
-        assertTrue(new BinaryValue(DATA).equals(
-                new BinaryValue(new ByteArrayInputStream(DATA))));
-        assertTrue(new BinaryValue(new ByteArrayInputStream(DATA)).equals(
-                new BinaryValue(DATA)));
-        assertTrue(new BinaryValue(DATA).equals(
-                new BinaryValue(new String(DATA))));
-        assertTrue(new BinaryValue(new String(DATA)).equals(
-                new BinaryValue(DATA)));
-    }
-
-}
Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/value/TestAll.java
===================================================================
--- jackrabbit-core/src/test/java/org/apache/jackrabbit/value/TestAll.java	(revision 490503)
+++ jackrabbit-core/src/test/java/org/apache/jackrabbit/value/TestAll.java	(working copy)
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.value;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-/**
- * Test cases value handling.
- */
-public class TestAll extends TestCase {
-
-    /**
-     * Returns a <code>Test</code> suite that executes all tests inside this
-     * package.
-     *
-     * @return a <code>Test</code> suite that executes all tests inside this
-     *         package.
-     */
-    public static Test suite() {
-        TestSuite suite = new TestSuite("Value handling");
-        suite.addTestSuite(BinaryValueTest.class);
-        return suite;
-    }
-
-}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java	(revision 490503)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java	(working copy)
@@ -31,7 +31,9 @@
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import javax.jcr.Value;
+import javax.jcr.ValueFactory;
 import javax.jcr.query.Row;
 import javax.jcr.query.RowIterator;
 import java.util.Arrays;
@@ -216,7 +218,9 @@
                     } else {
                         // property not set or jcr:path / jcr:score
                         if (QName.JCR_PATH.equals(properties[i])) {
-                            tmp[i] = PathValue.valueOf(node.getPath());
+                            Session session = node.getSession();
+                            tmp[i] = session.getValueFactory().createValue(
+                                    node.getPath(), PropertyType.PATH);
                         } else if (QName.JCR_SCORE.equals(properties[i])) {
                             tmp[i] = new LongValue((int) (score * 1000f));
                         } else {
@@ -266,7 +270,8 @@
                 } else {
                     // either jcr:score, jcr:path or not set
                     if (QName.JCR_PATH.equals(prop)) {
-                        return PathValue.valueOf(node.getPath());
+                        return node.getSession().getValueFactory().createValue(
+                                node.getPath(), PropertyType.PATH);
                     } else if (QName.JCR_SCORE.equals(prop)) {
                         return new LongValue((int) (score * 1000f));
                     } else {
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java	(revision 490503)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java	(working copy)
@@ -37,10 +37,12 @@
 import org.apache.jackrabbit.value.PathValue;
 import org.apache.jackrabbit.value.ReferenceValue;
 import org.apache.jackrabbit.value.StringValue;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.ValueFactory;
 import javax.jcr.ValueFormatException;
 import java.io.File;
 import java.io.IOException;
@@ -297,35 +299,38 @@
      */
     public Value toJCRValue(NamespaceResolver nsResolver)
             throws RepositoryException {
+        ValueFactory factory = ValueFactoryImpl.getInstance();
         switch (type) {
             case PropertyType.BINARY:
-                return new BinaryValue(((BLOBFileValue) val).getStream());
+                return factory.createValue(((BLOBFileValue) val).getStream());
             case PropertyType.BOOLEAN:
-                return new BooleanValue(((Boolean) val));
+                return factory.createValue(((Boolean) val).booleanValue());
             case PropertyType.DATE:
-                return new DateValue((Calendar) val);
+                return factory.createValue((Calendar) val);
             case PropertyType.DOUBLE:
-                return new DoubleValue((Double) val);
+                return factory.createValue(((Double) val).doubleValue());
             case PropertyType.LONG:
-                return new LongValue((Long) val);
+                return factory.createValue(((Long) val).longValue());
             case PropertyType.REFERENCE:
-                return ReferenceValue.valueOf(val.toString());
+                return factory.createValue(val.toString(), type);
             case PropertyType.PATH:
                 try {
-                    return PathValue.valueOf(PathFormat.format((Path) val, nsResolver));
+                    return factory.createValue(
+                            PathFormat.format((Path) val, nsResolver), type);
                 } catch (NoPrefixDeclaredException npde) {
                     // should never get here...
                     throw new RepositoryException("internal error: encountered unregistered namespace", npde);
                 }
             case PropertyType.NAME:
                 try {
-                    return NameValue.valueOf(NameFormat.format((QName) val, nsResolver));
+                    return factory.createValue(
+                            NameFormat.format((QName) val, nsResolver), type);
                 } catch (NoPrefixDeclaredException npde) {
                     // should never get here...
                     throw new RepositoryException("internal error: encountered unregistered namespace", npde);
                 }
             case PropertyType.STRING:
-                return new StringValue((String) val);
+                return factory.createValue((String) val);
             default:
                 throw new RepositoryException("illegal internal value type");
         }
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java	(revision 490503)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java	(working copy)
@@ -27,6 +27,7 @@
 import org.apache.jackrabbit.name.UnknownPrefixException;
 import org.apache.jackrabbit.name.PathFormat;
 import org.apache.jackrabbit.name.NameFormat;
+import org.apache.jackrabbit.util.ISO8601;
 import org.apache.jackrabbit.value.DateValue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -406,52 +407,48 @@
         Pattern pattern = Pattern.compile("([\\(\\[]) *([0-9TZ\\.\\+-:]*)? *, *([0-9TZ\\.\\+-:]*)? *([\\)\\]])");
         Matcher matcher = pattern.matcher(definition);
         if (matcher.matches()) {
-            try {
-                // group 1 is lower inclusive/exclusive
-                String s = matcher.group(1);
-                lowerInclusive = s.equals("[");
-                // group 2 is lower limit
-                s = matcher.group(2);
-                if (s == null || s.length() == 0) {
-                    lowerLimit = null;
-                } else {
-                    lowerLimit = DateValue.valueOf(matcher.group(2)).getDate();
+            // group 1 is lower inclusive/exclusive
+            String s = matcher.group(1);
+            lowerInclusive = s.equals("[");
+            // group 2 is lower limit
+            s = matcher.group(2);
+            if (s == null || s.length() == 0) {
+                lowerLimit = null;
+            } else {
+                lowerLimit = ISO8601.parse(s);
+                if (lowerLimit == null) {
+                    throw new InvalidConstraintException(
+                            "Invalid date limit: " + s);
                 }
-                // group 3 is upper limit
-                s = matcher.group(3);
-                if (s == null || s.length() == 0) {
-                    upperLimit = null;
-                } else {
-                    upperLimit = DateValue.valueOf(matcher.group(3)).getDate();
+            }
+            // group 3 is upper limit
+            s = matcher.group(3);
+            if (s == null || s.length() == 0) {
+                upperLimit = null;
+            } else {
+                upperLimit = ISO8601.parse(s);
+                if (upperLimit == null) {
+                    throw new InvalidConstraintException(
+                            "Invalid date limit: " + s);
                 }
-                // group 4 is upepr inclusive/exclusive
-                s = matcher.group(4);
-                upperInclusive = s.equals("]");
+            }
+            // group 4 is upepr inclusive/exclusive
+            s = matcher.group(4);
+            upperInclusive = s.equals("]");
 
-                if (lowerLimit == null && upperLimit == null) {
+            if (lowerLimit == null && upperLimit == null) {
+                String msg = "'" + definition
+                    + "' is not a valid value constraint format for dates: neither min- nor max-date specified";
+                log.debug(msg);
+                throw new InvalidConstraintException(msg);
+            }
+            if (lowerLimit != null && upperLimit != null) {
+                if (lowerLimit.after(upperLimit)) {
                     String msg = "'" + definition
-                            + "' is not a valid value constraint format for dates: neither min- nor max-date specified";
+                        + "' is not a valid value constraint format for dates: min-date > max-date";
                     log.debug(msg);
                     throw new InvalidConstraintException(msg);
                 }
-                if (lowerLimit != null && upperLimit != null) {
-                    if (lowerLimit.after(upperLimit)) {
-                        String msg = "'" + definition
-                                + "' is not a valid value constraint format for dates: min-date > max-date";
-                        log.debug(msg);
-                        throw new InvalidConstraintException(msg);
-                    }
-                }
-            } catch (ValueFormatException vfe) {
-                String msg = "'" + definition
-                        + "' is not a valid value constraint format for dates";
-                log.debug(msg);
-                throw new InvalidConstraintException(msg, vfe);
-            } catch (RepositoryException re) {
-                String msg = "'" + definition
-                        + "' is not a valid value constraint format for dates";
-                log.debug(msg);
-                throw new InvalidConstraintException(msg, re);
             }
         } else {
             String msg = "'" + definition
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java	(revision 490503)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java	(working copy)
@@ -295,7 +295,8 @@
                     UUID original = UUID.fromString(val.getString());
                     UUID adjusted = refTracker.getMappedUUID(original);
                     if (adjusted != null) {
-                        newVals[i] = new ReferenceValue(session.getNodeByUUID(adjusted));
+                        newVals[i] = session.getValueFactory().createValue(
+                                session.getNodeByUUID(adjusted));
                     } else {
                         // reference doesn't need adjusting, just copy old value
                         newVals[i] = val;
