Java tutorial
/******************************************************************************* * Copyright (C) 2013, 2014, 2015 by Inria and Paris-Sud University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package fr.inria.oak.paxquery.common.xml.construction; import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; import fr.inria.oak.paxquery.common.xml.construction.ConstructionTreePatternNode.ContentType; /** * This class models the construction tree patterns. * */ public class ConstructionTreePattern implements Serializable { private Set<ConstructionTreePatternNode> nodes; //Tree pattern nodes private ConstructionTreePatternNode root; //Tree pattern root private Map<ConstructionTreePatternNode, ConstructionTreePatternEdge> parentEdges; //From child private ListMultimap<ConstructionTreePatternNode, ConstructionTreePatternEdge> childrenEdges; //From parent public ConstructionTreePattern(ConstructionTreePatternNode root) { this.root = root; this.root.setConstructionTreePattern(this); this.nodes = new HashSet<ConstructionTreePatternNode>(); this.nodes.add(root); this.parentEdges = new HashMap<ConstructionTreePatternNode, ConstructionTreePatternEdge>(); this.childrenEdges = ArrayListMultimap.create(); } private ConstructionTreePattern() { this.nodes = new HashSet<ConstructionTreePatternNode>(); this.parentEdges = new HashMap<ConstructionTreePatternNode, ConstructionTreePatternEdge>(); this.childrenEdges = ArrayListMultimap.create(); } /** * Adds child node to the tree. * * @param parent parent of the child to add * @param child child node to add to the tree */ public void addChild(ConstructionTreePatternNode parent, ConstructionTreePatternNode child) { this.nodes.add(child); this.connect(parent, child); } private void connect(ConstructionTreePatternNode parent, ConstructionTreePatternNode child) { ConstructionTreePatternEdge edge = new ConstructionTreePatternEdge(parent, child); this.parentEdges.put(child, edge); this.childrenEdges.put(parent, edge); } /** * Adds a subtree to the current tree, under a given parent node. * * @param parent parent node of the new subtree * @param root root node of the subtree to add under parent */ /*public void moveSubtree(ConstructionTreePatternNode parent, ConstructionTreePatternNode root) { //Pass to assign nodes to this tree Deque<ConstructionTreePatternNode> stack = new ArrayDeque<ConstructionTreePatternNode>(); stack.push(null); ConstructionTreePattern rootCtp = root.getConstructionTreePattern(); ConstructionTreePatternNode top = root; while(top != null) { //Add node to this tree and remove from old tree this.nodes.add(top); rootCtp.nodes.remove(top); //Connect parent and remove edge from old tree if(top == root) { //If we are at the root of the subtree this.parentEdges.put(top, new ConstructionTreePatternEdge(parent, root)); } else { this.parentEdges.put(top, rootCtp.getParentEdges().get(top)); } rootCtp.parentEdges.remove(top); //Connect children and remove edges from old tree List<ConstructionTreePatternEdge> children = rootCtp.childrenEdges.get(top); if(children != null) { for(ConstructionTreePatternEdge edge: children) { this.childrenEdges.put(top, edge); stack.push(edge.getChild()); } rootCtp.childrenEdges.removeAll(top); } //New top top = stack.pop(); } }*/ public void moveSubtree(ConstructionTreePatternNode parent, ConstructionTreePatternNode root) { //Pass to assign nodes to this tree Deque<ConstructionTreePatternNode> stack = new ArrayDeque<ConstructionTreePatternNode>(); //stack.push(null); ConstructionTreePattern rootCtp = root.getConstructionTreePattern(); ConstructionTreePatternNode top = root; //while(top != null) { boolean end = false; do { //Add node to this tree and remove from old tree this.nodes.add(top); rootCtp.nodes.remove(top); //Connect parent and remove edge from old tree if (top == root) { //If we are at the root of the subtree ConstructionTreePatternEdge edge = new ConstructionTreePatternEdge(parent, root); //this.parentEdges.put(top, new ConstructionTreePatternEdge(parent, root)); //this.childrenEdges.put(parent, new ConstructionTreePatternEdge(root, parent)); this.parentEdges.put(top, edge); this.childrenEdges.put(parent, edge); } else { ConstructionTreePatternEdge edge = new ConstructionTreePatternEdge( rootCtp.getParentEdges().get(top).getParent(), rootCtp.getParentEdges().get(top).getChild()); //this.parentEdges.put(top, rootCtp.getParentEdges().get(top)); this.parentEdges.put(edge.getChild(), edge); this.childrenEdges.put(edge.getParent(), edge); } //rootCtp.parentEdges.remove(top); //Connect children and remove edges from old tree List<ConstructionTreePatternEdge> children = rootCtp.childrenEdges.get(top); if (children != null) { for (ConstructionTreePatternEdge edge : children) { //this.childrenEdges.put(top, edge); this.parentEdges.put(edge.getChild(), edge); this.parentEdges.put(edge.getParent(), edge); stack.push(edge.getChild()); } //rootCtp.childrenEdges.removeAll(top); } //New top if (stack.isEmpty() == false) top = stack.pop(); else end = true; } while (end == false); } /** * Adds a subtree to the current tree, under a given parent node. * The subtree is deep copied before being added. * * @param parent parent node of the new subtree * @param root root node of the subtree to add under parent */ public void addDeepCopySubtree(ConstructionTreePatternNode parent, ConstructionTreePatternNode root) { ConstructionTreePattern deepCopySubtree = deepCopySubtree(root); this.moveSubtree(parent, deepCopySubtree.getRoot()); } public void addDeepCopySubtreeDuplicateVarpaths(ConstructionTreePatternNode parent, ConstructionTreePatternNode root) { //ConstructionTreePattern deepCopySubtree = deepCopySubtree(root); ConstructionTreePattern deepCopySubtree = deepCopySubtreeDuplicateVarpaths(root); this.moveSubtree(parent, deepCopySubtree.getRoot()); } /** * Deep copy of a subtree. * * @param root root node of the subtree to deep copy */ public static ConstructionTreePattern deepCopySubtree(ConstructionTreePatternNode root) { ConstructionTreePattern newCtp = new ConstructionTreePattern(); Map<ConstructionTreePatternNode, ConstructionTreePatternNode> oldToNew = new HashMap<ConstructionTreePatternNode, ConstructionTreePatternNode>(); //Pass to assign nodes to this tree Deque<ConstructionTreePatternNode> stack = new ArrayDeque<ConstructionTreePatternNode>(); ConstructionTreePattern rootCtp = root.getConstructionTreePattern(); ConstructionTreePatternNode top = root; while (top != null) { ConstructionTreePatternNode topCopy = new ConstructionTreePatternNode(newCtp, top.getContentType(), top.getVarPath(), top.getValue(), top.isOptional()); newCtp.nodes.add(topCopy); if (top == root) { newCtp.root = topCopy; } else { newCtp.connect(oldToNew.get(rootCtp.parentEdges.get(top).getParent()), topCopy); } oldToNew.put(top, topCopy); //Add children List<ConstructionTreePatternEdge> children = rootCtp.childrenEdges.get(top); if (children != null) { for (int i = children.size() - 1; i >= 0; i--) stack.push(children.get(i).getChild()); } //New top if (stack.isEmpty()) top = null; else top = stack.pop(); } return newCtp; } public static ConstructionTreePattern deepCopySubtreeDuplicateVarpaths(ConstructionTreePatternNode root) { ConstructionTreePattern newCtp = new ConstructionTreePattern(); Map<ConstructionTreePatternNode, ConstructionTreePatternNode> oldToNew = new HashMap<ConstructionTreePatternNode, ConstructionTreePatternNode>(); //Pass to assign nodes to this tree Deque<ConstructionTreePatternNode> stack = new ArrayDeque<ConstructionTreePatternNode>(); ConstructionTreePattern rootCtp = root.getConstructionTreePattern(); ConstructionTreePatternNode top = root; while (top != null) { List<Integer> varPath = top.getVarPath(); List<Integer> duplicatedVarPath = null; if (varPath != null) { duplicatedVarPath = new ArrayList<Integer>(); for (Integer integer : varPath) duplicatedVarPath.add(integer); } //ConstructionTreePatternNode topCopy = new ConstructionTreePatternNode( // newCtp, top.getContentType(), top.getVarPath(), top.getValue(), top.isOptional()); ConstructionTreePatternNode topCopy = new ConstructionTreePatternNode(newCtp, top.getContentType(), duplicatedVarPath, top.getValue(), top.isOptional()); topCopy.setOuterVariable(top.getOuterVariable()); newCtp.nodes.add(topCopy); if (top == root) { newCtp.root = topCopy; } else { newCtp.connect(oldToNew.get(rootCtp.parentEdges.get(top).getParent()), topCopy); } oldToNew.put(top, topCopy); //Add children List<ConstructionTreePatternEdge> children = rootCtp.childrenEdges.get(top); if (children != null) { for (int i = children.size() - 1; i >= 0; i--) stack.push(children.get(i).getChild()); } //New top if (stack.isEmpty()) top = null; else top = stack.pop(); } return newCtp; } public Set<ConstructionTreePatternNode> getNodes() { return this.nodes; } public ConstructionTreePatternNode getRoot() { return this.root; } public Map<ConstructionTreePatternNode, ConstructionTreePatternEdge> getParentEdges() { return this.parentEdges; } public ListMultimap<ConstructionTreePatternNode, ConstructionTreePatternEdge> getChildrenEdges() { return this.childrenEdges; } public String toString() { StringBuilder sb = new StringBuilder(); toStringRecursive(root, sb); return sb.toString(); } private void toStringRecursive(ConstructionTreePatternNode node, StringBuilder sb) { sb.append(node.toString()); ArrayList<ConstructionTreePatternNode> children = node.getChildren(); if (children.size() > 0) { sb.append(" ( "); for (ConstructionTreePatternNode child : children) { toStringRecursive(child, sb); sb.append(" "); } sb.append(" ) "); } } public Set<Integer> getTopLevelIndices() { return getRecTopLevelIndices(root); } private static Set<Integer> getRecTopLevelIndices(ConstructionTreePatternNode node) { Set<Integer> usedPos = Sets.newTreeSet(); if (node.getContentType() == ContentType.VARIABLE_PATH) { usedPos.add(node.getVarPath().get(0)); } else { for (ConstructionTreePatternNode child : node.getChildren()) { usedPos.addAll(getRecTopLevelIndices(child)); } } return usedPos; } public void updateTopLevelIndices(Map<Integer, Integer> updatedColumns) { updateTopLevelIndices(root, updatedColumns); } private void updateTopLevelIndices(ConstructionTreePatternNode node, Map<Integer, Integer> updatedColumns) { if (node.getContentType() == ContentType.VARIABLE_PATH) { node.getVarPath().set(0, updatedColumns.get(node.getVarPath().get(0))); } else { for (ConstructionTreePatternNode child : node.getChildren()) { updateTopLevelIndices(child, updatedColumns); } } } }