com.softenido.cafedark.io.CachedFile.java Source code

Java tutorial

Introduction

Here is the source code for com.softenido.cafedark.io.CachedFile.java

Source

/*
 *  ForEachFile.java
 *
 *  Copyright (C) 2007-2010  Francisco Gmez Carrasco
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Report bugs or new features to: flikxxi@gmail.com
 *
 */
package com.softenido.cafedark.io;

import com.softenido.cafedark.io.virtual.VirtualFile;
import com.softenido.cafedark.io.virtual.VirtualFileFilter;
import com.softenido.cafedark.io.virtual.VirtualFiles;
import com.softenido.cafecore.os.OSName;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;

class CachedFile extends File {
    boolean directory = false;
    boolean directoryCached = false;

    public CachedFile(String pathname) {
        super(pathname);
    }

    @Override
    public boolean isDirectory() {
        if (!directoryCached) {
            directory = super.isDirectory();
            directoryCached = true;
        }
        return directory;
    }
}

/**
 *
 * @author franci
 */
public abstract class ForEachFile implements Runnable {

    private static int bufSize = 64 * 1024;
    private final VirtualFile[] base;
    private final ForEachFileOptions options;
    private final VirtualFileFilter filter;
    private final HashSet<File> autoOmitPaths = new HashSet<File>();
    private final CoveredPath coveredPath;
    static final Logger logger = Logger.getLogger(ForEachFile.class.getName());
    private static final ArchiveStreamFactory asf = new ArchiveStreamFactory();

    public ForEachFileOptions getOptions() {
        return new ForEachFileOptions(options);
    }

    public static int getBufSize() {
        return bufSize;
    }

    public static void setBufSize(int bufSize) {
        ForEachFile.bufSize = bufSize;
    }

    public ForEachFile(File[] files, FileFilter filter, ForEachFileOptions opt) throws IOException {
        this(VirtualFile.asVirtualFile(files), VirtualFile.buildFilter(filter), opt);
    }

    public ForEachFile(VirtualFile[] files, VirtualFileFilter filter, ForEachFileOptions opt) throws IOException {
        options = opt == null ? new ForEachFileOptions() : new ForEachFileOptions(opt);
        this.base = files;
        this.filter = filter;
        this.coveredPath = new CoveredPath(options.symlinks);

        if (OSName.os.isPosix()) {
            autoOmitPaths.add(new File(File.separator + "dev"));
            autoOmitPaths.add(new File(File.separator + "tmp"));
            autoOmitPaths.add(new File(File.separator + "lost+found"));
        }
        if (OSName.os.isLinux() || OSName.os.isSolaris()) {
            autoOmitPaths.add(new File(File.separator + "proc"));
        }
        if (OSName.os.isLinux()) {
            autoOmitPaths.add(new File(File.separator + "sys"));
            autoOmitPaths.add(new File(File.separator + "var" + File.separator + "run"));
            autoOmitPaths.add(new File(File.separator + "var" + File.separator + "lock"));
        }
        if (OSName.os.isSolaris()) {
            autoOmitPaths.add(new File(File.separator + "devices"));
        }

        if (autoOmitPaths.isEmpty()) {
            options.autoOmit = false;
        }
    }

    private boolean acceptSize(long size) {
        return (size >= options.minSize) && (size <= options.maxSize);
    }

    public void run() {
        for (VirtualFile item : base) {
            VirtualFile file;
            try {
                file = VirtualFiles.getNoDotFile(item);
                if (file != null) {
                    visit(file, null, 0);
                }
            } catch (IOException ex) {
                Logger.getLogger(ForEachFile.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void visit(VirtualFile file, InputStream in, final int level) {
        if (level > options.recursive) {
            return;
        }
        logger.log(Level.FINEST, "file={0}", file);
        try {
            if (!canVisit(file, level)) {
                return;
            }
            if (canDo(file)) {
                doForEach(file);
            }
            if (!file.canRead()) {
                return;
            }
            if (!file.isComplex() && file.isDirectory()) {
                followDirectory(file.getBaseFile(), level);
            } else if (canFollowArchive(file.getName())) {
                followArchive(file, in, level + 1);
            }
        } catch (Exception ex) {
            doException(file.toString(), ex);
        }
    }

    private void followDirectory(File file, int level) {
        File[] childs = file.listFiles();
        if (childs == null) {
            logger.log(Level.WARNING, "error in {0}", file);
            return;
        }
        for (File child : childs) {
            visit(new VirtualFile(child), null, level + 1);
        }
    }

    private void followArchive(VirtualFile pf, InputStream in, int level) throws ArchiveException, IOException {
        if (in == null) {
            in = pf.getInputStream();
        }

        ArchiveInputStream zip = asf.createArchiveInputStream(new BufferedInputStream(in));
        ArchiveEntry ent = null;
        try {
            while ((ent = zip.getNextEntry()) != null) {
                logger.log(Level.FINEST, "file={0}", ent.getName());
                VirtualFile child = new VirtualFile(pf, ent);
                visit(child, zip, level + 1);
            }
        } catch (Exception ex) {
            doException(pf.getPath(), ex);
        }
    }

    private boolean canDo(final VirtualFile file) {
        if (options.onlyPacked) {
            return false;
        }
        if (file.isFile()) {
            if (!options.file)
                return false;
            if (!acceptSize(file.length()))
                return false;
        } else if (file.isDirectory()) {
            if (!options.directory)
                return false;
        } else {
            if (!options.fifo)
                return false;
            if (!acceptSize(0))
                return false;
        }

        if (filter != null && !filter.accept(file)) {
            return false;
        }
        if (isOmitedFile(file)) {
            return false;
        }
        return true;
    }

    boolean canFollowArchive(String name) {
        name = name.toLowerCase();
        if (options.zip && name.endsWith(".zip")) {
            return true;
        }
        if (options.jar && name.endsWith(".jar")) {
            return true;
        }
        if (options.tar && name.endsWith(".tar")) {
            return true;
        }
        return false;
    }

    protected abstract void doForEach(VirtualFile fe);

    protected void doForEach(File file, String name) {
        doForEach(new VirtualFile(file));
    }

    private void doException(String msg, Exception ex) {
        logger.log(Level.SEVERE, msg, ex);
    }

    private boolean isOmitedPath(final VirtualFile file, boolean verifyParents) {
        final boolean omitImplicit = options.autoOmit && !autoOmitPaths.isEmpty();
        if (omitImplicit && autoOmitPaths.contains(file.getBaseFile())) {
            return true;
        }
        final boolean omitExplicit = options.hasOmitedPaths && !options.omitedPaths.isEmpty();
        if (omitExplicit && options.omitedPaths.contains(file)) {
            return true;
        }
        if ((omitImplicit || omitExplicit) && verifyParents) {
            File parent = file.getBaseFile();
            while ((parent = parent.getParentFile()) != null) {
                if (isOmitedPath(new VirtualFile(parent), false)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isOmitedDirName(final VirtualFile file) {
        if (options.hasOmitedDirNames) {
            for (VirtualFileFilter item : options.omitedDirNames) {
                if (item.accept(file)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isOmitedFile(final VirtualFile file) {
        if (options.hasOmitedFiles) {
            if (options.omitedFiles.contains(file)) {
                return true;
            }
        }
        if (options.hasOmitedFileNames) {
            for (VirtualFileFilter item : options.omitedFileNames) {
                if (item.accept(file)) {
                    return true;
                }
            }
        }
        // when there are filter for allowed files at least one should be satisfied
        if (options.hasAllowedFileNames) {
            for (VirtualFileFilter item : options.allowedFileNames) {
                if (item.accept(file)) {
                    return false;
                }
            }
            return true;
        }

        return false;
    }

    private boolean canVisit(VirtualFile file, int level) throws IOException {
        if (level != 0 && !options.hidden && file.isHidden()) {
            return false;
        }
        if (options.readable && !file.canRead()) {
            return false;
        }
        boolean link = file.isLink();
        if ((level > 0) && link && !options.symlinks) {
            return false;
        }

        if (file.isDirectory()) {
            if (link && Files.isCyclicLink(file.getBaseFile())) {
                return false;
            }

            // only follow directories that can be read
            if (isOmitedDirName(file)) {
                return false;
            }

            //        si un directorio no es padre de una ruta excluida no hay que comparar si no es un link
            //        si un directorio contiene una ruta excluida solo hay que comparar al concreto salvo que sea un link
            //        si un directorio canonico tiene menos niveles que una ruta excluida no est excluido
            // (file.isDirectory() && file.canRead() && ((level == 0) || (this.linkDir && !Files.isCyclicLink(file)) || !(Files.isLink(file))))

            //verify isn't omited in absolute form
            final VirtualFile absolute = file.getAbsoluteFile();
            final VirtualFile canonical = file.getCanonicalFile();

            if (isOmitedPath(absolute, false)) {
                return false;
            }
            if (link && isOmitedPath(canonical, true)) {
                return false;
            }
        }
        if (!coveredPath.add(file, level == 0, link)) {
            logger.log(Level.FINE, "already covered file={0} -> {1}",
                    new VirtualFile[] { file, file.getCanonicalFile() });
            return false;
        }
        return true;
    }

}