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

jetbrick.io.finder.FileFinder Maven / Gradle / Ivy

/**
 * Copyright 2013-2016 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 *   Author: Guoqiang Chen
 *    Email: [email protected]
 *   WebURL: https://github.com/subchen
 *
 * 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 jetbrick.io.finder;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import jetbrick.io.IoUtils;
import jetbrick.io.resource.AbstractResource;
import jetbrick.io.resource.FileSystemResource;
import jetbrick.io.resource.JbossVfsResource;
import jetbrick.io.resource.Resource;
import jetbrick.io.resource.ResourceNotFoundException;
import jetbrick.io.resource.ResourceUtils;
import jetbrick.io.resource.ZipEntryResource;
import jetbrick.util.ClassLoaderUtils;
import jetbrick.util.ClasspathUtils;
import jetbrick.util.StringUtils;
import jetbrick.util.Validate;

/**
 * 查找指定路径下面的所有匹配得文件.
 *
 * 子类需要实现自己的 visitXXX() 方法来搜集相关的内容.
 *
 * @author Guoqiang Chen
 */
public abstract class FileFinder {

    public void lookupFileSystem(File dir, boolean recursive) {
        Validate.notNull(dir);
        doLookupInFileSystem(dir, null, null, recursive);
    }

    public void lookupClasspath(Collection packageNames, boolean recursive) {
        ClassLoader loader = ClassLoaderUtils.getDefault();
        if (packageNames == null || packageNames.size() == 0) {
            Collection urls = ClasspathUtils.getClasspathURLs(loader);
            doGetClasspathResources(urls, null, recursive);
        } else {
            for (String pkg : packageNames) {
                Collection urls = ClasspathUtils.getClasspathURLs(loader, pkg);
                doGetClasspathResources(urls, pkg, recursive);
            }
        }
    }

    public void lookupZipFile(File zipFile, String entryName, boolean recursive) {
        Validate.notNull(zipFile);

        if (entryName != null) {
            entryName = StringUtils.removeEnd(entryName, "/");
        }
        entryName = StringUtils.trimToEmpty(entryName);

        ZipFile zip = null;
        try {
            zip = new ZipFile(zipFile);
            doLookupInZipFile(zip, entryName, recursive);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IoUtils.closeQuietly(zip);
        }
    }

    private void doGetClasspathResources(Collection urls, String pkg, boolean recursive) {
        for (URL url : urls) {
            String protocol = url.getProtocol();
            if ("file".equals(protocol)) {
                File file = ResourceUtils.create(url).getFile();
                if (file.isDirectory()) {
                    doLookupInFileSystem(file, pkg, null, recursive);
                } else if (file.isFile()) {
                    String name = file.getName().toLowerCase();
                    if (name.endsWith(".jar") || name.endsWith(".zip")) {
                        ZipFile zip = null;
                        try {
                            zip = new ZipFile(file);
                            doLookupInZipFile(zip, null, recursive);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        } finally {
                            IoUtils.closeQuietly(zip);
                        }
                    }
                }
            } else if ("jar".equals(protocol)) {
                ZipFile zip = null;
                try {
                    zip = ((JarURLConnection) url.openConnection()).getJarFile();
                    doLookupInZipFile(zip, pkg, recursive);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } finally {
                    IoUtils.closeQuietly(zip);
                }
            } else if ("zip".equals(protocol)) {
                ZipEntryResource resource = new ZipEntryResource(url);
                try {
                    doLookupInZipFile(resource.getZipFile(), pkg, recursive);
                } finally {
                    IoUtils.closeQuietly(resource.getZipFile());
                }
            } else if ("vfs".equals(protocol)) {
                JbossVfsResource resource = new JbossVfsResource(url);
                doLookupInVfsFile(resource, pkg, null, recursive);
            } else {
                throw new IllegalStateException("Unsupported url format: " + url.toString());
            }
        }
    }

    private void doLookupInFileSystem(File dir, String pkg, String relativePathName, boolean recursive) {
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            String javaName = file.getName();
            if (pkg != null) {
                javaName = pkg + '.' + javaName;
            }
            if (file.isFile()) {
                javaName = StringUtils.removeEnd(javaName, ".class");
            }
            String pathName = '/' + file.getName();
            if (relativePathName != null) {
                pathName = relativePathName + pathName;
            }

            ResourceEntry entry = new ResourceEntry(new FileSystemResource(file), javaName, pathName);
            if (file.isDirectory()) {
                if (visitDirectory(entry)) {
                    if (recursive) {
                        doLookupInFileSystem(file, javaName, pathName, true);
                    }
                }
            } else {
                visitFile(entry);
            }
        }
    }

    private void doLookupInZipFile(ZipFile zip, String pkg, boolean recursive) {
        List skipDirs = null;
        String rootdir = (pkg == null) ? null : pkg.replace('.', '/') + '/';

        Enumeration entries = zip.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            String entryName = entry.getName();

            String qualifiedJavaName;
            if (entry.isDirectory()) {
                qualifiedJavaName = entryName.substring(0, entryName.length() - 1).replace('/', '.');
            } else if (entryName.endsWith(".class")) {
                qualifiedJavaName = entryName.substring(0, entryName.length() - 6).replace('/', '.');
            } else {
                qualifiedJavaName = null;
            }

            ResourceEntry resourceEntry = null;
            if (rootdir == null) {
                ZipEntryResource resource = new ZipEntryResource(zip, entry);
                String relativePathName = StringUtils.removeEnd(entryName, "/");
                resourceEntry = new ResourceEntry(resource, qualifiedJavaName, relativePathName);
            } else {
                if (entryName.startsWith(rootdir)) {
                    String relativePathName = entryName.substring(rootdir.length() - 1);
                    if (relativePathName.length() > 1) {
                        relativePathName = StringUtils.removeEnd(relativePathName, "/");
                        if (recursive || relativePathName.lastIndexOf('/') <= 0) {
                            ZipEntryResource resource = new ZipEntryResource(zip, entry);
                            resourceEntry = new ResourceEntry(resource, qualifiedJavaName, relativePathName);
                        }
                    }
                }
            }

            if (resourceEntry != null) {
                if (entry.isDirectory()) {
                    if (!visitDirectory(resourceEntry)) {
                        if (skipDirs == null) {
                            skipDirs = new ArrayList();
                        }
                        skipDirs.add(entryName);
                    }
                } else {
                    if (skipDirs != null) {
                        for (String dir : skipDirs) {
                            if (entryName.startsWith(dir)) {
                                resourceEntry = null;
                                break;
                            }
                        }
                    }
                    if (resourceEntry != null) {
                        visitFile(resourceEntry);
                    }
                }
            }
        }
    }

    private void doLookupInVfsFile(JbossVfsResource resource, String pkg, String relativePathName, boolean recursive) {
        List children = resource.getChildren();
        for (JbossVfsResource file : children) {
            String javaName = file.getFileName();
            if (pkg != null) {
                javaName = pkg + '.' + javaName;
            }
            if (file.isFile()) {
                javaName = StringUtils.removeEnd(javaName, ".class");
            }
            String pathName = '/' + file.getFileName();
            if (relativePathName != null) {
                pathName = relativePathName + pathName;
            }

            ResourceEntry entry = new ResourceEntry(file, javaName, pathName);
            if (file.isDirectory()) {
                if (visitDirectory(entry)) {
                    if (recursive) {
                        doLookupInVfsFile(file, javaName, pathName, true);
                    }
                }
            } else {
                visitFile(entry);
            }
        }
    }

    //----------------------------------------------------------------
    // following visitXXX methods should be overrided by subclass.
    //
    protected boolean visitDirectory(ResourceEntry dir) {
        return true;
    }

    protected void visitFile(ResourceEntry file) {
    }

    public static final class ResourceEntry extends AbstractResource {
        private final Resource resource;
        private final String qualifiedJavaName;

        public ResourceEntry(Resource resource, String qualifiedJavaName, String relativePathName) {
            this.resource = resource;
            this.qualifiedJavaName = qualifiedJavaName;
            this.relativePathName = relativePathName;
        }

        @Override
        public InputStream openStream() throws ResourceNotFoundException {
            return resource.openStream();
        }

        @Override
        public byte[] toByteArray() throws ResourceNotFoundException {
            return resource.toByteArray();
        }

        @Override
        public char[] toCharArray(Charset charset) throws ResourceNotFoundException {
            return resource.toCharArray(charset);
        }

        @Override
        public String toString(Charset charset) throws ResourceNotFoundException {
            return resource.toString(charset);
        }

        @Override
        public File getFile() {
            return resource.getFile();
        }

        @Override
        public URI getURI() {
            return resource.getURI();
        }

        @Override
        public URL getURL() {
            return resource.getURL();
        }

        @Override
        public boolean exist() {
            return resource.exist();
        }

        @Override
        public boolean isDirectory() {
            return resource.isDirectory();
        }

        @Override
        public boolean isFile() {
            return resource.isFile();
        }

        @Override
        public String getFileName() {
            return resource.getFileName();
        }

        @Override
        public long length() {
            return resource.length();
        }

        @Override
        public long lastModified() {
            return resource.lastModified();
        }

        public String getQualifiedJavaName() {
            return qualifiedJavaName;
        }

        public boolean isJavaClass() {
            return relativePathName.endsWith(".class");
        }

        @Override
        public String toString() {
            return resource.toString();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy