Package net.paoding.rose.scanner

Source Code of net.paoding.rose.scanner.ModuleResourceProviderImpl$Local

/*
* 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.scanner;

import static net.paoding.rose.RoseConstants.CONF_INTERCEPTED_ALLOW;
import static net.paoding.rose.RoseConstants.CONF_INTERCEPTED_DENY;
import static net.paoding.rose.RoseConstants.CONF_MODULE_IGNORED;
import static net.paoding.rose.RoseConstants.CONF_MODULE_PATH;
import static net.paoding.rose.RoseConstants.CONF_PARENT_MODULE_PATH;
import static net.paoding.rose.RoseConstants.CONTROLLERS;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import net.paoding.rose.scanning.LoadScope;
import net.paoding.rose.scanning.ResourceRef;
import net.paoding.rose.scanning.RoseScanner;
import net.paoding.rose.scanning.vfs.FileName;
import net.paoding.rose.scanning.vfs.FileObject;
import net.paoding.rose.scanning.vfs.FileSystemManager;
import net.paoding.rose.util.RoseStringUtil;

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

/**
*
* @author 王志亮 [qieqie.wang@gmail.com]
*
*/
public class ModuleResourceProviderImpl implements ModuleResourceProvider {

    private Log logger = LogFactory.getLog(ModuleResourceProviderImpl.class);

    class Local {

        List<ModuleResource> moduleResourceList = new LinkedList<ModuleResource>();

        Map<FileObject, ModuleResource> moduleResourceMap = new HashMap<FileObject, ModuleResource>();
    }

    @Override
    public List<ModuleResource> findModuleResources(LoadScope scope) throws IOException {

        Local local = new Local();
        String[] controllersScope = scope.getScope("controllers");
        if (logger.isInfoEnabled()) {
            logger.info("[moduleResource] starting ...");
            logger.info("[moduleResource] call 'findFiles':"
                    + " to find classes or jar files by scope "//
                    + Arrays.toString(controllersScope));
        }

        List<ResourceRef> refers = RoseScanner.getInstance().getJarOrClassesFolderResources(
                controllersScope);

        if (logger.isInfoEnabled()) {
            logger.info("[moduleResource] exits from 'findFiles'");
            logger.info("[moduleResource] going to scan controllers"
                    + " from these folders or jar files:" + refers);
        }

        FileSystemManager fileSystem = new FileSystemManager();

        for (ResourceRef refer : refers) {
            Resource resource = refer.getResource();
            if (!refer.hasModifier("controllers")) {
                if (logger.isDebugEnabled()) {
                    logger.debug("[moduleResource] Ignored because not marked as 'controllers'"
                            + " in META-INF/rose.properties or META-INF/MANIFEST.MF: "
                            + resource.getURI());
                }
                continue;
            }
            File resourceFile = resource.getFile();
            String urlString;
            if ("jar".equals(refer.getProtocol())) {
                urlString = ResourceUtils.URL_PROTOCOL_JAR + ":" + resourceFile.toURI()
                        + ResourceUtils.JAR_URL_SEPARATOR;
            } else {
                urlString = resourceFile.toURI().toString();
            }
            FileObject rootObject = fileSystem.resolveFile(urlString);
            if (rootObject == null || !rootObject.exists()) {
                if (logger.isDebugEnabled()) {
                    logger.debug("[moduleResource] Ignored because not exists: " + urlString);
                }
                continue;
            }

            if (logger.isInfoEnabled()) {
                logger.info("[moduleResource] start to scan moduleResource in file: " + rootObject);
            }

            try {
                int oldSize = local.moduleResourceList.size();

                deepScanImpl(local, rootObject, rootObject);

                int newSize = local.moduleResourceList.size();

                if (logger.isInfoEnabled()) {
                    logger.info("[moduleResource] got " + (newSize - oldSize) + " modules in "
                            + rootObject);
                }

            } catch (Exception e) {
                logger.error("[moduleResource] error happend when scanning " + rootObject, e);
            }

            fileSystem.clearCache();
        }

        afterScanning(local);

        logger.info("[moduleResource] found " + local.moduleResourceList.size()
                + " module resources ");

        return local.moduleResourceList;
    }

    protected void deepScanImpl(Local local, FileObject root, FileObject target) throws IOException {
        if (CONTROLLERS.equals(target.getName().getBaseName())) {
            checkModuleResourceCandidate(local, root, target, target);
        } else {
            FileObject[] children = target.getChildren();
            for (FileObject child : children) {
                if (child.getType().hasChildren()) {
                    deepScanImpl(local, root, child);
                }
            }
        }
    }

    protected void checkModuleResourceCandidate(Local local, FileObject root,
            FileObject topModuleFile, FileObject candidate) throws IOException {

        String relative = topModuleFile.getName().getRelativeName(candidate.getName());
        String mappingPath = null;
        String[] interceptedAllow = null;
        String[] interceptedDeny = null;

        ModuleResource parentModule = local.moduleResourceMap.get(candidate.getParent());
        // 如果rose.properties设置了controllers的module.path?
        FileObject rosePropertiesFile = candidate.getChild("rose.properties");
        if (rosePropertiesFile != null && rosePropertiesFile.exists()) {
            Properties p = new Properties();
            InputStream in = rosePropertiesFile.getContent().getInputStream();
            p.load(in);
            in.close();

            // 如果controllers=ignored,则...
            String ignored = p.getProperty(CONF_MODULE_IGNORED, "false").trim();
            if ("true".equalsIgnoreCase(ignored) || "1".equalsIgnoreCase(ignored)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Ignored module(include submodules) by rose.properties[ignored="
                            + ignored + "]: " + candidate);
                }
                return;
            }

            mappingPath = p.getProperty(CONF_MODULE_PATH);
            if (mappingPath != null) {
                mappingPath = mappingPath.trim();
                String parentModulePlaceHolder = "${" + CONF_PARENT_MODULE_PATH + "}";
                if (mappingPath.indexOf(parentModulePlaceHolder) != -1) {
                    String parentModulePath = "";
                    if (candidate.getParent() != null) {
                        parentModulePath = (parentModule == null) ? "" : parentModule
                                .getMappingPath();
                    }
                    mappingPath = mappingPath.replace(parentModulePlaceHolder, parentModulePath);
                }
                if (mappingPath.length() != 0 && !mappingPath.startsWith("/")) {
                    if (parentModule != null) {
                        mappingPath = parentModule.getMappingPath() + "/" + mappingPath;
                    } else if (StringUtils.isNotEmpty(relative)) {
                        mappingPath = relative + "/" + mappingPath;
                    } else {
                        mappingPath = "/" + mappingPath;
                    }
                }
                mappingPath = RoseStringUtil.mappingPath(mappingPath);
            }

            //interceptedAllow、interceptedDeny
            String interceptedAllowStrings = p.getProperty(CONF_INTERCEPTED_ALLOW);
            interceptedAllowStrings = StringUtils.trimToEmpty(interceptedAllowStrings);
            if (interceptedAllowStrings.length() > 0) {
                interceptedAllow = StringUtils.split(interceptedAllowStrings, ",");
            }

            String interceptedDenyStrings = p.getProperty(CONF_INTERCEPTED_DENY);
            interceptedDenyStrings = StringUtils.trimToEmpty(interceptedDenyStrings);
            if (interceptedDenyStrings.length() > 0) {
                interceptedDeny = StringUtils.split(interceptedDenyStrings, ",");
            }

        }
        //
        if (mappingPath == null) {
            if (parentModule != null) {
                mappingPath = parentModule.getMappingPath() + "/"
                        + candidate.getName().getBaseName();
            } else {
                mappingPath = "";
            }
        }
        ModuleResource moduleResource = new ModuleResource();
        moduleResource.setMappingPath(mappingPath);
        moduleResource.setModuleUrl(candidate.getURL());
        moduleResource.setRelativePath(RoseStringUtil.relativePathToModulePath(relative));
        moduleResource.setParent(parentModule);
        if (interceptedAllow != null) {
            moduleResource.setInterceptedAllow(interceptedAllow);
        }
        if (interceptedDeny != null) {
            moduleResource.setInterceptedDeny(interceptedDeny);
        }
        local.moduleResourceMap.put(candidate, moduleResource);
        local.moduleResourceList.add(moduleResource);
        if (logger.isDebugEnabled()) {
            logger.debug("found module '" + mappingPath + "' in " + candidate.getURL());
        }

        FileObject[] children = candidate.getChildren();
        for (FileObject child : children) {
            if (child.getType().hasContent() && !child.getType().hasChildren()) {
                handlerModuleResource(local, root, candidate, child);
            }
        }
        for (FileObject child : children) {
            if (child.getType().hasChildren()) {
                checkModuleResourceCandidate(local, root, topModuleFile, child);
            }
        }
    }

    protected void handlerModuleResource(Local local, FileObject rootObject, FileObject thisFolder,
            FileObject resource) throws IOException {
        FileName fileName = resource.getName();
        String bn = fileName.getBaseName();
        if (logger.isDebugEnabled()) {
            logger.debug("handlerModuleResource baseName=" + bn + "; file="
                    + fileName.getFileObject());
        }
        if (bn.endsWith(".class") && bn.indexOf('$') == -1) {
            addModuleClass(local, rootObject, thisFolder, resource);
        } else if (bn.startsWith("applicationContext") && bn.endsWith(".xml")) {
            addModuleContext(local, rootObject, thisFolder, resource);
        } else if (bn.startsWith("messages") && (bn.endsWith(".xml") || bn.endsWith(".properties"))) {
            addModuleMessage(local, rootObject, thisFolder, resource);
        }
    }

    private void addModuleContext(Local local, FileObject rootObject, FileObject thisFolder,
            FileObject resource) throws IOException {
        ModuleResource moduleInfo = local.moduleResourceMap.get(thisFolder);
        moduleInfo.addContextResource(resource.getURL());
        if (logger.isDebugEnabled()) {
            logger.debug("module '" + moduleInfo.getMappingPath() + "': found context file, url="
                    + resource.getURL());
        }
    }

    private void addModuleMessage(Local local, FileObject rootObject, FileObject thisFolder,
            FileObject resource) throws IOException {
        ModuleResource moduleInfo = local.moduleResourceMap.get(thisFolder);
        String directory = resource.getParent().getURL().toString();
        String messageFileName = resource.getName().getBaseName();
        String msgBasename;
        if (messageFileName.indexOf('_') == -1) {
            msgBasename = messageFileName.substring(0, messageFileName.indexOf('.'));
        } else {
            msgBasename = messageFileName.substring(0, messageFileName.indexOf('_'));
        }
        moduleInfo.addMessageResource(directory + msgBasename);
        if (logger.isDebugEnabled()) {
            logger.debug("module '" + moduleInfo.getMappingPath() + "': found messages file, url="
                    + resource.getURL());
        }
    }

    private void addModuleClass(Local local, FileObject rootObject, FileObject thisFolder,
            FileObject resource) throws IOException {
        String className = rootObject.getName().getRelativeName(resource.getName());
        Assert.isTrue(!className.startsWith("/"));
        className = StringUtils.removeEnd(className, ".class");
        className = className.replace('/', '.');
        ModuleResource module = local.moduleResourceMap.get(thisFolder);
        try {
            // TODO: classloader...
            module.addModuleClass(Class.forName(className));
            if (logger.isDebugEnabled()) {
                logger.debug("module '" + module.getMappingPath() + "': found class, name="
                        + className);
            }
        } catch (ClassNotFoundException e) {
            logger.error("", e);
        }
    }

    // FIXME: 如果一个module只有rose.properties文件也会从moduleInfoList中remove,以后是否需要修改?
    protected void afterScanning(Local local) {
        for (ModuleResource moduleResource : local.moduleResourceMap.values()) {
            if (moduleResource.getContextResources().size() == 0
                    && moduleResource.getModuleClasses().size() == 0) {
                local.moduleResourceList.remove(moduleResource);
                if (logger.isInfoEnabled()) {
                    logger.info("remove empty module '" + moduleResource.getMappingPath() + "' "
                            + moduleResource.getModuleUrl());
                }
            }
        }
    }

}
TOP

Related Classes of net.paoding.rose.scanner.ModuleResourceProviderImpl$Local

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.