package play.utils.meta.cp; import java.lang.reflect.Modifier; import java.util.Map; import java.util.Set; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import play.GlobalSettings; import play.Logger; import play.Logger.ALogger; import play.utils.crud.APIController; import play.utils.crud.CRUD; import play.utils.crud.CRUDController; import play.utils.crud.ControllerProxy; import play.utils.crud.ControllerProxyCRUD; import play.utils.crud.ControllerProxyREST; import play.utils.dyn.Dynamic; import play.utils.meta.ControllerRegistry; import play.utils.meta.IncompatibleControllerException; import play.utils.meta.ModelMetadata; import play.utils.meta.ModelRegistry; import com.google.common.collect.Maps; public class ClasspathScanningControllerRegistry implements ControllerRegistry { private static ALogger log = Logger.of(ClasspathScanningControllerRegistry.class); private Map<Class<?>, ControllerProxy<?, ?>> restControllers; private Map<Class<?>, ControllerProxyCRUD<?, ?>> crudControllers; private ModelRegistry models; public ClasspathScanningControllerRegistry(GlobalSettings global, ModelRegistry models, ClassLoader... cls) { if (log.isDebugEnabled()) log.debug("ClasspathScanningControllerRegistry <-"); if (log.isDebugEnabled()) log.debug("global : " + global); this.models = models; this.restControllers = scanRest(global, APIController.class, cls); this.crudControllers = scanCrud(global, CRUDController.class, cls); } @SuppressWarnings("unchecked") public <K, M> ControllerProxy<K, M> getRestController(K keyClass, M modelClass, Map<Class<?>, ControllerProxy<?, ?>> controllers) throws IncompatibleControllerException { ControllerProxy<?, ?> cp = controllers.get(modelClass); ControllerProxy<K, M> controller = null; try { controller = ((ControllerProxy<K, M>) cp); if (log.isDebugEnabled()) log.debug("controller : " + controller); } catch (Exception e) { throw new IncompatibleControllerException(keyClass, modelClass, cp); } return controller; } @SuppressWarnings("unchecked") public <K, M> ControllerProxyCRUD<K, M> getCrudController(K keyClass, M modelClass, Map<Class<?>, ControllerProxyCRUD<?, ?>> controllers) throws IncompatibleControllerException { ControllerProxyCRUD<?, ?> cp = controllers.get(modelClass); ControllerProxyCRUD<K, M> controller = null; try { controller = ((ControllerProxyCRUD<K, M>) cp); if (log.isDebugEnabled()) log.debug("controller : " + controller); } catch (Exception e) { throw new IncompatibleControllerException(keyClass, modelClass, cp); } return controller; } @Override public <K, M> ControllerProxy<K, M> getRestController(K keyClass, M modelClass) throws IncompatibleControllerException { if (log.isDebugEnabled()) log.debug("getApiController <- key: " + keyClass + " model: " + modelClass); return getRestController(keyClass, modelClass, restControllers); } @Override public <K, M> ControllerProxyCRUD<K, M> getCrudController(K keyClass, M modelClass) throws IncompatibleControllerException { if (log.isDebugEnabled()) log.debug("getCrudController <- key: " + keyClass + " model: " + modelClass); return getCrudController(keyClass, modelClass, crudControllers); } @SuppressWarnings({ "rawtypes", "unchecked" }) private <C extends CRUD> Map<Class<?>, ControllerProxy<?, ?>> scanRest(GlobalSettings global, Class<C> superType, ClassLoader... cls) { final Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls( ClasspathHelper.forPackage("", cls)).setScanners(new SubTypesScanner(), new TypeAnnotationsScanner()).addClassLoaders(cls)); Map<Class<?>, ControllerProxy<?, ?>> map = Maps.newHashMap(); Set<Class<? extends C>> controllerClasses = reflections.getSubTypesOf(superType); for (Class<? extends C> controllerClass : controllerClasses) { try { if (log.isDebugEnabled()) log.debug("controllerClass : " + controllerClass); if (controllerClass.isAnnotationPresent(Dynamic.class)) { if (log.isDebugEnabled()) log.debug(controllerClass + "is @" + Dynamic.class); continue; } if (Modifier.isAbstract(controllerClass.getModifiers())) { if (log.isDebugEnabled()) log.debug(controllerClass + "is abstract"); continue; } C controller = null; try { controller = global.getControllerInstance(controllerClass); } catch (Exception e) { log.info("cannot get instances of controller: " + controllerClass, e); } if (controller != null) { Class modelClass = controller.getModelClass(); log.info("Found controller:" + controllerClass + " (" + modelClass + ")"); ModelMetadata model = models.getModel(modelClass); if (model != null) { map.put(modelClass, new ControllerProxyREST(controller, model)); } } } catch (Exception e) { e.printStackTrace(); } } return map; } @SuppressWarnings({ "rawtypes", "unchecked" }) private <C extends CRUD> Map<Class<?>, ControllerProxyCRUD<?, ?>> scanCrud(GlobalSettings global, Class<C> superType, ClassLoader... cls) { final Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls( ClasspathHelper.forPackage("", cls)).setScanners(new SubTypesScanner(), new TypeAnnotationsScanner()).addClassLoaders(cls)); Map<Class<?>, ControllerProxyCRUD<?, ?>> map = Maps.newHashMap(); Set<Class<? extends C>> controllerClasses = reflections.getSubTypesOf(superType); for (Class<? extends C> controllerClass : controllerClasses) { try { if (log.isDebugEnabled()) log.debug("controllerClass : " + controllerClass); if (controllerClass.isAnnotationPresent(Dynamic.class)) { if (log.isDebugEnabled()) log.debug(controllerClass + "is @" + Dynamic.class); continue; } if (Modifier.isAbstract(controllerClass.getModifiers())) { if (log.isDebugEnabled()) log.debug(controllerClass + "is abstract"); continue; } C controller = null; try { controller = global.getControllerInstance(controllerClass); } catch (Exception e) { log.info("cannot get instances of controller: " + controllerClass, e); } if (controller != null) { Class modelClass = controller.getModelClass(); log.info("Found controller:" + controllerClass + " (" + modelClass + ")"); ModelMetadata model = models.getModel(modelClass); if (model != null) { map.put(modelClass, new ControllerProxyCRUD(controller, model)); } } } catch (Exception e) { e.printStackTrace(); } } return map; } }