📄 propertyimpl.java
字号:
/* * 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.core;import org.apache.jackrabbit.core.state.ItemState;import org.apache.jackrabbit.core.state.ItemStateException;import org.apache.jackrabbit.core.state.PropertyState;import org.apache.jackrabbit.core.value.BLOBFileValue;import org.apache.jackrabbit.core.value.InternalValue;import org.apache.jackrabbit.name.NoPrefixDeclaredException;import org.apache.jackrabbit.name.Path;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.name.PathFormat;import org.apache.jackrabbit.name.NameFormat;import org.apache.jackrabbit.uuid.UUID;import org.apache.jackrabbit.value.BooleanValue;import org.apache.jackrabbit.value.DateValue;import org.apache.jackrabbit.value.DoubleValue;import org.apache.jackrabbit.value.LongValue;import org.apache.jackrabbit.value.ValueHelper;import org.apache.jackrabbit.value.ValueFactoryImpl;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.jcr.AccessDeniedException;import javax.jcr.ItemNotFoundException;import javax.jcr.ItemVisitor;import javax.jcr.Node;import javax.jcr.Property;import javax.jcr.PropertyType;import javax.jcr.RepositoryException;import javax.jcr.Value;import javax.jcr.ValueFormatException;import javax.jcr.InvalidItemStateException;import javax.jcr.lock.LockException;import javax.jcr.nodetype.ConstraintViolationException;import javax.jcr.nodetype.PropertyDefinition;import javax.jcr.version.VersionException;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.Calendar;/** * <code>PropertyImpl</code> implements the <code>Property</code> interface. */public class PropertyImpl extends ItemImpl implements Property { private static Logger log = LoggerFactory.getLogger(PropertyImpl.class); private PropertyDefinition definition; /** * Package private constructor. * * @param itemMgr the <code>ItemManager</code> that created this <code>Property</code> * @param session the <code>Session</code> through which this <code>Property</code> is acquired * @param id id of this <code>Property</code> * @param state state associated with this <code>Property</code> * @param definition definition of <i>this</i> <code>Property</code> * @param listeners listeners on life cylce changes of this <code>PropertyImpl</code> */ PropertyImpl(ItemManager itemMgr, SessionImpl session, PropertyId id, PropertyState state, PropertyDefinition definition, ItemLifeCycleListener[] listeners) { super(itemMgr, session, id, state, listeners); this.definition = definition; // value will be read on demand } protected synchronized ItemState getOrCreateTransientItemState() throws RepositoryException { if (!isTransient()) { // make transient (copy-on-write) try { PropertyState transientState = stateMgr.createTransientPropertyState((PropertyState) state, ItemState.STATUS_EXISTING_MODIFIED); // swap persistent with transient state state = transientState; } catch (ItemStateException ise) { String msg = "failed to create transient state"; log.debug(msg); throw new RepositoryException(msg, ise); } } return state; } protected void makePersistent() throws InvalidItemStateException { if (!isTransient()) { log.debug(safeGetJCRPath() + " (" + id + "): there's no transient state to persist"); return; } PropertyState transientState = (PropertyState) state; PropertyState persistentState = (PropertyState) transientState.getOverlayedState(); if (persistentState == null) { // this property is 'new' persistentState = stateMgr.createNew(transientState); } synchronized (persistentState) { // check staleness of transient state first if (transientState.isStale()) { String msg = safeGetJCRPath() + ": the property cannot be saved because it has been modified externally."; log.debug(msg); throw new InvalidItemStateException(msg); } // copy state from transient state persistentState.setDefinitionId(transientState.getDefinitionId()); persistentState.setType(transientState.getType()); persistentState.setMultiValued(transientState.isMultiValued()); persistentState.setValues(transientState.getValues()); // make state persistent stateMgr.store(persistentState); } // tell state manager to disconnect item state stateMgr.disconnectTransientItemState(transientState); // swap transient state with persistent state state = persistentState; // reset status status = STATUS_NORMAL; } protected void restoreTransient(PropertyState transientState) throws RepositoryException { PropertyState thisState = (PropertyState) getOrCreateTransientItemState(); if (transientState.getStatus() == ItemState.STATUS_NEW && thisState.getStatus() != ItemState.STATUS_NEW) { thisState.setStatus(ItemState.STATUS_NEW); stateMgr.disconnectTransientItemState(thisState); } // reapply transient changes thisState.setDefinitionId(transientState.getDefinitionId()); thisState.setType(transientState.getType()); thisState.setMultiValued(transientState.isMultiValued()); thisState.setValues(transientState.getValues()); } /** * Determines the length of the given value. * * @param value value whose length should be determined * @return the length of the given value * @throws RepositoryException if an error occurs * @see javax.jcr.Property#getLength() * @see javax.jcr.Property#getLengths() */ protected long getLength(InternalValue value) throws RepositoryException { switch (value.getType()) { case PropertyType.STRING: case PropertyType.LONG: case PropertyType.DOUBLE: return value.toString().length(); case PropertyType.NAME: QName name = (QName) value.internalValue(); return session.getJCRName(name).length(); case PropertyType.PATH: Path path = (Path) value.internalValue(); return session.getJCRPath(path).length(); case PropertyType.BINARY: BLOBFileValue blob = (BLOBFileValue) value.internalValue(); return blob.getLength(); default: return -1; } } /** * Checks various pre-conditions that are common to all * <code>setValue()</code> methods. The checks performed are: * <ul> * <li>parent node must be checked-out</li> * <li>property must not be protected</li> * <li>parent node must not be locked by somebody else</li> * <li>property must be multi-valued when set to an array of values * (and vice versa)</li> * </ul> * * @param multipleValues flag indicating whether the property is about to * be set to an array of values * @throws ValueFormatException if a single-valued property is set to an * array of values (and vice versa) * @throws VersionException if the parent node is not checked-out * @throws LockException if the parent node is locked by somebody else * @throws ConstraintViolationException if the property is protected * @throws RepositoryException if another error occurs * @see javax.jcr.Property#setValue */ protected void checkSetValue(boolean multipleValues) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { NodeImpl parent = (NodeImpl) getParent(); // verify that parent node is checked-out if (!parent.internalIsCheckedOut()) { throw new VersionException("cannot set the value of a property of a checked-in node " + safeGetJCRPath()); } // check protected flag if (definition.isProtected()) { throw new ConstraintViolationException("cannot set the value of a protected property " + safeGetJCRPath()); } // check multi-value flag if (multipleValues) { if (!definition.isMultiple()) { throw new ValueFormatException(safeGetJCRPath() + " is not multi-valued"); } } else { if (definition.isMultiple()) { throw new ValueFormatException(safeGetJCRPath() + " is multi-valued and can therefore only be set to an array of values"); } } // check lock status parent.checkLock(); } /** * @param values * @param type * @throws ConstraintViolationException * @throws RepositoryException */ protected void internalSetValue(InternalValue[] values, int type) throws ConstraintViolationException, RepositoryException { // check for null value if (values == null) { // setting a property to null removes it automatically ((NodeImpl) getParent()).removeChildProperty(((PropertyId) id).getName()); return; } ArrayList list = new ArrayList(); // compact array (purge null entries) for (int i = 0; i < values.length; i++) { if (values[i] != null) { list.add(values[i]); } } values = (InternalValue[]) list.toArray(new InternalValue[list.size()]); // modify the state of this property PropertyState thisState = (PropertyState) getOrCreateTransientItemState(); // free old values as necessary InternalValue[] oldValues = thisState.getValues(); if (oldValues != null) { for (int i = 0; i < oldValues.length; i++) { InternalValue old = oldValues[i]; if (old != null && old.getType() == PropertyType.BINARY) { // make sure temporarily allocated data is discarded // before overwriting it ((BLOBFileValue) old.internalValue()).discard(); } } } // set new values thisState.setValues(values); // set type if (type == PropertyType.UNDEFINED) { // fallback to default type type = PropertyType.STRING; } thisState.setType(type); } /** * Same as <code>{@link Property#setValue(String)}</code> except that * this method takes a <code>QName</code> instead of a <code>String</code> * value. * * @param name * @throws ValueFormatException * @throws VersionException * @throws LockException * @throws ConstraintViolationException * @throws RepositoryException */ public void setValue(QName name) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { // check state of this instance sanityCheck(); // check pre-conditions for setting property value checkSetValue(false); // check type according to definition of this property int reqType = definition.getRequiredType(); if (reqType == PropertyType.UNDEFINED) { reqType = PropertyType.NAME; } if (name == null) { internalSetValue(null, reqType); return; } InternalValue internalValue; if (reqType != PropertyType.NAME) { // type conversion required Value targetValue = ValueHelper.convert( InternalValue.create(name).toJCRValue(session.getNamespaceResolver()), reqType, ValueFactoryImpl.getInstance()); internalValue = InternalValue.create(targetValue, session.getNamespaceResolver()); } else { // no type conversion required internalValue = InternalValue.create(name); } internalSetValue(new InternalValue[]{internalValue}, reqType); } /** * Same as <code>{@link Property#setValue(String[])}</code> except that * this method takes an array of <code>QName</code> instead of * <code>String</code> values. * * @param names * @throws ValueFormatException * @throws VersionException * @throws LockException * @throws ConstraintViolationException * @throws RepositoryException */ public void setValue(QName[] names) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { // check state of this instance sanityCheck(); // check pre-conditions for setting property value checkSetValue(true); // check type according to definition of this property int reqType = definition.getRequiredType(); if (reqType == PropertyType.UNDEFINED) { reqType = PropertyType.NAME; } InternalValue[] internalValues = null; // convert to internal values of correct type if (names != null) { internalValues = new InternalValue[names.length]; for (int i = 0; i < names.length; i++) { QName name = names[i]; InternalValue internalValue = null; if (name != null) { if (reqType != PropertyType.NAME) { // type conversion required Value targetValue = ValueHelper.convert( InternalValue.create(name).toJCRValue(session.getNamespaceResolver()), reqType, ValueFactoryImpl.getInstance()); internalValue = InternalValue.create(targetValue, session.getNamespaceResolver()); } else { // no type conversion required internalValue = InternalValue.create(name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -