Java tutorial
/** * PlasmaSDO License * * This is a community release of PlasmaSDO, a dual-license * Service Data Object (SDO) 2.1 implementation. * This particular copy of the software is released under the * version 2 of the GNU General Public License. PlasmaSDO was developed by * TerraMeta Software, Inc. * * Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved. * * General License information can be found below. * * This distribution may include materials developed by third * parties. For license and attribution notices for these * materials, please refer to the documentation that accompanies * this distribution (see the "Licenses for Third-Party Components" * appendix) or view the online documentation at * <http://plasma-sdo.org/licenses/>. * */ package org.plasma.sdo.core; import java.util.ArrayList; import java.util.List; import java.util.Stack; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.plasma.sdo.PathAssembler; import org.plasma.sdo.PlasmaNode; import commonj.sdo.DataObject; import commonj.sdo.Property; /** * A graph visitor which assembles and stores a list of candidate * paths from the root data-object to the given target data-object * and returns the minimum (least hops) path * or set of paths as SDO path-strings. */ public class CorePathAssembler implements PathAssembler { private static Log log = LogFactory.getFactory().getInstance(CorePathAssembler.class); public static String PATH_PREFIX = "#/namespace:"; public static String PATH_DELIM = "/"; public static String PATH_INDEX_RIGHT = "["; public static String PATH_INDEX_LEFT = "]"; private PlasmaNode pathTarget; private Stack<PathNode> currentPath = new Stack<PathNode>(); private List<Stack<PathNode>> pathList = new ArrayList<Stack<PathNode>>(); @SuppressWarnings("unused") private CorePathAssembler() { } public CorePathAssembler(DataObject pathTarget) { this.pathTarget = (PlasmaNode) pathTarget; DataObject root = this.pathTarget.getDataObject().getDataGraph().getRootObject(); if (log.isDebugEnabled()) log.debug("finding paths from root: " + root.getType().getName() + "(" + ((PlasmaNode) root).getUUIDAsString() + ") to target " + this.pathTarget.getDataObject().getType().getName() + "(" + this.pathTarget.getUUIDAsString() + ")"); } public void visit(DataObject target, DataObject source, String propertyName, int level) { Property sourceProperty = null; if (source != null) { sourceProperty = source.getType().getProperty(propertyName); } else { // the root DataObject root = this.pathTarget.getDataObject().getDataGraph().getRootObject(); if (!target.equals(root)) { throw new IllegalArgumentException("expected data graph root as " + "traversal root"); } } if (log.isDebugEnabled()) if (source == null) log.debug("visit: " + target.getType().getName() + "(" + ((PlasmaNode) target).getUUIDAsString() + ")"); else log.debug("visit: " + source.getType().getName() + "(" + ((PlasmaNode) source).getUUIDAsString() + ")." + sourceProperty.getName() + "->" + target.getType().getName() + "(" + ((PlasmaNode) target).getUUIDAsString() + ")"); if (level == currentPath.size()) { currentPath.push(new PathNode(target, 0, source, sourceProperty)); if (target.equals(pathTarget)) { Stack<PathNode> path = new Stack<PathNode>(); path.addAll(currentPath); // copy current state pathList.add(path); } } else { PathNode pathNode = null; while (currentPath.size() > level) // pop to current level pathNode = currentPath.pop(); if (currentPath.size() != level) throw new IllegalStateException( "unexpected path size, " + currentPath.size() + " and traversal level, " + level); int siblingIndex = 0; // If current node is a sibling (e.g. same parent and same source property), assume // it's index is the previous path-node index +1 if (pathNode.getSource().equals(source)) { if (pathNode.getSourceProperty().getName().equals(sourceProperty.getName())) siblingIndex = pathNode.getIndex() + 1; } currentPath.push(new PathNode(target, siblingIndex, source, sourceProperty)); if (target.equals(pathTarget)) { Stack<PathNode> path = new Stack<PathNode>(); path.addAll(currentPath); // copy current state pathList.add(path); } } } @SuppressWarnings("unchecked") public String getMinimumPathString() { Stack<PathNode> path = getMinimumPath(); Stack<PathNode> clone = (Stack<PathNode>) path.clone(); String result = getPathString(clone); return result; } public int getMinimumPathDepth() { return getMinimumPath().size(); } private Stack<PathNode> getMinimumPath() { if (pathList.size() == 0) { DataObject root = this.pathTarget.getDataObject().getDataGraph().getRootObject(); throw new IllegalStateException("no paths from root data-object, " + root.getType().getURI() + "#" + root.getType().getName() + " (" + ((PlasmaNode) root).getUUIDAsString() + ") " + "to target, " + this.pathTarget.getDataObject().getType().getURI() + "#" + this.pathTarget.getDataObject().getType().getName() + " (" + this.pathTarget.getUUIDAsString() + ")"); } Stack<PathNode> minPath = null; for (Stack<PathNode> path : pathList) { if (minPath == null || path.size() < minPath.size()) minPath = path; } return minPath; } public int getPathCount() { return this.pathList.size(); } public String[] getAllPaths() { String[] result = new String[this.pathList.size()]; for (int i = 0; i < this.pathList.size(); i++) result[i] = getPathString(this.pathList.get(i)); return result; } private String getPathString(Stack<PathNode> path) { PathNode pathNode = null; int size = path.size(); List<String> tokens = new ArrayList<String>(); for (int i = 0; i < size; i++) { pathNode = path.pop(); if (pathNode.getSource() != null) { if (i > 0) tokens.add(PATH_DELIM); if (pathNode.getSourceProperty().isMany()) tokens.add(pathNode.getSourceProperty().getName() + PATH_INDEX_RIGHT + String.valueOf(pathNode.getIndex()) + PATH_INDEX_LEFT); else tokens.add(pathNode.getSourceProperty().getName()); } } tokens.add(PATH_PREFIX); StringBuffer buf = new StringBuffer(); for (int i = tokens.size() - 1; i >= 0; i--) buf.append(tokens.get(i)); return buf.toString(); } class PathNode { private DataObject target; private DataObject source; private Property sourceProperty; private int index = -1; @SuppressWarnings("unused") private PathNode() { } public PathNode(DataObject target, int index, DataObject source, Property sourceProperty) { this.target = target; this.index = index; this.source = source; this.sourceProperty = sourceProperty; } public DataObject getTarget() { return target; } public DataObject getSource() { return source; } public Property getSourceProperty() { return sourceProperty; } public int getIndex() { return index; } } }