Index: src/main/java/info/magnolia/module/blossom/annotation/IsAvailable.java =================================================================== --- src/main/java/info/magnolia/module/blossom/annotation/IsAvailable.java (revision 0) +++ src/main/java/info/magnolia/module/blossom/annotation/IsAvailable.java (revision 0) @@ -0,0 +1,60 @@ +/** + * This file Copyright (c) 2003-2010 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.module.blossom.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used on a controller method to expose it as that template's isAvailable() method. The method will be used in + * place of the default Magnolia template isAvailable() method and accepts the following parameter types in any + * order and must return a boolean: + * + * info.magnolia.module.templating.Template (The template being checked) + * info.magnolia.core.cms.Content (Content node for page in AdminCentral) + * + * Some examples: + * + * @IsAvailable + * public boolean isAvailable(Content node) { ... } + * + * @IsAvailable + * public boolean isAvailable(Template template, Content node) { ... } + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface IsAvailable {} \ No newline at end of file Index: src/main/java/info/magnolia/module/blossom/template/BlossomTemplateDescription.java =================================================================== --- src/main/java/info/magnolia/module/blossom/template/BlossomTemplateDescription.java (revision 35702) +++ src/main/java/info/magnolia/module/blossom/template/BlossomTemplateDescription.java (working copy) @@ -35,6 +35,8 @@ import info.magnolia.module.blossom.render.BlossomDispatcherServlet; +import java.lang.reflect.Method; + public class BlossomTemplateDescription { private String name; @@ -43,6 +45,8 @@ private String i18nBasename; private String handlerPath; private boolean visible; + private Object handler; + private Method isAvailableMethod; private BlossomDispatcherServlet dispatcherServlet; public String getI18nBasename() { @@ -100,4 +104,20 @@ public void setVisible(boolean visible) { this.visible = visible; } + + public void setHandler(Object handler) { + this.handler = handler; + } + + public Object getHandler() { + return handler; + } + + public Method getIsAvailableMethod() { + return isAvailableMethod; + } + + public void setIsAvailableMethod(Method isAvailableMethod) { + this.isAvailableMethod = isAvailableMethod; + } } Index: src/main/java/info/magnolia/module/blossom/template/BlossomTemplate.java =================================================================== --- src/main/java/info/magnolia/module/blossom/template/BlossomTemplate.java (revision 0) +++ src/main/java/info/magnolia/module/blossom/template/BlossomTemplate.java (revision 0) @@ -0,0 +1,106 @@ +/** + * This file Copyright (c) 2003-2010 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.module.blossom.template; + +import info.magnolia.cms.core.Content; +import info.magnolia.module.blossom.BlossomModule; +import info.magnolia.module.templating.Template; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.GenericTypeResolver; +import org.springframework.core.MethodParameter; +import org.springframework.util.ReflectionUtils; + +public class BlossomTemplate extends Template { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public boolean isAvailable(Content node) { + + BlossomTemplateRegistry registry = BlossomModule.getTemplateRegistry(); + BlossomTemplateDescription description = registry.getTemplate(getContent().getName()); + + Method isAvailableMethod = description.getIsAvailableMethod(); + if (isAvailableMethod == null) + return super.isAvailable(node); + + Object handler = description.getHandler(); + + try { + Object[] args = resolveHandlerArguments(isAvailableMethod, handler, this, node); + return (Boolean) doInvokeMethod(isAvailableMethod, handler, args); + } + catch (Exception e) { + logger.error("Exception occurred executing isAvailable method: " + e, e); + return false; + } + } + + @SuppressWarnings("unchecked") + private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, Template template, Content node) throws Exception { + + Class[] paramTypes = handlerMethod.getParameterTypes(); + Object[] args = new Object[paramTypes.length]; + + for (int i = 0; i < args.length; i++) { + MethodParameter methodParam = new MethodParameter(handlerMethod, i); + GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); + Class paramType = methodParam.getParameterType(); + + if (Template.class.isAssignableFrom(paramType)) + args[i] = template; + else if (Content.class.isAssignableFrom(paramType)) + args[i] = node; + else + throw new IllegalStateException("Unknown IsAvailable argument declared."); + } + + return args; + } + + private Object doInvokeMethod(Method method, Object target, Object[] args) throws Exception { + ReflectionUtils.makeAccessible(method); + try { + return method.invoke(target, args); + } + catch (InvocationTargetException ex) { + ReflectionUtils.rethrowException(ex.getTargetException()); + } + throw new IllegalStateException("Should never get here"); + } +} \ No newline at end of file Index: src/main/java/info/magnolia/module/blossom/template/DefaultBlossomTemplateRegistry.java =================================================================== --- src/main/java/info/magnolia/module/blossom/template/DefaultBlossomTemplateRegistry.java (revision 35702) +++ src/main/java/info/magnolia/module/blossom/template/DefaultBlossomTemplateRegistry.java (working copy) @@ -80,6 +80,7 @@ if (StringUtils.isNotBlank(templateDescription.getI18nBasename())) content1.createNodeData("i18nBasename", new StringValue(templateDescription.getI18nBasename())); content1.createNodeData("type", new StringValue("blossom")); + content1.createNodeData("class", "info.magnolia.module.blossom.template.BlossomTemplate"); content.save(); } Index: src/main/java/info/magnolia/module/blossom/template/TemplateDescriptionBuilder.java =================================================================== --- src/main/java/info/magnolia/module/blossom/template/TemplateDescriptionBuilder.java (revision 35702) +++ src/main/java/info/magnolia/module/blossom/template/TemplateDescriptionBuilder.java (working copy) @@ -34,25 +34,42 @@ package info.magnolia.module.blossom.template; import info.magnolia.module.blossom.annotation.I18nBasename; +import info.magnolia.module.blossom.annotation.IsAvailable; import info.magnolia.module.blossom.annotation.Template; import info.magnolia.module.blossom.render.BlossomDispatcherServlet; + +import java.lang.reflect.Method; + import org.apache.commons.lang.StringUtils; +import org.springframework.core.annotation.AnnotationUtils; public class TemplateDescriptionBuilder { public BlossomTemplateDescription buildDescription(BlossomDispatcherServlet dispatcherServlet, Object handler, String handlerPath) { - Template annotation = handler.getClass().getAnnotation(Template.class); + Template templateAnnotation = handler.getClass().getAnnotation(Template.class); I18nBasename i18nBasename = handler.getClass().getAnnotation(I18nBasename.class); + Method isAvailable = null; + for (Method m : handler.getClass().getMethods()) { + IsAvailable isAvailableAnnotation = AnnotationUtils.findAnnotation(m, IsAvailable.class); + + if (isAvailableAnnotation != null) { + isAvailable = m; + break; + } + } + BlossomTemplateDescription description = new BlossomTemplateDescription(); - description.setName(resolveName(handlerPath, handler, annotation)); - description.setTitle(resolveTitle(handlerPath, handler, annotation)); - description.setDescription(resolveDescription(handlerPath, handler, annotation)); + description.setName(resolveName(handlerPath, handler, templateAnnotation)); + description.setTitle(resolveTitle(handlerPath, handler, templateAnnotation)); + description.setDescription(resolveDescription(handlerPath, handler, templateAnnotation)); description.setI18nBasename(i18nBasename != null ? i18nBasename.value() : null); description.setHandlerPath(handlerPath); - description.setVisible(annotation.visible()); + description.setVisible(templateAnnotation.visible()); description.setDispatcherServlet(dispatcherServlet); + description.setHandler(handler); + description.setIsAvailableMethod(isAvailable); return description; }