org.kie.commons.java.nio.base.AbstractPath Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012 JBoss Inc
*
* 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.
*/
package org.kie.commons.java.nio.base;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
import org.apache.commons.io.FilenameUtils;
import org.kie.commons.data.Pair;
import org.kie.commons.java.nio.IOException;
import org.kie.commons.java.nio.file.ClosedWatchServiceException;
import org.kie.commons.java.nio.file.FileSystem;
import org.kie.commons.java.nio.file.InvalidPathException;
import org.kie.commons.java.nio.file.LinkOption;
import org.kie.commons.java.nio.file.Path;
import org.kie.commons.java.nio.file.WatchKey;
import org.kie.commons.java.nio.file.WatchService;
import org.kie.commons.java.nio.file.attribute.AttributeView;
import static org.kie.commons.data.Pair.*;
import static org.kie.commons.java.nio.file.WatchEvent.*;
import static org.kie.commons.validation.Preconditions.*;
public abstract class AbstractPath
implements Path,
AttrHolder {
public static final Pattern WINDOWS_DRIVER = Pattern.compile( "^/?[A-Z|a-z]+(:).*" );
public static final String DEFAULT_WINDOWS_DRIVER = "C:";
protected final FS fs;
protected final boolean usesWindowsFormat;
protected final boolean isAbsolute;
protected final byte[] path;
protected final boolean isRoot;
protected final boolean isRealPath;
protected final boolean isNormalized;
protected final String host;
protected String toStringFormat;
protected File file = null;
protected final List> offsets = new ArrayList>();
protected final AttrsStorage attrsStorage = new AttrsStorageImpl();
protected abstract Path newPath( FS fs,
String substring,
String host,
boolean realPath,
boolean isNormalized );
protected abstract Path newRoot( FS fs,
String substring,
String host,
boolean realPath );
protected AbstractPath( final FS fs,
final File file ) {
this( checkNotNull( "fs", fs ), checkNotNull( "file", file ).getAbsolutePath(), "", false, false, true );
}
protected AbstractPath( final FS fs,
final String path,
final String host,
boolean isRoot,
boolean isRealPath,
boolean isNormalized ) {
checkNotNull( "path", path );
this.fs = checkNotNull( "fs", fs );
this.host = checkNotNull( "host", host );
this.isRealPath = isRealPath;
this.isNormalized = isNormalized;
this.usesWindowsFormat = path.matches( ".*\\\\.*" );
final RootInfo rootInfo = setupRoot( fs, path, host, isRoot );
this.path = rootInfo.path;
checkNotNull( "rootInfo", rootInfo );
this.isAbsolute = rootInfo.isAbsolute;
int lastOffset = rootInfo.startOffset;
for ( int i = lastOffset; i < this.path.length; i++ ) {
final byte b = this.path[ i ];
if ( b == getSeparator() ) {
offsets.add( newPair( lastOffset, i ) );
i++;
lastOffset = i;
}
}
if ( lastOffset < this.path.length ) {
offsets.add( newPair( lastOffset, this.path.length ) );
}
this.isRoot = rootInfo.isRoot;
}
protected abstract RootInfo setupRoot( final FS fs,
final String path,
final String host,
final boolean isRoot );
@Override
public FS getFileSystem() {
return fs;
}
@Override
public boolean isAbsolute() {
return isAbsolute;
}
@Override
public Path getRoot() {
if ( isRoot ) {
return this;
}
if ( isAbsolute || !host.isEmpty() ) {
return newRoot( fs, substring( -1 ), host, isRealPath );
}
return null;
}
private String substring( int index ) {
final byte[] result;
if ( index == -1 ) {
result = new byte[ offsets.get( 0 ).getK1() ];
System.arraycopy( path, 0, result, 0, result.length );
} else {
final Pair offset = offsets.get( index );
result = new byte[ offset.getK2().intValue() - offset.getK1().intValue() ];
System.arraycopy( path, offset.getK1(), result, 0, result.length );
}
return new String( result );
}
private String substring( int beginIndex,
int endIndex ) {
final int initPos;
if ( beginIndex == -1 ) {
initPos = 0;
} else {
initPos = offsets.get( beginIndex ).getK1();
}
final Pair offsetEnd = offsets.get( endIndex );
final byte[] result = new byte[ offsetEnd.getK2().intValue() - initPos ];
System.arraycopy( path, initPos, result, 0, result.length );
return new String( result );
}
@Override
public Path getFileName() {
if ( getNameCount() == 0 ) {
return null;
}
return getName( getNameCount() - 1 );
}
@Override
public Path getParent() {
if ( getNameCount() <= 0 ) {
return null;
}
if ( getNameCount() == 1 ) {
return getRoot();
}
return newPath( fs, substring( -1, getNameCount() - 2 ), host, isRealPath, isNormalized );
}
@Override
public int getNameCount() {
return offsets.size();
}
@Override
public Path getName( int index ) throws IllegalArgumentException {
if ( isRoot && index > 0 ) {
throw new IllegalArgumentException();
}
if ( index < 0 ) {
throw new IllegalArgumentException();
}
if ( index >= offsets.size() ) {
throw new IllegalArgumentException();
}
return newPath( fs, substring( index ), host, isRealPath, false );
}
@Override
public Path subpath( int beginIndex,
int endIndex ) throws IllegalArgumentException {
if ( beginIndex < 0 ) {
throw new IllegalArgumentException();
}
if ( beginIndex >= offsets.size() ) {
throw new IllegalArgumentException();
}
if ( endIndex > offsets.size() ) {
throw new IllegalArgumentException();
}
if ( beginIndex >= endIndex ) {
throw new IllegalArgumentException();
}
return newPath( fs, substring( beginIndex, endIndex - 1 ), host, isRealPath, false );
}
@Override
public URI toUri() throws IOException, SecurityException {
if ( !isAbsolute() ) {
return toAbsolutePath().toUri();
}
if ( fs.provider().isDefault() && !isRealPath ) {
try {
return new URI( "default", host, toURIString(), null );
} catch ( URISyntaxException e ) {
return null;
}
}
try {
return new URI( fs.provider().getScheme(), host, toURIString(), null );
} catch ( URISyntaxException e ) {
return null;
}
}
private String toURIString() {
if ( usesWindowsFormat ) {
return "/" + toString().replace( "\\", "/" );
}
return new String( path );
}
@Override
public Path toAbsolutePath() throws IOException, SecurityException {
if ( isAbsolute() ) {
return this;
}
if ( host.isEmpty() ) {
return newPath( fs, FilenameUtils.normalize( defaultDirectory() + toString(), !usesWindowsFormat ), host, isRealPath, true );
}
return newPath( fs, defaultDirectory() + toString( false ), host, isRealPath, true );
}
protected abstract String defaultDirectory();
@Override
public Path toRealPath( final LinkOption... options )
throws IOException, SecurityException {
if ( isRealPath ) {
return this;
}
return newPath( fs, FilenameUtils.normalize( toString(), !usesWindowsFormat ), host, true, true );
}
@Override
public Iterator iterator() {
return new Iterator() {
private int i = 0;
@Override
public boolean hasNext() {
return i < getNameCount();
}
@Override
public Path next() {
if ( i < getNameCount() ) {
Path result = getName( i );
i++;
return result;
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public boolean startsWith( final Path other ) {
checkNotNull( "other", other );
if ( !( other instanceof AbstractPath ) ) {
return false;
}
final AbstractPath> that = (AbstractPath) other;
if ( that.path.length > path.length ) {
return false;
}
int thisOffsetCount = getNameCount();
int thatOffsetCount = that.getNameCount();
if ( thatOffsetCount > thisOffsetCount ) {
return false;
}
if ( ( thatOffsetCount == thisOffsetCount ) &&
( path.length != that.path.length ) ) {
return false;
}
for ( int i = 0; i < thatOffsetCount; i++ ) {
final Pair o1 = offsets.get( i );
final Pair o2 = that.offsets.get( i );
if ( !o1.equals( o2 ) ) {
return false;
}
}
int i = 0;
while ( i < that.path.length ) {
if ( this.path[ i ] != that.path[ i ] ) {
return false;
}
i++;
}
if ( i < path.length && this.path[ i ] != fs.getSeparator().charAt( 0 ) ) {
return false;
}
return true;
}
@Override
public boolean startsWith( final String other ) throws InvalidPathException {
checkNotNull( "other", other );
return startsWith( getFileSystem().getPath( other ) );
}
@Override
public boolean endsWith( final Path other ) {
checkNotNull( "other", other );
if ( !( other instanceof AbstractPath ) ) {
return false;
}
final AbstractPath> that = (AbstractPath) other;
int thisLen = path.length;
int thatLen = that.path.length;
if ( thatLen > thisLen ) {
return false;
}
if ( thisLen > 0 && thatLen == 0 ) {
return false;
}
if ( that.isAbsolute() && !this.isAbsolute() ) {
return false;
}
int thisOffsetCount = getNameCount();
int thatOffsetCount = that.getNameCount();
if ( thatOffsetCount > thisOffsetCount ) {
return false;
} else {
if ( thatOffsetCount == thisOffsetCount ) {
if ( thisOffsetCount == 0 ) {
return true;
}
int expectedLen = thisLen;
if ( this.isAbsolute() && !that.isAbsolute() ) {
expectedLen--;
}
if ( thatLen != expectedLen ) {
return false;
}
} else {
if ( that.isAbsolute() ) {
return false;
}
}
}
int thisPos = offsets.get( thisOffsetCount - thatOffsetCount ).getK1();
int thatPos = that.offsets.get( 0 ).getK1();
if ( ( thatLen - thatPos ) != ( thisLen - thisPos ) ) {
return false;
}
while ( thatPos < thatLen ) {
if ( this.path[ thisPos++ ] != that.path[ thatPos++ ] ) {
return false;
}
}
return true;
}
@Override
public boolean endsWith( final String other ) throws InvalidPathException {
checkNotNull( "other", other );
return endsWith( getFileSystem().getPath( other ) );
}
@Override
public Path normalize() {
if ( isNormalized ) {
return this;
}
return newPath( fs, FilenameUtils.normalize( new String( path ), !usesWindowsFormat ), host, isRealPath, true );
}
@Override
public Path resolve( final Path other ) {
checkNotNull( "other", other );
if ( other.isAbsolute() ) {
return other;
}
if ( other.toString().trim().length() == 0 ) {
return this;
}
final StringBuilder sb = new StringBuilder();
sb.append( new String( path ) );
if ( path[ path.length - 1 ] != getSeparator() ) {
sb.append( getSeparator() );
}
sb.append( other.toString() );
return newPath( fs, sb.toString(), host, isRealPath, false );
}
@Override
public Path resolve( final String other ) throws InvalidPathException {
checkNotNull( "other", other );
return resolve( newPath( fs, other, host, isRealPath, false ) );
}
@Override
public Path resolveSibling( final Path other ) {
checkNotNull( "other", other );
final Path parent = this.getParent();
if ( parent == null || other.isAbsolute() ) {
return other;
}
return parent.resolve( other );
}
@Override
public Path resolveSibling( final String other ) throws InvalidPathException {
checkNotNull( "other", other );
return resolveSibling( newPath( fs, other, host, isRealPath, false ) );
}
@Override
public Path relativize( final Path otherx ) throws IllegalArgumentException {
checkNotNull( "otherx", otherx );
final AbstractPath other = checkInstanceOf( "otherx", otherx, AbstractPath.class );
if ( this.equals( other ) ) {
return emptyPath();
}
if ( isAbsolute() != other.isAbsolute() ) {
throw new IllegalArgumentException();
}
if ( isAbsolute() && !this.getRoot().equals( other.getRoot() ) ) {
throw new IllegalArgumentException();
}
if ( this.path.length == 0 ) {
return other;
}
int n = ( getNameCount() > other.getNameCount() ) ? other.getNameCount() : getNameCount();
int i = 0;
while ( i < n ) {
if ( !this.getName( i ).equals( other.getName( i ) ) ) {
break;
}
i++;
}
int numberOfDots = getNameCount() - i;
if ( numberOfDots == 0 && i < other.getNameCount() ) {
return other.subpath( i, other.getNameCount() );
}
final StringBuilder sb = new StringBuilder();
while ( numberOfDots > 0 ) {
sb.append( ".." );
if ( numberOfDots > 1 ) {
sb.append( getSeparator() );
}
numberOfDots--;
}
if ( i < other.getNameCount() ) {
if ( sb.length() > 0 ) {
sb.append( getSeparator() );
}
sb.append( ( (AbstractPath) other.subpath( i, other.getNameCount() ) ).toString( false ) );
}
return newPath( fs, sb.toString(), host, isRealPath, false );
}
private Path emptyPath() {
return newPath( fs, "", host, isRealPath, true );
}
@Override
public int compareTo( final Path other ) {
checkNotNull( "other", other );
throw new UnsupportedOperationException();
}
@Override
public WatchKey register( WatchService watcher,
Kind>[] events,
Modifier... modifiers )
throws UnsupportedOperationException, IllegalArgumentException,
ClosedWatchServiceException, IOException, SecurityException {
return watcher.poll();
}
@Override
public WatchKey register( WatchService watcher,
Kind>... events )
throws UnsupportedOperationException, IllegalArgumentException,
ClosedWatchServiceException, IOException, SecurityException {
return watcher.poll();
}
@Override
public String toString() {
if ( toStringFormat == null ) {
toStringFormat = toString( false );
}
return toStringFormat;
}
public String toString( boolean addHost ) {
if ( !addHost || host.isEmpty() ) {
return new String( path );
}
if ( isAbsolute ) {
return host + new String( path );
} else {
return host + ":" + new String( path );
}
}
private char getSeparator() {
if ( usesWindowsFormat ) {
return '\\';
}
return fs.getSeparator().toCharArray()[ 0 ];
}
public void clearCache() {
file = null;
attrsStorage.clear();
}
@Override
public boolean equals( final Object o ) {
checkNotNull( "o", o );
if ( this == o ) {
return true;
}
if ( !( o instanceof AbstractPath ) ) {
return false;
}
AbstractPath other = (AbstractPath) o;
if ( isAbsolute != other.isAbsolute ) {
return false;
}
if ( isRealPath != other.isRealPath ) {
return false;
}
if ( isRoot != other.isRoot ) {
return false;
}
if ( usesWindowsFormat != other.usesWindowsFormat ) {
return false;
}
if ( !host.equals( other.host ) ) {
return false;
}
if ( !fs.equals( other.fs ) ) {
return false;
}
if ( !usesWindowsFormat && !Arrays.equals( path, other.path ) ) {
return false;
}
if ( usesWindowsFormat && !( new String( path ).equalsIgnoreCase( new String( other.path ) ) ) ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = fs != null ? fs.hashCode() : 0;
result = 31 * result + ( usesWindowsFormat ? 1 : 0 );
result = 31 * result + ( isAbsolute ? 1 : 0 );
if ( !usesWindowsFormat ) {
result = 31 * result + ( path != null ? Arrays.hashCode( path ) : 0 );
} else {
result = 31 * result + ( path != null ? new String( path ).toLowerCase().hashCode() : 0 );
}
result = 31 * result + ( isRoot ? 1 : 0 );
result = 31 * result + ( isRealPath ? 1 : 0 );
result = 31 * result + ( isNormalized ? 1 : 0 );
return result;
}
public String getHost() {
return host;
}
public boolean isRealPath() {
return isRealPath;
}
@Override
public AttrsStorage getAttrStorage() {
return attrsStorage;
}
@Override
public void addAttrView( final V view ) {
attrsStorage.addAttrView( view );
}
@Override
public V getAttrView( final Class type ) {
return attrsStorage.getAttrView( type );
}
@Override
public V getAttrView( final String name ) {
return attrsStorage.getAttrView( name );
}
public static class RootInfo {
private final int startOffset;
private final boolean isAbsolute;
private final boolean isRoot;
private final byte[] path;
public RootInfo( int startOffset,
boolean isAbsolute,
boolean isRoot,
byte[] path ) {
this.startOffset = startOffset;
this.isAbsolute = isAbsolute;
this.isRoot = isRoot;
this.path = path;
}
}
}