/** * */ package com.thinkbiganalytics.metadata.modeshape.support; /*- * #%L * thinkbig-metadata-modeshape * %% * Copyright (C) 2017 ThinkBig Analytics * %% * 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. * #L% */ import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.WatchEvent.Kind; import java.nio.file.WatchEvent.Modifier; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; /** * Really just a generic path implementation but currently being used in the JCR utilities. */ public class JcrPath implements Path { private final List<String> elements; private final boolean absolute; public JcrPath(boolean absolute, List<String> elements) { this.elements = Collections.unmodifiableList(elements); this.absolute = absolute; } public JcrPath(boolean absolute, String element) { this.elements = Collections.singletonList(element); this.absolute = absolute; } public static Path get(String first, String... more) { ArrayList<String> list = new ArrayList<>(); boolean absolute = first.trim().startsWith("/"); String[] firstElems = first.split("/"); for (int idx = (absolute ? 1 : 0); idx < firstElems.length; idx++) { if (StringUtils.isNotBlank(firstElems[idx])) { list.add(firstElems[idx]); } } for (String another : more) { String[] anotherElems = another.split("/"); for (String elem : anotherElems) { if (StringUtils.isNotBlank(elem)) { list.add(elem); } } } return new JcrPath(absolute, list); } /* (non-Javadoc) * @see java.nio.file.Path#getFileSystem() */ @Override public FileSystem getFileSystem() { return null; } /* (non-Javadoc) * @see java.nio.file.Path#isAbsolute() */ @Override public boolean isAbsolute() { return this.absolute; } /* (non-Javadoc) * @see java.nio.file.Path#getRoot() */ @Override public Path getRoot() { return this.absolute ? new JcrPath(true, Collections.emptyList()) : null; } /* (non-Javadoc) * @see java.nio.file.Path#getFileName() */ @Override public Path getFileName() { return this.elements.size() > 0 ? new JcrPath(false, this.elements.get(this.elements.size() - 1)) : null; } /* (non-Javadoc) * @see java.nio.file.Path#getParent() */ @Override public Path getParent() { if (this.elements.size() > 1) { return new JcrPath(this.absolute, this.elements.subList(0, this.elements.size() - 1)); } else { return null; } } /* (non-Javadoc) * @see java.nio.file.Path#getNameCount() */ @Override public int getNameCount() { return this.elements.size(); } /* (non-Javadoc) * @see java.nio.file.Path#getName(int) */ @Override public Path getName(int index) { if (index < 0 || index > this.elements.size() - 1) { throw new IllegalArgumentException("Index is out of bounds: " + index); } else if (index == 0) { return new JcrPath(this.isAbsolute(), this.elements.get(0)); } else { return new JcrPath(false, this.elements.get(index)); } } /* (non-Javadoc) * @see java.nio.file.Path#subpath(int, int) */ @Override public Path subpath(int beginIndex, int endIndex) { if (beginIndex < 0 || beginIndex > this.elements.size() - 1 || endIndex < beginIndex || endIndex > this.elements.size()) { throw new IllegalArgumentException("Invalid indices bounds: " + beginIndex + ", " + endIndex); } else { return new JcrPath(this.isAbsolute() && beginIndex == 0, this.elements.subList(beginIndex, endIndex)); } } /* (non-Javadoc) * @see java.nio.file.Path#startsWith(java.nio.file.Path) */ @Override public boolean startsWith(Path other) { if (other.isAbsolute() != isAbsolute()) { return false; } else if (other.getNameCount() > getNameCount()) { return false; } else { for (int idx = 0; idx < other.getNameCount(); idx++) { Path otherElem = other.getName(idx); if (otherElem.getFileName().equals(this.elements.get(idx))) { return false; } } return true; } } /* (non-Javadoc) * @see java.nio.file.Path#startsWith(java.lang.String) */ @Override public boolean startsWith(String other) { Path otherPath = get(other); return startsWith(otherPath); } /* (non-Javadoc) * @see java.nio.file.Path#endsWith(java.nio.file.Path) */ @Override public boolean endsWith(Path other) { int offset = getNameCount() - other.getNameCount(); if (offset < 0) { return false; } else { for (int idx = getNameCount() - 1; idx - offset >= 0; idx--) { Path otherElem = other.getName(idx - offset); if (otherElem.getFileName().equals(this.elements.get(idx))) { return false; } } return true; } } /* (non-Javadoc) * @see java.nio.file.Path#endsWith(java.lang.String) */ @Override public boolean endsWith(String other) { Path otherPath = get(other); return startsWith(otherPath); } /* (non-Javadoc) * @see java.nio.file.Path#normalize() */ @Override public Path normalize() { return this; } /* (non-Javadoc) * @see java.nio.file.Path#resolve(java.nio.file.Path) */ @Override public Path resolve(Path other) { if (other.isAbsolute()) { return other; } else if (other.getNameCount() == 0) { return this; } else { List<String> elements = new ArrayList<>(this.elements); for (int idx = 0; idx < other.getNameCount(); idx++) { elements.add(other.getName(idx).toString()); } return new JcrPath(this.absolute, elements); } } /* (non-Javadoc) * @see java.nio.file.Path#resolve(java.lang.String) */ @Override public Path resolve(String other) { Path otherPath = get(other); return resolve(otherPath); } /* (non-Javadoc) * @see java.nio.file.Path#resolveSibling(java.nio.file.Path) */ @Override public Path resolveSibling(Path other) { if (other.isAbsolute()) { return other; } else if (other.getNameCount() == 0) { return this; } else { return getParent().resolve(other); } } /* (non-Javadoc) * @see java.nio.file.Path#resolveSibling(java.lang.String) */ @Override public Path resolveSibling(String other) { Path otherPath = get(other); return resolveSibling(otherPath); } /* (non-Javadoc) * @see java.nio.file.Path#relativize(java.nio.file.Path) */ @Override public Path relativize(Path other) { if (other.isAbsolute() != isAbsolute() || other.getNameCount() < getNameCount()) { return other; } else if (other.getNameCount() == 0) { return this; } else { int idx = 0; for (; idx < getNameCount(); idx++) { if (!other.getName(idx).equals(getName(idx))) { return other; } } return other.subpath(idx - 1, other.getNameCount()); } } /* (non-Javadoc) * @see java.nio.file.Path#toUri() */ @Override public URI toUri() { return URI.create(toString()); } /* (non-Javadoc) * @see java.nio.file.Path#toAbsolutePath() */ @Override public Path toAbsolutePath() { // TODO Support a root node? return get("/").resolve(this); } /* (non-Javadoc) * @see java.nio.file.Path#toRealPath(java.nio.file.LinkOption[]) */ @Override public Path toRealPath(LinkOption... options) throws IOException { return this; } /* (non-Javadoc) * @see java.nio.file.Path#toFile() */ @Override public File toFile() { return new File(toUri()); } /* (non-Javadoc) * @see java.nio.file.Path#register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind[], java.nio.file.WatchEvent.Modifier[]) */ @Override public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException { throw new UnsupportedOperationException("Register not supported"); } /* (non-Javadoc) * @see java.nio.file.Path#register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind[]) */ @Override public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException { throw new UnsupportedOperationException("Register not supported"); } /* (non-Javadoc) * @see java.nio.file.Path#iterator() */ @Override public Iterator<Path> iterator() { return this.elements.stream().map(e -> new JcrPath(false, e)).collect(Collectors.<Path>toList()).iterator(); } /* (non-Javadoc) * @see java.nio.file.Path#compareTo(java.nio.file.Path) */ @Override public int compareTo(Path other) { int len = Math.min(other.getNameCount(), getNameCount()); for (int idx = 0; idx < len; idx++) { int value = other.getName(idx).toString().compareTo(getName(idx).toString()); if (value != 0) { return value; } } return Integer.compare(other.getNameCount(), getNameCount()); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj instanceof Path) { Path other = (Path) obj; if (isAbsolute() == other.isAbsolute()) { return compareTo(other) == 0; } else { return false; } } else { return false; } } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return Boolean.hashCode(this.absolute) + this.elements.stream() .mapToInt(String::hashCode) .reduce((h, e) -> h + e) .orElse(0); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder bldr = new StringBuilder(); if (this.absolute) { bldr.append("/"); } if (this.elements.size() > 0) { bldr.append(this.elements.get(0)); } for (int idx = 1; idx < this.elements.size(); idx++) { bldr.append("/").append(this.elements.get(idx)); } return bldr.toString(); } }