org.apache.jackrabbit.jcr2spi.PropertyImpl Maven / Gradle / Ivy
/*
* 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.jcr2spi;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Calendar;
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.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.version.VersionException;
import org.apache.jackrabbit.jcr2spi.operation.Operation;
import org.apache.jackrabbit.jcr2spi.operation.SetPropertyValue;
import org.apache.jackrabbit.jcr2spi.state.PropertyState;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.QPropertyDefinition;
import org.apache.jackrabbit.spi.QValue;
import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
import org.apache.jackrabbit.spi.commons.value.ValueFormat;
import org.apache.jackrabbit.value.ValueHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* PropertyImpl
...
*/
public class PropertyImpl extends ItemImpl implements Property {
private static Logger log = LoggerFactory.getLogger(PropertyImpl.class);
public static final int UNDEFINED_PROPERTY_LENGTH = -1;
public PropertyImpl(SessionImpl session, PropertyState state, ItemLifeCycleListener[] listeners) {
super(session, state, listeners);
// NOTE: JCR value(s) will be read (and converted from the internal value
// representation) on demand.
}
//-----------------------------------------------------< Item interface >---
/**
* @see Item#getName()
*/
@Override
public String getName() throws RepositoryException {
checkStatus();
Name name = getQName();
return session.getNameResolver().getJCRName(name);
}
/**
* Implementation of {@link Item#accept(javax.jcr.ItemVisitor)} for property.
*
* @param visitor
* @see Item#accept(javax.jcr.ItemVisitor)
*/
@Override
public void accept(ItemVisitor visitor) throws RepositoryException {
checkStatus();
visitor.visit(this);
}
/**
* Returns false
*
* @return false
* @see javax.jcr.Item#isNode()
*/
@Override
public boolean isNode() {
return false;
}
//-------------------------------------------------< Property interface >---
/**
* @see Property#setValue(javax.jcr.Value)
*/
public void setValue(Value value) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(false);
int valueType = (value != null) ? value.getType() : PropertyType.UNDEFINED;
int reqType = getRequiredType(valueType);
setValue(value, reqType);
}
/**
* @see Property#setValue(javax.jcr.Value[])
*/
public void setValue(Value[] values) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(true);
// assert equal types for all values entries
int valueType = PropertyType.UNDEFINED;
if (values != null) {
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
// skip null values as those will be purged later
continue;
}
if (valueType == PropertyType.UNDEFINED) {
valueType = values[i].getType();
} else if (valueType != values[i].getType()) {
String msg = "Inhomogeneous type of values (" + safeGetJCRPath() + ")";
log.debug(msg);
throw new ValueFormatException(msg);
}
}
}
int targetType = getDefinition().getRequiredType();
if (targetType == PropertyType.UNDEFINED) {
targetType = (valueType == PropertyType.UNDEFINED) ? PropertyType.STRING : valueType;
}
// convert to internal values of correct type
QValue[] qValues = null;
if (values != null) {
Value[] vs = ValueHelper.convert(values, targetType, session.getValueFactory());
qValues = ValueFormat.getQValues(vs, session.getNamePathResolver(), session.getQValueFactory());
}
setInternalValues(qValues, targetType);
}
/**
* @see Property#setValue(String)
*/
public void setValue(String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.STRING);
if (value == null) {
setInternalValues(null, reqType);
} else {
setValue(session.getValueFactory().createValue(value), reqType);
}
}
/**
* @see Property#setValue(String[])
*/
public void setValue(String[] values) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(true);
int reqType = getRequiredType(PropertyType.STRING);
QValue[] qValues = null;
// convert to internal values of correct type
if (values != null) {
qValues = new QValue[values.length];
for (int i = 0; i < values.length; i++) {
String string = values[i];
QValue qValue = null;
if (string != null) {
if (reqType != PropertyType.STRING) {
// type conversion required
Value v = ValueHelper.convert(string, reqType, session.getValueFactory());
qValue = ValueFormat.getQValue(v, session.getNamePathResolver(), session.getQValueFactory());
} else {
// no type conversion required
qValue = session.getQValueFactory().create(string, PropertyType.STRING);
}
}
qValues[i] = qValue;
}
}
setInternalValues(qValues, reqType);
}
/**
* @see Property#setValue(InputStream)
*/
public void setValue(InputStream value) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.BINARY);
if (value == null) {
setInternalValues(null, reqType);
} else {
setValue(session.getValueFactory().createValue(value), reqType);
}
}
/**
* @see Property#setValue(Binary)
*/
public void setValue(Binary value) throws RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.BINARY);
if (value == null) {
setInternalValues(null, reqType);
} else {
setValue(session.getValueFactory().createValue(value), reqType);
}
}
/**
* @see Property#setValue(long)
*/
public void setValue(long value) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.LONG);
setValue(session.getValueFactory().createValue(value), reqType);
}
/**
* @see Property#setValue(double)
*/
public void setValue(double value) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.DOUBLE);
setValue(session.getValueFactory().createValue(value), reqType);
}
/**
* @see Property#setValue(BigDecimal)
*/
public void setValue(BigDecimal value) throws RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.DECIMAL);
setValue(session.getValueFactory().createValue(value), reqType);
}
/**
* @see Property#setValue(Calendar)
*/
public void setValue(Calendar value) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.DATE);
if (value == null) {
setInternalValues(null, reqType);
} else {
setValue(session.getValueFactory().createValue(value), reqType);
}
}
/**
* @see Property#setValue(boolean)
*/
public void setValue(boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.BOOLEAN);
setValue(session.getValueFactory().createValue(value), reqType);
}
/**
* @see Property#setValue(Node)
*/
public void setValue(Node value) throws ValueFormatException, VersionException, LockException, RepositoryException {
checkIsWritable(false);
int reqType = getRequiredType(PropertyType.REFERENCE);
if (value == null) {
setInternalValues(null, reqType);
} else {
checkValidReference(value, reqType, session.getNameResolver());
QValue qValue = session.getQValueFactory().create(value.getUUID(), PropertyType.REFERENCE);
setInternalValues(new QValue[]{qValue}, reqType);
}
}
/**
* @see Property#getValue()
*/
public Value getValue() throws ValueFormatException, RepositoryException {
QValue value = getQValue();
return ValueFormat.getJCRValue(value, session.getNamePathResolver(), session.getJcrValueFactory());
}
/**
* @see Property#getValues()
*/
public Value[] getValues() throws ValueFormatException, RepositoryException {
QValue[] qValues = getQValues();
Value[] values = new Value[qValues.length];
for (int i = 0; i < qValues.length; i++) {
values[i] = ValueFormat.getJCRValue(qValues[i], session.getNamePathResolver(), session.getJcrValueFactory());
}
return values;
}
/**
* @see Property#getString()
*/
public String getString() throws ValueFormatException, RepositoryException {
return getValue().getString();
}
/**
* @see Property#getStream()
*/
public InputStream getStream() throws ValueFormatException, RepositoryException {
return getValue().getStream();
}
/**
* @see Property#getBinary()
*/
public Binary getBinary() throws RepositoryException {
return getValue().getBinary();
}
/**
* @see Property#getLong()
*/
public long getLong() throws ValueFormatException, RepositoryException {
return getValue().getLong();
}
/**
* @see Property#getDouble()
*/
public double getDouble() throws ValueFormatException, RepositoryException {
return getValue().getDouble();
}
/**
* @see Property#getDecimal()
*/
public BigDecimal getDecimal() throws RepositoryException {
return getValue().getDecimal();
}
/**
* @see Property#getDate()
*/
public Calendar getDate() throws ValueFormatException, RepositoryException {
return getValue().getDate();
}
/**
* @see Property#getBoolean()
*/
public boolean getBoolean() throws ValueFormatException, RepositoryException {
return getValue().getBoolean();
}
/**
* @see Property#getNode()
*/
public Node getNode() throws ValueFormatException, RepositoryException {
Value value = getValue();
switch (value.getType()) {
case PropertyType.REFERENCE:
case PropertyType.WEAKREFERENCE:
return session.getNodeByIdentifier(value.getString());
case PropertyType.PATH:
case PropertyType.NAME:
String path = value.getString();
Path p = session.getPathResolver().getQPath(path);
try {
return (p.isAbsolute()) ? session.getNode(path) : getParent().getNode(path);
} catch (PathNotFoundException e) {
throw new ItemNotFoundException(path);
}
case PropertyType.STRING:
try {
Value refValue = ValueHelper.convert(value, PropertyType.REFERENCE, session.getValueFactory());
return session.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, session.getValueFactory());
p = session.getPathResolver().getQPath(pathValue.getString());
try {
return (p.isAbsolute()) ? session.getNode(pathValue.getString()) : getParent().getNode(pathValue.getString());
} catch (PathNotFoundException e1) {
throw new ItemNotFoundException(pathValue.getString());
}
}
default:
throw new ValueFormatException("Property value cannot be converted to a PATH, REFERENCE or WEAKREFERENCE");
}
}
/**
* @see Property#getProperty()
*/
public Property getProperty() throws RepositoryException {
Value value = getValue();
Value pathValue = ValueHelper.convert(value, PropertyType.PATH, session.getValueFactory());
String path = pathValue.getString();
boolean absolute;
try {
Path p = session.getPathResolver().getQPath(path);
absolute = p.isAbsolute();
} catch (RepositoryException e) {
throw new ValueFormatException("Property value cannot be converted to a PATH");
}
try {
return (absolute) ? session.getProperty(path) : getParent().getProperty(path);
} catch (PathNotFoundException e) {
throw new ItemNotFoundException(path);
}
}
/**
* @see Property#getLength
*/
public long getLength() throws ValueFormatException, RepositoryException {
return getLength(getQValue());
}
/**
* @see Property#getLengths
*/
public long[] getLengths() throws ValueFormatException, RepositoryException {
QValue[] values = getQValues();
long[] lengths = new long[values.length];
for (int i = 0; i < values.length; i++) {
lengths[i] = getLength(values[i]);
}
return lengths;
}
/**
*
* @param value
* @return
* @throws RepositoryException
*/
private long getLength(QValue value) throws RepositoryException {
long length;
switch (value.getType()) {
case PropertyType.NAME:
case PropertyType.PATH:
String jcrString = ValueFormat.getJCRString(value, session.getNamePathResolver());
length = jcrString.length();
break;
default:
length = value.getLength();
break;
}
return length;
}
/**
* @see javax.jcr.Property#getDefinition()
*/
public PropertyDefinition getDefinition() throws RepositoryException {
checkStatus();
QPropertyDefinition qpd = getPropertyState().getDefinition();
return session.getNodeTypeManager().getPropertyDefinition(qpd);
}
/**
* @see javax.jcr.Property#getType()
*/
public int getType() throws RepositoryException {
checkStatus();
return getPropertyState().getType();
}
/**
*
* @return true if the definition indicates that this Property is multivalued.
*/
public boolean isMultiple() {
return getPropertyState().isMultiValued();
}
//-----------------------------------------------------------< ItemImpl >---
/**
* Returns the Name defined with this PropertyState
*
* @return
* @see PropertyState#getName()
* @see ItemImpl#getName()
*/
@Override
Name getQName() {
return getPropertyState().getName();
}
//------------------------------------------------------< check methods >---
/**
*
* @param multiValues
* @throws RepositoryException
*/
private void checkIsWritable(boolean multiValues) throws RepositoryException {
// check common to properties and nodes
checkIsWritable();
// property specific check
if (isMultiple() != multiValues) {
throw new ValueFormatException(getPath() + "Multivalue definition of " + safeGetJCRPath() + " does not match to given value(s).");
}
}
//---------------------------------------------< private implementation >---
/**
*
* @param defaultType
* @return the required type for this property.
*/
private int getRequiredType(int defaultType) throws RepositoryException {
// check type according to definition of this property
int reqType = getDefinition().getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
if (defaultType == PropertyType.UNDEFINED) {
reqType = PropertyType.STRING;
} else {
reqType = defaultType;
}
}
return reqType;
}
/**
*
* @return
* @throws ValueFormatException
* @throws RepositoryException
*/
private QValue getQValue() throws ValueFormatException, RepositoryException {
checkStatus();
if (isMultiple()) {
throw new ValueFormatException(safeGetJCRPath() + " is multi-valued and can therefore only be retrieved as an array of values");
}
// avoid unnecessary object creation if possible
return getPropertyState().getValue();
}
/**
*
* @return
* @throws ValueFormatException
* @throws RepositoryException
*/
private QValue[] getQValues() throws ValueFormatException, RepositoryException {
checkStatus();
if (!isMultiple()) {
throw new ValueFormatException(safeGetJCRPath() + " is not multi-valued and can therefore only be retrieved as single value");
}
// avoid unnecessary object creation if possible
return getPropertyState().getValues();
}
/**
*
* @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 (" + safeGetJCRPath() + ").");
}
if (value == null) {
setInternalValues(null, requiredType);
return;
}
QValue qValue;
if (requiredType != value.getType()) {
// type conversion required
Value v = ValueHelper.convert(value, requiredType, session.getValueFactory());
qValue = ValueFormat.getQValue(v, session.getNamePathResolver(), session.getQValueFactory());
} else {
// no type conversion required
qValue = ValueFormat.getQValue(value, session.getNamePathResolver(), session.getQValueFactory());
}
setInternalValues(new QValue[]{qValue}, requiredType);
}
/**
*
* @param qValues
* @param valueType
* @throws ConstraintViolationException
* @throws RepositoryException
*/
private void setInternalValues(QValue[] qValues, int valueType) throws ConstraintViolationException, RepositoryException {
// check for null value
if (qValues == null) {
// setting a property to null removes it automatically
remove();
return;
}
// modify the state of this property
Operation op = SetPropertyValue.create(getPropertyState(), qValues, valueType);
session.getSessionItemStateManager().execute(op);
}
/**
* Private helper to access the PropertyState
directly
*
* @return state for this Property
*/
private PropertyState getPropertyState() {
return (PropertyState) getItemState();
}
/**
*
* @param value
* @param propertyType
* @throws ValueFormatException
* @throws RepositoryException
*/
static void checkValidReference(Node value, int propertyType, NameResolver resolver) throws ValueFormatException, RepositoryException {
if (propertyType == PropertyType.REFERENCE) {
String jcrName = resolver.getJCRName(NameConstants.MIX_REFERENCEABLE);
if (!value.isNodeType(jcrName)) {
throw new ValueFormatException("Target node must be of node type mix:referenceable");
}
} else {
throw new ValueFormatException("Property must be of type REFERENCE.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy