1 package com.atlassian.plugin.osgi.factory;
2
3 import com.atlassian.plugin.*;
4 import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
5 import com.atlassian.plugin.event.PluginEventManager;
6 import com.atlassian.plugin.descriptors.ChainModuleDescriptorFactory;
7 import com.atlassian.plugin.factories.PluginFactory;
8 import com.atlassian.plugin.impl.UnloadablePlugin;
9 import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
10 import com.atlassian.plugin.osgi.container.OsgiContainerManager;
11 import com.atlassian.plugin.osgi.container.OsgiPersistentCache;
12 import com.atlassian.plugin.osgi.factory.transform.DefaultPluginTransformer;
13 import com.atlassian.plugin.osgi.factory.transform.PluginTransformationException;
14 import com.atlassian.plugin.osgi.factory.transform.PluginTransformer;
15 import com.atlassian.plugin.osgi.factory.transform.model.SystemExports;
16 import com.atlassian.plugin.osgi.factory.descriptor.ComponentModuleDescriptor;
17 import com.atlassian.plugin.osgi.factory.descriptor.ModuleTypeModuleDescriptor;
18 import com.atlassian.plugin.osgi.factory.descriptor.ComponentImportModuleDescriptor;
19 import com.atlassian.plugin.parsers.DescriptorParser;
20 import com.atlassian.plugin.parsers.DescriptorParserFactory;
21 import org.apache.commons.io.IOUtils;
22 import org.apache.commons.lang.Validate;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.osgi.util.tracker.ServiceTracker;
26 import org.osgi.framework.Constants;
27 import org.osgi.framework.Version;
28
29 import java.io.File;
30 import java.io.InputStream;
31 import java.util.*;
32
33
34
35
36 public class OsgiPluginFactory implements PluginFactory
37 {
38 private static final Log log = LogFactory.getLog(OsgiPluginFactory.class);
39
40 private final OsgiContainerManager osgi;
41 private final String pluginDescriptorFileName;
42 private final DescriptorParserFactory descriptorParserFactory;
43 private final PluginEventManager pluginEventManager;
44 private final Set<String> applicationKeys;
45 private final OsgiPersistentCache persistentCache;
46 private final ModuleDescriptorFactory transformedDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer())
47 {{
48 addModuleDescriptor("component", ComponentModuleDescriptor.class);
49 addModuleDescriptor("component-import", ComponentImportModuleDescriptor.class);
50 addModuleDescriptor("module-type", ModuleTypeModuleDescriptor.class);
51 }};
52
53 private volatile PluginTransformer pluginTransformer;
54
55 private ServiceTracker moduleDescriptorFactoryTracker;
56
57 public OsgiPluginFactory(String pluginDescriptorFileName, String applicationKey, OsgiPersistentCache persistentCache, OsgiContainerManager osgi, PluginEventManager pluginEventManager)
58 {
59 this(pluginDescriptorFileName, new HashSet<String>(Arrays.asList(applicationKey)), persistentCache, osgi, pluginEventManager);
60 }
61
62 public OsgiPluginFactory(String pluginDescriptorFileName, Set<String> applicationKeys, OsgiPersistentCache persistentCache, OsgiContainerManager osgi, PluginEventManager pluginEventManager)
63 {
64 Validate.notNull(pluginDescriptorFileName, "Plugin descriptor is required");
65 Validate.notNull(osgi, "The OSGi container is required");
66 Validate.notNull(applicationKeys, "The application keys are required");
67 Validate.notNull(persistentCache, "The osgi persistent cache is required");
68 Validate.notNull(persistentCache, "The plugin event manager is required");
69
70 this.osgi = osgi;
71 this.pluginDescriptorFileName = pluginDescriptorFileName;
72 this.descriptorParserFactory = new OsgiPluginXmlDescriptorParserFactory();
73 this.pluginEventManager = pluginEventManager;
74 this.applicationKeys = applicationKeys;
75 this.persistentCache = persistentCache;
76 }
77
78 private PluginTransformer getPluginTransformer()
79 {
80 if (pluginTransformer == null)
81 {
82 String exportString = (String) osgi.getBundles()[0].getHeaders()
83 .get(Constants.EXPORT_PACKAGE);
84 SystemExports exports = new SystemExports(exportString);
85 pluginTransformer = new DefaultPluginTransformer(persistentCache, exports, applicationKeys, pluginDescriptorFileName);
86 }
87 return pluginTransformer;
88 }
89
90 public String canCreate(PluginArtifact pluginArtifact) throws PluginParseException
91 {
92 Validate.notNull(pluginArtifact, "The plugin artifact is required");
93
94 String pluginKey = null;
95 InputStream descriptorStream = null;
96 try
97 {
98 descriptorStream = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
99
100 if (descriptorStream != null)
101 {
102 final DescriptorParser descriptorParser = descriptorParserFactory.getInstance(descriptorStream, applicationKeys.toArray(new String[applicationKeys.size()]));
103 if (descriptorParser.getPluginsVersion() == 2)
104 {
105 pluginKey = descriptorParser.getKey();
106 }
107 }
108 }
109 finally
110 {
111 IOUtils.closeQuietly(descriptorStream);
112 }
113 return pluginKey;
114 }
115
116
117
118
119 public Plugin create(DeploymentUnit deploymentUnit, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
120 {
121 Validate.notNull(deploymentUnit, "The deployment unit is required");
122 return create(new JarPluginArtifact(deploymentUnit.getPath()), moduleDescriptorFactory);
123 }
124
125
126
127
128
129
130
131
132
133
134 public Plugin create(PluginArtifact pluginArtifact, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
135 {
136 Validate.notNull(pluginArtifact, "The plugin deployment unit is required");
137 Validate.notNull(moduleDescriptorFactory, "The module descriptor factory is required");
138
139 Plugin plugin = null;
140 InputStream pluginDescriptor = null;
141 try
142 {
143 pluginDescriptor = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
144 if (pluginDescriptor == null)
145 {
146 throw new PluginParseException("No descriptor found in classloader for : " + pluginArtifact);
147 }
148
149 ModuleDescriptorFactory combinedFactory = getChainedModuleDescriptorFactory(moduleDescriptorFactory);
150 DescriptorParser parser = descriptorParserFactory.getInstance(pluginDescriptor, applicationKeys.toArray(new String[applicationKeys.size()]));
151
152 Plugin osgiPlugin = new OsgiPlugin(parser.getKey(), osgi, createOsgiPluginJar(pluginArtifact), pluginEventManager);
153
154
155 plugin = parser.configurePlugin(combinedFactory, osgiPlugin);
156 }
157 catch (PluginTransformationException ex)
158 {
159 return reportUnloadablePlugin(pluginArtifact.toFile(), ex);
160 }
161 finally
162 {
163 IOUtils.closeQuietly(pluginDescriptor);
164 }
165 return plugin;
166 }
167
168
169
170
171
172
173
174 private ModuleDescriptorFactory getChainedModuleDescriptorFactory(ModuleDescriptorFactory originalFactory)
175 {
176
177 synchronized (this)
178 {
179 if (moduleDescriptorFactoryTracker == null)
180 {
181 moduleDescriptorFactoryTracker = osgi.getServiceTracker(ModuleDescriptorFactory.class.getName());
182 }
183 }
184
185
186 if (moduleDescriptorFactoryTracker != null)
187 {
188 List<ModuleDescriptorFactory> factories = new ArrayList<ModuleDescriptorFactory>();
189
190 factories.add(transformedDescriptorFactory);
191 factories.add(originalFactory);
192 Object[] serviceObjs = moduleDescriptorFactoryTracker.getServices();
193
194
195 if (serviceObjs != null)
196 {
197 for (Object fac : serviceObjs)
198 {
199 factories.add((ModuleDescriptorFactory) fac);
200 }
201 }
202
203
204 factories.add(new UnrecognisedModuleDescriptorFallbackFactory());
205
206 return new ChainModuleDescriptorFactory(factories.toArray(new ModuleDescriptorFactory[]{}));
207 }
208 else
209 {
210 return originalFactory;
211 }
212
213
214 }
215
216 private PluginArtifact createOsgiPluginJar(PluginArtifact pluginArtifact)
217 {
218 File transformedFile = getPluginTransformer().transform(pluginArtifact, osgi.getHostComponentRegistrations());
219 return new JarPluginArtifact(transformedFile);
220 }
221
222 private Plugin reportUnloadablePlugin(File file, Exception e)
223 {
224 log.error("Unable to load plugin: " + file, e);
225
226 UnloadablePlugin plugin = new UnloadablePlugin();
227 plugin.setErrorText("Unable to load plugin: " + e.getMessage());
228 return plugin;
229 }
230 }