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