use of org.structr.web.diff.UpdateOperation in project structr by structr.
the class Importer method diffNodes.
public static List<InvertibleModificationOperation> diffNodes(final DOMNode sourceNode, final DOMNode modifiedNode) {
if (sourceNode == null) {
logger.warn("Source node was null, returning empty change set.");
return Collections.EMPTY_LIST;
}
if (modifiedNode == null) {
logger.warn("Modified node was null, returning empty change set.");
return Collections.EMPTY_LIST;
}
final List<InvertibleModificationOperation> changeSet = new LinkedList<>();
final Map<String, DOMNode> indexMappedExistingNodes = new LinkedHashMap<>();
final Map<String, DOMNode> hashMappedExistingNodes = new LinkedHashMap<>();
final Map<DOMNode, Integer> depthMappedExistingNodes = new LinkedHashMap<>();
final Map<String, DOMNode> indexMappedNewNodes = new LinkedHashMap<>();
final Map<String, DOMNode> hashMappedNewNodes = new LinkedHashMap<>();
final Map<DOMNode, Integer> depthMappedNewNodes = new LinkedHashMap<>();
InvertibleModificationOperation.collectNodes(sourceNode, indexMappedExistingNodes, hashMappedExistingNodes, depthMappedExistingNodes);
InvertibleModificationOperation.collectNodes(modifiedNode, indexMappedNewNodes, hashMappedNewNodes, depthMappedNewNodes);
// iterate over existing nodes and try to find deleted ones
for (final Iterator<Map.Entry<String, DOMNode>> it = hashMappedExistingNodes.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<String, DOMNode> existingNodeEntry = it.next();
final DOMNode existingNode = existingNodeEntry.getValue();
final String existingHash = existingNode.getIdHash();
// check for deleted nodes ignoring Page nodes
if (!hashMappedNewNodes.containsKey(existingHash) && !(existingNode instanceof Page)) {
changeSet.add(new DeleteOperation(hashMappedExistingNodes, existingNode));
}
}
// iterate over new nodes and try to find new ones
for (final Iterator<Map.Entry<String, DOMNode>> it = indexMappedNewNodes.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<String, DOMNode> newNodeEntry = it.next();
final DOMNode newNode = newNodeEntry.getValue();
// if newNode is a content element, do not rely on local hash property
String newHash = newNode.getDataHash();
if (newHash == null) {
newHash = newNode.getIdHash();
}
// check for deleted nodes ignoring Page nodes
if (!hashMappedExistingNodes.containsKey(newHash) && !(newNode instanceof Page)) {
final DOMNode newParent = newNode.getParent();
changeSet.add(new CreateOperation(hashMappedExistingNodes, getHashOrNull(newParent), getSiblingHashes(newNode), newNode, depthMappedNewNodes.get(newNode)));
}
}
// compare all new nodes with all existing nodes
for (final Map.Entry<String, DOMNode> newNodeEntry : indexMappedNewNodes.entrySet()) {
final String newTreeIndex = newNodeEntry.getKey();
final DOMNode newNode = newNodeEntry.getValue();
for (final Map.Entry<String, DOMNode> existingNodeEntry : indexMappedExistingNodes.entrySet()) {
final String existingTreeIndex = existingNodeEntry.getKey();
final DOMNode existingNode = existingNodeEntry.getValue();
DOMNode newParent = null;
int equalityBitmask = 0;
if (newTreeIndex.equals(existingTreeIndex)) {
equalityBitmask |= 1;
}
if (newNode.getIdHashOrProperty().equals(existingNode.getIdHash())) {
equalityBitmask |= 2;
}
if (newNode.contentEquals(existingNode)) {
equalityBitmask |= 4;
}
switch(equalityBitmask) {
case // same tree index (1), same node (2), same content (4) => node is completely unmodified
7:
break;
case // same content (2), same node (4), NOT same tree index => node has moved
6:
newParent = newNode.getParent();
changeSet.add(new MoveOperation(hashMappedExistingNodes, getHashOrNull(newParent), getSiblingHashes(newNode), newNode, existingNode));
break;
case // same tree index (1), NOT same node, same content (5) => node was deleted and restored, maybe the identification information was lost
5:
break;
case // NOT same tree index, NOT same node, same content (4) => different node, content is equal by chance?
4:
break;
case // same tree index, same node, NOT same content => node was modified but not moved
3:
changeSet.add(new UpdateOperation(hashMappedExistingNodes, existingNode, newNode));
break;
case // NOT same tree index, same node (2), NOT same content => node was moved and changed
2:
newParent = newNode.getParent();
changeSet.add(new UpdateOperation(hashMappedExistingNodes, existingNode, newNode));
changeSet.add(new MoveOperation(hashMappedExistingNodes, getHashOrNull(newParent), getSiblingHashes(newNode), newNode, existingNode));
break;
case // same tree index (1), NOT same node, NOT same content => ignore
1:
break;
case // NOT same tree index, NOT same node, NOT same content => ignore
0:
break;
}
}
}
return changeSet;
}
Aggregations