1 package com.atlassian.plugin.osgi.factory.transform;
2
3 import com.atlassian.plugin.Application;
4 import com.atlassian.plugin.InstallationMode;
5 import com.atlassian.plugin.PluginArtifact;
6 import com.atlassian.plugin.PluginParseException;
7 import com.atlassian.plugin.osgi.container.OsgiContainerManager;
8 import com.atlassian.plugin.osgi.factory.OsgiPlugin;
9 import com.atlassian.plugin.osgi.factory.transform.model.ComponentImport;
10 import com.atlassian.plugin.osgi.factory.transform.model.SystemExports;
11 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
12 import com.atlassian.plugin.parsers.XmlDescriptorParser;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableSet;
15 import org.apache.commons.io.IOUtils;
16 import org.dom4j.Document;
17 import org.dom4j.Element;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import java.io.File;
22 import java.io.InputStream;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.jar.JarEntry;
31 import java.util.jar.Manifest;
32
33 import static com.atlassian.fugue.Option.option;
34 import static com.atlassian.plugin.osgi.factory.transform.JarUtils.getEntries;
35 import static com.atlassian.plugin.osgi.factory.transform.JarUtils.getEntry;
36 import static com.atlassian.plugin.osgi.factory.transform.JarUtils.hasManifestEntry;
37 import static com.google.common.base.Preconditions.checkNotNull;
38
39
40
41
42
43
44 public final class TransformContext {
45 private final Manifest manifest;
46 private final List<HostComponentRegistration> regs;
47 private final Map<String, byte[]> fileOverrides;
48 private final Map<String, String> bndInstructions;
49 private final Document descriptorDocument;
50 private final List<String> extraImports;
51 private final List<String> extraExports;
52 private final Set<String> bundleClassPathJars;
53 private final PluginArtifact pluginArtifact;
54 private final Map<String, ComponentImport> componentImports;
55 private final SystemExports systemExports;
56 private final Set<Application> applications;
57 private boolean shouldRequireSpring = false;
58 private final OsgiContainerManager osgiContainerManager;
59 private final Set<HostComponentRegistration> requiredHostComponents;
60
61 private static final Logger LOG = LoggerFactory.getLogger(TransformContext.class);
62
63
64
65
66 private final Map<String, String> beanSourceMap = new LinkedHashMap<String, String>();
67
68 public TransformContext(final List<HostComponentRegistration> regs, final SystemExports systemExports, final PluginArtifact pluginArtifact, final Set<Application> applications, final String descriptorPath, final OsgiContainerManager osgiContainerManager) {
69 this.regs = regs;
70 this.systemExports = checkNotNull(systemExports);
71 this.osgiContainerManager = checkNotNull(osgiContainerManager);
72 this.pluginArtifact = checkNotNull(pluginArtifact);
73 this.applications = option(applications).getOrElse(ImmutableSet.<Application>of());
74
75 manifest = JarUtils.getManifest(pluginArtifact.toFile());
76 fileOverrides = new LinkedHashMap<String, byte[]>();
77 bndInstructions = new LinkedHashMap<String, String>();
78 descriptorDocument = retrieveDocFromJar(pluginArtifact, checkNotNull(descriptorPath));
79 extraImports = new ArrayList<String>();
80 extraExports = new ArrayList<String>();
81 bundleClassPathJars = new LinkedHashSet<String>();
82
83 componentImports = parseComponentImports(descriptorDocument);
84 requiredHostComponents = new LinkedHashSet<HostComponentRegistration>();
85 }
86
87 public File getPluginFile() {
88 return pluginArtifact.toFile();
89 }
90
91 public PluginArtifact getPluginArtifact() {
92 return pluginArtifact;
93 }
94
95 public List<HostComponentRegistration> getHostComponentRegistrations() {
96 return regs;
97 }
98
99 public Map<String, byte[]> getFileOverrides() {
100 return fileOverrides;
101 }
102
103 public Map<String, String> getBndInstructions() {
104 return bndInstructions;
105 }
106
107 public Document getDescriptorDocument() {
108 return descriptorDocument;
109 }
110
111 public Manifest getManifest() {
112 return manifest;
113 }
114
115 public List<String> getExtraImports() {
116 return extraImports;
117 }
118
119 public List<String> getExtraExports() {
120 return extraExports;
121 }
122
123 public void addBundleClasspathJar(String classpath) {
124 bundleClassPathJars.add(classpath);
125 }
126
127 public Set<String> getBundleClassPathJars() {
128 return Collections.unmodifiableSet(bundleClassPathJars);
129 }
130
131 public Map<String, ComponentImport> getComponentImports() {
132 return componentImports;
133 }
134
135 public SystemExports getSystemExports() {
136 return systemExports;
137 }
138
139 public Set<Application> getApplications() {
140 return ImmutableSet.copyOf(applications);
141 }
142
143 public boolean shouldRequireSpring() {
144 return shouldRequireSpring;
145 }
146
147 public void setShouldRequireSpring(final boolean shouldRequireSpring) {
148 this.shouldRequireSpring = shouldRequireSpring;
149 if (shouldRequireSpring) {
150 getFileOverrides().put("META-INF/spring/", new byte[0]);
151 }
152 }
153
154 public OsgiContainerManager getOsgiContainerManager() {
155 return osgiContainerManager;
156 }
157
158 public Iterable<JarEntry> getPluginJarEntries() {
159 return getEntries(pluginArtifact.toFile());
160 }
161
162 public JarEntry getPluginJarEntry(final String path) {
163 return getEntry(pluginArtifact.toFile(), path);
164 }
165
166 public void addRequiredHostComponent(final HostComponentRegistration hostComponent) {
167 requiredHostComponents.add(hostComponent);
168 }
169
170 public Set<HostComponentRegistration> getRequiredHostComponents() {
171 return requiredHostComponents;
172 }
173
174
175
176
177
178
179
180
181 public void trackBean(final String name, final String source) throws PluginTransformationException {
182 checkNotNull(name, "empty bean name");
183 checkNotNull(source, "source of bean is required");
184
185
186 if (beanSourceMap.containsKey(name)) {
187 final String message = String.format("The bean identifier '%s' is used by two different beans from %s and %s."
188 + "This is a bad practice and may not be supported in newer plugin framework version.",
189 name, source, beanSourceMap.get(name));
190
191 LOG.warn(message);
192
193 }
194
195
196 beanSourceMap.put(name, source);
197 }
198
199
200
201
202
203
204
205 public boolean beanExists(final String name) {
206 return beanSourceMap.containsKey(name);
207 }
208
209
210
211
212
213 private static Map<String, ComponentImport> parseComponentImports(final Document descriptorDocument) {
214 final Map<String, ComponentImport> componentImports = new LinkedHashMap<String, ComponentImport>();
215 @SuppressWarnings("unchecked")
216 final List<Element> elements = descriptorDocument.getRootElement().elements("component-import");
217 for (final Element component : elements) {
218 final ComponentImport ci = new ComponentImport(component);
219 componentImports.put(ci.getKey(), ci);
220 }
221 return ImmutableMap.copyOf(componentImports);
222 }
223
224 private static Document retrieveDocFromJar(final PluginArtifact pluginArtifact, final String descriptorPath) throws PluginTransformationException {
225 InputStream stream = null;
226 try {
227 stream = pluginArtifact.getResourceAsStream(descriptorPath);
228 if (stream == null) {
229 throw new PluginTransformationException("Unable to access descriptor " + descriptorPath);
230 }
231 return new DocumentExposingDescriptorParser(stream).getDocument();
232 } finally {
233 IOUtils.closeQuietly(stream);
234 }
235 }
236
237 public InstallationMode getInstallationMode() {
238 return hasManifestEntry(manifest, OsgiPlugin.REMOTE_PLUGIN_KEY) ? InstallationMode.REMOTE : InstallationMode.LOCAL;
239 }
240
241
242
243
244 private static class DocumentExposingDescriptorParser extends XmlDescriptorParser {
245
246
247
248 DocumentExposingDescriptorParser(final InputStream source) throws PluginParseException {
249
250 super(source, ImmutableSet.<Application>of());
251 }
252
253 @Override
254 public Document getDocument() {
255 return super.getDocument();
256 }
257 }
258 }