1   package com.atlassian.maven.plugins.amps.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.asm.AbstractAnnotationParser;
8   import com.atlassian.plugins.codegen.modules.PluginModuleCreatorRegistry;
9   
10  import org.apache.commons.io.IOUtils;
11  import org.apache.commons.lang.ArrayUtils;
12  import org.apache.commons.lang.StringUtils;
13  import org.apache.maven.plugin.logging.Log;
14  import org.objectweb.asm.*;
15  import org.objectweb.asm.commons.EmptyVisitor;
16  
17  /**
18   * @since 3.5
19   */
20  public class ProductContextProviderLocator extends AbstractAnnotationParser
21  {
22      protected static final Map<String, String> productContextPackages = new HashMap<String, String>();
23  
24      static
25      {
26          productContextPackages.put(PluginModuleCreatorRegistry.JIRA, "com.atlassian.jira.plugin.webfragment.contextproviders");
27          productContextPackages.put(PluginModuleCreatorRegistry.CONFLUENCE, "com.atlassian.jira.plugin.webfragment.contextproviders");
28          productContextPackages.put(PluginModuleCreatorRegistry.BAMBOO, "com.atlassian.jira.plugin.webfragment.contextproviders");
29          productContextPackages.put(PluginModuleCreatorRegistry.CROWD, "com.atlassian.jira.plugin.webfragment.contextproviders");
30          productContextPackages.put(PluginModuleCreatorRegistry.FECRU, "com.atlassian.jira.plugin.webfragment.contextproviders");
31          productContextPackages.put(PluginModuleCreatorRegistry.REFAPP, "com.atlassian.jira.plugin.webfragment.contextproviders");
32      }
33  
34      private Log log;
35      private String productId;
36      private Map<String, String> contextRegistry;
37  
38      public ProductContextProviderLocator(String productId, Map<String, String> contextRegistry)
39      {
40          this.productId = productId;
41          this.contextRegistry = contextRegistry;
42      }
43  
44      public void parse() throws Exception
45      {
46          String basePackage = productContextPackages.get(productId);
47          if (StringUtils.isNotBlank(basePackage))
48          {
49              parse(basePackage, new ContextProviderClassVisitor());
50          }
51  
52      }
53  
54      public void parse(String basePackage) throws Exception
55      {
56          parse(basePackage, new ContextProviderClassVisitor());
57      }
58  
59      public class ContextProviderClassVisitor extends EmptyVisitor
60      {
61  
62          private String visitedClassname;
63          private boolean isContextProvider;
64  
65          @Override
66          public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)
67          {
68              this.visitedClassname = normalize(name);
69              String iface = "com/atlassian/plugin/web/ContextProvider";
70  
71              this.isContextProvider = false;
72              boolean isAbstract = ((access & Opcodes.ACC_ABSTRACT) > 0);
73  
74              if (!isAbstract)
75              {
76                  this.isContextProvider = ArrayUtils.contains(interfaces, iface);
77                  if (!isContextProvider)
78                  {
79                      this.isContextProvider = superHasInterface(superName, iface);
80                  }
81              }
82  
83              if (isContextProvider)
84              {
85                  String simpleName = StringUtils.substringAfterLast(visitedClassname, ".");
86                  contextRegistry.put(simpleName, visitedClassname);
87              }
88  
89          }
90  
91          private boolean superHasInterface(String superName, String interfaceName)
92          {
93              boolean hasInterface = false;
94  
95              if (normalize(superName).equals("java.lang.Object"))
96              {
97                  return hasInterface;
98              }
99  
100             ClassLoader classLoader = Thread.currentThread()
101                     .getContextClassLoader();
102             String path = superName.replace('.', '/');
103 
104             InputStream is = null;
105             try
106             {
107                 is = classLoader.getResourceAsStream(path + ".class");
108                 if (null != is)
109                 {
110 
111                     ClassReader classReader = new ClassReader(is);
112                     String[] interfaces = classReader.getInterfaces();
113                     hasInterface = ArrayUtils.contains(classReader.getInterfaces(), interfaceName);
114                     if (!hasInterface)
115                     {
116                         hasInterface = superHasInterface(classReader.getSuperName(), interfaceName);
117                     }
118                 }
119             } catch (Exception e)
120             {
121                 //don't care
122             } finally
123             {
124                 IOUtils.closeQuietly(is);
125             }
126 
127             return hasInterface;
128         }
129 
130         @Override
131         public AnnotationVisitor visitAnnotation(String annotationName, boolean isVisible)
132         {
133             return null;
134         }
135 
136         @Override
137         public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings)
138         {
139             return null;
140         }
141 
142         @Override
143         public FieldVisitor visitField(int i, String s, String s1, String s2, Object o)
144         {
145             return null;
146         }
147     }
148 }