use of javax.jcr.nodetype.ConstraintViolationException in project jackrabbit by apache.
the class NodeImpl method addMixin.
/**
* @see Node#addMixin(String)
*/
public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
checkIsWritable();
Name mixinQName = getQName(mixinName);
// get mixin types present in the jcr:mixinTypes property without
// modifying the NodeState.
List<Name> mixinValue = getMixinTypes();
if (!mixinValue.contains(mixinQName) && !isNodeType(mixinQName)) {
if (!canAddMixin(mixinQName)) {
throw new ConstraintViolationException("Cannot add '" + mixinName + "' mixin type.");
}
mixinValue.add(mixinQName);
// perform the operation
Operation op = SetMixin.create(getNodeState(), mixinValue.toArray(new Name[mixinValue.size()]));
session.getSessionItemStateManager().execute(op);
}
}
use of javax.jcr.nodetype.ConstraintViolationException in project jackrabbit by apache.
the class ExceptionConverter method generate.
public static RepositoryException generate(DavException davExc, int methodCode, String name) {
String msg = davExc.getMessage();
if (davExc.hasErrorCondition()) {
try {
Element error = davExc.toXml(DomUtil.createDocument());
if (DomUtil.matches(error, DavException.XML_ERROR, DavConstants.NAMESPACE)) {
if (DomUtil.hasChildElement(error, "exception", null)) {
Element exc = DomUtil.getChildElement(error, "exception", null);
if (DomUtil.hasChildElement(exc, "message", null)) {
msg = DomUtil.getChildText(exc, "message", null);
}
if (DomUtil.hasChildElement(exc, "class", null)) {
Class<?> cl = Class.forName(DomUtil.getChildText(exc, "class", null));
Constructor<?> excConstr = cl.getConstructor(String.class);
if (excConstr != null) {
Object o = excConstr.newInstance(msg);
if (o instanceof PathNotFoundException && methodCode == DavMethods.DAV_POST) {
// see JCR-2536
return new InvalidItemStateException(msg);
} else if (o instanceof RepositoryException) {
return (RepositoryException) o;
} else if (o instanceof Exception) {
return new RepositoryException(msg, (Exception) o);
}
}
}
}
}
} catch (Exception e) {
return new RepositoryException(e);
}
}
// make sure an exception is generated
switch(davExc.getErrorCode()) {
// TODO: mapping DAV_error to jcr-exception is ambiguous. to be improved
case DavServletResponse.SC_NOT_FOUND:
switch(methodCode) {
case DavMethods.DAV_DELETE:
case DavMethods.DAV_MKCOL:
case DavMethods.DAV_PUT:
case DavMethods.DAV_POST:
// been made.
return new InvalidItemStateException(msg, davExc);
default:
return new ItemNotFoundException(msg, davExc);
}
case DavServletResponse.SC_LOCKED:
return new LockException(msg, davExc);
case DavServletResponse.SC_METHOD_NOT_ALLOWED:
return new ConstraintViolationException(msg, davExc);
case DavServletResponse.SC_CONFLICT:
return new InvalidItemStateException(msg, davExc);
case DavServletResponse.SC_PRECONDITION_FAILED:
return new LockException(msg, davExc);
case DavServletResponse.SC_NOT_IMPLEMENTED:
if (methodCode > 0 && name != null) {
return new UnsupportedRepositoryOperationException("Missing implementation: Method " + name + " could not be executed", davExc);
} else {
return new UnsupportedRepositoryOperationException("Missing implementation", davExc);
}
default:
return new RepositoryException(msg, davExc);
}
}
use of javax.jcr.nodetype.ConstraintViolationException in project jackrabbit by apache.
the class ItemSaveOperation method validateTransientItems.
/**
* the following validations/checks are performed on transient items:
*
* for every transient item:
* - if it is 'modified' or 'new' check the corresponding write permission.
* - if it is 'removed' check the REMOVE permission
*
* for every transient node:
* - if it is 'new' check that its node type satisfies the
* 'required node type' constraint specified in its definition
* - check if 'mandatory' child items exist
*
* for every transient property:
* - check if the property value satisfies the value constraints
* specified in the property's definition
*
* note that the protected flag is checked in Node.addNode/Node.remove
* (for adding/removing child entries of a node), in
* Node.addMixin/removeMixin/setPrimaryType (for type changes on nodes)
* and in Property.setValue (for properties to be modified).
*/
private void validateTransientItems(SessionContext context, Iterable<ItemState> dirty, Iterable<ItemState> removed) throws RepositoryException {
SessionImpl session = context.getSessionImpl();
ItemManager itemMgr = context.getItemManager();
SessionItemStateManager stateMgr = context.getItemStateManager();
AccessManager accessMgr = context.getAccessManager();
NodeTypeManagerImpl ntMgr = context.getNodeTypeManager();
// walk through list of dirty transient items and validate each
for (ItemState itemState : dirty) {
ItemDefinition def;
if (itemState.isNode()) {
def = itemMgr.getDefinition((NodeState) itemState);
} else {
def = itemMgr.getDefinition((PropertyState) itemState);
}
/* check permissions for non-protected items. protected items are
only added through API methods which need to assert that
permissions are not violated.
*/
if (!def.isProtected()) {
/* detect the effective set of modification:
- new added node -> add_node perm on the child
- new property added -> set_property permission
- property modified -> set_property permission
- modified nodes can be ignored for changes only included
child-item addition or removal or changes of protected
properties such as mixin-types which are covered separately
note: removed items are checked later on.
note: reordering of child nodes has been covered upfront as
this information isn't available here.
*/
Path path = stateMgr.getHierarchyMgr().getPath(itemState.getId());
boolean isGranted = true;
if (itemState.isNode()) {
if (itemState.getStatus() == ItemState.STATUS_NEW) {
isGranted = accessMgr.isGranted(path, Permission.ADD_NODE);
}
// else: modified node (see comment above)
} else {
// modified or new property: set_property permission
isGranted = accessMgr.isGranted(path, Permission.SET_PROPERTY);
}
if (!isGranted) {
String msg = itemMgr.safeGetJCRPath(path) + ": not allowed to add or modify item";
log.debug(msg);
throw new AccessDeniedException(msg);
}
}
if (itemState.isNode()) {
// the transient item is a node
NodeState nodeState = (NodeState) itemState;
ItemId id = nodeState.getNodeId();
NodeDefinition nodeDef = (NodeDefinition) def;
// primary type
NodeTypeImpl pnt = ntMgr.getNodeType(nodeState.getNodeTypeName());
// effective node type (primary type incl. mixins)
EffectiveNodeType ent = getEffectiveNodeType(context.getRepositoryContext().getNodeTypeRegistry(), nodeState);
/**
* if the transient node was added (i.e. if it is 'new') or if
* its primary type has changed, check its node type against the
* required node type in its definition
*/
boolean primaryTypeChanged = nodeState.getStatus() == ItemState.STATUS_NEW;
if (!primaryTypeChanged) {
NodeState overlaid = (NodeState) nodeState.getOverlayedState();
if (overlaid != null) {
Name newName = nodeState.getNodeTypeName();
Name oldName = overlaid.getNodeTypeName();
primaryTypeChanged = !newName.equals(oldName);
}
}
if (primaryTypeChanged) {
for (NodeType ntReq : nodeDef.getRequiredPrimaryTypes()) {
Name ntName = ((NodeTypeImpl) ntReq).getQName();
if (!(pnt.getQName().equals(ntName) || pnt.isDerivedFrom(ntName))) {
/**
* the transient node's primary node type does not
* satisfy the 'required primary types' constraint
*/
String msg = itemMgr.safeGetJCRPath(id) + " must be of node type " + ntReq.getName();
log.debug(msg);
throw new ConstraintViolationException(msg);
}
}
}
// mandatory child properties
for (QPropertyDefinition pd : ent.getMandatoryPropDefs()) {
if (pd.getDeclaringNodeType().equals(NameConstants.MIX_VERSIONABLE) || pd.getDeclaringNodeType().equals(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
/**
* todo FIXME workaround for mix:versionable:
* the mandatory properties are initialized at a
* later stage and might not exist yet
*/
continue;
}
String msg = itemMgr.safeGetJCRPath(id) + ": mandatory property " + pd.getName() + " does not exist";
if (!nodeState.hasPropertyName(pd.getName())) {
log.debug(msg);
throw new ConstraintViolationException(msg);
} else {
/*
there exists a property with the mandatory-name.
make sure the property really has the expected mandatory
property definition (and not another non-mandatory def,
such as e.g. multivalued residual instead of single-value
mandatory, named def).
*/
PropertyId pi = new PropertyId(nodeState.getNodeId(), pd.getName());
ItemData childData = itemMgr.getItemData(pi, null, false);
if (!childData.getDefinition().isMandatory()) {
throw new ConstraintViolationException(msg);
}
}
}
// mandatory child nodes
for (QItemDefinition cnd : ent.getMandatoryNodeDefs()) {
String msg = itemMgr.safeGetJCRPath(id) + ": mandatory child node " + cnd.getName() + " does not exist";
if (!nodeState.hasChildNodeEntry(cnd.getName())) {
log.debug(msg);
throw new ConstraintViolationException(msg);
} else {
/*
there exists a child node with the mandatory-name.
make sure the node really has the expected mandatory
node definition.
*/
boolean hasMandatoryChild = false;
for (ChildNodeEntry cne : nodeState.getChildNodeEntries(cnd.getName())) {
ItemData childData = itemMgr.getItemData(cne.getId(), null, false);
if (childData.getDefinition().isMandatory()) {
hasMandatoryChild = true;
break;
}
}
if (!hasMandatoryChild) {
throw new ConstraintViolationException(msg);
}
}
}
} else {
// the transient item is a property
PropertyState propState = (PropertyState) itemState;
ItemId propId = propState.getPropertyId();
org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl propDef = (org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl) def;
/**
* check value constraints
* (no need to check value constraints of protected properties
* as those are set by the implementation only, i.e. they
* cannot be set by the user through the api)
*/
if (!def.isProtected()) {
String[] constraints = propDef.getValueConstraints();
if (constraints != null) {
InternalValue[] values = propState.getValues();
try {
EffectiveNodeType.checkSetPropertyValueConstraints(propDef.unwrap(), values);
} catch (RepositoryException e) {
// repack exception for providing more verbose error message
String msg = itemMgr.safeGetJCRPath(propId) + ": " + e.getMessage();
log.debug(msg);
throw new ConstraintViolationException(msg);
}
/**
* need to manually check REFERENCE value constraints
* as this requires a session (target node needs to
* be checked)
*/
if (constraints.length > 0 && (propDef.getRequiredType() == PropertyType.REFERENCE || propDef.getRequiredType() == PropertyType.WEAKREFERENCE)) {
for (InternalValue internalV : values) {
boolean satisfied = false;
String constraintViolationMsg = null;
try {
NodeId targetId = internalV.getNodeId();
if (propDef.getRequiredType() == PropertyType.WEAKREFERENCE && !itemMgr.itemExists(targetId)) {
// target of weakref doesn;t exist, skip
continue;
}
Node targetNode = session.getNodeById(targetId);
/**
* constraints are OR-ed, i.e. at least one
* has to be satisfied
*/
for (String constrNtName : constraints) {
/**
* a [WEAK]REFERENCE value constraint specifies
* the name of the required node type of
* the target node
*/
if (targetNode.isNodeType(constrNtName)) {
satisfied = true;
break;
}
}
if (!satisfied) {
NodeType[] mixinNodeTypes = targetNode.getMixinNodeTypes();
String[] targetMixins = new String[mixinNodeTypes.length];
for (int j = 0; j < mixinNodeTypes.length; j++) {
targetMixins[j] = mixinNodeTypes[j].getName();
}
String targetMixinsString = Text.implode(targetMixins, ", ");
String constraintsString = Text.implode(constraints, ", ");
constraintViolationMsg = itemMgr.safeGetJCRPath(propId) + ": is constraint to [" + constraintsString + "] but references [primaryType=" + targetNode.getPrimaryNodeType().getName() + ", mixins=" + targetMixinsString + "]";
}
} catch (RepositoryException re) {
String msg = itemMgr.safeGetJCRPath(propId) + ": failed to check " + ((propDef.getRequiredType() == PropertyType.REFERENCE) ? "REFERENCE" : "WEAKREFERENCE") + " value constraint";
log.debug(msg);
throw new ConstraintViolationException(msg, re);
}
if (!satisfied) {
log.debug(constraintViolationMsg);
throw new ConstraintViolationException(constraintViolationMsg);
}
}
}
}
}
/**
* no need to check the protected flag as this is checked
* in PropertyImpl.setValue(Value)
*/
}
}
// walk through list of removed transient items and check REMOVE permission
for (ItemState itemState : removed) {
QItemDefinition def;
try {
if (itemState.isNode()) {
def = itemMgr.getDefinition((NodeState) itemState).unwrap();
} else {
def = itemMgr.getDefinition((PropertyState) itemState).unwrap();
}
} catch (ConstraintViolationException e) {
// of a mixin (see also JCR-2130 & JCR-2408)
continue;
}
if (!def.isProtected()) {
Path path = stateMgr.getAtticAwareHierarchyMgr().getPath(itemState.getId());
// check REMOVE permission
int permission = (itemState.isNode()) ? Permission.REMOVE_NODE : Permission.REMOVE_PROPERTY;
if (!accessMgr.isGranted(path, permission)) {
String msg = itemMgr.safeGetJCRPath(path) + ": not allowed to remove item";
log.debug(msg);
throw new AccessDeniedException(msg);
}
}
}
}
use of javax.jcr.nodetype.ConstraintViolationException in project jackrabbit by apache.
the class ItemSaveOperation method perform.
public Object perform(SessionContext context) throws RepositoryException {
SessionItemStateManager stateMgr = context.getItemStateManager();
/**
* build list of transient (i.e. new & modified) states that
* should be persisted
*/
Collection<ItemState> dirty;
try {
dirty = getTransientStates(context.getItemStateManager());
} catch (ConcurrentModificationException e) {
String msg = "Concurrent modification; session is closed";
log.error(msg, e);
context.getSessionImpl().logout();
throw e;
}
if (dirty.size() == 0) {
// no transient items, nothing to do here
return this;
}
/**
* build list of transient descendants in the attic
* (i.e. those marked as 'removed')
*/
Collection<ItemState> removed = getRemovedStates(context.getItemStateManager());
// All affected item states. The keys are used to look up whether
// an item is affected, and the values are iterated through below
Map<ItemId, ItemState> affected = new HashMap<ItemId, ItemState>(dirty.size() + removed.size());
for (ItemState state : dirty) {
affected.put(state.getId(), state);
}
for (ItemState state : removed) {
affected.put(state.getId(), state);
}
/**
* make sure that this save operation is totally 'self-contained'
* and independent; items within the scope of this save operation
* must not have 'external' dependencies;
* (e.g. moving a node requires that the target node including both
* old and new parents are saved)
*/
for (ItemState transientState : affected.values()) {
if (transientState.isNode()) {
NodeState nodeState = (NodeState) transientState;
Set<NodeId> dependentIDs = new HashSet<NodeId>();
if (nodeState.hasOverlayedState()) {
NodeState overlayedState = (NodeState) nodeState.getOverlayedState();
NodeId oldParentId = overlayedState.getParentId();
NodeId newParentId = nodeState.getParentId();
if (oldParentId != null) {
if (newParentId == null) {
// to dependencies
if (overlayedState.isShareable()) {
dependentIDs.addAll(overlayedState.getSharedSet());
} else {
dependentIDs.add(oldParentId);
}
} else {
if (!oldParentId.equals(newParentId)) {
// node has been moved to a new location,
// add old and new parent to dependencies
dependentIDs.add(oldParentId);
dependentIDs.add(newParentId);
} else {
// the node has been renamed (JCR-1034)
if (!affected.containsKey(newParentId) && stateMgr.hasTransientItemState(newParentId)) {
try {
NodeState parent = (NodeState) stateMgr.getTransientItemState(newParentId);
// check parent's renamed child node entries
for (ChildNodeEntry cne : parent.getRenamedChildNodeEntries()) {
if (cne.getId().equals(nodeState.getId())) {
// node has been renamed,
// add parent to dependencies
dependentIDs.add(newParentId);
}
}
} catch (ItemStateException ise) {
// should never get here
log.warn("failed to retrieve transient state: " + newParentId, ise);
}
}
}
}
}
}
// removed child node entries
for (ChildNodeEntry cne : nodeState.getRemovedChildNodeEntries()) {
dependentIDs.add(cne.getId());
}
// added child node entries
for (ChildNodeEntry cne : nodeState.getAddedChildNodeEntries()) {
dependentIDs.add(cne.getId());
}
// are within the scope of this save operation
for (NodeId id : dependentIDs) {
if (!affected.containsKey(id)) {
// otherwise ignore them
if (stateMgr.hasTransientItemState(id) || stateMgr.hasTransientItemStateInAttic(id)) {
// need to save dependency as well
String msg = context.getItemManager().safeGetJCRPath(id) + " needs to be saved as well.";
log.debug(msg);
throw new ConstraintViolationException(msg);
}
}
}
}
}
// validate access and node type constraints
// (this will also validate child removals)
validateTransientItems(context, dirty, removed);
// start the update operation
try {
stateMgr.edit();
} catch (IllegalStateException e) {
throw new RepositoryException("Unable to start edit operation", e);
}
boolean succeeded = false;
try {
// process transient items marked as 'removed'
removeTransientItems(context.getItemStateManager(), removed);
// process transient items that have change in mixins
processShareableNodes(context.getRepositoryContext().getNodeTypeRegistry(), dirty);
// initialize version histories for new nodes (might generate new transient state)
if (initVersionHistories(context, dirty)) {
// re-build the list of transient states because the previous call
// generated new transient state
dirty = getTransientStates(context.getItemStateManager());
}
// process 'new' or 'modified' transient states
persistTransientItems(context.getItemManager(), dirty);
// item state which is not referenced by any node instance.
for (ItemState transientState : dirty) {
// dispose the transient state, it is no longer used
stateMgr.disposeTransientItemState(transientState);
}
// end update operation
stateMgr.update();
// update operation succeeded
succeeded = true;
} catch (StaleItemStateException e) {
throw new InvalidItemStateException("Unable to update a stale item: " + this, e);
} catch (ItemStateException e) {
throw new RepositoryException("Unable to update item: " + this, e);
} finally {
if (!succeeded) {
// update operation failed, cancel all modifications
stateMgr.cancel();
// JCR-288: if an exception has been thrown during
// update() the transient changes have already been
// applied by persistTransientItems() and we need to
// restore transient state, i.e. undo the effect of
// persistTransientItems()
restoreTransientItems(context, dirty);
}
}
// items in store().
for (ItemState transientState : removed) {
// dispose the transient state, it is no longer used
stateMgr.disposeTransientItemStateInAttic(transientState);
}
return this;
}
use of javax.jcr.nodetype.ConstraintViolationException in project jackrabbit by apache.
the class ItemValidator method validate.
/**
* Checks whether the given property state satisfies the constraints
* specified by its definition. The following validations/checks are
* performed:
* <ul>
* <li>check if the type of the property values does comply with the
* requiredType specified in the property's definition</li>
* <li>check if the property values satisfy the value constraints
* specified in the property's definition</li>
* </ul>
*
* @param propState state of property to be validated
* @throws ConstraintViolationException if any of the validations fail
* @throws RepositoryException if another error occurs
*/
public void validate(PropertyState propState) throws ConstraintViolationException, RepositoryException {
QPropertyDefinition def = context.getItemManager().getDefinition(propState).unwrap();
InternalValue[] values = propState.getValues();
int type = PropertyType.UNDEFINED;
for (InternalValue value : values) {
if (type == PropertyType.UNDEFINED) {
type = value.getType();
} else if (type != value.getType()) {
throw new ConstraintViolationException(safeGetJCRPath(propState.getPropertyId()) + ": inconsistent value types");
}
if (def.getRequiredType() != PropertyType.UNDEFINED && def.getRequiredType() != type) {
throw new ConstraintViolationException(safeGetJCRPath(propState.getPropertyId()) + ": requiredType constraint is not satisfied");
}
}
EffectiveNodeType.checkSetPropertyValueConstraints(def, values);
}
Aggregations