All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy