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.Collections;
41 import java.util.List;
42
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.aop.support.AopUtils;
46 import org.springframework.util.ClassUtils;
47 import org.springframework.util.ReflectionUtils;
48
49 import info.magnolia.module.blossom.annotation.DialogFactory;
50 import info.magnolia.module.blossom.annotation.I18nBasename;
51 import info.magnolia.module.blossom.annotation.PostCreate;
52 import info.magnolia.module.blossom.annotation.TabFactory;
53 import info.magnolia.module.blossom.annotation.TabOrder;
54
55
56
57
58
59
60 public class DialogDescriptionBuilder {
61
62 private final Logger logger = LoggerFactory.getLogger(getClass());
63
64 private DialogCreator dialogCreator;
65
66 public void setDialogCreator(DialogCreator dialogCreator) {
67 this.dialogCreator = dialogCreator;
68 }
69
70 public DialogCreator getDialogCreator() {
71 if (dialogCreator == null) {
72 dialogCreator = new DefaultDialogCreator();
73 }
74 return dialogCreator;
75 }
76
77 public BlossomDialogDescription buildDescription(Object factoryObject) {
78 return buildDescription(factoryObject, null);
79 }
80
81 public List<BlossomDialogDescription> buildDescriptions(final Object handler) {
82
83 final List<Method> factoryMethods = new ArrayList<Method>();
84
85 final Class<?> handlerClass = AopUtils.getTargetClass(handler);
86 ReflectionUtils.doWithMethods(handlerClass, new ReflectionUtils.MethodCallback() {
87
88 @Override
89 public void doWith(Method method) {
90 DialogFactory dialogFactory = method.getAnnotation(DialogFactory.class);
91 if (dialogFactory != null && method.equals(ClassUtils.getMostSpecificMethod(method, handlerClass))) {
92 if (Modifier.isStatic(method.getModifiers())) {
93 throw new IllegalStateException("DialogFactory annotation is not supported on static methods");
94 }
95 factoryMethods.add(method);
96 }
97 }
98 });
99
100 List<BlossomDialogDescription> descriptions = new ArrayList<BlossomDialogDescription>();
101
102 for (Method method : factoryMethods) {
103 descriptions.add(buildDescription(handler, method));
104 }
105
106 return descriptions;
107 }
108
109 public BlossomDialogDescription buildDescription(Object factoryObject, Method factoryMethod) {
110 DialogFactory annotation = findAnnotation(DialogFactory.class, factoryObject, factoryMethod);
111 return buildDescription(annotation.value(), annotation.label(), factoryObject, factoryMethod);
112 }
113
114 public BlossomDialogDescription buildDescription(String id, String label, Object factoryObject) {
115 return buildDescription(id, label, factoryObject, null);
116 }
117
118 protected BlossomDialogDescription buildDescription(String id, String label, Object factoryObject, Method factoryMethod) {
119 BlossomDialogDescription dialogDescription = new BlossomDialogDescription();
120 dialogDescription.setId(id);
121 dialogDescription.setFactoryMetaData(buildFactoryMetaData(label, factoryObject, factoryMethod));
122 dialogDescription.setDialogCreator(getDialogCreator());
123 return dialogDescription;
124 }
125
126 protected DialogFactoryMetaData buildFactoryMetaData(String label, Object factoryObject, Method factoryMethod) {
127
128 DialogFactoryMetaData factoryMetaData = new DialogFactoryMetaData();
129 factoryMetaData.setLabel(label);
130 factoryMetaData.setFactoryObject(factoryObject);
131 factoryMetaData.setFactoryMethod(factoryMethod);
132
133 TabOrder tabOrder = findAnnotation(TabOrder.class, factoryObject, factoryMethod);
134 I18nBasename i18nBasename = findAnnotation(I18nBasename.class, factoryObject, factoryMethod);
135
136 factoryMetaData.setTabOrder(tabOrder != null ? tabOrder.value() : null);
137 factoryMetaData.setI18nBasename(i18nBasename != null ? i18nBasename.value() : null);
138
139 if (factoryMethod == null) {
140
141 Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
142
143 List<Class<?>> classHierarchy = getClassHierarchyInTopToBottomOrder(factoryClass);
144
145 List<Method> methodsAdded = new ArrayList<Method>();
146
147 for (Class<?> clazz : classHierarchy) {
148
149 DialogFactoryClassMetaData classMetaData = new DialogFactoryClassMetaData();
150 classMetaData.setClazz(clazz);
151
152 for (Method method : clazz.getDeclaredMethods()) {
153
154 if (method.isAnnotationPresent(TabFactory.class) && method.isAnnotationPresent(PostCreate.class)) {
155 throw new IllegalStateException("TabFactory and PostCreate annotations cannot both be used on the same method");
156 }
157 if (method.isAnnotationPresent(TabFactory.class)) {
158 if (Modifier.isStatic(method.getModifiers())) {
159 throw new IllegalStateException("TabFactory annotation is not supported on static methods");
160 }
161 Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, factoryClass);
162 if (mostSpecificMethod.isAnnotationPresent(TabFactory.class) && !methodsAdded.contains(mostSpecificMethod)) {
163 classMetaData.addTabFactory(mostSpecificMethod);
164 methodsAdded.add(mostSpecificMethod);
165 }
166 }
167 if (method.isAnnotationPresent(PostCreate.class)) {
168 if (Modifier.isStatic(method.getModifiers())) {
169 throw new IllegalStateException("PostCreate annotation is not supported on static methods");
170 }
171 Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, factoryClass);
172 if (mostSpecificMethod.isAnnotationPresent(PostCreate.class) && !methodsAdded.contains(mostSpecificMethod)) {
173 PostCreate annotation = mostSpecificMethod.getAnnotation(PostCreate.class);
174 if (annotation.value() == PostCreate.Phase.AFTER_TAB_FACTORIES_IN_SAME_CLASS) {
175 classMetaData.addPostCreateCallback(mostSpecificMethod);
176 } else if (annotation.value() == PostCreate.Phase.AFTER_SUB_CLASSES) {
177 factoryMetaData.addPostCreateCallback(mostSpecificMethod);
178 }
179 methodsAdded.add(mostSpecificMethod);
180 }
181 }
182 }
183
184 if (!classMetaData.isEmpty()) {
185 factoryMetaData.addClassMetaData(classMetaData);
186 }
187 }
188 }
189
190 return factoryMetaData;
191 }
192
193 protected <T extends Annotation> T findAnnotation(Class<T> annotationClass, Object factoryObject, Method factoryMethod) {
194 if (factoryMethod != null) {
195 return factoryMethod.getAnnotation(annotationClass);
196 }
197 Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
198 return factoryClass.getAnnotation(annotationClass);
199 }
200
201 private List<Class<?>> getClassHierarchyInTopToBottomOrder(Class<?> factoryClass) {
202 List<Class<?>> hierarchy = new ArrayList<Class<?>>();
203 while (factoryClass != null) {
204 hierarchy.add(factoryClass);
205 factoryClass = factoryClass.getSuperclass();
206 }
207 Collections.reverse(hierarchy);
208 return hierarchy;
209 }
210 }