package org.concordion.api; import org.concordion.internal.util.Check; public final class Resource { private final String path; private final String[] parts; private final String name; private final boolean isPackage; public Resource(String path) { path = path.replaceAll("\\\\", "/"); Check.isTrue(path.startsWith("/"), "Internal error: Resource path should start with a slash"); this.path = path; isPackage = endsWithSlash(path); parts = path.split("/"); if (parts.length == 0) { name = ""; } else { name = parts[parts.length - 1]; } } public String getPath() { return path; } private boolean isPackage() { return isPackage; } private boolean endsWithSlash(String s) { return s.endsWith("/"); } private Resource getPackage() { if (isPackage()) { return this; } return getParent(); } public Resource getParent() { if (getPath().equals("/")) { return null; } String parentPath = "/"; for (int i = 1; i < parts.length - 1; i++) { parentPath += parts[i] + "/"; } return new Resource(parentPath); } public String getRelativePath(Resource resource) { if (resource.getPath().equals(path)) { return name; } // Find common stem and ignore it // Use ../ to move up the path from here to common stem // Append the rest of the path from resource String[] therePieces = resource.getPackage().getPath().split("/"); String[] herePieces = getPackage().getPath().split("/"); int sharedPiecesCount = 0; for (int i = 0; i < herePieces.length; i++) { if (therePieces.length <= i) { break; } if (therePieces[i].equals(herePieces[i])) { sharedPiecesCount++; } else { break; } } String r = ""; for (int i = sharedPiecesCount; i < herePieces.length; i++) { r += "../"; } for (int i = sharedPiecesCount; i < therePieces.length; i++) { r += therePieces[i] + "/"; } if (resource.isPackage()) { return r; } return r + resource.getName(); } public String getName() { return name; } public Resource getRelativeResource(String relativePath) { Check.isFalse(relativePath.startsWith("/"), "Relative path should not start with a slash"); String subPath = removeAnyLeadingDotSlashFrom(relativePath); Resource p = getPackage(); while (subPath.startsWith("../")) { p = p.getParent(); if (p == null) { throw new RuntimeException("Path '" + relativePath + "' relative to '" + getPath() + "' " + "evaluates above the root package."); } subPath = subPath.replaceFirst("../", ""); } Check.isFalse(subPath.contains("../"), "The ../ operator is currently only supported at the start of expressions"); return new Resource(p.getPath() + subPath); } private String removeAnyLeadingDotSlashFrom(String subPath) { return subPath.replaceFirst("^\\./", ""); } @Override public String toString() { return "[Resource: " + path + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((path == null) ? 0 : path.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; } final Resource other = (Resource) obj; if (path == null) { if (other.path != null) { return false; } } else if (!path.equals(other.path)) { return false; } return true; } }