View Javadoc

1   package com.atlassian.plugin.osgi.factory.transform.stage;
2   
3   import com.atlassian.plugin.osgi.factory.transform.PluginTransformationException;
4   import com.atlassian.plugin.osgi.factory.transform.TransformContext;
5   import com.atlassian.plugin.osgi.factory.transform.TransformStage;
6   import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
7   import com.atlassian.plugin.util.ClassLoaderUtils;
8   import org.dom4j.Attribute;
9   import org.dom4j.DocumentHelper;
10  import org.dom4j.XPath;
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  import java.lang.reflect.Constructor;
15  import java.lang.reflect.Method;
16  import java.util.HashMap;
17  import java.util.List;
18  import java.util.Map;
19  
20  /**
21   * Scans the plugin descriptor for any "class" attribute, and ensures that it will be imported, if appropriate.
22   *
23   * @since 2.2.0
24   */
25  public class ScanDescriptorForHostClassesStage implements TransformStage
26  {
27      private static final Logger log = LoggerFactory.getLogger(ScanDescriptorForHostClassesStage.class);
28  
29      @SuppressWarnings("unchecked")
30      public void execute(TransformContext context) throws PluginTransformationException
31      {
32          XPath xpath = DocumentHelper.createXPath("//@class");
33          List<Attribute> attributes = xpath.selectNodes(context.getDescriptorDocument());
34          for (Attribute attr : attributes)
35          {
36              String className = attr.getValue();
37  
38              scanForHostComponents(context, className);
39  
40              int dotpos = className.lastIndexOf(".");
41              if (dotpos > -1)
42              {
43                  String pkg = className.substring(0, dotpos);
44                  String pkgPath = pkg.replace('.', '/') + '/';
45  
46                  // Only add an import if the system exports it and the plugin isn't using the package
47                  if (context.getSystemExports().isExported(pkg))
48                  {
49                      if (context.getPluginArtifact().doesResourceExist(pkgPath))
50                      {
51                          log.warn("The plugin '" + context.getPluginArtifact().toString() + "' uses a package '" +
52                                  pkg + "' that is also exported by the application.  It is highly recommended that the " +
53                                  "plugin use its own packages.");
54                      }
55                      else
56                      {
57                          context.getExtraImports().add(pkg);
58                      }
59                  }
60              }
61          }
62      }
63  
64      private void scanForHostComponents(TransformContext context, String className)
65      {
66          // Class name can be prefixed with 'bean:' to reference a spring bean, in this case don't attempt to load it. 
67          if (className != null && className.indexOf(":") != -1)
68          {
69              return;
70          }
71  
72          Map<Class<?>, HostComponentRegistration> hostComponentInterfaces = new HashMap<Class<?>, HostComponentRegistration>();
73          for (HostComponentRegistration registration : context.getHostComponentRegistrations())
74          {
75              for (Class<?> cls : registration.getMainInterfaceClasses())
76              {
77                  hostComponentInterfaces.put(cls, registration);
78              }
79          }
80  
81          Class cls;
82          try
83          {
84              cls = ClassLoaderUtils.loadClass(className, getClass());
85          }
86          catch (ClassNotFoundException e)
87          {
88              // not a host class, ignore
89              return;
90          }
91  
92          // Check constructor arguments for host component interfaces
93          for (Constructor ctor : cls.getConstructors())
94          {
95              for (Class<?> ctorParam : ctor.getParameterTypes())
96              {
97                  if (hostComponentInterfaces.containsKey(ctorParam))
98                  {
99                      context.addRequiredHostComponent(hostComponentInterfaces.get(ctorParam));  
100                 }
101             }
102         }
103 
104         // Check setters for host component interface arguments
105         for (Method method : cls.getMethods()) 
106         {
107             if (method.getName().startsWith("set") && method.getParameterTypes().length == 1)
108             {
109                 if (hostComponentInterfaces.containsKey(method.getParameterTypes()[0]))
110                 {
111                     context.addRequiredHostComponent(hostComponentInterfaces.get(method.getParameterTypes()[0]));
112                 }
113             }
114         }
115     }
116 }