use of org.apache.jackrabbit.core.version.VersionHistoryInfo 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.core.version.VersionHistoryInfo in project jackrabbit by apache.
the class BatchedItemOperations method copyNodeState.
/**
* Recursively copies the specified node state including its properties and
* child nodes.
*
* @param srcState
* @param srcPath
* @param srcStateMgr
* @param srcAccessMgr
* @param destParentId
* @param flag one of
* <ul>
* <li><code>COPY</code></li>
* <li><code>CLONE</code></li>
* <li><code>CLONE_REMOVE_EXISTING</code></li>
* </ul>
* @param refTracker tracks uuid mappings and processed reference properties
* @return a deep copy of the given node state and its children
* @throws RepositoryException if an error occurs
*/
private NodeState copyNodeState(NodeState srcState, Path srcPath, ItemStateManager srcStateMgr, AccessManager srcAccessMgr, NodeId destParentId, int flag, ReferenceChangeTracker refTracker) throws RepositoryException {
NodeState newState;
try {
NodeId id = null;
EffectiveNodeType ent = getEffectiveNodeType(srcState);
boolean referenceable = ent.includesNodeType(NameConstants.MIX_REFERENCEABLE);
boolean versionable = ent.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE);
boolean fullVersionable = ent.includesNodeType(NameConstants.MIX_VERSIONABLE);
boolean shareable = ent.includesNodeType(NameConstants.MIX_SHAREABLE);
switch(flag) {
case COPY:
/* if this node is shareable and another node in the same shared set
* has been already been copied and given a new uuid, use this one
* (see section 14.5 of the specification)
*/
if (shareable && refTracker.getMappedId(srcState.getNodeId()) != null) {
NodeId newId = refTracker.getMappedId(srcState.getNodeId());
NodeState sharedState = (NodeState) stateMgr.getItemState(newId);
sharedState.addShare(destParentId);
return sharedState;
}
break;
case CLONE:
if (!referenceable) {
// non-referenceable node: always create new node id
break;
}
// use same uuid as source node
id = srcState.getNodeId();
if (stateMgr.hasItemState(id)) {
if (shareable) {
NodeState sharedState = (NodeState) stateMgr.getItemState(id);
sharedState.addShare(destParentId);
return sharedState;
}
// node with this uuid already exists
throw new ItemExistsException(safeGetJCRPath(id));
}
break;
case CLONE_REMOVE_EXISTING:
if (!referenceable) {
// non-referenceable node: always create new node id
break;
}
// use same uuid as source node
id = srcState.getNodeId();
if (stateMgr.hasItemState(id)) {
NodeState existingState = (NodeState) stateMgr.getItemState(id);
// or an ancestor thereof
if (id.equals(destParentId) || hierMgr.isAncestor(id, destParentId)) {
String msg = "cannot remove node " + safeGetJCRPath(srcPath) + " because it is an ancestor of the destination";
log.debug(msg);
throw new RepositoryException(msg);
}
// check if existing can be removed
// (access rights, locking & versioning status,
// node type constraints and retention/hold)
checkRemoveNode(existingState, CHECK_ACCESS | CHECK_LOCK | CHECK_CHECKED_OUT | CHECK_CONSTRAINTS | CHECK_HOLD | CHECK_RETENTION);
// do remove existing
removeNodeState(existingState);
}
break;
default:
throw new IllegalArgumentException("unknown flag for copying node state: " + flag);
}
newState = stateMgr.createNew(id, srcState.getNodeTypeName(), destParentId);
id = newState.getNodeId();
if (flag == COPY && referenceable) {
// remember uuid mapping
refTracker.mappedId(srcState.getNodeId(), id);
}
// copy node state
newState.setMixinTypeNames(srcState.getMixinTypeNames());
if (shareable) {
// initialize shared set
newState.addShare(destParentId);
}
// copy child nodes
for (ChildNodeEntry entry : srcState.getChildNodeEntries()) {
Path srcChildPath = PathFactoryImpl.getInstance().create(srcPath, entry.getName(), true);
if (!srcAccessMgr.isGranted(srcChildPath, Permission.READ)) {
continue;
}
NodeId nodeId = entry.getId();
NodeState srcChildState = (NodeState) srcStateMgr.getItemState(nodeId);
/**
* If child is shareble and its UUID has already been remapped,
* then simply add a reference to the state with that remapped
* UUID instead of copying the whole subtree.
*/
if (srcChildState.isShareable()) {
NodeId mappedId = refTracker.getMappedId(srcChildState.getNodeId());
if (mappedId != null) {
if (stateMgr.hasItemState(mappedId)) {
NodeState destState = (NodeState) stateMgr.getItemState(mappedId);
if (!destState.isShareable()) {
String msg = "Remapped child (" + safeGetJCRPath(srcPath) + ") is not shareable.";
throw new ItemStateException(msg);
}
if (!destState.addShare(id)) {
String msg = "Unable to add share to node: " + id;
throw new ItemStateException(msg);
}
stateMgr.store(destState);
newState.addChildNodeEntry(entry.getName(), mappedId);
continue;
}
}
}
// recursive copying of child node
NodeState newChildState = copyNodeState(srcChildState, srcChildPath, srcStateMgr, srcAccessMgr, id, flag, refTracker);
// store new child node
stateMgr.store(newChildState);
// add new child node entry to new node
newState.addChildNodeEntry(entry.getName(), newChildState.getNodeId());
}
// init version history if needed
VersionHistoryInfo history = null;
if (versionable && flag == COPY) {
NodeId copiedFrom = null;
if (fullVersionable) {
// base version of copied versionable node is reference value of
// the histories jcr:copiedFrom property
PropertyId propId = new PropertyId(srcState.getNodeId(), NameConstants.JCR_BASEVERSION);
PropertyState prop = (PropertyState) srcStateMgr.getItemState(propId);
copiedFrom = prop.getValues()[0].getNodeId();
}
InternalVersionManager manager = session.getInternalVersionManager();
history = manager.getVersionHistory(session, newState, copiedFrom);
}
// copy properties
for (Name propName : srcState.getPropertyNames()) {
Path propPath = PathFactoryImpl.getInstance().create(srcPath, propName, true);
PropertyId propId = new PropertyId(srcState.getNodeId(), propName);
if (!srcAccessMgr.canRead(propPath, propId)) {
continue;
}
PropertyState srcChildState = (PropertyState) srcStateMgr.getItemState(propId);
/**
* special handling required for properties with special semantics
* (e.g. those defined by mix:referenceable, mix:versionable,
* mix:lockable, et.al.)
*
* todo FIXME delegate to 'node type instance handler'
*/
QPropertyDefinition def = ent.getApplicablePropertyDef(srcChildState.getName(), srcChildState.getType(), srcChildState.isMultiValued());
if (NameConstants.MIX_LOCKABLE.equals(def.getDeclaringNodeType())) {
// skip properties defined by mix:lockable
continue;
}
PropertyState newChildState = copyPropertyState(srcChildState, id, propName, def);
if (history != null) {
if (fullVersionable) {
if (propName.equals(NameConstants.JCR_VERSIONHISTORY)) {
// jcr:versionHistory
InternalValue value = InternalValue.create(history.getVersionHistoryId());
newChildState.setValues(new InternalValue[] { value });
} else if (propName.equals(NameConstants.JCR_BASEVERSION) || propName.equals(NameConstants.JCR_PREDECESSORS)) {
// jcr:baseVersion or jcr:predecessors
InternalValue value = InternalValue.create(history.getRootVersionId());
newChildState.setValues(new InternalValue[] { value });
} else if (propName.equals(NameConstants.JCR_ISCHECKEDOUT)) {
// jcr:isCheckedOut
newChildState.setValues(new InternalValue[] { InternalValue.create(true) });
}
} else {
// version history when we see the jcr:isCheckedOut
if (propName.equals(NameConstants.JCR_ISCHECKEDOUT)) {
// jcr:isCheckedOut
newChildState.setValues(new InternalValue[] { InternalValue.create(true) });
}
}
}
if (newChildState.getType() == PropertyType.REFERENCE || newChildState.getType() == PropertyType.WEAKREFERENCE) {
refTracker.processedReference(newChildState);
}
// store new property
stateMgr.store(newChildState);
// add new property entry to new node
newState.addPropertyName(propName);
}
return newState;
} catch (ItemStateException ise) {
String msg = "internal error: failed to copy state of " + srcState.getNodeId();
log.debug(msg);
throw new RepositoryException(msg, ise);
}
}
use of org.apache.jackrabbit.core.version.VersionHistoryInfo in project jackrabbit by apache.
the class WorkspaceImporter method postProcessNode.
/**
* Post-process imported node (initialize properties with special
* semantics etc.)
*
* @param node the node state
* @throws RepositoryException if an error occurs
*/
protected void postProcessNode(NodeState node) throws RepositoryException {
/**
* special handling required for properties with special semantics
* (e.g. those defined by mix:referenceable, mix:versionable,
* mix:lockable, et.al.)
*
* todo FIXME delegate to 'node type instance handler'
*/
EffectiveNodeType ent = itemOps.getEffectiveNodeType(node);
if (ent.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
/**
* check if there's already a version history for that
* node; this would e.g. be the case if a versionable node
* had been exported, removed and re-imported with either
* IMPORT_UUID_COLLISION_REMOVE_EXISTING or
* IMPORT_UUID_COLLISION_REPLACE_EXISTING;
* otherwise create a new version history
*/
VersionHistoryInfo history = versionManager.getVersionHistory(session, node, null);
InternalValue historyId = InternalValue.create(history.getVersionHistoryId());
InternalValue versionId = InternalValue.create(history.getRootVersionId());
// jcr:isCheckedOut
conditionalAddProperty(node, NameConstants.JCR_ISCHECKEDOUT, PropertyType.BOOLEAN, false, InternalValue.create(true));
// set extra properties only for full versionable nodes
if (ent.includesNodeType(NameConstants.MIX_VERSIONABLE)) {
// jcr:versionHistory
conditionalAddProperty(node, NameConstants.JCR_VERSIONHISTORY, PropertyType.REFERENCE, false, historyId);
// jcr:baseVersion
conditionalAddProperty(node, NameConstants.JCR_BASEVERSION, PropertyType.REFERENCE, false, versionId);
// jcr:predecessors
conditionalAddProperty(node, NameConstants.JCR_PREDECESSORS, PropertyType.REFERENCE, true, versionId);
}
}
}
use of org.apache.jackrabbit.core.version.VersionHistoryInfo in project jackrabbit by apache.
the class ItemSaveOperation method initVersionHistories.
/**
* Initialises the version history of all new nodes of node type
* <code>mix:versionable</code>.
*
* @param states
* @return true if this call generated new transient state; otherwise false
* @throws RepositoryException
*/
private boolean initVersionHistories(SessionContext context, Iterable<ItemState> states) throws RepositoryException {
SessionImpl session = context.getSessionImpl();
ItemManager itemMgr = context.getItemManager();
// walk through list of transient items and search for new versionable nodes
boolean createdTransientState = false;
for (ItemState itemState : states) {
if (itemState.isNode()) {
NodeState nodeState = (NodeState) itemState;
EffectiveNodeType nt = getEffectiveNodeType(context.getRepositoryContext().getNodeTypeRegistry(), nodeState);
if (nt.includesNodeType(NameConstants.MIX_VERSIONABLE)) {
if (!nodeState.hasPropertyName(NameConstants.JCR_VERSIONHISTORY)) {
NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId(), false);
InternalVersionManager vMgr = session.getInternalVersionManager();
/**
* check if there's already a version history for that
* node; this would e.g. be the case if a versionable
* node had been exported, removed and re-imported with
* either IMPORT_UUID_COLLISION_REMOVE_EXISTING or
* IMPORT_UUID_COLLISION_REPLACE_EXISTING;
* otherwise create a new version history
*/
VersionHistoryInfo history = vMgr.getVersionHistory(session, nodeState, null);
InternalValue historyId = InternalValue.create(history.getVersionHistoryId());
InternalValue versionId = InternalValue.create(history.getRootVersionId());
node.internalSetProperty(NameConstants.JCR_VERSIONHISTORY, historyId);
node.internalSetProperty(NameConstants.JCR_BASEVERSION, versionId);
node.internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(true));
node.internalSetProperty(NameConstants.JCR_PREDECESSORS, new InternalValue[] { versionId });
createdTransientState = true;
}
} else if (nt.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
// we need to check the version manager for an existing
// version history, since simple versioning does not
// expose it's reference in a property
InternalVersionManager vMgr = session.getInternalVersionManager();
vMgr.getVersionHistory(session, nodeState, null);
// create isCheckedOutProperty if not already exists
NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId(), false);
if (!nodeState.hasPropertyName(NameConstants.JCR_ISCHECKEDOUT)) {
node.internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(true));
createdTransientState = true;
}
}
}
}
return createdTransientState;
}
Aggregations