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 DefaultDialogCreatortor.html#DefaultDialogCreator">DefaultDialogCreator defaultDialogCreator = new DefaultDialogCreator();
73 try {
74 defaultDialogCreator.afterPropertiesSet();
75 } catch (Exception e) {
76 throw new RuntimeException("Could not create DefaultDialogCreator", e);
77 }
78 dialogCreator = defaultDialogCreator;
79 }
80 return dialogCreator;
81 }
82
83 public BlossomDialogDescription buildDescription(Object factoryObject) {
84 return buildDescription(factoryObject, null);
85 }
86
87 public List<BlossomDialogDescription> buildDescriptions(final Object handler) {
88
89 final List<Method> factoryMethods = new ArrayList<Method>();
90
91 final Class<?> handlerClass = AopUtils.getTargetClass(handler);
92 ReflectionUtils.doWithMethods(handlerClass, new ReflectionUtils.MethodCallback() {
93
94 @Override
95 public void doWith(Method method) {
96 DialogFactory dialogFactory = method.getAnnotation(DialogFactory.class);
97 if (dialogFactory != null && method.equals(ClassUtils.getMostSpecificMethod(method, handlerClass))) {
98 if (Modifier.isStatic(method.getModifiers())) {
99 throw new IllegalStateException("DialogFactory annotation is not supported on static methods");
100 }
101 factoryMethods.add(method);
102 }
103 }
104 });
105
106 List<BlossomDialogDescription> descriptions = new ArrayList<BlossomDialogDescription>();
107
108 for (Method method : factoryMethods) {
109 descriptions.add(buildDescription(handler, method));
110 }
111
112 return descriptions;
113 }
114
115 public BlossomDialogDescription buildDescription(Object factoryObject, Method factoryMethod) {
116 DialogFactory annotation = findAnnotation(DialogFactory.class, factoryObject, factoryMethod);
117 return buildDescription(annotation.value(), annotation.label(), factoryObject, factoryMethod);
118 }
119
120 public BlossomDialogDescription buildDescription(String id, String label, Object factoryObject) {
121 return buildDescription(id, label, factoryObject, null);
122 }
123
124 protected BlossomDialogDescription buildDescription(String id, String label, Object factoryObject, Method factoryMethod) {
125 BlossomDialogDescriptioniption.html#BlossomDialogDescription">BlossomDialogDescription dialogDescription = new BlossomDialogDescription();
126 dialogDescription.setId(id);
127 dialogDescription.setFactoryMetaData(buildFactoryMetaData(label, factoryObject, factoryMethod));
128 dialogDescription.setDialogCreator(getDialogCreator());
129 return dialogDescription;
130 }
131
132 protected DialogFactoryMetaData buildFactoryMetaData(String label, Object factoryObject, Method factoryMethod) {
133
134 DialogFactoryMetaDataMetaData.html#DialogFactoryMetaData">DialogFactoryMetaData factoryMetaData = new DialogFactoryMetaData();
135 factoryMetaData.setLabel(label);
136 factoryMetaData.setFactoryObject(factoryObject);
137 factoryMetaData.setFactoryMethod(factoryMethod);
138
139 TabOrder tabOrder = findAnnotation(TabOrder.class, factoryObject, factoryMethod);
140 I18nBasename i18nBasename = findAnnotation(I18nBasename.class, factoryObject, factoryMethod);
141
142 factoryMetaData.setTabOrder(tabOrder != null ? tabOrder.value() : null);
143 factoryMetaData.setI18nBasename(i18nBasename != null ? i18nBasename.value() : null);
144
145 if (factoryMethod == null) {
146
147 Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
148
149 List<Class<?>> classHierarchy = getClassHierarchyInTopToBottomOrder(factoryClass);
150
151 List<Method> methodsAdded = new ArrayList<Method>();
152
153 for (Class<?> clazz : classHierarchy) {
154
155 DialogFactoryClassMetaDatassMetaData.html#DialogFactoryClassMetaData">DialogFactoryClassMetaData classMetaData = new DialogFactoryClassMetaData();
156 classMetaData.setClazz(clazz);
157
158 for (Method method : clazz.getDeclaredMethods()) {
159
160 if (method.isAnnotationPresent(TabFactory.class) && method.isAnnotationPresent(PostCreate.class)) {
161 throw new IllegalStateException("TabFactory and PostCreate annotations cannot both be used on the same method");
162 }
163 if (method.isAnnotationPresent(TabFactory.class)) {
164 if (Modifier.isStatic(method.getModifiers())) {
165 throw new IllegalStateException("TabFactory annotation is not supported on static methods");
166 }
167 Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, factoryClass);
168 if (mostSpecificMethod.isAnnotationPresent(TabFactory.class) && !methodsAdded.contains(mostSpecificMethod)) {
169 classMetaData.addTabFactory(mostSpecificMethod);
170 methodsAdded.add(mostSpecificMethod);
171 }
172 }
173 if (method.isAnnotationPresent(PostCreate.class)) {
174 if (Modifier.isStatic(method.getModifiers())) {
175 throw new IllegalStateException("PostCreate annotation is not supported on static methods");
176 }
177 Method mostSpecificMethod = ClassUtils.getMostSpecificMethod(method, factoryClass);
178 if (mostSpecificMethod.isAnnotationPresent(PostCreate.class) && !methodsAdded.contains(mostSpecificMethod)) {
179 PostCreate annotation = mostSpecificMethod.getAnnotation(PostCreate.class);
180 if (annotation.value() == PostCreate.Phase.AFTER_TAB_FACTORIES_IN_SAME_CLASS) {
181 classMetaData.addPostCreateCallback(mostSpecificMethod);
182 } else if (annotation.value() == PostCreate.Phase.AFTER_SUB_CLASSES) {
183 factoryMetaData.addPostCreateCallback(mostSpecificMethod);
184 }
185 methodsAdded.add(mostSpecificMethod);
186 }
187 }
188 }
189
190 if (!classMetaData.isEmpty()) {
191 factoryMetaData.addClassMetaData(classMetaData);
192 }
193 }
194 }
195
196 return factoryMetaData;
197 }
198
199 protected <T extends Annotation> T findAnnotation(Class<T> annotationClass, Object factoryObject, Method factoryMethod) {
200 if (factoryMethod != null) {
201 return factoryMethod.getAnnotation(annotationClass);
202 }
203 Class<?> factoryClass = AopUtils.getTargetClass(factoryObject);
204 return factoryClass.getAnnotation(annotationClass);
205 }
206
207 private List<Class<?>> getClassHierarchyInTopToBottomOrder(Class<?> factoryClass) {
208 List<Class<?>> hierarchy = new ArrayList<Class<?>>();
209 while (factoryClass != null) {
210 hierarchy.add(factoryClass);
211 factoryClass = factoryClass.getSuperclass();
212 }
213 Collections.reverse(hierarchy);
214 return hierarchy;
215 }
216 }