Skip to content

Class FileSystemVisitor

Ori Roth edited this page Apr 2, 2017 · 3 revisions

Synopsis of Class FileSystemVisitor

public class FileSystemVisitor { 
    /*
     * Forge (6)
     */
        FileSystemVisitor(File[] from, Action visitor, String[] extensions); 
        FileSystemVisitor(File from, Action visitor, String[] extensions); 
        FileSystemVisitor(String[] from, Action visitor, String[] extensions); 
        FileSystemVisitor(String from, Searcher visitor, String[] extensions); 
        FileSystemVisitor(String from, Action visitor, String[] extensions); 
        FileSystemVisitor(Collection<String> from, Action visitor, String[] extensions); 
    /*
     * Type (1)
     */
        void go() throws IOException, StopTraversal; 
    /*
     * Nested types (3)
     */
        abstract static interface Action { ... } 
        abstract static class EmptyAction implements NonStopAction { ... } 
        abstract static class FileOnlyAction extends EmptyAction { ... } 
} 

Input types: Action, Collection, File, Searcher.

Exception types: IOException, StopTraversal.

Synopsis of Interface FileSystemVisitor.Action

public interface FileSystemVisitor.Action { 
    /*
     * Type (5)
     */
        void visitFile(File f) throws StopTraversal; 
        void visitZipEntry(String zipName, String entryName, InputStream stream) throws StopTraversal; 
        void visitDirectory(File f) throws StopTraversal; 
        void visitZip(File f) throws StopTraversal; 
        void visitZipDirectory(String zipName, String entryName, InputStream stream) throws StopTraversal; 
    /*
     * Nested types (1)
     */
        static class StopTraversal extends Exception { ... } 
} 

Input types: File, InputStream.

Exception types: StopTraversal.

Synopsis of Class FileSystemVisitor.Action.StopTraversal

public static class FileSystemVisitor.Action.StopTraversal extends Exception { 
    /*
     * Forge (2)
     */
        StopTraversal(); 
        StopTraversal(String message); 
} 

Synopsis of Interface FileSystemVisitor.NonStopAction

interface FileSystemVisitor.NonStopAction extends Action { 
    /*
     * Type (5)
     */
        void visitFile(File f); 
        void visitZipEntry(String zipName, String entryName, InputStream stream); 
        void visitDirectory(File f); 
        void visitZip(File f); 
        void visitZipDirectory(String zipName, String entryName, InputStream stream); 
}

Input types: File, InputStream.

Synopsis of Class FileSystemVisitor.EmptyAction

public abstract static class FileSystemVisitor.EmptyAction implements NonStopAction { 
    /*
     * Forge (1)
     */
        EmptyAction(); 
    /*
     * Type (5)
     */
        void visitDirectory(File _); 
        void visitZip(File _); 
        void visitZipDirectory(String _, String __, InputStream ___); 
        void visitZipEntry(String _, String __, InputStream ___); 
        void visitFile(File _); 
} 

Input types: File, InputStream.

Synopsis of Class FileSystemVisitor.FileOnlyAction

public abstract static class FileSystemVisitor.FileOnlyAction extends EmptyAction { 
    /*
     * Forge (1)
     */
        FileOnlyAction(); 
    /*
     * Type (3)
     */
        final void visitZipEntry(String zipName, String entryName, InputStream stream); 
        abstract void visitFile(File f); 
        abstract void visitZipEntry(String entryName, InputStream stream); 
} 

Input types: File, InputStream.

Synopsis of Class FileSystemVisitor.DirectoryOnlyAction

protected abstract static class FileSystemVisitor.DirectoryOnlyAction extends EmptyAction { 
    /*
     * Type (2)
     */
        final void visitZipDirectory(String zipName, String entryName, InputStream stream); 
        abstract void visitDirectory(File d); 
} 

Input types: File, InputStream.

Code

// SSDLPedia
package il.ac.technion.cs.ssdl.files.visitors;

import static il.ac.technion.cs.ssdl.utils.DBC.nonnull;
import static il.ac.technion.cs.ssdl.utils.DBC.require;
import static il.ac.technion.cs.ssdl.utils.DBC.unused;
import il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action.StopTraversal;
import il.ac.technion.cs.ssdl.files.visitors.FindClassFile.Searcher;
import il.ac.technion.cs.ssdl.strings.Suffixed;
import il.ac.technion.cs.ssdl.utils.All;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * A class realizing a file system traversal algorithm, including delving into
 * archives such as ZIP and JAR files.
 * 
 * The traversal is carried out by calling the class constructor
 * {@link FileSystemVisitor#FileSystemVisitor(String[], il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action, String[])}
 * to set up the traversal parameters, and then function #go() to
 * conduct the actual traversal.
 * 
 * 
 * Author: Yossi Gil @since 21/05/2007
 * @see #go()
 * See: FileSystemVisitor#FileSystemVisitor(String[],
 *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
 *      String[])
 * See: Action
 */
public class FileSystemVisitor {
    /**
     * Create a new visitor object to scan an array of Files naming the
     * search locations.
     * 
     * from a non-null specifying the names of the
     *            directories where the traversal should begin. If this array is
     *            of length 0, then no traversal shall be carried out. Also, if
     *            the supplied directories are not disjoint, then the same file
     *            may be visited more than once.
     * visitor a non-null specifying what to do in
     *            each visited file
     * extensions an array of non-null String
     *            s specifying which file extensions the visitor should call,
     *            e.g., ".class", ".csv", etc. If this parameter is
     *            null, or of length 0, or contains a
     *            String of length 0, then the visitor is invoked for
     *            all files found in the supplied path.
     * @see #go
     * @see #FileSystemVisitor(Collection,
     *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
     *      String[])
     */
    public FileSystemVisitor(final File[] from, final Action visitor, final String... extensions) {
        nonnull(from);
        nonnull(visitor);
        nonnull(extensions);
        require(All.notNull((Object[]) from));
        require(All.notNull((Object[]) extensions));
        this.from = from;
        this.visitor = visitor;
        this.extensions = extensions;
    }
    
    /**
     * Create a new visitor object to scan an array of Files naming the
     * search locations.
     * 
     * from a non-null specifying the directory or
     *            archive file where the traversal should begin.
     * visitor a non-null specifying what to do in
     *            each visited file
     * extensions an array of non-null String
     *            s specifying which file extensions the visitor should call,
     *            e.g., ".class", ".csv", etc. If this parameter is
     *            null, or of length 0, or contains a
     *            String of length 0, then the visitor is invoked for
     *            all files found in the supplied path.
     * @see #go
     * @see #FileSystemVisitor(Collection,
     *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
     *      String[])
     */
    public FileSystemVisitor(final File from, final Action visitor, final String... extensions) {
        this(new File[] { from }, visitor, extensions);
    }
    
    /**
     * Create a new visitor object to scan an array of Strings naming
     * the search locations.
     * 
     * from a non-null specifying where the traversal
     *            should begin. If this array is of length 0, then no traversal
     *            shall be carried out. Also, if the supplied directories are
     *            not disjoint, then the same file may be visited more than
     *            once.
     * visitor a non-null specifying what to do in
     *            each visited file
     * extensions an array of non-null String
     *            s specifying which file extensions the visitor shold call,
     *            e.g., ".class", ".csv", etc. If this parameter is
     *            null, or of length 0, or contains a
     *            String of length 0, then the visitor is invoked for
     *            all files found in the supplied path.
     * @see #go
     * @see #FileSystemVisitor(Collection,
     *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
     *      String[])
     */
    public FileSystemVisitor(final String[] from, final Action visitor, final String... extensions) {
        this(asFiles(from), visitor, extensions);
    }
    
    /**
     * Create a new visitor object to scan a String naming the search
     * location.
     * 
     * from a non-null specifying where the traversal
     *            should begin.
     * visitor a non-null specifying what to do in
     *            each visited file
     * extensions an array of non-null String
     *            s specifying which file extensions the visitor shold call,
     *            e.g., ".class", ".csv", etc. If this parameter is
     *            null, or of length 0, or contains a
     *            String of length 0, then the visitor is invoked for
     *            all files found in the supplied path.
     * @see #go
     * @see #FileSystemVisitor(Collection,
     *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
     *      String[])
     */
    public FileSystemVisitor(final String from, final Searcher visitor, final String... extensions) {
        this(new String[] { from }, visitor, extensions);
    }
    
    private static File[] asFiles(final String[] ss) {
        final File[] $ = new File[ss.length];
        for (int i = 0; i < ss.length; i++)
            $[i] = new File(ss[i]);
        return $;
    }
    
    /**
     * Create a new visitor object to scan a single directory.
     * 
     * from a non-null specifying where the traversal
     *            should begin.
     * visitor a non-null specifying what to do in
     *            each visited file
     * extensions an array of non-null String
     *            s specifying which file extensions the visitor shold call,
     *            e.g., ".class", ".csv", etc. If this parameter is
     *            null, or of length 0, or contains a
     *            String of length 0, then the visitor is invoked for
     *            all files found in the supplied path.
     * @see #go
     * @see #FileSystemVisitor(Collection,
     *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
     *      String[])
     */
    public FileSystemVisitor(final String from, final Action visitor, final String[] extensions) {
        this(new String[] { from }, visitor, extensions);
    }
    
    /**
     * Create a new visitor object to scan an array of Strings naming
     * the search locations.
     * 
     * from a non-null specifying where the traversal
     *            should begin. If this collection is empty, then no traversal
     *            shall be carried out. Also, if the supplied directories are
     *            not disjoint, then the same file may be visited more than
     *            once.
     * visitor a non-null specifying what to do in
     *            each visited file
     * extensions an array of non-null String
     *            s specifying which file extensions the visitor shold call,
     *            e.g., ".class", ".csv", etc. If this parameter is
     *            null, or of length 0, or contains a
     *            String of length 0, then the visitor is invoked for
     *            all files found in the supplied path.
     * @see #go
     * @see #FileSystemVisitor(String[],
     *      il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action,
     *      String[])
     */
    public FileSystemVisitor(final Collection<String> from, final Action visitor, final String... extensions) {
        this(from.toArray(new String[from.size()]), visitor, extensions);
    }
    
    /**
     * Conduct the traversal. For each file encountered during the traversal,
     * the FileSystemVisitor invokes one of
     * 
     * 1.Action#visitFile(File), 2.
     * Action#visitDirectory(File), 3.{@ink #visitZipEntry(String,
     * String, InputStreamReader)}, or 4.Action#visitZip(File)
     * 
     * functions, depending on the file type. If this function throws
     * Action.StopTraversal exception, then the traversal stops:
     * completely if the current file was a plain file, i.e.,
     * Action#visitFile(File) or {@ink #visitZipEntry(String, String,
     * InputStreamReader)} was called, or just of the contained files, if this
     * was an archive or a directory file.
     * 
     * IOException if the file system could not traversed for some
     *             reason
     * StopTraversal if the visitor object requested to stop the
     *             visitation.
     */
    public void go() throws IOException, StopTraversal {
        for (final File f : from)
            recurse(f);
    }
    
    /**
     * Conduct recursive traversal starting at a given file
     * 
     * f a file, which may be a directory, a ZIP, or a plain file, at
     *            which the traversal begins
     * IOException if the file system could not traversed for some
     *             reason
     * StopTraversal if the visitor object requested to stop the
     *             visitation.
     */
    private void recurse(final File f) throws IOException, StopTraversal {
        if (f.isDirectory()) {
            recurseDirectory(f);
            return;
        }
        if (Zip.isZipFile(f)) {
            scanZip(f);
            return;
        }
        if (Suffixed.by(f, extensions))
            visitor.visitFile(f);
    }
    
    /**
     * conduct recursive traversal of a directory
     * 
     * d a directory
     * IOException if the file system could not be traversed for some
     *             reason
     */
    private void recurseDirectory(final File d) throws IOException {
        try {
            visitor.visitDirectory(d);
            if (d.list() == null) // Weird directories such as
                // "System Volume Information"
                return;
            for (final String name : d.list())
                if (name != null)
                    recurse(new File(d, name));
        } catch (final Action.StopTraversal _) {
            // do not visit children of this directory
        }
    }
    
    /**
     * Scan entries of a ZIP file.
     * 
     * f a ZIP or other archive file
     * IOException if the file system could not traversed for some
     *             reason
     * StopTraversal if the visitor object requested to stop the
     *             visitation. However, if the visitor requested to stop the
     *             visitation of the ZIP file itself, the scanning of this ZIP
     *             file will stop, but the no exception is thrown, and the
     *             entire traversal continue.
     */
    private void scanZip(final File f) throws StopTraversal {
        try {
            visitor.visitZip(f);
        } catch (final Action.StopTraversal e) {
            return; // do not visit any elements of this ZIP file, but continue
            // traversal.
        }
        ZipFile Z;
        try {
            Z = new ZipFile(f.getAbsoluteFile());
        } catch (final Exception z) {
            System.err.println(f.getAbsolutePath() + ": " + z.getMessage());
            return;
        }
        for (final Enumeration<? extends ZipEntry> es = Z.entries(); es.hasMoreElements();) {
            final ZipEntry e = es.nextElement();
            try {
                final InputStream is = Z.getInputStream(e);
                if (e.isDirectory()) {
                    visitor.visitZipDirectory(Z.getName(), e.getName(), is);
                    continue;
                }
                if (Suffixed.by(e.getName(), extensions))
                    visitor.visitZipEntry(Z.getName(), e.getName(), is);
            } catch (final StopTraversal x) {
                System.out.println("Found at ZIP!!!");
                throw x;
            } catch (final IOException exception) {
                System.err.println("Error reading " + Z + ": " + exception.getMessage());
                continue;
            }
        }
    }
    
    /**
     * at which directories in the file system should the traversal start?
     */
    private final File[] from;
    /**
     * what should be done for each file traversed?
     */
    private final Action visitor;
    /**
     * for which extensions should the Action object be invoked.
     */
    private final String[] extensions;
    
    /**
     * Author: Yossi Gil @since 21/05/2007
     */
    public static interface Action {
        /**
         * action to conduct for each ordinary, i.e., non-ZIP and non-directory,
         * file.
         * 
         * f the file to visit
         * StopTraversal in case the visitor wishes to completely
         *             stop the traversal
         * @see #visitDirectory(File)
         * @see #visitZip(File)
         */
        void visitFile(File f) throws StopTraversal;
        
        /**
         * action to conduct for each entry found in a ZIP file, encountered
         * throughout the traversal
         * 
         * zipName the name of the ZIP file from which this entry was
         *            taken
         * entryName the name of the visited entry in the ZIP file
         * stream an open stream into the content of this entry
         * StopTraversal in case the visitor wishes to terminate the
         *             entire traversal process
         */
        void visitZipEntry(String zipName, String entryName, InputStream stream) throws StopTraversal;
        
        /**
         * action to conduct for each directory encountered throught the
         * traversal.
         * 
         * f the directory file object
         * StopTraversal in case the visitor wishes to stop the
         *             traversal of this directory.
         * @see #visitFile(File)
         * @see #visitZip(File)
         * @see #visitZipEntry(String, String, InputStream)
         */
        void visitDirectory(File f) throws StopTraversal;
        
        /**
         * action to conduct for each ZIP and other archive files encountered
         * throughout the traversal.
         * 
         * f the archive file object
         * StopTraversal in case the visitor wishes to stop the
         *             traversal of this archive file.
         * @see #visitFile(File)
         * @see #visitDirectory(File)
         */
        void visitZip(File f) throws StopTraversal;
        
        /**
         * action to conduct for each directory encountered in an archival file
         * scanned through the traversal.
         * 
         * zipName the name of the ZIP file from which this entry was
         *            taken
         * entryName the name of the visited entry in the ZIP file
         * stream an open stream into the content of this entry
         * StopTraversal in case the visitor wishes to terminate the
         *             entire traversal process
         * @see #visitFile(File)
         * @see #visitDirectory(File)
         */
        void visitZipDirectory(String zipName, String entryName, InputStream stream) throws StopTraversal;
        
        /**
         * Author: Yossi Gil @since 21/05/2007
         */
        class StopTraversal extends Exception {
            /**
             * Create a new StopTraversal object
             */
            public StopTraversal() {
                super();
            }
            
            /**
             * Create a new StopTraversal object with a specific message
             * 
             * message a message to record
             * See: Exception
             */
            public StopTraversal(final String message) {
                super(message);
            }
            
            private static final long serialVersionUID = -4658857180021394864L;
        }
    }
    
    static interface NonStopAction extends Action {
        void visitFile(File f);
        
        void visitZipEntry(String zipName, String entryName, InputStream stream);
        
        void visitDirectory(File f);
        
        void visitZip(File f);
        
        void visitZipDirectory(String zipName, String entryName, InputStream stream);
    }
    
    /**
     * A simplified Action with no exceptions thrown whose
     * implementation does absolutely nothing. It leaves it to the extending
     * class to re-implement concrete actions.
     * 
     * Author: Yossi Gil @since 18/06/2007
     */
    public abstract static class EmptyAction implements NonStopAction {
        /**
         * A do-nothing function, ignoring its arguments
         * 
         * _ ignored
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action#visitDirectory(java.io.File)
         */
        public void visitDirectory(final File _) {
            unused(_);
        }
        
        /**
         * A do-nothing function, ignoring its arguments
         * 
         * _ ignored
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action#visitZip(java.io.File)
         */
        public void visitZip(final File _) {
            unused(_);
        }
        
        /**
         * A do-nothing function, ignoring its arguments
         * 
         * _ ignored
         * __ ignored
         * ___ ignored
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action#visitZipDirectory(java.lang.String,
         *      java.lang.String, java.io.InputStream)
         */
        public void visitZipDirectory(final String _, final String __, final InputStream ___) {
            unused(_, __, ___);
        }
        
        /**
         * A do-nothing function, ignoring its arguments
         * 
         * _ ignored
         * __ ignored
         * ___ ignored
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action#visitZipEntry(java.lang.String,
         *      java.lang.String, java.io.InputStream)
         */
        public void visitZipEntry(final String _, final String __, final InputStream ___) {
            unused(_, __, ___);
        }
        
        /**
         * A do-nothing function, ignoring its arguments
         * 
         * _ ignored
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.Action#visitFile(java.io.File)
         */
        public void visitFile(final File _) {
            unused(_);
        }
    }
    
    /**
     * An abstract class, to be extended by those clients
     * interested in examining files only during a file system traversal as
     * carried out by class FileSystemVisitor. Such clients must give
     * body to two functions only:
     * 
     * 1. #visitFile(File) - action to carry out on ordinary files,
     * 2. {@link #visitZipEntry(String, InputStream)} - action for files found
     * in an archive.
     * 
     * Class FileOnlyAction is in fact a Facade offering a simplified
     * interface to the more general Action. Simplifications are:
     * 
     * 1.no exceptions thrown 2.partial implementation that does nothing for
     * directories and archives, and leaves it to the extending class to
     * implement a concrete action for files and archive entries visitation. 
     * 3.In visiting archive entries it invokes function
     * #visitZip(File) (instead of
     * {@link #visitZipDirectory(String, String, InputStream)}), i.e., the
     * implementor of this function does is not bothered with the archive name.
     * 
     * 
     * Author: Yossi Gil @since 18/06/2007
     */
    public abstract static class FileOnlyAction extends EmptyAction {
        /**
         * Not to be used by clients.
         * 
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.EmptyAction#visitZipEntry(java.lang.String,
         *      java.lang.String, java.io.InputStream)
         */
        @Override public final void visitZipEntry(@SuppressWarnings("unused") final String zipName, final String entryName,
                final InputStream stream) {
            visitZipEntry(entryName, stream);
        }
        
        @Override public abstract void visitFile(File f);
        
        public abstract void visitZipEntry(String entryName, InputStream stream);
    }
    
    /**
     * An abstract class, to be extended by those clients
     * interested in examining directories only during a file system traversal
     * as carried out by class FileSystemVisitor. Such clients must give
     * body to two functions only:
     * 
</font>
     * 
#visitDirectory(File)</dt> 
Action for ordinary
     * directories</dd> 
{@link #visitZipDirectory(String, InputStream)}</dt>
     * 
Action for directories found in an archive.</dd>
     * </dl>
     * 
     * Class DirectoryOnlyAction is in fact a Facade offering a
     * simplified interface to the more general Action. Simplifcation
     * are:
     * 
     * 1.no exceptions thrown
     * 2.partial implementation that does nothing for files and archives, and
     * leaves it to the extending class to implement concrete a concrete action
     * for directories and archived directories encountered in the course of the
     * visitation.
     * 3.in visiting directories found in archive entries it uses the
     * {@link #visitZipDirectory(String, InputStream)} (instead of the more
     * general {@link #visitZipDirectory(String, String, InputStream)}), that
     * is, the implementor is not supplied with the directory name.
     * 
     * 
     * Author: Yossi Gil @since 18/06/2007
     */
    protected abstract static class DirectoryOnlyAction extends EmptyAction {
        /**
         * Not to be called by clients
         * 
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.EmptyAction#visitZipDirectory(java.lang.String,
         *      java.lang.String, java.io.InputStream)
         */
        @Override public final void visitZipDirectory(final String zipName, final String entryName, final InputStream stream) {
            unused(zipName);
            visitZipDirectory(entryName, stream);
        }
        
        /**
         * Visit a directory entry contained in an archive.
         * 
         * entryName the name of the discovered directory
         * stream to be used for opening it if necessary
         */
        protected abstract void visitZipDirectory(String entryName, InputStream stream);
        
        /**
         * A function to be realized by an extending class, with actions to be
         * carried out for each encountered directory.
         * 
         * d the directory currently being visited.
         * See: il.ac.technion.cs.ssdl.files.visitors.FileSystemVisitor.EmptyAction#visitDirectory(java.io.File)
         */
        @Override public abstract void visitDirectory(File d);
    }
}

Metrics

Metric Value Acronym Explanation
LOC 596 Lines Of Code Total number of lines in the code
SCC 87 SemiColons Count Total number of semicolon tokens found in the code.
NOT 1346 Number Of Tokens Comments, whitespace and text which cannot be made into a token not included.
VCC 17126 Visible Characters Count The total number of non-white (i.e., not space, tab, newline, carriage return, form feed) characters.
CCC 4890 Code Characters Count Total number of non-white characters in tokens. White space characters in string and character literals are not counted.
UIC 93 Unique Identifiers Count The number of different identifiers found in the code
WHC 5 Weighted Horizontal Complexity A heuritistic on horizontal complexity

Statistics

Statistic Value
Average token length 3.6
Tokens/line 2.3
Visible characters/line 29
Code characters/line 8.2
Semicolons/tokens 6%
Comment text percentage 71%

Tokens by Kind

Token Kind Occurrences
KEYWORD 218
OPERATOR 26
LITERAL 7
ID 476
PUNCTUATION 619
COMMENT 41
OTHER 654
Clone this wiki locally