1 package com.atlassian.maven.plugins.amps.codegen.annotations.asm;
2
3 import java.io.InputStream;
4 import java.lang.reflect.Constructor;
5
6 import com.atlassian.maven.plugins.amps.codegen.annotations.ModuleCreatorClass;
7 import com.atlassian.maven.plugins.amps.codegen.prompter.AbstractModulePrompter;
8 import com.atlassian.maven.plugins.amps.codegen.prompter.PluginModulePrompter;
9 import com.atlassian.maven.plugins.amps.codegen.prompter.PluginModulePrompterRegistry;
10 import com.atlassian.plugins.codegen.annotations.asm.AbstractAnnotationParser;
11
12 import org.apache.commons.io.IOUtils;
13 import org.apache.commons.lang.ArrayUtils;
14 import org.apache.maven.plugin.logging.Log;
15 import org.codehaus.plexus.components.interactivity.Prompter;
16 import org.objectweb.asm.*;
17 import org.objectweb.asm.commons.EmptyVisitor;
18
19
20
21
22 public class ModulePrompterAnnotationParser extends AbstractAnnotationParser
23 {
24 public static final String PROMPTER_PACKAGE = "com.atlassian.maven.plugins.amps.codegen.prompter";
25 private Log log;
26
27 private PluginModulePrompterRegistry pluginModulePrompterRegistry;
28 private Prompter mavenPrompter;
29
30 public ModulePrompterAnnotationParser(PluginModulePrompterRegistry pluginModulePrompterRegistry)
31 {
32 this.pluginModulePrompterRegistry = pluginModulePrompterRegistry;
33 }
34
35 public void parse() throws Exception
36 {
37 ClassLoader oldLoader = Thread.currentThread()
38 .getContextClassLoader();
39 Thread.currentThread()
40 .setContextClassLoader(getClass().getClassLoader());
41 parse(PROMPTER_PACKAGE, new PropmpterClassVisitor());
42 Thread.currentThread()
43 .setContextClassLoader(oldLoader);
44 }
45
46 public void parse(String basePackage) throws Exception
47 {
48 ClassLoader oldLoader = Thread.currentThread()
49 .getContextClassLoader();
50 Thread.currentThread()
51 .setContextClassLoader(getClass().getClassLoader());
52 parse(basePackage, new PropmpterClassVisitor());
53 Thread.currentThread()
54 .setContextClassLoader(oldLoader);
55 }
56
57 public class PropmpterClassVisitor extends EmptyVisitor
58 {
59
60 private String visitedClassname;
61 private boolean isModulePrompter;
62
63 @Override
64 public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)
65 {
66 this.visitedClassname = normalize(name);
67 String iface = PluginModulePrompter.class.getName()
68 .replace('.', '/');
69 this.isModulePrompter = ArrayUtils.contains(interfaces, iface);
70 if (!isModulePrompter)
71 {
72 this.isModulePrompter = superHasInterface(superName, iface);
73 }
74
75 Class modulePrompterClass = null;
76 try
77 {
78 modulePrompterClass = Class.forName(visitedClassname);
79 } catch (ClassNotFoundException e)
80 {
81
82 }
83
84 if (isModulePrompter && !AbstractModulePrompter.class.isAssignableFrom(modulePrompterClass))
85 {
86 isModulePrompter = false;
87 if (null != log)
88 {
89 log.warn(visitedClassname + " MUST extend " + AbstractModulePrompter.class.getName() + ". NOT REGISTERED");
90 }
91 }
92 }
93
94 private boolean superHasInterface(String superName, String interfaceName)
95 {
96 boolean hasInterface = false;
97
98 if (normalize(superName).equals("java.lang.Object"))
99 {
100 return hasInterface;
101 }
102
103 ClassLoader classLoader = Thread.currentThread()
104 .getContextClassLoader();
105 String path = superName.replace('.', '/');
106
107 InputStream is = null;
108 try
109 {
110 is = classLoader.getResourceAsStream(path + ".class");
111 if (null != is)
112 {
113
114 ClassReader classReader = new ClassReader(is);
115 hasInterface = ArrayUtils.contains(classReader.getInterfaces(), interfaceName);
116 if (!hasInterface)
117 {
118 hasInterface = superHasInterface(classReader.getSuperName(), interfaceName);
119 }
120 }
121 } catch (Exception e)
122 {
123
124 } finally
125 {
126 IOUtils.closeQuietly(is);
127 }
128
129 return hasInterface;
130 }
131
132 @Override
133 public AnnotationVisitor visitAnnotation(String annotationName, boolean isVisible)
134 {
135 String normalizedName = normalize(annotationName);
136
137 if (isModulePrompter && ModuleCreatorClass.class.getName()
138 .equals(normalizedName))
139 {
140 return new ModuleCreatorClassAnnotationVisitor(normalizedName);
141 }
142
143 return null;
144 }
145
146
147 @Override
148 public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings)
149 {
150 return null;
151 }
152
153 @Override
154 public FieldVisitor visitField(int i, String s, String s1, String s2, Object o)
155 {
156 return null;
157 }
158
159 private class ModuleCreatorClassAnnotationVisitor extends EmptyVisitor
160 {
161
162 private String annotationName;
163
164 private ModuleCreatorClassAnnotationVisitor(String annotationName)
165 {
166 this.annotationName = annotationName;
167 }
168
169 @Override
170 public void visit(String name, Object value)
171 {
172 super.visit(name, value);
173 Type creatorType = (Type) value;
174 String normalizedCreatorName = normalize(creatorType.getClassName());
175
176 try
177 {
178 Class creatorClass = Class.forName(normalizedCreatorName);
179 Class modulePrompterClass = Class.forName(visitedClassname);
180 Class[] argTypes = new Class[]{Prompter.class};
181 Object[] args = new Object[]{mavenPrompter};
182
183 Constructor prompterConstructor = modulePrompterClass.getConstructor(argTypes);
184 if (null != prompterConstructor)
185 {
186 PluginModulePrompter modulePrompter = (PluginModulePrompter) prompterConstructor.newInstance(args);
187 pluginModulePrompterRegistry.registerModulePrompter(creatorClass, modulePrompter);
188 }
189
190 } catch (Exception e)
191 {
192 e.printStackTrace();
193 }
194 }
195
196 @Override
197 public void visitEnd()
198 {
199 super.visitEnd();
200 }
201 }
202 }
203
204 public Prompter getMavenPrompter()
205 {
206 return mavenPrompter;
207 }
208
209 public void setMavenPrompter(Prompter mavenPrompter)
210 {
211 this.mavenPrompter = mavenPrompter;
212 }
213
214 public Log getLog()
215 {
216 return log;
217 }
218
219 public void setLog(Log log)
220 {
221 this.log = log;
222 }
223 }