1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.blossom.template;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.module.blossom.annotation.Available;
38 import info.magnolia.module.blossom.annotation.I18nBasename;
39 import info.magnolia.module.blossom.annotation.Template;
40 import info.magnolia.module.blossom.dispatcher.BlossomDispatcher;
41 import info.magnolia.module.blossom.support.MethodInvocationUtils;
42 import info.magnolia.module.blossom.support.ParameterResolver;
43 import org.apache.commons.lang.StringUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.util.ClassUtils;
47
48 import java.lang.reflect.Method;
49 import java.util.ArrayList;
50 import java.util.List;
51
52
53
54
55 public class TemplateDescriptionBuilder {
56
57 private final Logger logger = LoggerFactory.getLogger(getClass());
58
59 public BlossomTemplateDescription buildDescription(BlossomDispatcher dispatcher, Object handler, String handlerPath) {
60
61 Template annotation = handler.getClass().getAnnotation(Template.class);
62 I18nBasename i18nBasename = handler.getClass().getAnnotation(I18nBasename.class);
63
64 BlossomTemplateDescription description = new BlossomTemplateDescription();
65 description.setName(resolveName(handlerPath, handler, annotation));
66 description.setTitle(resolveTitle(handlerPath, handler, annotation));
67 description.setDescription(resolveDescription(handlerPath, handler, annotation));
68 description.setI18nBasename(i18nBasename != null ? i18nBasename.value() : null);
69 description.setHandlerPath(handlerPath);
70 description.setVisible(annotation.visible());
71 description.setDispatcher(dispatcher);
72 description.setHandler(handler);
73 description.setAvailabilityStrategy(resolveAvailabilityStrategy(handler));
74
75 return description;
76 }
77
78 protected String resolveName(String handlerPath, Object handler, Template annotation) {
79 if (StringUtils.isNotEmpty(annotation.name()))
80 return annotation.name();
81 return StringUtils.replaceChars(StringUtils.strip(handlerPath, "/"), '/', '_');
82 }
83
84 protected String resolveTitle(String handlerPath, Object handler, Template annotation) {
85 return annotation.value();
86 }
87
88 protected String resolveDescription(String handlerPath, Object handler, Template annotation) {
89 return annotation.description();
90 }
91
92 protected TemplateAvailabilityStrategy resolveAvailabilityStrategy(final Object handler) {
93
94 final Class<?> handlerClass = handler.getClass();
95
96 final List<Method> matchingMethods = new ArrayList<Method>();
97
98
99
100 Class<?> clazz = handler.getClass();
101 do {
102 Method[] methods = clazz.getDeclaredMethods();
103 for (final Method method : methods) {
104
105
106 if (!method.isAnnotationPresent(Available.class))
107 continue;
108
109
110 if (!method.equals(ClassUtils.getMostSpecificMethod(method, handlerClass)))
111 continue;
112
113 if (!method.getReturnType().equals(Boolean.TYPE))
114 continue;
115
116 matchingMethods.add(method);
117 }
118 clazz = clazz.getSuperclass();
119 } while (clazz != null);
120
121 if (!matchingMethods.isEmpty()) {
122 if (matchingMethods.size() == 1) {
123 final Method method = matchingMethods.get(0);
124 return new TemplateAvailabilityStrategy() {
125 public boolean isAvailable(Content node) {
126
127 ParameterResolver parameters = getTemplateAvailabilityParameters(node);
128 return (Boolean) MethodInvocationUtils.invoke(method, handler, parameters);
129 }
130 };
131 } else {
132 logger.error("Multiple @Available annotated methods found for handler [" + handler.getClass() + "]");
133 }
134 }
135
136 return null;
137 }
138
139 protected ParameterResolver getTemplateAvailabilityParameters(final Content node) {
140 return new ParameterResolver() {
141 public Object resolveParameter(Class<?> parameterType) {
142 if (parameterType.equals(Content.class))
143 return node;
144 return super.resolveParameter(parameterType);
145 }
146 };
147 }
148 }