use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class RemoveMixinOperation method perform.
public Object perform(SessionContext context) throws RepositoryException {
SessionImpl session = context.getSessionImpl();
ItemManager itemMgr = context.getItemManager();
SessionItemStateManager stateMgr = context.getItemStateManager();
context.getItemValidator().checkModify(node, CHECK_LOCK | CHECK_CHECKED_OUT | CHECK_CONSTRAINTS | CHECK_HOLD, Permission.NODE_TYPE_MNGMT);
// check if mixin is assigned
NodeState state = node.getNodeState();
if (!state.getMixinTypeNames().contains(mixinName)) {
throw new NoSuchNodeTypeException("Mixin " + context.getJCRName(mixinName) + " not included in " + node);
}
NodeTypeManagerImpl ntMgr = context.getNodeTypeManager();
NodeTypeRegistry ntReg = context.getNodeTypeRegistry();
// build effective node type of remaining mixin's & primary type
Set<Name> remainingMixins = new HashSet<Name>(state.getMixinTypeNames());
// remove name of target mixin
remainingMixins.remove(mixinName);
EffectiveNodeType entResulting;
try {
// build effective node type representing primary type
// including remaining mixin's
entResulting = ntReg.getEffectiveNodeType(state.getNodeTypeName(), remainingMixins);
} catch (NodeTypeConflictException e) {
throw new ConstraintViolationException(e.getMessage(), e);
}
// mix:referenceable needs special handling because it has
// special semantics:
// it can only be removed if there no more references to this node
NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
if (isReferenceable(mixin) && !entResulting.includesNodeType(MIX_REFERENCEABLE)) {
if (node.getReferences().hasNext()) {
throw new ConstraintViolationException(mixinName + " can not be removed:" + " the node is being referenced through at least" + " one property of type REFERENCE");
}
}
// currently locked even if the editing session is the lock holder.
if ((NameConstants.MIX_LOCKABLE.equals(mixinName) || mixin.isDerivedFrom(NameConstants.MIX_LOCKABLE)) && !entResulting.includesNodeType(NameConstants.MIX_LOCKABLE) && node.isLocked()) {
throw new ConstraintViolationException(mixinName + " can not be removed: the node is locked.");
}
NodeState thisState = (NodeState) node.getOrCreateTransientItemState();
// collect information about properties and nodes which require further
// action as a result of the mixin removal; we need to do this *before*
// actually changing the assigned mixin types, otherwise we wouldn't
// be able to retrieve the current definition of an item.
Map<PropertyId, PropertyDefinition> affectedProps = new HashMap<PropertyId, PropertyDefinition>();
Map<ChildNodeEntry, NodeDefinition> affectedNodes = new HashMap<ChildNodeEntry, NodeDefinition>();
try {
Set<Name> names = thisState.getPropertyNames();
for (Name propName : names) {
PropertyId propId = new PropertyId(thisState.getNodeId(), propName);
PropertyState propState = (PropertyState) stateMgr.getItemState(propId);
PropertyDefinition oldDef = itemMgr.getDefinition(propState);
// check if property has been defined by mixin type
// (or one of its supertypes)
NodeTypeImpl declaringNT = (NodeTypeImpl) oldDef.getDeclaringNodeType();
if (!entResulting.includesNodeType(declaringNT.getQName())) {
// the resulting effective node type doesn't include the
// node type that declared this property
affectedProps.put(propId, oldDef);
}
}
List<ChildNodeEntry> entries = thisState.getChildNodeEntries();
for (ChildNodeEntry entry : entries) {
NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
NodeDefinition oldDef = itemMgr.getDefinition(nodeState);
// check if node has been defined by mixin type
// (or one of its supertypes)
NodeTypeImpl declaringNT = (NodeTypeImpl) oldDef.getDeclaringNodeType();
if (!entResulting.includesNodeType(declaringNT.getQName())) {
// the resulting effective node type doesn't include the
// node type that declared this child node
affectedNodes.put(entry, oldDef);
}
}
} catch (ItemStateException e) {
throw new RepositoryException("Failed to determine effect of removing mixin " + context.getJCRName(mixinName), e);
}
// modify the state of this node
thisState.setMixinTypeNames(remainingMixins);
// set jcr:mixinTypes property
node.setMixinTypesProperty(remainingMixins);
// process affected nodes & properties:
// 1. try to redefine item based on the resulting
// new effective node type (see JCR-2130)
// 2. remove item if 1. fails
boolean success = false;
try {
for (Map.Entry<PropertyId, PropertyDefinition> entry : affectedProps.entrySet()) {
PropertyId id = entry.getKey();
PropertyImpl prop = (PropertyImpl) itemMgr.getItem(id);
PropertyDefinition oldDef = entry.getValue();
if (oldDef.isProtected()) {
// remove 'orphaned' protected properties immediately
node.removeChildProperty(id.getName());
continue;
}
// redefine property if possible (JCR-2130)
try {
PropertyDefinitionImpl newDef = node.getApplicablePropertyDefinition(id.getName(), prop.getType(), oldDef.isMultiple(), false);
if (newDef.getRequiredType() != PropertyType.UNDEFINED && newDef.getRequiredType() != prop.getType()) {
// value conversion required
if (oldDef.isMultiple()) {
// convert value
Value[] values = ValueHelper.convert(prop.getValues(), newDef.getRequiredType(), session.getValueFactory());
// redefine property
prop.onRedefine(newDef.unwrap());
// set converted values
prop.setValue(values);
} else {
// convert value
Value value = ValueHelper.convert(prop.getValue(), newDef.getRequiredType(), session.getValueFactory());
// redefine property
prop.onRedefine(newDef.unwrap());
// set converted values
prop.setValue(value);
}
} else {
// redefine property
prop.onRedefine(newDef.unwrap());
}
} catch (ValueFormatException vfe) {
// value conversion failed, remove it
node.removeChildProperty(id.getName());
} catch (ConstraintViolationException cve) {
// no suitable definition found for this property,
// remove it
node.removeChildProperty(id.getName());
}
}
for (ChildNodeEntry entry : affectedNodes.keySet()) {
NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
NodeImpl childNode = (NodeImpl) itemMgr.getItem(entry.getId());
NodeDefinition oldDef = affectedNodes.get(entry);
if (oldDef.isProtected()) {
// remove 'orphaned' protected child node immediately
node.removeChildNode(entry.getId());
continue;
}
// redefine node if possible (JCR-2130)
try {
NodeDefinitionImpl newDef = node.getApplicableChildNodeDefinition(entry.getName(), nodeState.getNodeTypeName());
// redefine node
childNode.onRedefine(newDef.unwrap());
} catch (ConstraintViolationException cve) {
// no suitable definition found for this child node,
// remove it
node.removeChildNode(entry.getId());
}
}
success = true;
} catch (ItemStateException e) {
throw new RepositoryException("Failed to clean up child items defined by removed mixin " + context.getJCRName(mixinName), e);
} finally {
if (!success) {
// TODO JCR-1914: revert any changes made so far
}
}
return this;
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class RepositoryChecker method checkVersionHistory.
private void checkVersionHistory(NodeState node) {
String message = null;
NodeId nid = node.getNodeId();
boolean isVersioned = node.hasPropertyName(JCR_VERSIONHISTORY);
NodeId vhid = null;
try {
String type = isVersioned ? "in-use" : "candidate";
log.debug("Checking " + type + " version history of node {}", nid);
String intro = "Removing references to an inconsistent " + type + " version history of node " + nid;
message = intro + " (getting the VersionInfo)";
VersionHistoryInfo vhi = versionManager.getVersionHistoryInfoForNode(node);
if (vhi != null) {
// get the version history's node ID as early as possible
// so we can attempt a fixup even when the next call fails
vhid = vhi.getVersionHistoryId();
}
message = intro + " (getting the InternalVersionHistory)";
InternalVersionHistory vh = null;
try {
vh = versionManager.getVersionHistoryOfNode(nid);
} catch (ItemNotFoundException ex) {
// it's ok if we get here if the node didn't claim to be versioned
if (isVersioned) {
throw ex;
}
}
if (vh == null) {
if (isVersioned) {
message = intro + "getVersionHistoryOfNode returned null";
throw new InconsistentVersioningState(message);
}
} else {
vhid = vh.getId();
// additional checks, see JCR-3101
message = intro + " (getting the version names failed)";
Name[] versionNames = vh.getVersionNames();
boolean seenRoot = false;
for (Name versionName : versionNames) {
seenRoot |= JCR_ROOTVERSION.equals(versionName);
log.debug("Checking version history of node {}, version {}", nid, versionName);
message = intro + " (getting version " + versionName + " failed)";
InternalVersion v = vh.getVersion(versionName);
message = intro + "(frozen node of root version " + v.getId() + " missing)";
if (null == v.getFrozenNode()) {
throw new InconsistentVersioningState(message);
}
}
if (!seenRoot) {
message = intro + " (root version is missing)";
throw new InconsistentVersioningState(message);
}
}
} catch (InconsistentVersioningState e) {
log.info(message, e);
NodeId nvhid = e.getVersionHistoryNodeId();
if (nvhid != null) {
if (vhid != null && !nvhid.equals(vhid)) {
log.error("vhrid returned with InconsistentVersioningState does not match the id we already had: " + vhid + " vs " + nvhid);
}
vhid = nvhid;
}
removeVersionHistoryReferences(node, vhid);
} catch (Exception e) {
log.info(message, e);
removeVersionHistoryReferences(node, vhid);
}
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class BundleReader method readBundleOld.
private void readBundleOld(NodePropBundle bundle) throws IOException {
// read primary type...special handling
int a = in.readUnsignedByte();
int b = in.readUnsignedByte();
int c = in.readUnsignedByte();
String uri = binding.nsIndex.indexToString(a << 16 | b << 8 | c);
String local = binding.nameIndex.indexToString(in.readInt());
bundle.setNodeTypeName(NameFactoryImpl.getInstance().create(uri, local));
// parentUUID
bundle.setParentId(readNodeId());
// definitionId
in.readUTF();
// mixin types
Name name = readIndexedQName();
if (name != null) {
Set<Name> mixinTypeNames = new HashSet<Name>();
do {
mixinTypeNames.add(name);
name = readIndexedQName();
} while (name != null);
bundle.setMixinTypeNames(mixinTypeNames);
} else {
bundle.setMixinTypeNames(Collections.<Name>emptySet());
}
// properties
name = readIndexedQName();
while (name != null) {
PropertyId pId = new PropertyId(bundle.getId(), name);
NodePropBundle.PropertyEntry pState = readPropertyEntry(pId);
// skip redundant primaryType, mixinTypes and uuid properties
if (!name.equals(NameConstants.JCR_PRIMARYTYPE) && !name.equals(NameConstants.JCR_UUID)) {
bundle.addProperty(pState);
}
name = readIndexedQName();
}
// set referenceable flag
bundle.setReferenceable(in.readBoolean());
// child nodes (list of uuid/name pairs)
NodeId childId = readNodeId();
while (childId != null) {
bundle.addChildNodeEntry(readQName(), childId);
childId = readNodeId();
}
// read modcount, since version 1.0
if (version >= BundleBinding.VERSION_1) {
bundle.setModCount(in.readShort());
}
// read shared set, since version 2.0
if (version >= BundleBinding.VERSION_2) {
// shared set (list of parent uuids)
NodeId parentId = readNodeId();
if (parentId != null) {
Set<NodeId> shared = new HashSet<NodeId>();
do {
shared.add(parentId);
parentId = readNodeId();
} while (parentId != null);
bundle.setSharedSet(shared);
} else {
bundle.setSharedSet(Collections.<NodeId>emptySet());
}
} else {
bundle.setSharedSet(Collections.<NodeId>emptySet());
}
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class BundleWriter method writeBundle.
/**
* Serializes a <code>NodePropBundle</code> to a data output stream
*
* @param bundle the bundle to serialize
* @throws IOException if an I/O error occurs.
*/
public void writeBundle(NodePropBundle bundle) throws IOException {
long size = out.size();
// primaryType
writeName(bundle.getNodeTypeName());
// parentUUID
NodeId parentId = bundle.getParentId();
if (parentId == null) {
parentId = BundleBinding.NULL_PARENT_ID;
}
writeNodeId(parentId);
// write mod count
writeVarInt(bundle.getModCount());
Collection<Name> mixins = bundle.getMixinTypeNames();
Collection<PropertyEntry> properties = bundle.getPropertyEntries();
Collection<ChildNodeEntry> nodes = bundle.getChildNodeEntries();
Collection<NodeId> shared = bundle.getSharedSet();
int mn = mixins.size();
int pn = properties.size();
int nn = nodes.size();
int sn = shared.size();
int referenceable = 0;
if (bundle.isReferenceable()) {
referenceable = 1;
}
out.writeByte(Math.min(mn, 1) << 7 | Math.min(pn, 7) << 4 | Math.min(nn, 3) << 2 | Math.min(sn, 1) << 1 | referenceable);
// mixin types
writeVarInt(mn, 1);
for (Name name : mixins) {
writeName(name);
}
// properties
writeVarInt(pn, 7);
for (PropertyEntry property : properties) {
writeState(property);
}
// child nodes (list of name/uuid pairs)
writeVarInt(nn, 3);
for (ChildNodeEntry child : nodes) {
// name
writeName(child.getName());
// uuid
writeNodeId(child.getId());
}
// write shared set
writeVarInt(sn, 1);
for (NodeId nodeId : shared) {
writeNodeId(nodeId);
}
// set size of bundle
bundle.setSize(out.size() - size);
}
use of org.apache.jackrabbit.spi.Name in project jackrabbit by apache.
the class Serializer method deserialize.
/**
* Deserializes a <code>NodeState</code> object from the given binary
* <code>stream</code>.
*
* @param state <code>state</code> to deserialize
* @param stream the stream where the <code>state</code> should be deserialized from
* @throws Exception if an error occurs during the deserialization
* @see #serialize(NodeState, OutputStream)
*/
public static void deserialize(NodeState state, InputStream stream) throws Exception {
DataInputStream in = new DataInputStream(stream);
// primaryType
String s = in.readUTF();
state.setNodeTypeName(NameFactoryImpl.getInstance().create(s));
// parentUUID (may be null)
byte[] uuidBytes = new byte[NodeId.UUID_BYTE_LENGTH];
in.readFully(uuidBytes);
if (!Arrays.equals(uuidBytes, NULL_UUID_PLACEHOLDER_BYTES)) {
state.setParentId(new NodeId(uuidBytes));
}
// definitionId
in.readUTF();
// mixin types
// count
int count = in.readInt();
Set<Name> set = new HashSet<Name>(count);
for (int i = 0; i < count; i++) {
set.add(NameFactoryImpl.getInstance().create(in.readUTF()));
}
if (set.size() > 0) {
state.setMixinTypeNames(set);
}
// modCount
short modCount = in.readShort();
state.setModCount(modCount);
// properties (names)
// count
count = in.readInt();
for (int i = 0; i < count; i++) {
// name
state.addPropertyName(NameFactoryImpl.getInstance().create(in.readUTF()));
}
// child nodes (list of name/uuid pairs)
// count
count = in.readInt();
for (int i = 0; i < count; i++) {
// name
Name name = NameFactoryImpl.getInstance().create(in.readUTF());
// uuid
in.readFully(uuidBytes);
state.addChildNodeEntry(name, new NodeId(uuidBytes));
}
}
Aggregations