1   package com.atlassian.plugins.codegen.annotations.asm;
2   
3   import java.io.InputStream;
4   import java.util.HashMap;
5   import java.util.Map;
6   
7   import com.atlassian.plugins.codegen.annotations.*;
8   import com.atlassian.plugins.codegen.modules.PluginModuleCreator;
9   import com.atlassian.plugins.codegen.modules.PluginModuleCreatorRegistry;
10  
11  import org.apache.commons.io.IOUtils;
12  import org.apache.commons.lang.ArrayUtils;
13  import org.apache.commons.lang.StringUtils;
14  import org.objectweb.asm.AnnotationVisitor;
15  import org.objectweb.asm.ClassReader;
16  import org.objectweb.asm.FieldVisitor;
17  import org.objectweb.asm.MethodVisitor;
18  import org.objectweb.asm.commons.EmptyVisitor;
19  
20  /**
21   * @since 3.6
22   */
23  public class ModuleCreatorAnnotationParser extends AbstractAnnotationParser
24  {
25  
26      public static final String MODULE_PACKAGE = "com.atlassian.plugins.codegen.modules";
27      protected static final Map<String, String> annotationProductMap = new HashMap<String, String>();
28  
29      static
30      {
31          annotationProductMap.put(JiraPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.JIRA);
32          annotationProductMap.put(ConfluencePluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.CONFLUENCE);
33          annotationProductMap.put(BambooPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.BAMBOO);
34          annotationProductMap.put(CrowdPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.CROWD);
35          annotationProductMap.put(FeCruPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.FECRU);
36          annotationProductMap.put(StashPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.STASH);
37          annotationProductMap.put(RefAppPluginModuleCreator.class.getName(), PluginModuleCreatorRegistry.REFAPP);
38      }
39  
40      private final PluginModuleCreatorRegistry pluginModuleCreatorRegistry;
41  
42      public ModuleCreatorAnnotationParser(PluginModuleCreatorRegistry pluginModuleCreatorRegistry)
43      {
44          super();
45          this.pluginModuleCreatorRegistry = pluginModuleCreatorRegistry;
46      }
47  
48      public void parse() throws Exception
49      {
50          ClassLoader oldLoader = Thread.currentThread()
51                  .getContextClassLoader();
52          Thread.currentThread()
53                  .setContextClassLoader(getClass().getClassLoader());
54          parse(MODULE_PACKAGE, new ModuleClassVisitor());
55          Thread.currentThread()
56                  .setContextClassLoader(oldLoader);
57      }
58  
59      public void parse(String basePackage) throws Exception
60      {
61          ClassLoader oldLoader = Thread.currentThread()
62                  .getContextClassLoader();
63          Thread.currentThread()
64                  .setContextClassLoader(getClass().getClassLoader());
65          parse(basePackage, new ModuleClassVisitor());
66          Thread.currentThread()
67                  .setContextClassLoader(oldLoader);
68      }
69  
70      public class ModuleClassVisitor extends EmptyVisitor
71      {
72  
73          private String visitedClassname;
74          private boolean isModuleCreator;
75  
76          @Override
77          public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)
78          {
79              this.visitedClassname = normalize(name);
80              String iface = PluginModuleCreator.class.getName()
81                      .replace('.', '/');
82              this.isModuleCreator = ArrayUtils.contains(interfaces, iface);
83              if (!isModuleCreator)
84              {
85                  this.isModuleCreator = superHasInterface(superName, iface);
86              }
87          }
88  
89          private boolean superHasInterface(String superName, String interfaceName)
90          {
91              boolean hasInterface = false;
92  
93              if (normalize(superName).equals("java.lang.Object"))
94              {
95                  return hasInterface;
96              }
97  
98              ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
99              String path = superName.replace('.', '/');
100 
101             InputStream is = null;
102             try
103             {
104                 is = classLoader.getResourceAsStream(path + ".class");
105                 if (null != is)
106                 {
107 
108                     ClassReader classReader = new ClassReader(is);
109                     hasInterface = ArrayUtils.contains(classReader.getInterfaces(), interfaceName);
110                     if (!hasInterface)
111                     {
112                         hasInterface = superHasInterface(classReader.getSuperName(), interfaceName);
113                     }
114                 }
115             } catch (Exception e)
116             {
117                 //don't care
118             } finally
119             {
120                 IOUtils.closeQuietly(is);
121             }
122 
123             return hasInterface;
124         }
125 
126         @Override
127         public AnnotationVisitor visitAnnotation(String annotationName, boolean isVisible)
128         {
129             String normalizedName = normalize(annotationName);
130 
131             if (isModuleCreator && annotationProductMap.containsKey(normalizedName))
132             {
133                 return new ProductCreatorAnnotationVisitor(normalizedName);
134             }
135 
136             return null;
137         }
138 
139 
140         @Override
141         public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings)
142         {
143             return null;
144         }
145 
146         @Override
147         public FieldVisitor visitField(int i, String s, String s1, String s2, Object o)
148         {
149             return null;
150         }
151 
152         private class ProductCreatorAnnotationVisitor extends EmptyVisitor
153         {
154 
155             private String annotationName;
156 
157             private ProductCreatorAnnotationVisitor(String annotationName)
158             {
159                 this.annotationName = annotationName;
160             }
161 
162             @Override
163             public void visitEnd()
164             {
165 
166                 super.visitEnd();
167 
168                 String productId = annotationProductMap.get(annotationName);
169                 if (StringUtils.isNotBlank(productId))
170                 {
171                     try
172                     {
173                         PluginModuleCreator creator = (PluginModuleCreator) Class.forName(visitedClassname)
174                                 .newInstance();
175                         pluginModuleCreatorRegistry.registerModuleCreator(productId, creator);
176                     } catch (Exception e)
177                     {
178                         e.printStackTrace();
179                         //just don't register
180                     }
181                 }
182             }
183         }
184     }
185 }