1 package com.atlassian.plugin.osgi.factory.transform;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.Enumeration;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13 import java.util.jar.JarEntry;
14 import java.util.jar.JarFile;
15 import java.util.jar.Manifest;
16
17 import org.apache.commons.io.IOUtils;
18 import org.apache.commons.lang.Validate;
19 import org.dom4j.Document;
20 import org.dom4j.Element;
21
22 import com.atlassian.plugin.PluginArtifact;
23 import com.atlassian.plugin.PluginParseException;
24 import com.atlassian.plugin.osgi.factory.transform.model.ComponentImport;
25 import com.atlassian.plugin.osgi.factory.transform.model.SystemExports;
26 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
27 import com.atlassian.plugin.parsers.XmlDescriptorParser;
28
29
30
31
32
33
34 public class TransformContext
35 {
36
37 private final Manifest manifest;
38 private final List<HostComponentRegistration> regs;
39 private final Map<String, byte[]> fileOverrides;
40 private final Map<String, String> bndInstructions;
41 private final Document descriptorDocument;
42 private final List<String> extraImports;
43 private final List<String> extraExports;
44 private final PluginArtifact pluginArtifact;
45 private final Map<String, ComponentImport> componentImports;
46 private final SystemExports systemExports;
47 private final Set<String> applicationKeys;
48 private boolean shouldRequireSpring = false;
49
50 public TransformContext(final List<HostComponentRegistration> regs, final SystemExports systemExports,
51 final PluginArtifact pluginArtifact, final Set<String> applicationKeys, final String descriptorPath)
52 {
53 Validate.notNull(pluginArtifact, "The plugin artifact must be specified");
54 Validate.notNull(descriptorPath, "The plugin descriptor path must be specified");
55 Validate.notNull(systemExports, "The system exports must be specified");
56
57 this.regs = regs;
58 this.systemExports = systemExports;
59 this.pluginArtifact = pluginArtifact;
60 this.applicationKeys = (applicationKeys == null ? Collections.<String>emptySet() : applicationKeys);
61
62 JarFile jarFile = null;
63 try
64 {
65 jarFile = new JarFile(pluginArtifact.toFile());
66 this.manifest = jarFile.getManifest();
67 }
68 catch (final IOException e)
69 {
70 throw new IllegalArgumentException("File must be a jar", e);
71 } finally
72 {
73 closeJarQuietly(jarFile);
74 }
75 fileOverrides = new HashMap<String, byte[]>();
76 bndInstructions = new HashMap<String, String>();
77 this.descriptorDocument = retrieveDocFromJar(pluginArtifact, descriptorPath);
78 this.extraImports = new ArrayList<String>();
79 this.extraExports = new ArrayList<String>();
80
81 this.componentImports = Collections.unmodifiableMap(parseComponentImports(descriptorDocument));
82 }
83
84 private Map<String, ComponentImport> parseComponentImports(final Document descriptorDocument)
85 {
86 final Map<String,ComponentImport> componentImports = new HashMap<String,ComponentImport>();
87 final List<Element> elements = descriptorDocument.getRootElement().elements("component-import");
88 for (final Element component : elements)
89 {
90 final ComponentImport ci = new ComponentImport(component);
91 componentImports.put(ci.getKey(), ci);
92 }
93 return componentImports;
94 }
95
96 private Document retrieveDocFromJar(final PluginArtifact pluginArtifact, final String descriptorPath) throws PluginTransformationException
97 {
98 Document document;
99 InputStream stream = null;
100 try
101 {
102 stream = pluginArtifact.getResourceAsStream(descriptorPath);
103 if (stream == null)
104 {
105 throw new PluginTransformationException("Unable to access descriptor " + descriptorPath);
106 }
107 final DocumentExposingDescriptorParser parser = new DocumentExposingDescriptorParser(stream);
108 document = parser.getDocument();
109 }
110 finally
111 {
112 IOUtils.closeQuietly(stream);
113 }
114 return document;
115 }
116
117 public File getPluginFile()
118 {
119 return pluginArtifact.toFile();
120 }
121
122 public PluginArtifact getPluginArtifact()
123 {
124 return pluginArtifact;
125 }
126
127 public List<HostComponentRegistration> getHostComponentRegistrations()
128 {
129 return regs;
130 }
131
132 public Map<String, byte[]> getFileOverrides()
133 {
134 return fileOverrides;
135 }
136
137 public Map<String, String> getBndInstructions()
138 {
139 return bndInstructions;
140 }
141
142 public Document getDescriptorDocument()
143 {
144 return descriptorDocument;
145 }
146
147 public Manifest getManifest()
148 {
149 return manifest;
150 }
151
152 public List<String> getExtraImports()
153 {
154 return extraImports;
155 }
156
157 public List<String> getExtraExports()
158 {
159 return extraExports;
160 }
161
162 public Map<String, ComponentImport> getComponentImports()
163 {
164 return componentImports;
165 }
166
167 public SystemExports getSystemExports()
168 {
169 return systemExports;
170 }
171
172 public Set<String> getApplicationKeys()
173 {
174 return applicationKeys;
175 }
176
177 public boolean shouldRequireSpring()
178 {
179 return shouldRequireSpring;
180 }
181
182 public void setShouldRequireSpring(final boolean shouldRequireSpring)
183 {
184 this.shouldRequireSpring = shouldRequireSpring;
185 if (shouldRequireSpring)
186 {
187 getFileOverrides().put("META-INF/spring/", new byte[0]);
188 }
189
190 }
191
192 private static class DocumentExposingDescriptorParser extends XmlDescriptorParser
193 {
194
195
196
197
198 public DocumentExposingDescriptorParser(final InputStream source) throws PluginParseException
199 {
200
201 super(source, null);
202 }
203
204 @Override
205 public Document getDocument()
206 {
207 return super.getDocument();
208 }
209 }
210
211 public List<JarEntry> getPluginJarEntries()
212 {
213 final List<JarEntry> list = new ArrayList<JarEntry>();
214 JarFile jarFile = null;
215 try
216 {
217 jarFile = new JarFile(pluginArtifact.toFile());
218 final Enumeration<JarEntry> entries = jarFile.entries();
219 for (final Enumeration<JarEntry> e = entries; e.hasMoreElements();)
220 {
221 final JarEntry entry = e.nextElement();
222 list.add(entry);
223 }
224 return list;
225 }
226 catch (final IOException e)
227 {
228 throw new IllegalArgumentException("File must be a jar", e);
229 } finally
230 {
231 closeJarQuietly(jarFile);
232 }
233 }
234
235 public Object getPluginJarEntry(final String path)
236 {
237 JarFile jarFile = null;
238 try
239 {
240 jarFile = new JarFile(pluginArtifact.toFile());
241 return jarFile.getEntry(path);
242 }
243 catch (final IOException e)
244 {
245 throw new IllegalArgumentException("File must be a jar", e);
246 } finally
247 {
248 closeJarQuietly(jarFile);
249 }
250 }
251
252 private void closeJarQuietly(final JarFile jarFile)
253 {
254 if (jarFile!=null)
255 try
256 {
257 jarFile.close();
258 } catch (final IOException e)
259 {
260
261 }
262 }
263 }