/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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:
* bstefanescu
*/
package org.eclipse.ecr.web.jaxrs.servlet.mapping;
import java.util.Arrays;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public final class Path {
public static final int HAS_LEADING_SLASH = 1;
public static final int HAS_TRAILING_SLASH = 2;
public static final String[] EMPTY_SEGMENTS = new String[0];
public static final Path ROOT = new Path(EMPTY_SEGMENTS, HAS_LEADING_SLASH|HAS_TRAILING_SLASH);
public static final Path EMPTY = new Path(EMPTY_SEGMENTS);
public static Path parse(String path) {
return new PathParser().parse(path);
}
protected int bits;
protected final String[] segments;
public Path(String[] segments) {
this (segments, 0);
}
public Path(String[] segments, int bits) {
this (segments, bits, true);
}
protected Path(String[] segments, int bits, boolean updateHashCode) {
this.segments = segments;
this.bits = bits;
if (updateHashCode) {
updateHashCode();
}
}
public int length() {
return segments.length;
}
public String[] segments() {
return segments;
}
public boolean hasLeadingSlash() {
return (bits & HAS_LEADING_SLASH) == HAS_LEADING_SLASH;
}
public boolean hasTrailingSlash() {
return (bits & HAS_TRAILING_SLASH) == HAS_TRAILING_SLASH;
}
public boolean isAbsolute() {
return (bits & HAS_LEADING_SLASH) == HAS_LEADING_SLASH;
}
public Path copy() {
return new Path(segments, bits, false);
}
public Path copy(int bits) {
return new Path(segments, (bits & ~3) | (bits & 3), false);
}
@Override
public String toString() {
int len = segments.length;
if (len == 0) {
return hasLeadingSlash() || hasTrailingSlash() ? "/" : "";
}
StringBuilder buf = new StringBuilder(segments.length*16);
if (hasLeadingSlash()) {
buf.append('/');
}
buf.append(segments[0]);
for (int i=1; i<segments.length; i++) {
buf.append('/').append(segments[i]);
}
if (hasTrailingSlash()) {
buf.append('/');
}
return buf.toString();
}
public String lastSegment() {
return segments.length == 0 ? "" : segments[segments.length-1];
}
public String getFileExtension() {
if (segments.length == 0) {
return null;
}
String last = segments[segments.length-1];
int i = last.lastIndexOf('.');
return i > -1 ? last.substring(i+1) : null;
}
public String getFileName() {
if (segments.length == 0) {
return "";
}
String last = segments[segments.length-1];
int i = last.lastIndexOf('.');
return i > -1 ? last.substring(0, i) : null;
}
public Path append(String segment) {
String[] ar = new String[segments.length];
System.arraycopy(segments, 0, ar, 0, segments.length);
return new Path(segments, bits);
}
public Path makeAbsolute() {
return hasLeadingSlash() ? this : new Path(segments, bits | HAS_LEADING_SLASH);
}
public Path makeRelative() {
return hasLeadingSlash() ? new Path(segments, bits & ~HAS_LEADING_SLASH) : this;
}
public Path removeTrailingSlash() {
return hasTrailingSlash() ? new Path(segments, bits & ~HAS_TRAILING_SLASH) : this;
}
public boolean isRoot() {
return segments.length == 0 && hasLeadingSlash();
}
public String segment(int i) {
return segments[i];
}
public Path removeLastSegment() {
return removeLastSegments(1);
}
public Path removeLastSegments(int i) {
String[] ar = new String[segments.length];
System.arraycopy(segments, 0, ar, 0, segments.length);
return new Path(segments, bits);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (obj.getClass() == Path.class) {
Path path = (Path)obj;
return path.bits == bits && Arrays.equals(path.segments, segments);
}
return false;
}
@Override
public int hashCode() {
return bits;
}
private void updateHashCode() {
bits = (bits & 3) | (computeHashCode() << 2);
}
private int computeHashCode() {
int hash = 17;
int segmentCount = segments.length;
for (int i = 0; i < segmentCount; i++) {
//this function tends to given a fairly even distribution
hash = hash * 37 + segments[i].hashCode();
}
return hash;
}
}