use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class ItemValidator method validate.
/**
* Checks whether the given node state satisfies the constraints specified
* by its primary and mixin node types. The following validations/checks are
* performed:
* <ul>
* <li>check if its node type satisfies the 'required node types' constraint
* specified in its definition</li>
* <li>check if all 'mandatory' child items exist</li>
* <li>for every property: check if the property value satisfies the
* value constraints specified in the property's definition</li>
* </ul>
*
* @param nodeState state of node to be validated
* @throws ConstraintViolationException if any of the validations fail
* @throws RepositoryException if another error occurs
*/
public void validate(NodeState nodeState) throws ConstraintViolationException, RepositoryException {
// effective primary node type
NodeTypeRegistry registry = context.getNodeTypeRegistry();
EffectiveNodeType entPrimary = registry.getEffectiveNodeType(nodeState.getNodeTypeName());
// effective node type (primary type incl. mixins)
EffectiveNodeType entPrimaryAndMixins = getEffectiveNodeType(nodeState);
QNodeDefinition def = context.getItemManager().getDefinition(nodeState).unwrap();
// check if primary type satisfies the 'required node types' constraint
for (Name requiredPrimaryType : def.getRequiredPrimaryTypes()) {
if (!entPrimary.includesNodeType(requiredPrimaryType)) {
String msg = safeGetJCRPath(nodeState.getNodeId()) + ": missing required primary type " + requiredPrimaryType;
log.debug(msg);
throw new ConstraintViolationException(msg);
}
}
// mandatory properties
for (QPropertyDefinition pd : entPrimaryAndMixins.getMandatoryPropDefs()) {
if (!nodeState.hasPropertyName(pd.getName())) {
String msg = safeGetJCRPath(nodeState.getNodeId()) + ": mandatory property " + pd.getName() + " does not exist";
log.debug(msg);
throw new ConstraintViolationException(msg);
}
}
// mandatory child nodes
for (QItemDefinition cnd : entPrimaryAndMixins.getMandatoryNodeDefs()) {
if (!nodeState.hasChildNodeEntry(cnd.getName())) {
String msg = safeGetJCRPath(nodeState.getNodeId()) + ": mandatory child node " + cnd.getName() + " does not exist";
log.debug(msg);
throw new ConstraintViolationException(msg);
}
}
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class NodeImpl method setPrimaryType.
/**
* {@inheritDoc}
*/
public void setPrimaryType(String nodeTypeName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
// check state of this instance
sanityCheck();
// make sure this node is checked-out, neither protected nor locked and
// the editing session has sufficient permission to change the primary type.
int options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
sessionContext.getItemValidator().checkModify(this, options, Permission.NODE_TYPE_MNGMT);
final NodeState state = data.getNodeState();
if (state.getParentId() == null) {
String msg = "changing the primary type of the root node is not supported";
log.debug(msg);
throw new RepositoryException(msg);
}
Name ntName = sessionContext.getQName(nodeTypeName);
if (ntName.equals(state.getNodeTypeName())) {
log.debug("Node already has " + nodeTypeName + " as primary node type.");
return;
}
NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
NodeType nt = ntMgr.getNodeType(ntName);
if (nt.isMixin()) {
throw new ConstraintViolationException(nodeTypeName + ": not a primary node type.");
} else if (nt.isAbstract()) {
throw new ConstraintViolationException(nodeTypeName + ": is an abstract node type.");
}
// build effective node type of new primary type & existing mixin's
// in order to detect conflicts
NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
EffectiveNodeType entNew, entOld, entAll;
try {
entNew = ntReg.getEffectiveNodeType(ntName);
entOld = ntReg.getEffectiveNodeType(state.getNodeTypeName());
// try to build new effective node type (will throw in case of conflicts)
entAll = ntReg.getEffectiveNodeType(ntName, state.getMixinTypeNames());
} catch (NodeTypeConflictException ntce) {
throw new ConstraintViolationException(ntce.getMessage());
}
// get applicable definition for this node using new primary type
QNodeDefinition nodeDef;
try {
NodeImpl parent = (NodeImpl) getParent();
nodeDef = parent.getApplicableChildNodeDefinition(getQName(), ntName).unwrap();
} catch (RepositoryException re) {
String msg = this + ": no applicable definition found in parent node's node type";
log.debug(msg);
throw new ConstraintViolationException(msg, re);
}
if (!nodeDef.equals(itemMgr.getDefinition(state).unwrap())) {
onRedefine(nodeDef);
}
Set<QItemDefinition> oldDefs = new HashSet<QItemDefinition>(Arrays.asList(entOld.getAllItemDefs()));
Set<QItemDefinition> newDefs = new HashSet<QItemDefinition>(Arrays.asList(entNew.getAllItemDefs()));
Set<QItemDefinition> allDefs = new HashSet<QItemDefinition>(Arrays.asList(entAll.getAllItemDefs()));
// added child item definitions
Set<QItemDefinition> addedDefs = new HashSet<QItemDefinition>(newDefs);
addedDefs.removeAll(oldDefs);
// referential integrity check
boolean referenceableOld = entOld.includesNodeType(NameConstants.MIX_REFERENCEABLE);
boolean referenceableNew = entNew.includesNodeType(NameConstants.MIX_REFERENCEABLE);
if (referenceableOld && !referenceableNew) {
// node would become non-referenceable;
// make sure no references exist
PropertyIterator iter = getReferences();
if (iter.hasNext()) {
throw new ConstraintViolationException("the new primary type cannot be set as it would render " + "this node 'non-referenceable' while it is still being " + "referenced through at least one property of type REFERENCE");
}
}
// do the actual modifications in content as mandated by the new primary type
// modify the state of this node
NodeState thisState = (NodeState) getOrCreateTransientItemState();
thisState.setNodeTypeName(ntName);
// set jcr:primaryType property
internalSetProperty(NameConstants.JCR_PRIMARYTYPE, InternalValue.create(ntName));
// walk through properties and child nodes and change definition as necessary
// use temp set to avoid ConcurrentModificationException
HashSet<Name> set = new HashSet<Name>(thisState.getPropertyNames());
for (Name propName : set) {
try {
PropertyState propState = (PropertyState) stateMgr.getItemState(new PropertyId(thisState.getNodeId(), propName));
if (!allDefs.contains(itemMgr.getDefinition(propState).unwrap())) {
// redefine property if possible
try {
PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
if (prop.getDefinition().isProtected()) {
// remove 'orphaned' protected properties immediately
removeChildProperty(propName);
continue;
}
PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(propName, propState.getType(), propState.isMultiValued(), false);
if (pdi.getRequiredType() != PropertyType.UNDEFINED && pdi.getRequiredType() != propState.getType()) {
// value conversion required
if (propState.isMultiValued()) {
// convert value
Value[] values = ValueHelper.convert(prop.getValues(), pdi.getRequiredType(), getSession().getValueFactory());
// redefine property
prop.onRedefine(pdi.unwrap());
// set converted values
prop.setValue(values);
} else {
// convert value
Value value = ValueHelper.convert(prop.getValue(), pdi.getRequiredType(), getSession().getValueFactory());
// redefine property
prop.onRedefine(pdi.unwrap());
// set converted values
prop.setValue(value);
}
} else {
// redefine property
prop.onRedefine(pdi.unwrap());
}
// update collection of added definitions
addedDefs.remove(pdi.unwrap());
} catch (ValueFormatException vfe) {
// value conversion failed, remove it
removeChildProperty(propName);
} catch (ConstraintViolationException cve) {
// no suitable definition found for this property,
// remove it
removeChildProperty(propName);
}
}
} catch (ItemStateException ise) {
String msg = propName + ": failed to retrieve property state";
log.error(msg, ise);
throw new RepositoryException(msg, ise);
}
}
// use temp array to avoid ConcurrentModificationException
ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(thisState.getChildNodeEntries());
// start from tail to avoid problems with same-name siblings
for (int i = list.size() - 1; i >= 0; i--) {
ChildNodeEntry entry = list.get(i);
try {
NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
if (!allDefs.contains(itemMgr.getDefinition(nodeState).unwrap())) {
// redefine node if possible
try {
NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
if (node.getDefinition().isProtected()) {
// remove 'orphaned' protected child node immediately
removeChildNode(entry.getId());
continue;
}
NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(entry.getName(), nodeState.getNodeTypeName());
// redefine node
node.onRedefine(ndi.unwrap());
// update collection of added definitions
addedDefs.remove(ndi.unwrap());
} catch (ConstraintViolationException cve) {
// no suitable definition found for this child node,
// remove it
removeChildNode(entry.getId());
}
}
} catch (ItemStateException ise) {
String msg = entry.getName() + ": failed to retrieve node state";
log.error(msg, ise);
throw new RepositoryException(msg, ise);
}
}
// type and at the same time were not present with the old nt
for (QItemDefinition def : addedDefs) {
if (def.isAutoCreated()) {
if (def.definesNode()) {
NodeDefinitionImpl ndi = ntMgr.getNodeDefinition((QNodeDefinition) def);
createChildNode(def.getName(), (NodeTypeImpl) ndi.getDefaultPrimaryType(), null);
} else {
PropertyDefinitionImpl pdi = ntMgr.getPropertyDefinition((QPropertyDefinition) def);
createChildProperty(pdi.unwrap().getName(), pdi.getRequiredType(), pdi);
}
}
}
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class HierarchyManagerImpl method resolvePath.
//-------------------------------------------------------< implementation >
/**
* Internal implementation that iteratively resolves a path into an item.
*
* @param elements path elements
* @param next index of next item in <code>elements</code> to inspect
* @param id id of item at path <code>elements[0]</code>..<code>elements[next - 1]</code>
* @param typesAllowed one of <code>RETURN_ANY</code>, <code>RETURN_NODE</code>
* or <code>RETURN_PROPERTY</code>
* @return id or <code>null</code>
* @throws ItemStateException if an intermediate item state is not found
* @throws MalformedPathException if building an intermediate path fails
*/
protected ItemId resolvePath(Path.Element[] elements, int next, ItemId id, int typesAllowed) throws ItemStateException, MalformedPathException {
PathBuilder builder = new PathBuilder();
for (int i = 0; i < next; i++) {
builder.addLast(elements[i]);
}
for (int i = next; i < elements.length; i++) {
Path.Element elem = elements[i];
NodeId parentId = (NodeId) id;
id = null;
Name name = elem.getName();
int index = elem.getIndex();
if (index == 0) {
index = 1;
}
int typeExpected = typesAllowed;
if (i < elements.length - 1) {
// intermediate items must always be nodes
typeExpected = RETURN_NODE;
}
NodeState parentState = (NodeState) getItemState(parentId);
if ((typeExpected & RETURN_NODE) != 0) {
ChildNodeEntry nodeEntry = getChildNodeEntry(parentState, name, index);
if (nodeEntry != null) {
id = nodeEntry.getId();
}
}
if (id == null && (typeExpected & RETURN_PROPERTY) != 0) {
if (parentState.hasPropertyName(name) && (index <= 1)) {
// property
id = new PropertyId(parentState.getNodeId(), name);
}
}
if (id == null) {
break;
}
builder.addLast(elements[i]);
pathResolved(id, builder);
}
return id;
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class NodeImpl method replaceChildNode.
/**
* Replaces the child node with the specified <code>id</code>
* by a new child node with the same id and specified <code>nodeName</code>,
* <code>nodeTypeName</code> and <code>mixinNames</code>.
*
* @param id id of the child node to be replaced
* @param nodeName name of the new node
* @param nodeTypeName name of the new node's node type
* @param mixinNames name of the new node's mixin types
*
* @return the new child node replacing the existing child
* @throws ItemNotFoundException
* @throws NoSuchNodeTypeException
* @throws VersionException
* @throws ConstraintViolationException
* @throws LockException
* @throws RepositoryException
*/
public synchronized NodeImpl replaceChildNode(NodeId id, Name nodeName, Name nodeTypeName, Name[] mixinNames) throws ItemNotFoundException, NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
// check state of this instance
sanityCheck();
Node existing = (Node) itemMgr.getItem(id);
// 'replace' is actually a 'remove existing/add new' operation;
// this unfortunately changes the order of this node's
// child node entries (JCR-1055);
// => backup list of child node entries beforehand in order
// to restore it afterwards
NodeState state = data.getNodeState();
ChildNodeEntry cneExisting = state.getChildNodeEntry(id);
if (cneExisting == null) {
throw new ItemNotFoundException(this + ": no child node entry with id " + id);
}
List<ChildNodeEntry> cneList = new ArrayList<ChildNodeEntry>(state.getChildNodeEntries());
// remove existing
existing.remove();
// create new child node
NodeImpl node = addNode(nodeName, nodeTypeName, id);
if (mixinNames != null) {
for (Name mixinName : mixinNames) {
node.addMixin(mixinName);
}
}
// fetch <code>state</code> again, as it changed while removing child
state = data.getNodeState();
// restore list of child node entries (JCR-1055)
if (cneExisting.getName().equals(nodeName)) {
// restore original child node list
state.setChildNodeEntries(cneList);
} else {
// replace child node entry with different name
// but preserving original position
state.removeAllChildNodeEntries();
for (ChildNodeEntry cne : cneList) {
if (cne.getId().equals(id)) {
// replace entry with different name
state.addChildNodeEntry(nodeName, id);
} else {
state.addChildNodeEntry(cne.getName(), cne.getId());
}
}
}
return node;
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class Join method create.
/**
* Creates a new join result.
*
* @param left the left query hits.
* @param right the right query hits.
* @param joinType the join type.
* @param condition the QOM join condition.
* @param reader the index reader.
* @param resolver the hierarchy resolver.
* @param nsMappings namespace mappings of this index
* @param hmgr the hierarchy manager of the workspace.
* @return the join result.
* @throws IOException if an error occurs while executing the join.
*/
public static Join create(final MultiColumnQueryHits left, final MultiColumnQueryHits right, final JoinType joinType, final JoinConditionImpl condition, final IndexReader reader, final HierarchyResolver resolver, final NamespaceMappings nsMappings, final HierarchyManager hmgr) throws IOException {
try {
return (Join) condition.accept(new DefaultQOMTreeVisitor() {
private boolean isInner = JoinType.INNER == joinType;
private MultiColumnQueryHits outer;
private int outerIdx;
public Object visit(DescendantNodeJoinConditionImpl node, Object data) throws Exception {
MultiColumnQueryHits ancestor = getSourceWithName(node.getAncestorSelectorQName(), left, right);
MultiColumnQueryHits descendant = getSourceWithName(node.getDescendantSelectorQName(), left, right);
Condition c;
if (isInner || descendant == left && JoinType.LEFT == joinType || descendant == right && JoinType.RIGHT == joinType) {
// also applies to inner join
// assumption: DescendantNodeJoin is more
// efficient than AncestorNodeJoin, TODO: verify
outer = descendant;
outerIdx = getIndex(outer, node.getDescendantSelectorQName());
c = new DescendantNodeJoin(ancestor, node.getAncestorSelectorQName(), reader, resolver);
} else {
// left == ancestor
outer = ancestor;
outerIdx = getIndex(outer, node.getAncestorSelectorQName());
c = new AncestorNodeJoin(descendant, node.getDescendantSelectorQName(), reader, resolver);
}
return new Join(outer, outerIdx, isInner, c);
}
public Object visit(EquiJoinConditionImpl node, Object data) throws Exception {
MultiColumnQueryHits src1 = getSourceWithName(node.getSelector1QName(), left, right);
MultiColumnQueryHits src2 = getSourceWithName(node.getSelector2QName(), left, right);
MultiColumnQueryHits inner;
Name innerName;
Name innerPropName;
Name outerPropName;
if (isInner || src1 == left && JoinType.LEFT == joinType || src1 == right && JoinType.RIGHT == joinType) {
outer = src1;
outerIdx = getIndex(outer, node.getSelector1QName());
inner = src2;
innerName = node.getSelector2QName();
innerPropName = node.getProperty2QName();
outerPropName = node.getProperty1QName();
} else {
outer = src2;
outerIdx = getIndex(outer, node.getSelector2QName());
inner = src1;
innerName = node.getSelector1QName();
innerPropName = node.getProperty1QName();
outerPropName = node.getProperty2QName();
}
Condition c = new EquiJoin(inner, getIndex(inner, innerName), nsMappings, reader, innerPropName, outerPropName);
return new Join(outer, outerIdx, isInner, c);
}
public Object visit(ChildNodeJoinConditionImpl node, Object data) throws Exception {
MultiColumnQueryHits child = getSourceWithName(node.getChildSelectorQName(), left, right);
MultiColumnQueryHits parent = getSourceWithName(node.getParentSelectorQName(), left, right);
Condition c;
if (child == left && JoinType.LEFT == joinType || child == right && JoinType.RIGHT == joinType) {
outer = child;
outerIdx = getIndex(outer, node.getChildSelectorQName());
c = new ChildNodeJoin(parent, reader, resolver, node);
} else {
// also applies to inner joins
// assumption: ParentNodeJoin is more efficient than
// ChildNodeJoin, TODO: verify
outer = parent;
outerIdx = getIndex(outer, node.getParentSelectorQName());
c = new ParentNodeJoin(child, reader, resolver, node);
}
return new Join(outer, outerIdx, isInner, c);
}
public Object visit(SameNodeJoinConditionImpl node, Object data) throws Exception {
MultiColumnQueryHits src1 = getSourceWithName(node.getSelector1QName(), left, right);
MultiColumnQueryHits src2 = getSourceWithName(node.getSelector2QName(), left, right);
Condition c;
if (isInner || src1 == left && JoinType.LEFT == joinType || src1 == right && JoinType.RIGHT == joinType) {
outer = src1;
outerIdx = getIndex(outer, node.getSelector1QName());
Path selector2Path = node.getSelector2QPath();
if (selector2Path == null || (selector2Path.getLength() == 1 && selector2Path.denotesCurrent())) {
c = new SameNodeJoin(src2, node.getSelector2QName(), reader);
} else {
c = new DescendantPathNodeJoin(src2, node.getSelector2QName(), node.getSelector2QPath(), hmgr);
}
} else {
outer = src2;
outerIdx = getIndex(outer, node.getSelector2QName());
Path selector2Path = node.getSelector2QPath();
if (selector2Path == null || (selector2Path.getLength() == 1 && selector2Path.denotesCurrent())) {
c = new SameNodeJoin(src1, node.getSelector1QName(), reader);
} else {
c = new AncestorPathNodeJoin(src1, node.getSelector1QName(), node.getSelector2QPath(), hmgr);
}
}
return new Join(outer, outerIdx, isInner, c);
}
}, null);
} catch (IOException e) {
throw e;
} catch (Exception e) {
IOException ex = new IOException(e.getMessage());
ex.initCause(e);
throw ex;
}
}
Aggregations