// look at the node's children
Collection<NodePropBundle.ChildNodeEntry> missingChildren = new ArrayList<NodePropBundle.ChildNodeEntry>();
Collection<NodePropBundle.ChildNodeEntry> disconnectedChildren = new ArrayList<NodePropBundle.ChildNodeEntry>();
NodePropBundle bundle = null;
for (final NodeId childNodeId : nodeInfo.getChildren()) {
// skip check for system nodes (root, system root, version storage,
// node types)
if (childNodeId.toString().endsWith("babecafebabe")) {
continue;
}
try {
// analyze child node bundles
NodePropBundle childBundle = null;
NodeInfo childNodeInfo = infos.get(childNodeId);
// does the child exist?
if (childNodeInfo == null) {
// try to load the bundle
childBundle = pm.loadBundle(childNodeId);
if (childBundle == null) {
// the child indeed does not exist
// double check whether we still exist and the child entry is still there
if (bundle == null) {
bundle = pm.loadBundle(id);
}
if (bundle != null) {
NodePropBundle.ChildNodeEntry childNodeEntry = null;
for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) {
if (entry.getId().equals(childNodeId)) {
childNodeEntry = entry;
break;
}
}
if (childNodeEntry != null) {
String message = "NodeState '" + id + "' references inexistent child '" + childNodeId + "'";
log.error(message);
addMessage(reports, id, message, ReportItem.Type.MISSING);
missingChildren.add(childNodeEntry);
}
} else {
return;
}
} else {
// exists after all
childNodeInfo = new NodeInfo(childBundle);
}
}
if (childNodeInfo != null) {
// if the child exists does it reference the current node as its parent?
NodeId cp = childNodeInfo.getParentId();
if (!id.equals(cp)) {
// double check whether the child still has a different parent
if (childBundle == null) {
childBundle = pm.loadBundle(childNodeId);
}
if (childBundle != null && !childBundle.getParentId().equals(id)) {
// double check if we still exist
if (bundle == null) {
bundle = pm.loadBundle(id);
}
if (bundle != null) {
// double check if the child node entry is still there
NodePropBundle.ChildNodeEntry childNodeEntry = null;
for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) {
if (entry.getId().equals(childNodeId)) {
childNodeEntry = entry;
break;
}
}
if (childNodeEntry != null) {
// indeed we have a disconnected child
String message = "Node has invalid parent id: '" + cp + "' (instead of '" + id + "')";
log.error(message);
addMessage(reports, childNodeId, message, ReportItem.Type.DISCONNECTED);
disconnectedChildren.add(childNodeEntry);
}
} else {
return;
}
}
}
}
} catch (ItemStateException e) {
// problem already logged (loadBundle called with
// logDetailedErrors=true)
addMessage(reports, id, e.getMessage(), ReportItem.Type.ERROR);
}
}
// remove child node entry (if fixing is enabled)
if (fix && (!missingChildren.isEmpty() || !disconnectedChildren.isEmpty())) {
for (NodePropBundle.ChildNodeEntry entry : missingChildren) {
bundle.getChildNodeEntries().remove(entry);
}
for (NodePropBundle.ChildNodeEntry entry : disconnectedChildren) {
bundle.getChildNodeEntries().remove(entry);
}
fixBundle(bundle);
}
// check parent reference
NodeId parentId = nodeInfo.getParentId();
try {
// skip root nodes (that point to itself)
if (parentId != null && !id.toString().endsWith("babecafebabe")) {
NodePropBundle parentBundle = null;
NodeInfo parentInfo = infos.get(parentId);
// does the parent exist?
if (parentInfo == null) {
// try to load the bundle
parentBundle = pm.loadBundle(parentId);
if (parentBundle == null) {
// indeed the parent doesn't exist
// double check whether we still exist and the parent is still the same\
if (bundle == null) {
bundle = pm.loadBundle(id);
}
if (bundle != null) {
if (parentId.equals(bundle.getParentId())) {
// indeed we have an orphaned node
String message = "NodeState '" + id + "' references inexistent parent id '" + parentId + "'";
log.error(message);
addMessage(reports, id, message, ReportItem.Type.ORPHANED);
if (fix && lostNFoundId != null) {
// add a child to lost+found
NodePropBundle lfBundle = pm.loadBundle(lostNFoundId);
lfBundle.markOld();
String nodeName = id + "-" + System.currentTimeMillis();
lfBundle.addChildNodeEntry(NF.create("", nodeName), id);
pm.storeBundle(lfBundle);
pm.evictBundle(lostNFoundId);
// set lost+found parent
bundle.setParentId(lostNFoundId);