/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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 org.civilian.resource.scan; import java.lang.reflect.Modifier; import java.util.Set; import org.civilian.Application; import org.civilian.Controller; import org.civilian.Resource; import org.civilian.controller.ControllerNaming; import org.civilian.internal.classpath.ClassFilter; import org.civilian.internal.classpath.ClassPathScan; import org.civilian.resource.PathParamMap; /** * ResourceScan scans the class path, collects all controller classes * of an application and creates a resource tree. * The resource tree determines which dynamic resources are known to the * application. * @see Application#generateResourceTree(org.civilian.controller.classloader.ReloadConfig) */ public class ResourceScan { public ResourceScan(String rootPackage, ControllerNaming naming, PathParamMap pathParams, ClassLoader classLoader) throws ScanException { classLoader_ = classLoader != null ? classLoader : getClass().getClassLoader(); resFactory_ = new ResourceFactory(rootPackage, naming, pathParams); } public Resource run() throws ScanException { return getInfo().toResource(); } public ResourceInfo getInfo() throws ScanException { scanClassPath(); ResourceInfo root = resFactory_.getRoot(); root.sortChildren(); return root; } private void scanClassPath() throws ScanException { String rootPackage = resFactory_.getRootPackage(); if (verbose) log("scanning classes below " + rootPackage); ClassPathScan scan = new ClassPathScan(rootPackage); Set<String> candidateClasses; try { candidateClasses = scan.collect(new CtrlClassFilter(resFactory_.getNaming())); } catch (Exception e) { throw new ScanException("error during classpath scan", e); } if (verbose) log("found " + candidateClasses.size() + " potential resource classes"); for (String c : candidateClasses) scanClass(c); } @SuppressWarnings("unchecked") private void scanClass(String className) { Class<?> c; try { c = Class.forName(className, false, classLoader_); } catch(ClassNotFoundException e) { // weird situation throw new ScanException("class '" + className + "' not found, but was part of classpath scan", e); } // ignore if not a resource class (naming failed) or if abstract // (map annotations on abstract classes are ignored) if (Controller.class.isAssignableFrom(c) && !Modifier.isAbstract(c.getModifiers())) resFactory_.mapController((Class<? extends Controller>)c); } private static class CtrlClassFilter implements ClassFilter { public CtrlClassFilter(ControllerNaming naming) { naming_ = naming; } @Override public boolean accept(String className) { return naming_.isControllerClass(className); } private ControllerNaming naming_; } public static void log(String message) { System.out.println(message); } private ClassLoader classLoader_; private ResourceFactory resFactory_; boolean verbose; }