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

net.paoding.rose.scanning.RoseScanner Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2007-2009 the original author or authors.
 *
 * 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 net.paoding.rose.scanning;

import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;

/**
 * @author zhiliang.wang 王志亮 [[email protected]]
 */
public class RoseScanner {

    private static SoftReference softReference;

    public synchronized static RoseScanner getInstance() {
        if (softReference == null || softReference.get() == null) {
            RoseScanner roseScanner = new RoseScanner();
            softReference = new SoftReference(roseScanner);
        }
        return softReference.get();
    }

    // -------------------------------------------------------------

    protected Log logger = LogFactory.getLog(getClass());

    protected Date createTime = new Date();

    protected ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private List classesFolderResources;

    private List jarResources;

    // -------------------------------------------------------------

    private RoseScanner() {
    }

    public Date getCreateTime() {
        return createTime;
    }

    // -------------------------------------------------------------
    public List getJarOrClassesFolderResources() throws IOException {
        return getJarOrClassesFolderResources(null);
    }

    public List getJarOrClassesFolderResources(String[] scope) throws IOException {
        if (logger.isInfoEnabled()) {
            logger.info("[findFiles] start to found classes folders "
                    + "or rosed jar files by scope:" + Arrays.toString(scope));
        }
        List resources;
        if (scope == null) {
            resources = new LinkedList();
            if (logger.isDebugEnabled()) {
                logger.debug("[findFiles] call 'classesFolder'");
            }
            resources.addAll(getClassesFolderResources());
            //
            if (logger.isDebugEnabled()) {
                logger.debug("[findFiles] exits from 'classesFolder'");
                logger.debug("[findFiles] call 'jarFile'");
            }
            resources.addAll(getJarResources());
            if (logger.isDebugEnabled()) {
                logger.debug("[findFiles] exits from 'jarFile'");
            }
        } else if (scope.length == 0) {
            return new ArrayList();
        } else {
            resources = new LinkedList();
            for (String scopeEntry : scope) {
                String packagePath = scopeEntry.replace('.', '/');
                Resource[] packageResources = resourcePatternResolver.getResources("classpath*:"
                        + packagePath);
                for (Resource pkgResource : packageResources) {
                    String uri = pkgResource.getURI().toString();
                    uri = StringUtils.removeEnd(uri, "/");
                    packagePath = StringUtils.removeEnd(packagePath, "/");
                    uri = StringUtils.removeEnd(uri, packagePath);
                    int beginIndex = uri.lastIndexOf("file:");
                    if (beginIndex == -1) {
                        beginIndex = 0;
                    } else {
                        beginIndex += "file:".length();
                    }
                    int endIndex = uri.lastIndexOf('!');
                    if (endIndex == -1) {
                        endIndex = uri.length();
                    }
                    String path = uri.substring(beginIndex, endIndex);
                    Resource folder = new FileSystemResource(path);
                    ResourceRef ref = ResourceRef.toResourceRef(folder);
                    if (!resources.contains(ref)) {
                        resources.add(ref);
                        if (logger.isDebugEnabled()) {
                            logger.debug("[findFiles] found classes folders "
                                    + "or rosed jar files by scope:" + ref);
                        }
                    }
                }
            }
        }
        //
        if (logger.isInfoEnabled()) {
            logger.info("[findFiles] found " + resources.size() + " classes folders "
                    + "or rosed jar files : " + resources);
        }

        return resources;
    }

    /**
     * 将要被扫描的普通类地址(比如WEB-INF/classes或target/classes之类的地址)
     * 
     * @param resourceLoader
     * @return
     * @throws IOException
     * @throws URISyntaxException
     */
    public List getClassesFolderResources() throws IOException {
        if (classesFolderResources == null) {
            if (logger.isInfoEnabled()) {
                logger.info("[classesFolder] start to found available classes folders ...");
            }
            List classesFolderResources = new ArrayList();
            Enumeration founds = resourcePatternResolver.getClassLoader().getResources("");
            while (founds.hasMoreElements()) {
                URL urlObject = founds.nextElement();
                if (!"file".equals(urlObject.getProtocol())) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("[classesFolder] Ignored classes folder because "
                                + "not a file protocol url: " + urlObject);
                    }
                    continue;
                }
                String path = urlObject.getPath();
                Assert.isTrue(path.endsWith("/"));
                if (!path.endsWith("/classes/") && !path.endsWith("/bin/")) {
                    if (logger.isInfoEnabled()) {
                        logger.info("[classesFolder] Ignored classes folder because "
                                + "not ends with '/classes/' or '/bin/': " + urlObject);
                    }
                    continue;
                }
                File file;
                try {
                    file = new File(urlObject.toURI());
                } catch (URISyntaxException e) {
                    throw new IOException(e);
                }
                if (file.isFile()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("[classesFolder] Ignored because not a directory: "
                                + urlObject);
                    }
                    continue;
                }
                Resource resource = new FileSystemResource(file);
                ResourceRef resourceRef = ResourceRef.toResourceRef(resource);
                if (classesFolderResources.contains(resourceRef)) {
                    // 删除重复的地址
                    if (logger.isDebugEnabled()) {
                        logger.debug("[classesFolder] remove replicated classes folder: "
                                + resourceRef);
                    }
                } else {
                    classesFolderResources.add(resourceRef);
                    if (logger.isDebugEnabled()) {
                        logger.debug("[classesFolder] add classes folder: " + resourceRef);
                    }
                }
            }
            // 删除含有一个地址包含另外一个地址的
            Collections.sort(classesFolderResources);
            List toRemove = new LinkedList();
            for (int i = 0; i < classesFolderResources.size(); i++) {
                ResourceRef ref = classesFolderResources.get(i);
                String refURI = ref.getResource().getURI().toString();
                for (int j = i + 1; j < classesFolderResources.size(); j++) {
                    ResourceRef refj = classesFolderResources.get(j);
                    String refjURI = refj.getResource().getURI().toString();
                    if (refURI.startsWith(refjURI)) {
                        toRemove.add(refj);
                        if (logger.isInfoEnabled()) {
                            logger.info("[classesFolder] remove wrapper classes folder: " //
                                    + refj);
                        }
                    } else if (refjURI.startsWith(refURI) && refURI.length() != refjURI.length()) {
                        toRemove.add(ref);
                        if (logger.isInfoEnabled()) {
                            logger.info("[classesFolder] remove wrapper classes folder: " //
                                    + ref);
                        }
                    }
                }
            }
            classesFolderResources.removeAll(toRemove);
            //
            this.classesFolderResources = new ArrayList(classesFolderResources);
            if (logger.isInfoEnabled()) {
                logger.info("[classesFolder] found " + classesFolderResources.size()
                        + " classes folders: " + classesFolderResources);
            }
        } else {
            if (logger.isInfoEnabled()) {
                logger.info("[classesFolder] found cached " + classesFolderResources.size()
                        + " classes folders: " + classesFolderResources);
            }
        }
        return Collections.unmodifiableList(classesFolderResources);
    }

    /**
     * 将要被扫描的jar资源
     * 
     * @param resourceLoader
     * @return
     * @throws IOException
     */
    public List getJarResources() throws IOException {
        if (jarResources == null) {
            if (logger.isInfoEnabled()) {
                logger.info("[jarFile] start to found available jar files for rose to scanning...");
            }
            List jarResources = new LinkedList();
            Resource[] metaInfResources = resourcePatternResolver
                    .getResources("classpath*:/META-INF/");
            for (Resource metaInfResource : metaInfResources) {
                URL urlObject = metaInfResource.getURL();
                if (ResourceUtils.isJarURL(urlObject)) {
                    try {
                        String path = URLDecoder.decode(urlObject.getPath(), "UTF-8"); // fix 20%
                        if (path.startsWith("file:")) {
                            path = path.substring("file:".length(), path.lastIndexOf('!'));
                        } else {
                            path = path.substring(0, path.lastIndexOf('!'));
                        }
                        Resource resource = new FileSystemResource(path);
                        if (jarResources.contains(resource)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("[jarFile] skip replicated jar resource: " + path);// 在多个 linux环境 下发现有重复,fix it!
                            }
                        } else {
                            ResourceRef ref = ResourceRef.toResourceRef(resource);
                            if (ref.getModifiers() != null) {
                                jarResources.add(ref);
                                if (logger.isInfoEnabled()) {
                                    logger.info("[jarFile] add jar resource: " + ref);
                                }
                            } else {
                                if (logger.isDebugEnabled()) {
                                    logger.debug("[jarFile] not rose jar resource: " + path);
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.error(urlObject, e);
                    }
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("[jarFile] not rose type(not a jar) " + urlObject);
                    }
                }
            }
            this.jarResources = jarResources;
            if (logger.isInfoEnabled()) {
                logger.info("[jarFile] found " + jarResources.size() + " jar files: "
                        + jarResources);
            }
        } else {
            if (logger.isInfoEnabled()) {
                logger.info("[jarFile] found cached " + jarResources.size() + " jar files: "
                        + jarResources);
            }
        }
        return Collections.unmodifiableList(jarResources);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy