package play.utils.crud; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import org.springframework.util.StringUtils; import play.Logger; import play.Logger.ALogger; import play.cache.Cache; import play.libs.F; import play.mvc.Controller; import play.mvc.Result; import play.utils.meta.ControllerRegistry; import play.utils.meta.IncompatibleControllerException; import play.utils.meta.ModelMetadata; import play.utils.meta.ModelRegistry; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; @SuppressWarnings("rawtypes") public abstract class RouterController extends Controller { private static ALogger log = Logger.of(RouterController.class); protected ModelRegistry modelRegistry; protected ControllerRegistry controllerRegistry; protected Map<Class<?>, ControllerProxy<?, ?>> dynamicRestControllers = new HashMap<Class<?>, ControllerProxy<?, ?>>(); protected Map<Class<?>, ControllerProxy<?, ?>> dynamicCrudControllers = new HashMap<Class<?>, ControllerProxy<?, ?>>(); public RouterController(ControllerRegistry controllerRegistry, ModelRegistry modelRegistry) { this.controllerRegistry = controllerRegistry; this.modelRegistry = modelRegistry; } public Result list(String name) { if (log.isDebugEnabled()) log.debug("list <-"); F.Either<ControllerProxy, ? extends Result> cnf = controllerOrNotFound(name); if (cnf.right.isDefined()) return cnf.right.get(); ControllerProxy controller = cnf.left.get(); if (controller == null) { return controllerNotFound(name); } return controller.list(); } public Result create(String name) { if (log.isDebugEnabled()) log.debug("create <- " + name); F.Either<ControllerProxy, ? extends Result> cnf = controllerOrNotFound(name); if (cnf.right.isDefined()) return cnf.right.get(); ControllerProxy controller = cnf.left.get(); if (controller == null) { return controllerNotFound(name); } return controller.create(); } public Result show(String name, String key) { if (log.isDebugEnabled()) log.debug("show <- " + name + ", " + key); F.Either<ControllerProxy, ? extends Result> cnf = controllerOrNotFound(name); if (cnf.right.isDefined()) return cnf.right.get(); ControllerProxy controller = cnf.left.get(); if (controller == null) { return controllerNotFound(name); } return controller.show(key); } public Result update(String name, String key) { if (log.isDebugEnabled()) log.debug("update <- " + name + ", " + key); F.Either<ControllerProxy, ? extends Result> cnf = controllerOrNotFound(name); if (cnf.right.isDefined()) return cnf.right.get(); ControllerProxy controller = cnf.left.get(); if (controller == null) { return controllerNotFound(name); } return controller.update(key); } public Result save(String name, String key) { if (StringUtils.hasLength(key)) return update(name, key); else return create(name); } public Result delete(String name, String key) { if (log.isDebugEnabled()) log.debug("delete <- " + name + ", " + key); F.Either<ControllerProxy, ? extends Result> cnf = controllerOrNotFound(name); if (cnf.right.isDefined()) return cnf.right.get(); ControllerProxy controller = cnf.left.get(); if (controller == null) { return controllerNotFound(name); } return controller.delete(key); } protected Result controllerNotFound(String name) { return notFound("Controller not found : " + name); } protected F.Either<ControllerProxy, ? extends Result> controllerOrNotFound(final String name) { F.Option<ModelMetadata> modelInfo = getModel(name); if (!modelInfo.isDefined()) return F.Either.Right(notFound("Model with name " + name + " not found!")); ModelMetadata model = modelInfo.get(); ControllerProxy<?,?> crud; try { crud = getController(model); } catch (IncompatibleControllerException e) { crud = null; } if (crud == null) return F.Either.Right(notFound("Controller for model " + model.getType() + " not found")); ControllerProxy controller = crud; return F.Either.Left(controller); } protected F.Option<ModelMetadata> getModel(final String name) { ModelMetadata modelInfo = null; try { modelInfo = (ModelMetadata) Cache.getOrElse(getClass().getName() + "_ModelMetadata_" + name, new Callable<Object>() { @Override public Object call() throws Exception { return Iterables.find(modelRegistry.getModels(), new Predicate<ModelMetadata>() { @Override public boolean apply(ModelMetadata model) { String modelName = model.getName(); return modelName.equals(name); } }, null); } }, 0); } catch (Exception e) { e.printStackTrace(); } return modelInfo == null ? F.Option.<ModelMetadata> None() : F.Option.Some(modelInfo); } protected ControllerProxy<?,?> getController(ModelMetadata model) throws IncompatibleControllerException { Class<?> keyType = model.getKeyField().getType(); Class<?> modelType = model.getType(); ControllerProxy<?,?> crud = getControllerProxy(keyType, modelType); if (crud == null) crud = getDynamicController(keyType, modelType, model); return crud; } protected abstract ControllerProxy<?, ?> getDynamicController(Class<?> keyType, Class<?> modelType, ModelMetadata model); protected abstract ControllerProxy<?, ?> getControllerProxy(Class<?> keyType, Class<?> modelType) throws IncompatibleControllerException; }