Package org.apache.jackrabbit.oak.jcr

Source Code of org.apache.jackrabbit.oak.jcr.PropertyImpl

/*
* 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.jcr;

import org.apache.jackrabbit.mk.model.PropertyState;
import org.apache.jackrabbit.oak.jcr.state.TransientNodeState;
import org.apache.jackrabbit.oak.jcr.util.LogUtil;
import org.apache.jackrabbit.oak.jcr.util.Path;
import org.apache.jackrabbit.oak.jcr.util.ValueConverter;
import org.apache.jackrabbit.value.ValueHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Binary;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.PropertyDefinition;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Calendar;

/**
* {@code PropertyImpl}...
*/
public class PropertyImpl extends ItemImpl implements Property {

    /**
     * logger instance
     */
    private static final Logger log = LoggerFactory.getLogger(PropertyImpl.class);

    private final TransientNodeState parentState;
    private final PropertyState state;

    static Property create(SessionContext<SessionImpl> sessionContext, Path path) throws PathNotFoundException,
            ItemNotFoundException {

        TransientNodeState parentState = getNodeState(sessionContext, path.getParent());
        if (parentState == null) {
            throw new PathNotFoundException(path.toJcrPath());
        }

        String name = path.getName();
        PropertyState state = parentState.getPropertyState(name);
        return new PropertyImpl(sessionContext, parentState, state);
    }

    static Property create(SessionContext<SessionImpl> sessionContext, TransientNodeState parentState, PropertyState state) {
        return new PropertyImpl(sessionContext, parentState, state);
    }

    public static boolean exist(SessionContext<SessionImpl> sessionContext, Path path) {
        TransientNodeState parentState = getNodeState(sessionContext, path.getParent());
        return parentState != null && parentState.hasProperty(path.getName());
    }

    private PropertyImpl(SessionContext<SessionImpl> sessionContext, TransientNodeState parentState, PropertyState state) {
        super(sessionContext);
        this.parentState = parentState;
        this.state = state;
    }

    //---------------------------------------------------------------< Item >---
    /**
     * @see javax.jcr.Item#isNode()
     */
    @Override
    public boolean isNode() {
        return false;
    }

    /**
     * @see javax.jcr.Item#getName()
     */
    @Override
    public String getName() throws RepositoryException {
        return state.getName();
    }

    /**
     * @see javax.jcr.Property#getPath() ()
     */
    @Override
    public String getPath() throws RepositoryException {
        return parentState.getPath().concat(state.getName()).toJcrPath();
    }

    /**
     * @see javax.jcr.Item#getParent()
     */
    @Override
    public Node getParent() throws RepositoryException {
        return NodeImpl.create(sessionContext, parentState);
    }

    /**
     * @see Item#getAncestor(int)
     */
    @Override
    public Item getAncestor(int depth) throws RepositoryException {
        if (depth == getDepth() - 1) {
            return getParent();
        } else {
            return getParent().getAncestor(depth);
        }
    }

    /**
     * @see javax.jcr.Item#getDepth()
     */
    @Override
    public int getDepth() throws RepositoryException {
        return parentState.getPath().getDepth() + 1;
    }

    /**
     * @see javax.jcr.Item#isNew()
     */
    @Override
    public boolean isNew() {
        return parentState.isPropertyNew(state.getName());
    }

    /**
     * @see javax.jcr.Item#isModified() ()
     */
    @Override
    public boolean isModified() {
        return parentState.isPropertyModified(state.getName());
    }

    /**
     * @see javax.jcr.Item#isNew()
     */
    @Override
    public void remove() throws RepositoryException {
        parentState.removeProperty(state.getName());
    }

    /**
     * @see javax.jcr.Item#accept(javax.jcr.ItemVisitor)
     */
    @Override
    public void accept(ItemVisitor visitor) throws RepositoryException {
        checkStatus();
        visitor.visit(this);
    }

    //-----------------------------------------------------------< Property >---
    /**
     * @see Property#setValue(Value)
     */
    @Override
    public void setValue(Value value) throws RepositoryException {
        checkStatus();

        int valueType = (value != null) ? value.getType() : PropertyType.UNDEFINED;
        int reqType = getRequiredType(valueType);
        setValue(value, reqType);
    }

    /**
     * @see Property#setValue(Value[])
     */
    @Override
    public void setValue(Value[] values) throws RepositoryException {
        checkStatus();

        // assert equal types for all values entries
        int valueType = PropertyType.UNDEFINED;
        if (values != null) {
            for (Value value : values) {
                if (value == null) {
                    // skip null values as those will be purged later
                    continue;
                }
                if (valueType == PropertyType.UNDEFINED) {
                    valueType = value.getType();
                }
                else if (valueType != value.getType()) {
                    String msg = "Inhomogeneous type of values (" + LogUtil.safeGetJCRPath(this) + ')';
                    log.debug(msg);
                    throw new ValueFormatException(msg);
                }
            }
        }

        int reqType = getRequiredType(valueType);
        setValues(values, reqType);
    }

    /**
     * @see Property#setValue(String)
     */
    @Override
    public void setValue(String value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.STRING);
        if (value == null) {
            setValue(null, reqType);
        } else {
            setValue(getValueFactory().createValue(value), reqType);
        }
    }

    /**
     * @see Property#setValue(String[])
     */
    @Override
    public void setValue(String[] values) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.STRING);
        Value[] vs;
        if (values == null) {
            vs = null;
        } else {
            vs = new Value[values.length];
            for (int i = 0; i < values.length; i++) {
                vs[i] = getValueFactory().createValue(values[i]);
            }
        }
        setValues(vs, reqType);
    }

    /**
     * @see Property#setValue(InputStream)
     */
    @Override
    public void setValue(InputStream value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.BINARY);
        if (value == null) {
            setValue(null, reqType);
        } else {
            setValue(getValueFactory().createValue(value), reqType);
        }
    }

    /**
     * @see Property#setValue(Binary)
     */
    @Override
    public void setValue(Binary value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.BINARY);
        if (value == null) {
            setValue(null, reqType);
        } else {
            setValue(getValueFactory().createValue(value), reqType);
        }
    }

    /**
     * @see Property#setValue(long)
     */
    @Override
    public void setValue(long value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.LONG);
        setValue(getValueFactory().createValue(value), reqType);
    }

    /**
     * @see Property#setValue(double)
     */
    @Override
    public void setValue(double value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.DOUBLE);
        setValue(getValueFactory().createValue(value), reqType);
    }

    /**
     * @see Property#setValue(BigDecimal)
     */
    @Override
    public void setValue(BigDecimal value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.DECIMAL);
        setValue(getValueFactory().createValue(value), reqType);
    }

    /**
     * @see Property#setValue(Calendar)
     */
    @Override
    public void setValue(Calendar value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.DATE);
        if (value == null) {
            setValue(null, reqType);
        } else {
            setValue(getValueFactory().createValue(value), reqType);
        }
    }

    /**
     * @see Property#setValue(boolean)
     */
    @Override
    public void setValue(boolean value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.BOOLEAN);
        setValue(getValueFactory().createValue(value), reqType);
    }

    /**
     * @see Property#setValue(javax.jcr.Node)
     */
    @Override
    public void setValue(Node value) throws RepositoryException {
        checkStatus();

        int reqType = getRequiredType(PropertyType.REFERENCE);
        if (value == null) {
            setValue(null, reqType);
        } else {
            setValue(getValueFactory().createValue(value), reqType);
        }
    }

    @Override
    public Value getValue() throws RepositoryException {
        checkStatus();
        if (isMultiple()) {
            throw new ValueFormatException(LogUtil.safeGetJCRPath(this) + " is multi-valued.");
        }

        return ValueConverter.toValue(getValueFactory(), state.getScalar());
    }

    @Override
    public Value[] getValues() throws RepositoryException {
        checkStatus();
        if (!isMultiple()) {
            throw new ValueFormatException(LogUtil.safeGetJCRPath(this) + " is not multi-valued.");
        }

        return ValueConverter.toValues(getValueFactory(), state.getArray());
    }

    /**
     * @see Property#getString()
     */
    @Override
    public String getString() throws RepositoryException {
        return getValue().getString();
    }

    /**
     * @see Property#getStream()
     */
    @Override
    public InputStream getStream() throws RepositoryException {
        return getValue().getStream();
    }

    /**
     * @see javax.jcr.Property#getBinary()
     */
    @Override
    public Binary getBinary() throws RepositoryException {
        return getValue().getBinary();
    }

    /**
     * @see Property#getLong()
     */
    @Override
    public long getLong() throws RepositoryException {
        return getValue().getLong();
    }

    /**
     * @see Property#getDouble()
     */
    @Override
    public double getDouble() throws RepositoryException {
        return getValue().getDouble();
    }

    /**
     * @see Property#getDecimal()
     */
    @Override
    public BigDecimal getDecimal() throws RepositoryException {
        return getValue().getDecimal();
    }

    /**
     * @see Property#getDate()
     */
    @Override
    public Calendar getDate() throws RepositoryException {
        return getValue().getDate();
    }

    /**
     * @see Property#getBoolean()
     */
    @Override
    public boolean getBoolean() throws RepositoryException {
        return getValue().getBoolean();
    }

    /**
     * @see javax.jcr.Property#getNode()
     */
    @Override
    public Node getNode() throws RepositoryException {
        Value value = getValue();
        switch (value.getType()) {
            case PropertyType.REFERENCE:
            case PropertyType.WEAKREFERENCE:
                return getSession().getNodeByIdentifier(value.getString());

            case PropertyType.PATH:
            case PropertyType.NAME:
                String path = value.getString();
                try {
                    return (path.charAt(0) == '/') ? getSession().getNode(path) : getParent().getNode(path);
                } catch (PathNotFoundException e) {
                    throw new ItemNotFoundException(path);
                }

            case PropertyType.STRING:
                try {
                    Value refValue = ValueHelper.convert(value, PropertyType.REFERENCE, getValueFactory());
                    return getSession().getNodeByIdentifier(refValue.getString());
                } catch (ItemNotFoundException e) {
                    throw e;
                } catch (RepositoryException e) {
                    // try if STRING value can be interpreted as PATH value
                    Value pathValue = ValueHelper.convert(value, PropertyType.PATH, getValueFactory());
                    path = pathValue.getString();
                    try {
                        return (path.charAt(0) == '/') ? getSession().getNode(path) : getParent().getNode(path);
                    } catch (PathNotFoundException e1) {
                        throw new ItemNotFoundException(pathValue.getString());
                    }
                }

            default:
                throw new ValueFormatException("Property value cannot be converted to a PATH, REFERENCE or WEAKREFERENCE");
        }
    }

    /**
     * @see javax.jcr.Property#getProperty()
     */
    @Override
    public Property getProperty() throws RepositoryException {
        Value value = getValue();
        Value pathValue = ValueHelper.convert(value, PropertyType.PATH, getValueFactory());
        String path = pathValue.getString();
        try {
            return (path.charAt(0) == '/') ? getSession().getProperty(path) : getParent().getProperty(path);
        } catch (PathNotFoundException e) {
            throw new ItemNotFoundException(path);
        }
    }

    /**
     * @see javax.jcr.Property#getLength()
     */
    @Override
    public long getLength() throws RepositoryException {
        return getLength(getValue());
    }

    /**
     * @see javax.jcr.Property#getLengths()
     */
    @Override
    public long[] getLengths() throws RepositoryException {
        Value[] values = getValues();
        long[] lengths = new long[values.length];

        for (int i = 0; i < values.length; i++) {
            lengths[i] = getLength(values[i]);
        }
        return lengths;
    }

    @Override
    public PropertyDefinition getDefinition() throws RepositoryException {
        // TODO
        return null;
    }

    /**
     * @see javax.jcr.Property#getType()
     */
    @Override
    public int getType() throws RepositoryException {
        if (isMultiple()) {
            Value[] values = getValues();
            if (values.length == 0) {
                // retrieve the type from the property definition
                return getRequiredType(PropertyType.UNDEFINED);
            } else {
                return values[0].getType();
            }
        } else {
            return getValue().getType();
        }
    }

    /**
     * @see javax.jcr.Property#isMultiple()
     */
    @Override
    public boolean isMultiple() throws RepositoryException {
        return state.isArray();
    }

    //------------------------------------------------------------< private >---

    /**
     *
     * @param defaultType
     * @return the required type for this property.
     */
    private int getRequiredType(int defaultType) throws RepositoryException {
        // check type according to definition of this property
        PropertyDefinition def = getDefinition();
        int reqType = (def == null) ? PropertyType.UNDEFINED : getDefinition().getRequiredType();
        if (reqType == PropertyType.UNDEFINED) {
            if (defaultType == PropertyType.UNDEFINED) {
                reqType = PropertyType.STRING;
            } else {
                reqType = defaultType;
            }
        }
        return reqType;
    }

    /**
     *
     * @param value
     * @param requiredType
     * @throws RepositoryException
     */
    private void setValue(Value value, int requiredType) throws RepositoryException {
        if (requiredType == PropertyType.UNDEFINED) {
            // should never get here since calling methods assert valid type
            throw new IllegalArgumentException("Property type of a value cannot be undefined (" + LogUtil.safeGetJCRPath(this) + ").");
        }

        if (value == null) {
            remove();
        }
        else {
            parentState.setProperty(state.getName(), ValueConverter.toScalar(value));
        }
    }

    /**
     *
     * @param values
     * @param requiredType
     * @throws RepositoryException
     */
    private void setValues(Value[] values, int requiredType) throws RepositoryException {
        if (requiredType == PropertyType.UNDEFINED) {
            // should never get here since calling methods assert valid type
            throw new IllegalArgumentException("Property type of a value cannot be undefined (" + LogUtil.safeGetJCRPath(this) + ").");
        }

        if (values == null) {
            remove();
        }
        else {
            parentState.setProperty(state.getName(), ValueConverter.toScalar(values));
        }
    }

    /**
     * Return the length of the specified JCR value object.
     *
     * @param value The value.
     * @return The length of the given value.
     * @throws RepositoryException If an error occurs.
     */
    private static long getLength(Value value) throws RepositoryException {
        if (value.getType() == PropertyType.BINARY) {
            return value.getBinary().getSize();
        }
        else {
            return value.getString().length();
        }
    }

}
TOP

Related Classes of org.apache.jackrabbit.oak.jcr.PropertyImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.