/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.utilbox.misc;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import static melnorme.utilbox.core.CoreUtil.areEqual;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import melnorme.utilbox.core.CommonException;
/**
* A location is a normalized, absolute path, based upon {@link Path}.
*/
public class Location {
public static Location create_fromValid(Path path) {
return fromAbsolutePath(path);
}
/** @return a new {@link Location} from given absolutePath, which must be an absolute path. */
public static Location fromAbsolutePath(Path absolutePath) {
return new Location(absolutePath);
}
public static Location create(Path path) throws CommonException {
return createValidLocation(path, "Invalid location: ");
}
public static Location create(String pathString) throws CommonException {
return createValidLocation(pathString, "Invalid location: ");
}
/** @return a valid {@link Location} from given path.
* @throws CommonException if a valid Location could not be created.
* Given errorMessagePrefix will be used as a prefix in {@link CommonException}'s message. */
public static Location createValidLocation(Path path, String errorMessagePrefix) throws CommonException {
if(!path.isAbsolute()) {
throw new CommonException(errorMessagePrefix + "Path `"+ path.toString()+"` is not absolute.");
}
return new Location(path);
}
/** @return a valid {@link Location} from given pathString.
* @throws CommonException if a valid Location could not be created.
* Given errorMessagePrefix will be used as a prefix in {@link CommonException}'s message. */
public static Location createValidLocation(String pathString, String errorMessagePrefix) throws CommonException {
Path path = PathUtil.createPath(pathString, errorMessagePrefix);
return createValidLocation(path, errorMessagePrefix);
}
/** @return a new {@link Location} from given path, or null if path is not absolute. */
public static Location createValidOrNull(Path path) {
if(path == null) {
return null;
}
try {
return create(path);
} catch(CommonException e) {
return null;
}
}
/** @return a new {@link Location} from given path, or null if pathString is not valid. */
public static Location createValidOrNull(String pathString) {
return Location.createValidOrNull(PathUtil.createPathOrNull(pathString));
}
/**
* @return Create a location based on given baseLocation if given pathString is a relative path,
* otherwise return the pathString location.
*/
public static Location create(Location baseLocation, String pathString) throws CommonException {
Path path = PathUtil.createPath(pathString);
return baseLocation.resolve(path);
}
public static Location validateLocation(Path filePath, boolean isRequired, String descText)
throws CommonException {
if(filePath == null) {
if(isRequired) {
throw new CommonException("Path not specified for " + descText + ".");
}
return null;
}
try {
return create(filePath);
} catch (CommonException e) {
throw new CommonException("Invalid location for " + descText + ", path not absolute: " + filePath);
}
}
/* ----------------- ----------------- */
public final Path path; // non-null
protected Location(Path absolutePath) {
assertNotNull(absolutePath);
assertTrue(absolutePath.isAbsolute());
this.path = absolutePath.normalize();
}
public Path getPath() {
return path;
}
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof Location)) return false;
Location other = (Location) obj;
return areEqual(path, other.path);
}
@Override
public int hashCode() {
return path.hashCode();
}
@Override
public String toString() {
return toPathString();
}
public String toPathString() {
return path.toString();
}
public Path toPath() {
return path;
}
public File toFile() {
return path.toFile();
}
public URI toUri() {
return path.toUri();
}
/** @return whether location is a root location. */
public boolean isRoot() {
return path.getNameCount() == 0;
}
/** @return the filename of this location. Can be null if location is the root location. */
public String getFileName() {
Path fileName = path.getFileName();
return fileName == null ? null : fileName.toString();
}
/* ----------------- ----------------- */
public Location resolve(String subPathStr) throws CommonException {
Path subPath = PathUtil.createPath(subPathStr);
return resolve(subPath);
}
/**
* @return an new Location resolved from this Location against the given otherPathString.
* null if the other path is not valid.
*/
public Location resolveOrNull(String otherPathString) {
Path otherPath = PathUtil.createPathOrNull(otherPathString);
if(otherPath == null) {
return null;
}
return resolve(otherPath);
}
/**
* @return an new Location resolved from this Location against the given otherPathString. Non-null.
* The other path *must* be valid.
* (as such this method is usually used when otherPathString is known at compile-time.)
*/
public Location resolve_fromValid(String otherPathString) {
Path otherPath = PathUtil.createValidPath(otherPathString);
return resolve(otherPath);
}
public Location resolve_valid(String otherPathString) {
return resolve_fromValid(otherPathString);
}
public Location resolve(Path otherPath) {
// resolving should always result in a valid path: absolute and non-null
return Location.create_fromValid(path.resolve(otherPath));
}
public Location getParent() {
Path parent = path.getParent();
if(parent == null) {
return null;
}
return Location.create_fromValid(parent);
}
public boolean startsWith(Location otherLoc) {
return path.startsWith(otherLoc.path);
}
public Path relativize(Location packageLoc) {
return path.relativize(packageLoc.path);
}
}