package ch.x42.terye.path; import javax.jcr.RepositoryException; public abstract class AbstractPath implements Path { private final Path parent; private final String name; private final int depth; private final int length; private String pathString; AbstractPath(Path parent, String name) { this.parent = parent; this.name = name; int depth = 0; if (parent != null) { depth += parent.getDepth(); } this.depth = depth + getDepthIncrease(); int length = 0; if (parent != null) { length += parent.getLength(); } this.length = length + 1; } @Override public boolean isRoot() { return false; } @Override public boolean isRelative() { return !isAbsolute(); } @Override public boolean isAbsolute() { if (getParent() != null) { return getParent().isAbsolute(); } return false; } @Override public boolean isCanonical() { return isAbsolute() && isNormalized(); } protected int getDepthIncrease() { return 1; } @Override public int getDepth() { return depth; } @Override public int getLength() { return length; } @Override public Path getAncestor(int degree) throws RepositoryException { if (degree < 0) { throw new IllegalArgumentException( "Invalid degree: must be non-negative"); } else if (degree == 0) { return getNormalizedPath(); } else if (getParent() == null) { throw new IllegalArgumentException( "Invalid degree: reached topmost ancestor"); } return getParent().getAncestor(degree - 1); } @Override public Path getParent() { return parent; } @Override public Path getCanonicalPath() throws RepositoryException { if (isRelative()) { throw new RepositoryException( "Cannot make a relative path canonical"); } return getNormalizedPath(); } @Override public Path resolve(Path relative) { if (relative.isAbsolute()) { throw new IllegalArgumentException("Argument must be relative"); } String last = relative.getLastElement(); Path path = this; if (relative.getLength() > 1) { Path parent = relative.getParent(); path = resolve(parent); } return path.resolve(last); } @Override public Path resolve(String element) { // XXX: validate element if (Path.CURRENT.equals(element)) { return new CurrentPath(this); } else if (Path.PARENT.equals(element)) { return new ParentPath(this); } else { return new NamePath(this, element); } } @Override public boolean isEquivalentTo(Path path) throws RepositoryException { return getNormalizedPath().equals(path.getNormalizedPath()); } @Override public boolean isDescendantOf(Path path) throws RepositoryException { if (isRelative() || path.isRelative()) { // XXX: true? throw new RepositoryException("Both paths must be absolute"); } int d = getDepth() - path.getDepth(); return d > 0 && getAncestor(d).isEquivalentTo(path); } @Override public boolean isAncestorOf(Path path) throws RepositoryException { return path.isDescendantOf(this); } @Override public String getLastElement() { return name; } @Override public String toString() { if (pathString == null) { pathString = ""; if (getParent() != null) { pathString = getParent().toString(); if (!getParent().isRoot()) { pathString += Path.DELIMITER; } } pathString += name; } return pathString; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + toString().hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AbstractPath other = (AbstractPath) obj; return toString().equals(other.toString()); } }