You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2015/03/02 13:50:39 UTC

svn commit: r1663288 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins: nodetype/TypeEditor.java value/BinaryImpl.java value/ErrorValue.java value/ValueFactoryImpl.java value/ValueImpl.java

Author: mduerig
Date: Mon Mar  2 12:50:39 2015
New Revision: 1663288

URL: http://svn.apache.org/r1663288
Log:
OAK-2384: SegmentNotFoundException when keeping JCR Value references
Throw RepositoryException instead of SegmentNotFoundException when a reference has been cleared by the garbage collector

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ErrorValue.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/BinaryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueFactoryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueImpl.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java?rev=1663288&r1=1663287&r2=1663288&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditor.java Mon Mar  2 12:50:39 2015
@@ -16,26 +16,6 @@
  */
 package org.apache.jackrabbit.oak.plugins.nodetype;
 
-import java.util.List;
-import java.util.Set;
-
-import javax.jcr.PropertyType;
-import javax.jcr.Value;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Lists;
-
-import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
-import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
-import org.apache.jackrabbit.oak.spi.commit.Editor;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Predicates.in;
 import static com.google.common.collect.Iterables.any;
@@ -56,6 +36,26 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_ABSTRACT;
 import static org.apache.jackrabbit.oak.plugins.nodetype.constraint.Constraints.valueConstraint;
 
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Validator implementation that check JCR node type constraints.
  *
@@ -374,7 +374,7 @@ class TypeEditor extends DefaultEditor {
 
         for (String constraint : constraints.getValue(STRINGS)) {
             Predicate<Value> predicate = valueConstraint(type, constraint);
-            for (Value v : ValueFactoryImpl.createValues(property, null)) {
+            for (Value v : ValueFactoryImpl.createValues(property, NamePathMapper.DEFAULT)) {
                 if (predicate.apply(v)) {
                     return;
                 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/BinaryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/BinaryImpl.java?rev=1663288&r1=1663287&r2=1663288&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/BinaryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/BinaryImpl.java Mon Mar  2 12:50:39 2015
@@ -27,11 +27,14 @@ import javax.jcr.RepositoryException;
 
 import com.google.common.base.Objects;
 import org.apache.jackrabbit.api.ReferenceBinary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * TODO document
  */
 class BinaryImpl implements ReferenceBinary {
+    private static final Logger LOG = LoggerFactory.getLogger(BinaryImpl.class);
 
     private final ValueImpl value;
 
@@ -46,12 +49,12 @@ class BinaryImpl implements ReferenceBin
     //-------------------------------------------------------------< Binary >---
 
     @Override
-    public InputStream getStream() {
+    public InputStream getStream() throws RepositoryException {
         return value.getBlob().getNewStream();
     }
 
     @Override
-    public int read(byte[] b, long position) throws IOException {
+    public int read(byte[] b, long position) throws IOException, RepositoryException {
         InputStream stream = getStream();
         try {
             if (position != stream.skip(position)) {
@@ -84,7 +87,12 @@ class BinaryImpl implements ReferenceBin
 
     @Override @CheckForNull
     public String getReference() {
-        return value.getBlob().getReference();
+        try {
+            return value.getBlob().getReference();
+        } catch (RepositoryException e) {
+            LOG.warn("Error getting binary reference", e);
+            return null;
+        }
     }
 
     @Override

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ErrorValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ErrorValue.java?rev=1663288&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ErrorValue.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ErrorValue.java Mon Mar  2 12:50:39 2015
@@ -0,0 +1,101 @@
+/*
+ * 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.oak.plugins.value;
+
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.Calendar;
+
+import javax.jcr.Binary;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+/**
+ * Instances of this class represent a {@code Value} which couldn't be retrieved.
+ * All its accessors throw a {@code RepositoryException}.
+ */
+class ErrorValue implements Value {
+    private final Exception exception;
+    private final int type;
+
+    ErrorValue(Exception exception, int type) {
+        this.exception = exception;
+        this.type = type;
+    }
+
+    ErrorValue(RepositoryException e) {
+        this(e, PropertyType.UNDEFINED);
+    }
+
+    @Override
+    public String getString() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public InputStream getStream() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public Binary getBinary() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public long getLong() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public double getDouble() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public BigDecimal getDecimal() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public Calendar getDate() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public boolean getBoolean() throws RepositoryException {
+        throw createException();
+    }
+
+    @Override
+    public int getType() {
+        return type;
+    }
+
+    private RepositoryException createException() {
+        return new RepositoryException("Inaccessible value", exception);
+    }
+
+    @Override
+    public String toString() {
+        return "Inaccessible value: " + exception.getMessage();
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueFactoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueFactoryImpl.java?rev=1663288&r1=1663287&r2=1663288&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueFactoryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueFactoryImpl.java Mon Mar  2 12:50:39 2015
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.plugins.value;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.oak.plugins.value.ValueImpl.newValue;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -87,7 +88,7 @@ public class ValueFactoryImpl implements
      * @throws IllegalArgumentException if {@code property.isArray()} is {@code true}.
      */
     public static Value createValue(PropertyState property, NamePathMapper namePathMapper) {
-        return new ValueImpl(property, namePathMapper);
+        return newValue(property, namePathMapper);
     }
 
     /**
@@ -99,7 +100,7 @@ public class ValueFactoryImpl implements
      * @throws IllegalArgumentException if {@code property.isArray()} is {@code true}.
      */
     public static Value createValue(PropertyValue property, NamePathMapper namePathMapper) {
-        return new ValueImpl(PropertyValues.create(property), namePathMapper);
+        return newValue(PropertyValues.create(property), namePathMapper);
     }
 
     /**
@@ -112,7 +113,7 @@ public class ValueFactoryImpl implements
     public static List<Value> createValues(PropertyState property, NamePathMapper namePathMapper) {
         List<Value> values = Lists.newArrayList();
         for (int i = 0; i < property.count(); i++) {
-            values.add(new ValueImpl(property, i, namePathMapper));
+            values.add(newValue(property, i, namePathMapper));
         }
         return values;
     }
@@ -125,7 +126,7 @@ public class ValueFactoryImpl implements
     public List<Value> createValues(PropertyState property) {
         List<Value> values = Lists.newArrayList();
         for (int i = 0; i < property.count(); i++) {
-            values.add(new ValueImpl(property, i, namePathMapper));
+            values.add(newValue(property, i, namePathMapper));
         }
         return values;
     }
@@ -134,7 +135,7 @@ public class ValueFactoryImpl implements
 
     @Override
     public Value createValue(String value) {
-        return new ValueImpl(StringPropertyState.stringProperty("", value), namePathMapper);
+        return newValue(StringPropertyState.stringProperty("", value), namePathMapper);
     }
 
     @Override
@@ -143,6 +144,8 @@ public class ValueFactoryImpl implements
             return createBinaryValue(value);
         } catch (IOException e) {
             return new ErrorValue(e, PropertyType.BINARY);
+        } catch (RepositoryException e) {
+            return new ErrorValue(e, PropertyType.BINARY);
         }
     }
 
@@ -169,22 +172,22 @@ public class ValueFactoryImpl implements
 
     @Override
     public Value createValue(long value) {
-        return new ValueImpl(LongPropertyState.createLongProperty("", value), namePathMapper);
+        return newValue(LongPropertyState.createLongProperty("", value), namePathMapper);
     }
 
     @Override
     public Value createValue(double value) {
-        return new ValueImpl(DoublePropertyState.doubleProperty("", value), namePathMapper);
+        return newValue(DoublePropertyState.doubleProperty("", value), namePathMapper);
     }
 
     @Override
     public Value createValue(Calendar value) {
-        return new ValueImpl(PropertyStates.createProperty("", value), namePathMapper);
+        return newValue(PropertyStates.createProperty("", value), namePathMapper);
     }
 
     @Override
     public Value createValue(boolean value) {
-        return new ValueImpl(BooleanPropertyState.booleanProperty("", value), namePathMapper);
+        return newValue(BooleanPropertyState.booleanProperty("", value), namePathMapper);
     }
 
     @Override
@@ -199,13 +202,13 @@ public class ValueFactoryImpl implements
                     "Node is not referenceable: " + value.getPath());
         }
         return weak
-            ? new ValueImpl(GenericPropertyState.weakreferenceProperty("", value.getUUID()), namePathMapper)
-            : new ValueImpl(GenericPropertyState.referenceProperty("", value.getUUID()), namePathMapper);
+            ? newValue(GenericPropertyState.weakreferenceProperty("", value.getUUID()), namePathMapper)
+            : newValue(GenericPropertyState.referenceProperty("", value.getUUID()), namePathMapper);
     }
 
     @Override
     public Value createValue(BigDecimal value) {
-        return new ValueImpl(DecimalPropertyState.decimalProperty("", value), namePathMapper);
+        return newValue(DecimalPropertyState.decimalProperty("", value), namePathMapper);
     }
 
     @Override
@@ -219,7 +222,7 @@ public class ValueFactoryImpl implements
                 case PropertyType.STRING:
                     return createValue(value);
                 case PropertyType.BINARY:
-                    return new ValueImpl(BinaryPropertyState.binaryProperty("", value), namePathMapper);
+                    return newValue(BinaryPropertyState.binaryProperty("", value), namePathMapper);
                 case PropertyType.LONG:
                     return createValue(Conversions.convert(value).toLong());
                 case PropertyType.DOUBLE:
@@ -228,7 +231,7 @@ public class ValueFactoryImpl implements
                     if (ISO8601.parse(value) == null) {
                         throw new ValueFormatException("Invalid date " + value);
                     }
-                    return new ValueImpl(GenericPropertyState.dateProperty("", value), namePathMapper);
+                    return newValue(GenericPropertyState.dateProperty("", value), namePathMapper);
                 case PropertyType.BOOLEAN:
                     return createValue(Conversions.convert(value).toBoolean());
                 case PropertyType.NAME:
@@ -236,7 +239,7 @@ public class ValueFactoryImpl implements
                     if (oakName == null || !JcrNameParser.validate(oakName)) {
                         throw new ValueFormatException("Invalid name: " + value);
                     }
-                    return new ValueImpl(GenericPropertyState.nameProperty("", oakName), namePathMapper);
+                    return newValue(GenericPropertyState.nameProperty("", oakName), namePathMapper);
                 case PropertyType.PATH:
                     String oakValue = value;
                     if (value.startsWith("[") && value.endsWith("]")) {
@@ -247,20 +250,20 @@ public class ValueFactoryImpl implements
                             throw new ValueFormatException("Invalid path: " + value);
                         }
                     }
-                    return new ValueImpl(GenericPropertyState.pathProperty("", oakValue), namePathMapper);
+                    return newValue(GenericPropertyState.pathProperty("", oakValue), namePathMapper);
                 case PropertyType.REFERENCE:
                     if (!IdentifierManager.isValidUUID(value)) {
                         throw new ValueFormatException("Invalid reference value " + value);
                     }
-                    return new ValueImpl(GenericPropertyState.referenceProperty("", value), namePathMapper);
+                    return newValue(GenericPropertyState.referenceProperty("", value), namePathMapper);
                 case PropertyType.WEAKREFERENCE:
                     if (!IdentifierManager.isValidUUID(value)) {
                         throw new ValueFormatException("Invalid weak reference value " + value);
                     }
-                    return new ValueImpl(GenericPropertyState.weakreferenceProperty("", value), namePathMapper);
+                    return newValue(GenericPropertyState.weakreferenceProperty("", value), namePathMapper);
                 case PropertyType.URI:
                     new URI(value);
-                    return new ValueImpl(GenericPropertyState.uriProperty("", value), namePathMapper);
+                    return newValue(GenericPropertyState.uriProperty("", value), namePathMapper);
                 case PropertyType.DECIMAL:
                     return createValue(Conversions.convert(value).toDecimal());
                 default:
@@ -282,81 +285,14 @@ public class ValueFactoryImpl implements
         }
     }
 
-    private ValueImpl createBinaryValue(InputStream value) throws IOException {
+    private ValueImpl createBinaryValue(InputStream value) throws IOException, RepositoryException {
         return createBinaryValue(root.createBlob(value));
     }
 
-    private ValueImpl createBinaryValue(Blob blob) {
+    private ValueImpl createBinaryValue(Blob blob) throws RepositoryException {
         return new ValueImpl(BinaryPropertyState.binaryProperty("", blob), namePathMapper);
     }
 
     //------------------------------------------------------------< ErrorValue >---
 
-    /**
-     * Instances of this class represent a {@code Value} which couldn't be retrieved.
-     * All its accessors throw a {@code RepositoryException}.
-     */
-    private static class ErrorValue implements Value {
-        private final Exception exception;
-        private final int type;
-
-        private ErrorValue(Exception exception, int type) {
-            this.exception = exception;
-            this.type = type;
-        }
-
-        @Override
-        public String getString() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public InputStream getStream() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public Binary getBinary() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public long getLong() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public double getDouble() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public BigDecimal getDecimal() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public Calendar getDate() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public boolean getBoolean() throws RepositoryException {
-            throw createException();
-        }
-
-        @Override
-        public int getType() {
-            return type;
-        }
-
-        private RepositoryException createException() {
-            return new RepositoryException("Inaccessible value", exception);
-        }
-
-        @Override
-        public String toString() {
-            return "Inaccessible value: " + exception.getMessage();
-        }
-    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueImpl.java?rev=1663288&r1=1663287&r2=1663288&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/value/ValueImpl.java Mon Mar  2 12:50:39 2015
@@ -17,12 +17,14 @@
 package org.apache.jackrabbit.oak.plugins.value;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.util.Calendar;
 
+import javax.annotation.Nonnull;
 import javax.jcr.Binary;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -35,11 +37,15 @@ import org.apache.jackrabbit.oak.api.Blo
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.segment.SegmentNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Implementation of {@link Value} based on {@code PropertyState}.
  */
 public class ValueImpl implements JackrabbitValue {
+    private static final Logger LOG = LoggerFactory.getLogger(ValueImpl.class);
 
     public static Blob getBlob(Value value) throws RepositoryException {
         if (value instanceof ValueImpl) {
@@ -50,6 +56,7 @@ public class ValueImpl implements Jackra
     }
 
     private final PropertyState propertyState;
+    private final Type<?> type;
     private final int index;
     private final NamePathMapper namePathMapper;
 
@@ -62,12 +69,15 @@ public class ValueImpl implements Jackra
      * @param namePathMapper The name/path mapping used for converting JCR names/paths to
      * the internal representation.
      * @throws IllegalArgumentException if {@code index < propertyState.count()}
+     * @throws RepositoryException if the underlying node state cannot be accessed
      */
-    ValueImpl(PropertyState property, int index, NamePathMapper namePathMapper) {
+    ValueImpl(@Nonnull PropertyState property, int index, @Nonnull NamePathMapper namePathMapper)
+            throws RepositoryException {
         checkArgument(index < property.count());
-        this.propertyState = property;
+        this.propertyState = checkNotNull(property);
+        this.type = getType(property);
         this.index = index;
-        this.namePathMapper = namePathMapper;
+        this.namePathMapper = checkNotNull(namePathMapper);
     }
 
     /**
@@ -76,13 +86,53 @@ public class ValueImpl implements Jackra
      * @param namePathMapper The name/path mapping used for converting JCR names/paths to
      * the internal representation.
      * @throws IllegalArgumentException if {@code property.isArray()} is {@code true}.
+     * @throws RepositoryException if the underlying node state cannot be accessed
      */
-    ValueImpl(PropertyState property, NamePathMapper namePathMapper) {
+    ValueImpl(@Nonnull PropertyState property, @Nonnull NamePathMapper namePathMapper)
+            throws RepositoryException {
         this(checkSingleValued(property), 0, namePathMapper);
     }
 
-    Blob getBlob() {
-        return propertyState.getValue(Type.BINARY, index);
+    private static PropertyState checkSingleValued(PropertyState property) {
+        checkArgument(!property.isArray());
+        return property;
+    }
+
+    /**
+     * Create a new {@code Value} instance
+     * @param property  The property state this instance is based on
+     * @param index  The index
+     * @param namePathMapper The name/path mapping used for converting JCR names/paths to
+     * the internal representation.
+     * @throws IllegalArgumentException if {@code index < propertyState.count()}
+     */
+    @Nonnull
+    static Value newValue(@Nonnull PropertyState property, int index, @Nonnull NamePathMapper namePathMapper) {
+        try {
+            return new ValueImpl(property, index, namePathMapper);
+        } catch (RepositoryException e) {
+            return new ErrorValue(e);
+        }
+    }
+
+    /**
+     * Create a new {@code Value} instance
+     * @param property  The property state this instance is based on
+     * @param namePathMapper The name/path mapping used for converting JCR names/paths to
+     * the internal representation.
+     * @throws IllegalArgumentException if {@code property.isArray()} is {@code true}.
+     */
+    @Nonnull
+    static Value newValue(@Nonnull PropertyState property, @Nonnull NamePathMapper namePathMapper) {
+        try {
+            return new ValueImpl(property, 0, namePathMapper);
+        } catch (RepositoryException e) {
+            return new ErrorValue(e);
+        }
+    }
+
+    Blob getBlob() throws RepositoryException {
+        return getValue(Type.BINARY, index);
     }
 
     /**
@@ -90,13 +140,8 @@ public class ValueImpl implements Jackra
      * Oak representation instead of being mapped to their JCR representation.
      * @return  A String representation of the value of this property.
      */
-    public String getOakString() {
-        return propertyState.getValue(Type.STRING, index);
-    }
-
-    private static PropertyState checkSingleValued(PropertyState property) {
-        checkArgument(!property.isArray());
-        return property;
+    public String getOakString() throws RepositoryException {
+        return getValue(Type.STRING, index);
     }
 
     //--------------------------------------------------------------< Value >---
@@ -106,7 +151,7 @@ public class ValueImpl implements Jackra
      */
     @Override
     public int getType() {
-        return propertyState.getType().tag();
+        return type.tag();
     }
 
     /**
@@ -118,7 +163,7 @@ public class ValueImpl implements Jackra
             case PropertyType.STRING:
             case PropertyType.BINARY:
             case PropertyType.BOOLEAN:
-                return propertyState.getValue(Type.BOOLEAN, index);
+                return getValue(Type.BOOLEAN, index);
             default:
                 throw new ValueFormatException("Incompatible type " + PropertyType.nameFromValue(getType()));
         }
@@ -134,12 +179,12 @@ public class ValueImpl implements Jackra
                 case PropertyType.STRING:
                 case PropertyType.BINARY:
                 case PropertyType.DATE:
-                    String value = propertyState.getValue(Type.DATE, index);
+                    String value = getValue(Type.DATE, index);
                     return Conversions.convert(value).toCalendar();
                 case PropertyType.LONG:
                 case PropertyType.DOUBLE:
                 case PropertyType.DECIMAL:
-                    return Conversions.convert(propertyState.getValue(Type.LONG, index)).toCalendar();
+                    return Conversions.convert(getValue(Type.LONG, index)).toCalendar();
                 default:
                     throw new ValueFormatException("Incompatible type " + PropertyType.nameFromValue(getType()));
             }
@@ -162,7 +207,7 @@ public class ValueImpl implements Jackra
                 case PropertyType.DOUBLE:
                 case PropertyType.DATE:
                 case PropertyType.DECIMAL:
-                    return propertyState.getValue(Type.DECIMAL, index);
+                    return getValue(Type.DECIMAL, index);
                 default:
                     throw new ValueFormatException("Incompatible type " + PropertyType.nameFromValue(getType()));
             }
@@ -185,7 +230,7 @@ public class ValueImpl implements Jackra
                 case PropertyType.DOUBLE:
                 case PropertyType.DATE:
                 case PropertyType.DECIMAL:
-                    return propertyState.getValue(Type.DOUBLE, index);
+                    return getValue(Type.DOUBLE, index);
                 default:
                     throw new ValueFormatException("Incompatible type " + PropertyType.nameFromValue(getType()));
             }
@@ -208,7 +253,7 @@ public class ValueImpl implements Jackra
                 case PropertyType.DOUBLE:
                 case PropertyType.DATE:
                 case PropertyType.DECIMAL:
-                    return propertyState.getValue(Type.LONG, index);
+                    return getValue(Type.LONG, index);
                 default:
                     throw new ValueFormatException("Incompatible type " + PropertyType.nameFromValue(getType()));
             }
@@ -247,7 +292,7 @@ public class ValueImpl implements Jackra
      * @see javax.jcr.Value#getStream()
      */
     @Override
-    public InputStream getStream() throws IllegalStateException {
+    public InputStream getStream() throws IllegalStateException, RepositoryException {
         if (stream == null) {
             stream = getBlob().getNewStream();
         }
@@ -264,7 +309,12 @@ public class ValueImpl implements Jackra
 
     @Override
     public String getContentIdentity() {
-        return getBlob().getContentIdentity();
+        try {
+            return getBlob().getContentIdentity();
+        } catch (RepositoryException e) {
+            LOG.warn("Error getting content identity", e);
+            return null;
+        }
     }
 
     //-------------------------------------------------------------< Object >---
@@ -276,14 +326,23 @@ public class ValueImpl implements Jackra
     public boolean equals(Object other) {
         if (other instanceof ValueImpl) {
             ValueImpl that = (ValueImpl) other;
-            Type<?> type = propertyState.getType();
-            if (type.isArray()) {
-                type = type.getBaseType();
+            Type<?> thisType = this.type;
+            if (thisType.isArray()) {
+                thisType = thisType.getBaseType();
+            }
+            Type<?> thatType = that.type;
+            if (thatType.isArray()) {
+                thatType = thatType.getBaseType();
+            }
+            try {
+                return thisType == thatType
+                        && Objects.equal(
+                        getValue(thatType, index),
+                        that.getValue(thatType, that.index));
+            } catch (RepositoryException e) {
+                LOG.warn("Error while comparing values", e);
+                return false;
             }
-            return type.tag() == that.propertyState.getType().tag()
-                    && Objects.equal(
-                            propertyState.getValue(type, index),
-                            that.propertyState.getValue(type, that.index));
         } else {
             return false;
         }
@@ -294,16 +353,43 @@ public class ValueImpl implements Jackra
      */
     @Override
     public int hashCode() {
-        if (getType() == PropertyType.BINARY) {
-            return propertyState.getValue(Type.BINARY, index).hashCode();
-        } else {
-            return getOakString().hashCode();
+        try {
+            if (getType() == PropertyType.BINARY) {
+                    return getValue(Type.BINARY, index).hashCode();
+            } else {
+                return getValue(Type.STRING, index).hashCode();
+            }
+        } catch (RepositoryException e) {
+            LOG.warn("Error while calculating hash code", e);
+            return 0;
         }
     }
 
     @Override
     public String toString() {
-        return getOakString();
+        try {
+            return getValue(Type.STRING, index);
+        } catch (RepositoryException e) {
+            return e.toString();
+        }
+    }
+
+    //------------------------------------------------------------< private >---
+
+    private <T> T getValue(Type<T> type, int index) throws RepositoryException {
+        try {
+            return propertyState.getValue(type, index);
+        } catch (SegmentNotFoundException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    private Type<?> getType(PropertyState property) throws RepositoryException {
+        try {
+            return propertyState.getType();
+        } catch (SegmentNotFoundException e) {
+            throw new RepositoryException(e);
+        }
     }
 
 }
\ No newline at end of file