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  
56                  // Don't export anything by default
57                  //properties.put(Analyzer.EXPORT_PACKAGE, "*");
58  
59                  properties.put(Analyzer.BUNDLE_VERSION, info.getVersion());
60  
61                  // remove the verbose Include-Resource entry from generated manifest
62                  properties.put(Analyzer.REMOVE_HEADERS, Analyzer.INCLUDE_RESOURCE);
63  
64                  header(properties, Analyzer.BUNDLE_DESCRIPTION, info.getDescription());
65                  header(properties, Analyzer.BUNDLE_NAME, parser.getKey());
66                  header(properties, Analyzer.BUNDLE_VENDOR, info.getVendorName());
67                  header(properties, Analyzer.BUNDLE_DOCURL, info.getVendorUrl());
68  
69                  // Scan for embedded jars
70                  StringBuilder classpath = new StringBuilder();
71                  classpath.append(".");
72                  for (Enumeration<JarEntry> e = context.getPluginJar().entries(); e.hasMoreElements();)
73                  {
74                      JarEntry entry = e.nextElement();
75                      if (entry.getName().startsWith("META-INF/lib/") && entry.getName().endsWith(".jar"))
76                      {
77                          classpath.append(",").append(entry.getName());
78                      }
79                  }
80                  header(properties, Analyzer.BUNDLE_CLASSPATH, classpath.toString());
81  
82                  // Process any bundle instructions in atlassian-plugin.xml
83                  properties.putAll(context.getBndInstructions());
84  
85                  // Add extra imports to the imports list
86                  properties.put(Analyzer.IMPORT_PACKAGE, addExtraImports(properties.getProperty(Analyzer.IMPORT_PACKAGE), context.getExtraImports()));
87  
88                  // Add extra exports to the exports list
89                  if (!properties.containsKey(Analyzer.EXPORT_PACKAGE))
90                  {
91                      properties.put(Analyzer.EXPORT_PACKAGE, addExtraExports(context.getExtraExports()));
92                  }
93                  builder.setProperties(properties);
94              }
95  
96              builder.calcManifest();
97              Jar jar = builder.build();
98              Manifest mf = jar.getManifest();
99              ByteArrayOutputStream bout = new ByteArrayOutputStream();
100             mf.write(bout);
101             context.getFileOverrides().put("META-INF/MANIFEST.MF", bout.toByteArray());
102         }
103         catch (Exception t)
104         {
105             throw new PluginParseException("Unable to process plugin to generate OSGi manifest", t);
106         }
107     }
108 
109     private String addExtraExports(List<String> extraExports)
110     {
111         StringBuilder result = new StringBuilder();
112         for (String exp : extraExports)
113         {
114             result.append(exp).append(",");
115         }
116         if (result.length() > 0)
117         {
118             result.deleteCharAt(result.length() - 1);
119         }
120 
121         return result.toString();
122     }
123 
124     private boolean isOsgiBundle(Manifest manifest) throws IOException
125     {
126         return manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME) != null;
127     }
128 
129     private String addExtraImports(String imports, List<String> extraImports)
130     {
131         StringBuilder referrers = new StringBuilder();
132         for (String imp : extraImports)
133         {
134             referrers.append(imp).append(",");
135         }
136 
137         if (imports != null && imports.length() > 0)
138         {
139             imports = referrers + imports;
140         }
141         else
142         {
143             imports = referrers.substring(0, referrers.length() - 1);
144         }
145         return imports;
146     }
147 
148     private static void header(Properties properties, String key, Object value)
149     {
150         if (value == null)
151         {
152             return;
153         }
154 
155         if (value instanceof Collection && ((Collection) value).isEmpty())
156         {
157             return;
158         }
159 
160         properties.put(key, value.toString().replaceAll("[\r\n]", ""));
161     }
162 
163 }