View Javadoc

1   package com.atlassian.plugin.osgi.factory.transform.stage;
2   
3   import aQute.lib.osgi.Analyzer;
4   import aQute.lib.osgi.Builder;
5   import aQute.lib.osgi.Jar;
6   import com.atlassian.plugin.PluginInformation;
7   import com.atlassian.plugin.PluginParseException;
8   import com.atlassian.plugin.osgi.factory.transform.PluginTransformationException;
9   import com.atlassian.plugin.osgi.factory.transform.TransformContext;
10  import com.atlassian.plugin.osgi.factory.transform.TransformStage;
11  import com.atlassian.plugin.parsers.XmlDescriptorParser;
12  import org.osgi.framework.Constants;
13  
14  import java.io.ByteArrayOutputStream;
15  import java.io.IOException;
16  import java.util.Collection;
17  import java.util.Enumeration;
18  import java.util.List;
19  import java.util.Properties;
20  import java.util.jar.JarEntry;
21  import java.util.jar.Manifest;
22  
23  /**
24   * Generates an OSGi manifest if not already defined.  Should be the last stage.
25   *
26   * @since 2.2.0
27   */
28  public class GenerateManifestStage implements TransformStage
29  {
30      public void execute(TransformContext context) throws PluginTransformationException
31      {
32          Builder builder = new Builder();
33          try
34          {
35              builder.setJar(context.getPluginFile());
36  
37              // Possibly necessary due to Spring XML creation
38              if (isOsgiBundle(builder.getJar().getManifest()))
39              {
40                  String imports = addExtraImports(builder.getJar().getManifest().getMainAttributes().getValue(Constants.IMPORT_PACKAGE), context.getExtraImports());
41                  builder.setProperty(Constants.IMPORT_PACKAGE, imports);
42                  builder.mergeManifest(builder.getJar().getManifest());
43              }
44              else
45              {
46                  XmlDescriptorParser parser = new XmlDescriptorParser(context.getDescriptorDocument());
47                  PluginInformation info = parser.getPluginInformation();
48  
49                  Properties properties = new Properties();
50  
51                  // Setup defaults
52                  properties.put("Spring-Context", "*;timeout:=60");
53                  properties.put(Analyzer.BUNDLE_SYMBOLICNAME, parser.getKey());
54                  properties.put(Analyzer.IMPORT_PACKAGE, "*;resolution:=optional");
55                  properties.put(Analyzer.EXPORT_PACKAGE, "*");
56                  properties.put(Analyzer.BUNDLE_VERSION, info.getVersion());
57  
58                  // remove the verbose Include-Resource entry from generated manifest
59                  properties.put(Analyzer.REMOVE_HEADERS, Analyzer.INCLUDE_RESOURCE);
60  
61                  header(properties, Analyzer.BUNDLE_DESCRIPTION, info.getDescription());
62                  header(properties, Analyzer.BUNDLE_NAME, parser.getKey());
63                  header(properties, Analyzer.BUNDLE_VENDOR, info.getVendorName());
64                  header(properties, Analyzer.BUNDLE_DOCURL, info.getVendorUrl());
65  
66                  // Scan for embedded jars
67                  StringBuilder classpath = new StringBuilder();
68                  classpath.append(".");
69                  for (Enumeration<JarEntry> e = context.getPluginJar().entries(); e.hasMoreElements();)
70                  {
71                      JarEntry entry = e.nextElement();
72                      if (entry.getName().startsWith("META-INF/lib/") && entry.getName().endsWith(".jar"))
73                      {
74                          classpath.append(",").append(entry.getName());
75                      }
76                  }
77                  header(properties, Analyzer.BUNDLE_CLASSPATH, classpath.toString());
78  
79                  // Process any bundle instructions in atlassian-plugin.xml
80                  properties.putAll(context.getBndInstructions());
81  
82                  // Add extra imports to the imports list
83                  properties.put(Analyzer.IMPORT_PACKAGE, addExtraImports(properties.getProperty(Analyzer.IMPORT_PACKAGE), context.getExtraImports()));
84                  builder.setProperties(properties);
85              }
86  
87              builder.calcManifest();
88              Jar jar = builder.build();
89              Manifest mf = jar.getManifest();
90              ByteArrayOutputStream bout = new ByteArrayOutputStream();
91              mf.write(bout);
92              context.getFileOverrides().put("META-INF/MANIFEST.MF", bout.toByteArray());
93          }
94          catch (Exception t)
95          {
96              throw new PluginParseException("Unable to process plugin to generate OSGi manifest", t);
97          }
98      }
99  
100     private boolean isOsgiBundle(Manifest manifest) throws IOException
101     {
102         return manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME) != null;
103     }
104 
105     private String addExtraImports(String imports, List<String> extraImports)
106     {
107         StringBuilder referrers = new StringBuilder();
108         for (String imp : extraImports)
109         {
110             referrers.append(imp).append(",");
111         }
112 
113         if (imports != null && imports.length() > 0)
114         {
115             imports = referrers + imports;
116         }
117         else
118         {
119             imports = referrers.substring(0, referrers.length() - 1);
120         }
121         return imports;
122     }
123 
124     private static void header(Properties properties, String key, Object value)
125     {
126         if (value == null)
127         {
128             return;
129         }
130 
131         if (value instanceof Collection && ((Collection) value).isEmpty())
132         {
133             return;
134         }
135 
136         properties.put(key, value.toString().replaceAll("[\r\n]", ""));
137     }
138 
139 }