1 package com.atlassian.plugins.codegen.annotations.asm;
2
3 import java.io.InputStream;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import com.atlassian.plugins.codegen.annotations.*;
10 import com.atlassian.plugins.codegen.modules.PluginModuleCreator;
11 import com.atlassian.plugins.codegen.modules.PluginModuleCreatorRegistry;
12
13 import org.apache.commons.io.IOUtils;
14 import org.apache.commons.lang.ArrayUtils;
15 import org.apache.commons.lang.StringUtils;
16 import org.objectweb.asm.AnnotationVisitor;
17 import org.objectweb.asm.ClassReader;
18 import org.objectweb.asm.FieldVisitor;
19 import org.objectweb.asm.MethodVisitor;
20 import org.objectweb.asm.commons.EmptyVisitor;
21
22
23
24
25 public class ModuleCreatorAnnotationParser extends AbstractAnnotationParser
26 {
27
28 public static final String MODULE_PACKAGE = "com.atlassian.plugins.codegen.modules";
29 protected static final Map<String, String> annotationProductMap = new HashMap<String, String>();
30
31 static
32 {
33 annotationProductMap.put(JiraPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.JIRA);
34 annotationProductMap.put(ConfluencePluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.CONFLUENCE);
35 annotationProductMap.put(BambooPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.BAMBOO);
36 annotationProductMap.put(CrowdPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.CROWD);
37 annotationProductMap.put(FeCruPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.FECRU);
38 annotationProductMap.put(RefAppPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.REFAPP);
39 }
40
41 private final PluginModuleCreatorRegistry pluginModuleCreatorRegistry;
42
43 public ModuleCreatorAnnotationParser(PluginModuleCreatorRegistry pluginModuleCreatorRegistry)
44 {
45 super();
46 this.pluginModuleCreatorRegistry = pluginModuleCreatorRegistry;
47 }
48
49 public void parse() throws Exception
50 {
51 ClassLoader oldLoader = Thread.currentThread()
52 .getContextClassLoader();
53 Thread.currentThread()
54 .setContextClassLoader(getClass().getClassLoader());
55 parse(MODULE_PACKAGE, new ModuleClassVisitor());
56 Thread.currentThread()
57 .setContextClassLoader(oldLoader);
58 }
59
60 public void parse(String basePackage) throws Exception
61 {
62 ClassLoader oldLoader = Thread.currentThread()
63 .getContextClassLoader();
64 Thread.currentThread()
65 .setContextClassLoader(getClass().getClassLoader());
66 parse(basePackage, new ModuleClassVisitor());
67 Thread.currentThread()
68 .setContextClassLoader(oldLoader);
69 }
70
71 public class ModuleClassVisitor extends EmptyVisitor
72 {
73
74 private String visitedClassname;
75 private boolean isModuleCreator;
76
77 @Override
78 public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)
79 {
80 this.visitedClassname = normalize(name);
81 String iface = PluginModuleCreator.class.getName()
82 .replace('.', '/');
83 this.isModuleCreator = ArrayUtils.contains(interfaces, iface);
84 if (!isModuleCreator)
85 {
86 this.isModuleCreator = superHasInterface(superName, iface);
87 }
88 }
89
90 private boolean superHasInterface(String superName, String interfaceName)
91 {
92 boolean hasInterface = false;
93
94 if (normalize(superName).equals("java.lang.Object"))
95 {
96 return hasInterface;
97 }
98
99 ClassLoader classLoader = Thread.currentThread()
100 .getContextClassLoader();
101 String path = superName.replace('.', '/');
102
103 InputStream is = null;
104 try
105 {
106 is = classLoader.getResourceAsStream(path + ".class");
107 if (null != is)
108 {
109
110 ClassReader classReader = new ClassReader(is);
111 hasInterface = ArrayUtils.contains(classReader.getInterfaces(), interfaceName);
112 if (!hasInterface)
113 {
114 hasInterface = superHasInterface(classReader.getSuperName(), interfaceName);
115 }
116 }
117 } catch (Exception e)
118 {
119
120 } finally
121 {
122 IOUtils.closeQuietly(is);
123 }
124
125 return hasInterface;
126 }
127
128 @Override
129 public AnnotationVisitor visitAnnotation(String annotationName, boolean isVisible)
130 {
131 String normalizedName = normalize(annotationName);
132
133 if (isModuleCreator && annotationProductMap.containsKey(normalizedName))
134 {
135 return new ProductCreatorAnnotationVisitor(normalizedName);
136 }
137
138 if (isModuleCreator && (Dependencies.class.getName()
139 .equals(normalizedName) || Dependency.class.equals(normalizedName)))
140 {
141 return new DependenciesAnnotationVisitor(normalizedName);
142 }
143
144 return null;
145 }
146
147
148 @Override
149 public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings)
150 {
151 return null;
152 }
153
154 @Override
155 public FieldVisitor visitField(int i, String s, String s1, String s2, Object o)
156 {
157 return null;
158 }
159
160 private class ProductCreatorAnnotationVisitor extends EmptyVisitor
161 {
162
163 private String annotationName;
164
165 private ProductCreatorAnnotationVisitor(String annotationName)
166 {
167 this.annotationName = annotationName;
168 }
169
170 @Override
171 public void visitEnd()
172 {
173
174 super.visitEnd();
175
176 String productId = annotationProductMap.get(annotationName);
177 if (StringUtils.isNotBlank(productId))
178 {
179 try
180 {
181 PluginModuleCreator creator = (PluginModuleCreator) Class.forName(visitedClassname)
182 .newInstance();
183 pluginModuleCreatorRegistry.registerModuleCreator(productId, creator);
184 } catch (Exception e)
185 {
186 e.printStackTrace();
187
188 }
189 }
190 }
191
192 }
193
194 private class DependenciesAnnotationVisitor extends EmptyVisitor
195 {
196
197 private String annotationName;
198 private List<DependencyDescriptor> dependencies;
199
200 private DependenciesAnnotationVisitor(String annotationName)
201 {
202 this.annotationName = annotationName;
203 this.dependencies = new ArrayList<DependencyDescriptor>();
204 }
205
206
207 @Override
208 public AnnotationVisitor visitAnnotation(String name, String annotationName)
209 {
210 String normalizedName = normalize(annotationName);
211 return new DependencyAnnotationVisitor(normalizedName, dependencies);
212 }
213
214 @Override
215 public void visitEnd()
216 {
217
218 super.visitEnd();
219
220 if (!dependencies.isEmpty())
221 {
222 try
223 {
224 Class creatorClass = Class.forName(visitedClassname);
225 pluginModuleCreatorRegistry.registerModuleCreatorDependencies(creatorClass, dependencies);
226 } catch (Exception e)
227 {
228 e.printStackTrace();
229
230 }
231 }
232 }
233
234 }
235
236 private class DependencyAnnotationVisitor extends EmptyVisitor
237 {
238 private String annotationName;
239 private List<DependencyDescriptor> dependencies;
240 private DependencyDescriptor descriptor;
241
242 private DependencyAnnotationVisitor(String annotationName, List<DependencyDescriptor> dependencies)
243 {
244 this.annotationName = annotationName;
245 this.dependencies = dependencies;
246 this.descriptor = new DependencyDescriptor();
247 }
248
249
250 @Override
251 public void visit(String name, Object value)
252 {
253 if (name.equals("groupId"))
254 {
255 descriptor.setGroupId((String) value);
256 } else if (name.equals("artifactId"))
257 {
258 descriptor.setArtifactId((String) value);
259 } else if (name.equals("version"))
260 {
261 descriptor.setVersion((String) value);
262 } else if (name.equals("scope"))
263 {
264 descriptor.setScope((String) value);
265 }
266 }
267
268 @Override
269 public void visitEnd()
270 {
271 super.visitEnd();
272 dependencies.add(descriptor);
273 }
274 }
275
276 }
277
278 }