All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.modeshape.jcr.JcrValue Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 *
 * Licensed 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.modeshape.jcr;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Calendar;
import javax.jcr.Node;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import org.modeshape.common.SystemFailureException;
import org.modeshape.common.annotation.NotThreadSafe;
import org.modeshape.common.util.IoUtil;
import org.modeshape.jcr.api.value.DateTime;
import org.modeshape.jcr.value.BinaryFactory;
import org.modeshape.jcr.value.BinaryValue;
import org.modeshape.jcr.value.DateTimeFactory;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.NameFactory;
import org.modeshape.jcr.value.Path;
import org.modeshape.jcr.value.PathFactory;
import org.modeshape.jcr.value.ValueFactories;

/**
 * ModeShape implementation of a {@link Value JCR Value}.
 */
@NotThreadSafe
final class JcrValue implements javax.jcr.Value {

    private final ValueFactories factories;
    private final int type;
    private final Object value;
    private InputStream asStream = null;

    JcrValue( ValueFactories factories,
              int type,
              Object value ) {
        assert factories != null;
        this.factories = factories;

        assert type == PropertyType.BINARY || type == PropertyType.BOOLEAN || type == PropertyType.DATE
               || type == PropertyType.DECIMAL || type == PropertyType.DOUBLE || type == PropertyType.LONG
               || type == PropertyType.NAME || type == PropertyType.PATH || type == PropertyType.REFERENCE
               || type == PropertyType.WEAKREFERENCE || type == PropertyType.STRING || type == org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE
               || type == PropertyType.URI :
                  "Unxpected PropertyType: " + org.modeshape.jcr.api.PropertyType.nameFromValue(type) + " for value " + (value == null ? "null" : ("\"" + value + "\""));

        // Leaving this assertion out for now so that values can be created in node type sources, which are created outside
        // the context of any particular session.
        // assert sessionCache != null;
        assert value != null;

        this.type = type;
        this.value = convertToType(this.type, value);
    }

    JcrValue( ValueFactories factories,
              Value value ) throws RepositoryException {
        assert factories != null;
        assert value != null;
        this.factories = factories;
        this.type = value.getType();
        this.value = valueToType(this.type, value);
    }

    private ValueFormatException createValueFormatException( Class type ) {
        return new ValueFormatException(JcrI18n.cannotConvertValue.text(value.getClass().getSimpleName(), type.getSimpleName()));
    }

    private ValueFormatException createValueFormatException( org.modeshape.jcr.value.ValueFormatException vfe ) {
        return new ValueFormatException(vfe);
    }

    final ValueFactories factories() {
        return factories;
    }

    /**
     * Returns a direct reference to the internal value object wrapped by this {@link JcrValue}. Useful to avoid the expense of
     * {@link #asType(int)} if the caller already knows the type of the value.
     * 
     * @return a reference to the {@link #value} field.
     */
    final Object value() {
        return value;
    }

    @Override
    public boolean getBoolean() throws ValueFormatException {
        try {
            boolean convertedValue = factories().getBooleanFactory().create(value);
            return convertedValue;
        } catch (RuntimeException error) {
            throw createValueFormatException(boolean.class);
        }
    }

    @Override
    public Calendar getDate() throws ValueFormatException {
        if (value == null) return null;
        try {
            Calendar convertedValue = factories().getDateFactory().create(value).toCalendar();
            return convertedValue;
        } catch (RuntimeException error) {
            throw createValueFormatException(Calendar.class);
        }
    }

    @Override
    public BigDecimal getDecimal() throws ValueFormatException, RepositoryException {
        if (value == null) return null;
        try {
            BigDecimal convertedValue = factories().getDecimalFactory().create(value);
            return convertedValue;
        } catch (RuntimeException error) {
            throw createValueFormatException(double.class);
        }
    }

    @Override
    public double getDouble() throws ValueFormatException {
        try {
            double convertedValue = factories().getDoubleFactory().create(value);
            return convertedValue;
        } catch (RuntimeException error) {
            throw createValueFormatException(double.class);
        }
    }

    long getLength() throws RepositoryException {
        if (value == null) return 0L;
        if (type == PropertyType.BINARY) {
            return factories().getBinaryFactory().create(value).getSize();
        }
        return getString().length();
    }

    @Override
    public long getLong() throws ValueFormatException {
        try {
            long convertedValue = factories().getLongFactory().create(value);
            return convertedValue;
        } catch (RuntimeException error) {
            throw createValueFormatException(long.class);
        }
    }

    @Override
    public InputStream getStream() throws ValueFormatException {
        if (value == null) return null;
        try {
            if (asStream == null) {
                BinaryValue binary = factories().getBinaryFactory().create(value);
                asStream = binary.getStream();
            }
            return asStream;
        } catch (Exception error) {
            throw createValueFormatException(InputStream.class);
        }
    }

    @Override
    public BinaryValue getBinary() throws RepositoryException {
        if (value == null) return null;
        try {
            BinaryValue binary = factories().getBinaryFactory().create(value);
            return binary;
        } catch (RuntimeException error) {
            throw createValueFormatException(InputStream.class);
        }
    }

    @Override
    public String getString() throws ValueFormatException {
        try {
            return factories().getStringFactory().create(value);
        } catch (RuntimeException error) {
            throw createValueFormatException(String.class);
        }
    }

    @Override
    public int getType() {
        return type;
    }

    @Override
    public int hashCode() {
        // Use the value's hash code
        return value.hashCode();
    }

    @Override
    public boolean equals( Object obj ) {
        if (obj == this) return true;
        if (obj instanceof JcrValue) {
            JcrValue that = (JcrValue)obj;
            if (this.type != that.type) return false;
            try {
                switch (this.type) {
                    case PropertyType.STRING:
                        return this.getString().equals(that.getString());
                    case PropertyType.BINARY:
                        BinaryFactory binaryFactory = factories().getBinaryFactory();
                        BinaryValue thisValue = binaryFactory.create(this.value);
                        BinaryValue thatValue = binaryFactory.create(that.value);
                        return thisValue.equals(thatValue);
                    case PropertyType.BOOLEAN:
                        return this.getBoolean() == that.getBoolean();
                    case PropertyType.DOUBLE:
                        return this.getDouble() == that.getDouble();
                    case PropertyType.LONG:
                        return this.getLong() == that.getLong();
                    case PropertyType.DECIMAL:
                        return getDecimal().equals(that.getDecimal());
                    case PropertyType.DATE:
                        DateTimeFactory dateFactory = factories().getDateFactory();
                        DateTime thisDateValue = dateFactory.create(this.value);
                        DateTime thatDateValue = dateFactory.create(that.value);
                        return thisDateValue.equals(thatDateValue);
                    case PropertyType.PATH:
                        PathFactory pathFactory = factories().getPathFactory();
                        Path thisPathValue = pathFactory.create(this.value);
                        Path thatPathValue = pathFactory.create(that.value);
                        return thisPathValue.equals(thatPathValue);
                    case PropertyType.NAME:
                        NameFactory nameFactory = factories().getNameFactory();
                        Name thisNameValue = nameFactory.create(this.value);
                        Name thatNameValue = nameFactory.create(that.value);
                        return thisNameValue.equals(thatNameValue);
                    case PropertyType.REFERENCE:
                    case PropertyType.WEAKREFERENCE:
                    case org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE:
                        return this.getString().equals(that.getString());
                    case PropertyType.URI:
                        return this.getString().equals(that.getString());
                    default:
                        throw new SystemFailureException(JcrI18n.invalidPropertyType.text(this.type));
                }
            } catch (RepositoryException e) {
                return false;
            }
            // will not get here
        }
        if (obj instanceof Value) {
            Value that = (Value)obj;
            if (this.type != that.getType()) return false;
            try {
                switch (this.type) {
                    case PropertyType.STRING:
                        return this.getString().equals(that.getString());
                    case PropertyType.BINARY:
                        return IoUtil.isSame(this.getStream(), that.getBinary().getStream());
                    case PropertyType.BOOLEAN:
                        return this.getBoolean() == that.getBoolean();
                    case PropertyType.DOUBLE:
                        return this.getDouble() == that.getDouble();
                    case PropertyType.LONG:
                        return this.getLong() == that.getLong();
                    case PropertyType.DECIMAL:
                        return this.getDecimal().equals(that.getDecimal());
                    case PropertyType.DATE:
                        return this.getDate().equals(that.getDate());
                    case PropertyType.PATH:
                        return this.getString().equals(that.getString());
                    case PropertyType.NAME:
                        return this.getString().equals(that.getString());
                    case PropertyType.REFERENCE:
                    case PropertyType.WEAKREFERENCE:
                    case org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE:
                        return this.getString().equals(that.getString());
                    case PropertyType.URI:
                        return this.getString().equals(that.getString());
                    default:
                        throw new SystemFailureException(JcrI18n.invalidPropertyType.text(this.type));
                }
            } catch (IOException e) {
                return false;
            } catch (RepositoryException e) {
                return false;
            }
            // will not get here
        }
        return false;
    }

    private JcrValue withTypeAndValue( int type,
                                       Object value ) {
        return new JcrValue(factories, type, value);
    }

    /**
     * Returns a copy of the current {@link JcrValue} cast to the JCR type specified by the type argument. This
     * method will attempt to convert the value (using the JCR type conversion rules) only if the existing type does not match the
     * supplied type, and if the conversion fails a {@link ValueFormatException} will be thrown. See the
     * {@link #asType(int, boolean)} method, which is the same as this method except that the conversion can be forced.
     * 

* Calling this method is equivalent to calling: * *

     * asType(type, false);
     * 
* *

* * @param type the JCR type from {@link PropertyType} that the new {@link JcrValue} should have. * @return a new {@link JcrValue} with the given JCR type and an equivalent value. * @throws ValueFormatException if the value contained by this {@link JcrValue} cannot be converted to the desired type. * @see PropertyType * @see #asType(int, boolean) */ final JcrValue asType( int type ) throws ValueFormatException { return asType(type, false); } /** * Returns a copy of the current {@link JcrValue} cast to the JCR type specified by the type argument. If the * value cannot be converted base don the JCR type conversion rules, a {@link ValueFormatException} will be thrown. * * @param type the JCR type from {@link PropertyType} that the new {@link JcrValue} should have. * @param force true if the conversion should always be done, even if this value's type is the same as the expected type * @return a new {@link JcrValue} with the given JCR type and an equivalent value. * @throws ValueFormatException if the value contained by this {@link JcrValue} cannot be converted to the desired type. * @see PropertyType */ final JcrValue asType( int type, boolean force ) throws ValueFormatException { if (!force && type == this.type) { return this.withTypeAndValue(this.type, this.value); } Object value = this.value; switch (type) { case PropertyType.BOOLEAN: // Make sure the existing value is valid per the current type. // This is required if we rely upon the value factories to cast correctly. if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY) { throw createValueFormatException(boolean.class); } try { return this.withTypeAndValue(type, factories().getBooleanFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.DATE: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.DOUBLE && this.type != PropertyType.LONG) { throw createValueFormatException(Calendar.class); } try { return this.withTypeAndValue(type, factories().getDateFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.NAME: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.PATH) { throw createValueFormatException(Name.class); } try { return this.withTypeAndValue(type, factories().getNameFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.PATH: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.NAME) { throw createValueFormatException(Path.class); } try { return this.withTypeAndValue(type, factories().getPathFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.REFERENCE: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.WEAKREFERENCE) { throw createValueFormatException(Node.class); } try { return this.withTypeAndValue(type, factories().getReferenceFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.WEAKREFERENCE: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.REFERENCE) { throw createValueFormatException(Node.class); } try { return this.withTypeAndValue(type, factories().getWeakReferenceFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.REFERENCE && this.type != PropertyType.WEAKREFERENCE) { throw createValueFormatException(Node.class); } try { return this.withTypeAndValue(type, factories().getSimpleReferenceFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.DOUBLE: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.LONG && this.type != PropertyType.DATE) { throw createValueFormatException(double.class); } try { return this.withTypeAndValue(type, factories().getDoubleFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.LONG: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.DOUBLE && this.type != PropertyType.DATE) { throw createValueFormatException(long.class); } try { return this.withTypeAndValue(type, factories().getLongFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.DECIMAL: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.DOUBLE && this.type != PropertyType.LONG && this.type != PropertyType.DATE) { throw createValueFormatException(BigDecimal.class); } try { return this.withTypeAndValue(type, factories().getDecimalFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.URI: if (this.type != PropertyType.STRING && this.type != PropertyType.BINARY && this.type != PropertyType.URI) { throw createValueFormatException(URI.class); } try { return this.withTypeAndValue(type, factories().getUriFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } // Anything can be converted to these types case PropertyType.BINARY: try { return this.withTypeAndValue(type, factories().getBinaryFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.STRING: try { return this.withTypeAndValue(type, factories().getStringFactory().create(value)); } catch (org.modeshape.jcr.value.ValueFormatException vfe) { throw createValueFormatException(vfe); } case PropertyType.UNDEFINED: return this.withTypeAndValue(this.type, this.value); default: assert false : "Unexpected JCR property type " + type; // This should still throw an exception even if assertions are turned off throw new IllegalStateException("Invalid property type " + type); } } protected Object valueToType( int type, Value value ) throws RepositoryException { switch (type) { case PropertyType.BOOLEAN: return factories().getBooleanFactory().create(value.getBoolean()); case PropertyType.DATE: return factories().getDateFactory().create(value.getDate()); case PropertyType.NAME: return factories().getNameFactory().create(value.getString()); case PropertyType.PATH: return factories().getPathFactory().create(value.getString()); case PropertyType.REFERENCE: return factories().getReferenceFactory().create(value.getString()); case PropertyType.WEAKREFERENCE: return factories().getWeakReferenceFactory().create(value.getString()); case org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE: return factories().getSimpleReferenceFactory().create(value.getString()); case PropertyType.DOUBLE: return factories().getDoubleFactory().create(value.getDouble()); case PropertyType.LONG: return factories().getLongFactory().create(value.getLong()); case PropertyType.DECIMAL: return factories().getDecimalFactory().create(value.getDecimal()); case PropertyType.URI: return factories().getUriFactory().create(value.getString()); case PropertyType.BINARY: return factories().getBinaryFactory().create(value.getBinary()); case PropertyType.STRING: return factories().getStringFactory().create(value.getString()); case PropertyType.UNDEFINED: return value.getString(); default: assert false : "Unexpected JCR property type " + type; // This should still throw an exception even if assertions are turned off throw new IllegalStateException("Invalid property type " + type); } } protected Object convertToType( int type, Object value ) { if (value == null) return null; switch (type) { case PropertyType.BOOLEAN: return factories().getBooleanFactory().create(value); case PropertyType.DATE: return factories().getDateFactory().create(value); case PropertyType.NAME: return factories().getNameFactory().create(value); case PropertyType.PATH: return factories().getPathFactory().create(value); case PropertyType.REFERENCE: return factories().getReferenceFactory().create(value); case PropertyType.WEAKREFERENCE: return factories().getWeakReferenceFactory().create(value); case org.modeshape.jcr.api.PropertyType.SIMPLE_REFERENCE: return factories().getSimpleReferenceFactory().create(value); case PropertyType.DOUBLE: return factories().getDoubleFactory().create(value); case PropertyType.LONG: return factories().getLongFactory().create(value); case PropertyType.DECIMAL: return factories().getDecimalFactory().create(value); case PropertyType.URI: return factories().getUriFactory().create(value); case PropertyType.BINARY: return factories().getBinaryFactory().create(value); case PropertyType.STRING: return factories().getStringFactory().create(value); case PropertyType.UNDEFINED: return value; default: assert false : "Unexpected JCR property type " + type; // This should still throw an exception even if assertions are turned off throw new IllegalStateException("Invalid property type " + type); } } @Override public String toString() { return value == null ? "null" : value.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy