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);
       }
     }
   }
 }
 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 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);
   }
 }
 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());
   }
 }
 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);
   }
 }
  @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 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);
      }
    }
  }