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.dialog;
35
36 import java.lang.annotation.Annotation;
37 import java.lang.reflect.Method;
38 import java.lang.reflect.Modifier;
39 import java.util.ArrayList;
40 import java.util.List;
41
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.springframework.aop.support.AopUtils;
45 import org.springframework.util.ClassUtils;
46 import org.springframework.util.ReflectionUtils;
47
48 import info.magnolia.module.admininterface.SaveHandler;
49 import info.magnolia.module.blossom.annotation.DialogFactory;
50 import info.magnolia.module.blossom.annotation.DialogValidator;
51 import info.magnolia.module.blossom.annotation.I18nBasename;
52 import info.magnolia.module.blossom.annotation.InitSaveHandler;
53 import info.magnolia.module.blossom.annotation.TabFactory;
54 import info.magnolia.module.blossom.annotation.TabOrder;
55 import info.magnolia.module.blossom.annotation.TabValidator;
56
57
58
59
60
61
62 public class DialogDescriptionBuilder {
63
64 private final Logger logger = LoggerFactory.getLogger(getClass());
65
66 private DialogCreator dialogCreator;
67
68 public void setDialogCreator(DialogCreator dialogCreator) {
69 this.dialogCreator = dialogCreator;
70 }
71
72 public DialogCreator getDialogCreator() {
73 if (dialogCreator == null) {
74 dialogCreator = new DefaultDialogCreator();
75 }
76 return dialogCreator;
77 }
78
79 public BlossomDialogDescription buildDescription(Object factoryObject) {
80 return buildDescription(factoryObject, null);
81 }
82
83 public List<BlossomDialogDescription> buildDescriptions(final Object handler) {
84
85 final List<Method> factoryMethods = new ArrayList<Method>();
86
87 final Class<?> handlerClass = AopUtils.getTargetClass(handler);
88 ReflectionUtils.doWithMethods(handlerClass, new ReflectionUtils.MethodCallback() {
89
90 @Override
91 public void doWith(Method method) {
92 DialogFactory dialogFactory = method.getAnnotation(DialogFactory.class);
93 if (dialogFactory != null && method.equals(ClassUtils.getMostSpecificMethod(method, handlerClass))) {
94 if (Modifier.isStatic(method.getModifiers())) {
95 throw new IllegalStateException("DialogFactory annotation is not supported on static methods");
96 }
97 factoryMethods.add(method);
98 }
99 }
100 });
101
102 List<BlossomDialogDescription> descriptions = new ArrayList<BlossomDialogDescription>();
103
104 for (Method method : factoryMethods) {
105 descriptions.add(buildDescription(handler, method));
106 }
107
108 return descriptions;
109 }
110
111 public BlossomDialogDescription buildDescription(Object factoryObject, Method factoryMethod) {
112 DialogFactory annotation = findAnnotation(DialogFactory.class, factoryObject, factoryMethod);
113 return buildDescription(annotation.value(), annotation.label(), factoryObject, factoryMethod);
114 }
115
116 public BlossomDialogDescription buildDescription(String name, String label, Object factoryObject) {
117 return buildDescription(name, label, factoryObject, null);
118 }
119
120 protected BlossomDialogDescription buildDescription(String id, String label, Object factoryObject, Method factoryMethod) {
121 TabOrder tabOrder = findAnnotation(TabOrder.class, factoryObject, factoryMethod);
122 I18nBasename i18nBasename = findAnnotation(I18nBasename.class, factoryObject, factoryMethod);
123 final DialogFactoryMetaData factoryMetaData = new DialogFactoryMetaData();
124 factoryMetaData.setLabel(label);
125 factoryMetaData.setI18nBasename(i18nBasename != null ? i18nBasename.value() : null);
126 factoryMetaData.setFactoryObject(factoryObject);
127 factoryMetaData.setFactoryMethod(factoryMethod);
128 factoryMetaData.setTabOrder(tabOrder != null ? tabOrder.value() : null);
129 factoryMetaData.setInitSaveHandlerMethod(findInitSaveHandlerMethod(factoryObject));
130
131 final Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
132
133 ReflectionUtils.doWithMethods(factoryClass, new ReflectionUtils.MethodCallback() {
134
135 @Override
136 public void doWith(Method method) {
137 if (method.isAnnotationPresent(TabFactory.class) && method.equals(ClassUtils.getMostSpecificMethod(method, factoryClass))) {
138 if (Modifier.isStatic(method.getModifiers())) {
139 throw new IllegalStateException("TabFactory annotation is not supported on static methods");
140 }
141 factoryMetaData.addTabFactory(method);
142 }
143 if (method.isAnnotationPresent(TabValidator.class) && method.equals(ClassUtils.getMostSpecificMethod(method, factoryClass))) {
144 if (Modifier.isStatic(method.getModifiers())) {
145 throw new IllegalStateException("TabValidator annotation is not supported on static methods");
146 }
147 factoryMetaData.addTabValidator(method);
148 }
149 if (method.isAnnotationPresent(DialogValidator.class) && method.equals(ClassUtils.getMostSpecificMethod(method, factoryClass))) {
150 if (Modifier.isStatic(method.getModifiers())) {
151 throw new IllegalStateException("DialogValidator annotation is not supported on static methods");
152 }
153 factoryMetaData.addDialogValidator(method);
154 }
155 }
156 });
157
158 BlossomDialogDescription dialogDescription = new BlossomDialogDescription();
159 dialogDescription.setId(id);
160 dialogDescription.setFactoryMetaData(factoryMetaData);
161 dialogDescription.setDialogClass(BlossomConfiguredDialog.class.getName());
162 dialogDescription.setDialogCreator(getDialogCreator());
163
164 return dialogDescription;
165 }
166
167 protected <T extends Annotation> T findAnnotation(Class<T> annotationClass, Object factoryObject, Method factoryMethod) {
168 if (factoryMethod != null) {
169 return factoryMethod.getAnnotation(annotationClass);
170 }
171 Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
172 return factoryClass.getAnnotation(annotationClass);
173 }
174
175 protected Method findInitSaveHandlerMethod(final Object factoryObject) {
176
177 final Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
178
179 final List<Method> matchingMethods = new ArrayList<Method>();
180
181
182
183 Class<?> clazz = factoryObject.getClass();
184 while (matchingMethods.isEmpty() && clazz != null) {
185 Method[] methods = clazz.getDeclaredMethods();
186 for (final Method method : methods) {
187
188
189 if (!method.isAnnotationPresent(InitSaveHandler.class)) {
190 continue;
191 }
192
193
194 if (!method.equals(ClassUtils.getMostSpecificMethod(method, factoryClass))) {
195 continue;
196 }
197
198 if (!method.getReturnType().equals(SaveHandler.class)) {
199 if (logger.isDebugEnabled()) {
200 logger.debug("Method annotated with @InitSaveHandler has wrong return type [" + method.getClass() + "] should be SaveHandler.");
201 }
202 continue;
203 }
204
205 matchingMethods.add(method);
206 }
207 clazz = clazz.getSuperclass();
208 }
209
210 if (!matchingMethods.isEmpty()) {
211 if (matchingMethods.size() == 1) {
212 return matchingMethods.get(0);
213 } else {
214 logger.error("Multiple @InitSaveHandler annotated methods found in [" + factoryObject.getClass() + "]");
215 }
216 }
217
218 return null;
219 }
220 }