org.codehaus.mojo.vfs.internal.DefaultVfsDirectoryScanner.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.mojo.vfs.internal.DefaultVfsDirectoryScanner.java

Source

package org.codehaus.mojo.vfs.internal;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.vfs2.FileNotFolderException;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;

public class DefaultVfsDirectoryScanner implements VfsDirectoryScanner {

    // ///////////////////////////////////////////////////////////////////////////
    // Configurations
    // ///////////////////////////////////////////////////////////////////////////

    /**
     * The starting directory under VFS
     */
    private FileObject startingDirectory;

    /*
     * (non-Javadoc)
     * @see org.codehaus.mojo.vfs.DirectoryScanner#setStartingDirectory(org.apache.commons.vfs2.FileObject)
     */
    public void setStartingDirectory(FileObject directory) {
        this.startingDirectory = directory;
    }

    // ///////////////////////////////////////////////////////////////////////////

    /** The patterns for the remote files to be included. */
    private String[] includes;

    /*
     * (non-Javadoc)
     * @see org.codehaus.mojo.vfs.DirectoryScanner#setIncludes(java.lang.String[])
     */
    public void setIncludes(String[] includes) {
        if (includes == null) {
            this.includes = null;
        } else {
            this.includes = new String[includes.length];
            for (int i = 0; i < includes.length; i++) {
                String pattern = includes[i].trim();

                if (pattern.endsWith("/")) {
                    pattern += "**";
                }
                this.includes[i] = pattern;
            }
        }
    }

    // ///////////////////////////////////////////////////////////////////////////

    /** The patterns for the remote files to be excluded. */
    private String[] excludes;

    /*
     * (non-Javadoc)
     * @see org.codehaus.mojo.vfs.DirectoryScanner#setExcludes(java.lang.String[])
     */
    public void setExcludes(String[] excludes) {
        if (excludes == null) {
            this.excludes = null;
        } else {
            this.excludes = new String[excludes.length];
            for (int i = 0; i < excludes.length; i++) {
                String pattern = excludes[i].trim();

                if (pattern.endsWith("/")) {
                    pattern += "**";
                }
                this.excludes[i] = pattern;
            }
        }
    }

    // ///////////////////////////////////////////////////////////////////////////

    /**
     * Whether or not the file system should be treated as a case sensitive one.
     */
    private boolean isCaseSensitive = true;

    /*
     * (non-Javadoc)
     * @see org.codehaus.mojo.vfs.DirectoryScanner#setCaseSensitive(boolean)
     */
    public void setCaseSensitive(boolean isCaseSensitive) {
        this.isCaseSensitive = isCaseSensitive;
    }

    // ///////////////////////////////////////////////////////////////////////////
    // Outputs
    // ///////////////////////////////////////////////////////////////////////////

    /**
     * The files which matched at least one include and at least one exclude and relative to directory
     */
    private List<FileObject> includedFiles = new ArrayList<FileObject>();

    // ///////////////////////////////////////////////////////////////////////////
    // public interface
    // ///////////////////////////////////////////////////////////////////////////

    /*
     * (non-Javadoc)
     * @see org.codehaus.mojo.vfs.DirectoryScanner#scan()
     */
    public List<FileObject> scan() throws FileSystemException {
        if (startingDirectory == null) {
            throw new IllegalStateException("Starting directory is not set");
        }

        if (includes == null) {
            // No includes supplied, so set it to 'matches all'
            includes = new String[1];
            includes[0] = "**";
        }

        if (excludes == null) {
            excludes = new String[0];
        }

        includedFiles = new ArrayList<FileObject>();

        scanSubDir(startingDirectory, "");

        return includedFiles;

    }

    /**
     * Scans the given directory for files and directories. Found files are placed in a collection, based on the
     * matching of includes, excludes, and the selectors. When a directory is found, it is scanned recursively.
     *
     * @throws FileSystemException
     * @see #includedFiles
     */
    private void scanSubDir(FileObject dir, String relativePath) throws FileSystemException {

        FileObject[] children = dir.getChildren();

        for (FileObject child : children) {
            String newRelativePath = child.getName().getBaseName();
            if (!relativePath.isEmpty()) {
                newRelativePath = relativePath + "/" + child.getName().getBaseName();
            }

            if (this.isDirectory(child)) {
                if (!surelyExcluded(newRelativePath)) {
                    // FIXME we need one more check to see if we really need to scan the subdir
                    // to solve the case where includes="{'*'}", scanning sub-directory does not help
                    // but only slow down the completion
                    scanSubDir(child, newRelativePath);
                }
            } else {
                if (isIncluded(newRelativePath)) {
                    if (!isExcluded(newRelativePath)) {
                        includedFiles.add(child);
                    }
                }
            }
        }
    }

    private boolean isDirectory(FileObject file) throws FileSystemException {
        if (FileType.FOLDER == file.getType()) {
            return true;
        }

        if (FileType.FILE_OR_FOLDER == file.getType()) {
            try {
                file.getChildren();
            } catch (FileNotFolderException e) {
                return false;
            }

            return true;
        }

        return false;
    }

    // ///////////////////////////////////////////////////////////////////////////
    // Helpers
    // ///////////////////////////////////////////////////////////////////////////
    /**
     * Tests whether or not a name matches against at least one include pattern.
     *
     * @param name The name to match. Must not be <code>null</code>.
     * @return <code>true</code> when the name matches against at least one include pattern, or <code>false</code>
     *         otherwise.
     */
    private boolean isIncluded(String name) {
        for (int i = 0; i < includes.length; i++) {
            if (matchPath(includes[i], name, isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether or not a name matches against at least one exclude pattern.
     *
     * @param name The name to match. Must not be <code>null</code>.
     * @return <code>true</code> when the name matches against at least one exclude pattern, or <code>false</code>
     *         otherwise.
     */
    private boolean isExcluded(String name) {
        for (int i = 0; i < excludes.length; i++) {
            if (matchPath(excludes[i], name, isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether or not a name matches the start of at least one include pattern.
     *
     * @param name The name to match. Must not be <code>null</code>.
     * @return <code>true</code> when the name matches against the start of at least one include pattern, or
     *         <code>false</code> otherwise.
     */
    private boolean couldHoldIncluded(String name) {
        for (int i = 0; i < includes.length; i++) {
            if (matchPatternStart(includes[i], name, isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether or not a given path matches the start of a given pattern up to the first "**".
     * <p>
     * This is not a general purpose test and should only be used if you can live with false positives. For example,
     * <code>pattern=**\a</code> and <code>str=b</code> will yield <code>true</code>.
     *
     * @param pattern The pattern to match against. Must not be <code>null</code>.
     * @param str The path to match, as a String. Must not be <code>null</code>.
     * @param isCaseSensitive Whether or not matching should be performed case sensitively.
     * @return whether or not a given path matches the start of a given pattern up to the first "**".
     */
    private static boolean matchPatternStart(String pattern, String str, boolean isCaseSensitive) {
        return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
    }

    /**
     * Tests whether or not a given path matches a given pattern.
     *
     * @param pattern The pattern to match against. Must not be <code>null</code>.
     * @param str The path to match, as a String. Must not be <code>null</code>.
     * @param isCaseSensitive Whether or not matching should be performed case sensitively.
     * @return <code>true</code> if the pattern matches against the string, or <code>false</code> otherwise.
     */
    private static boolean matchPath(String pattern, String str, boolean isCaseSensitive) {
        return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
    }

    private boolean surelyExcluded(String newRelativePath) {

        boolean maybeIncluded = false;

        if (isIncluded(newRelativePath)) {
            if (!isExcluded(newRelativePath)) {
                maybeIncluded = true;
            } else {
                if (couldHoldIncluded(newRelativePath)) {
                    maybeIncluded = true;
                }
            }
        } else {
            if (couldHoldIncluded(newRelativePath)) {
                maybeIncluded = true;
            }
        }

        return !maybeIncluded;
    }

}