1 package com.atlassian.plugin.osgi.factory;
2
3 import com.atlassian.plugin.*;
4 import com.atlassian.plugin.classloader.PluginClassLoader;
5 import com.atlassian.plugin.descriptors.ChainModuleDescriptorFactory;
6 import com.atlassian.plugin.factories.PluginFactory;
7 import com.atlassian.plugin.impl.UnloadablePlugin;
8 import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
9 import com.atlassian.plugin.osgi.container.OsgiContainerException;
10 import com.atlassian.plugin.osgi.container.OsgiContainerManager;
11 import com.atlassian.plugin.osgi.factory.transform.DefaultPluginTransformer;
12 import com.atlassian.plugin.osgi.factory.transform.PluginTransformationException;
13 import com.atlassian.plugin.osgi.factory.transform.PluginTransformer;
14 import com.atlassian.plugin.parsers.DescriptorParser;
15 import com.atlassian.plugin.parsers.DescriptorParserFactory;
16 import org.apache.commons.io.IOUtils;
17 import org.apache.commons.lang.Validate;
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.osgi.util.tracker.ServiceTracker;
21 import org.osgi.framework.Bundle;
22 import org.osgi.framework.Constants;
23
24 import java.io.File;
25 import java.io.InputStream;
26 import java.util.List;
27 import java.util.ArrayList;
28
29
30
31
32 public class OsgiPluginFactory implements PluginFactory
33 {
34 private static final Log log = LogFactory.getLog(OsgiPluginFactory.class);
35
36 private final OsgiContainerManager osgi;
37 private final PluginTransformer pluginTransformer;
38 private final String pluginDescriptorFileName;
39 private final DescriptorParserFactory descriptorParserFactory;
40
41 private ServiceTracker moduleDescriptorFactoryTracker;
42
43 public OsgiPluginFactory(String pluginDescriptorFileName, OsgiContainerManager osgi)
44 {
45 Validate.notNull(pluginDescriptorFileName, "Plugin descriptor is required");
46 Validate.notNull(osgi, "The OSGi container is required");
47
48 pluginTransformer = new DefaultPluginTransformer(pluginDescriptorFileName);
49 this.osgi = osgi;
50 this.pluginDescriptorFileName = pluginDescriptorFileName;
51 this.descriptorParserFactory = new OsgiPluginXmlDescriptorParserFactory();
52 }
53
54 public String canCreate(PluginArtifact pluginArtifact) throws PluginParseException {
55 Validate.notNull(pluginArtifact, "The plugin artifact is required");
56
57 String pluginKey = null;
58 InputStream descriptorStream = null;
59 try
60 {
61 descriptorStream = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
62
63 if (descriptorStream != null)
64 {
65 final DescriptorParser descriptorParser = descriptorParserFactory.getInstance(descriptorStream);
66 if (descriptorParser.getPluginsVersion() == 2)
67 pluginKey = descriptorParser.getKey();
68 }
69 }
70 finally
71 {
72 IOUtils.closeQuietly(descriptorStream);
73 }
74 return pluginKey;
75 }
76
77 public Plugin create(DeploymentUnit deploymentUnit, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException {
78 Validate.notNull(deploymentUnit, "The plugin deployment unit is required");
79 Validate.notNull(moduleDescriptorFactory, "The module descriptor factory is required");
80
81 Plugin plugin = null;
82 InputStream pluginDescriptor = null;
83 PluginClassLoader loader = new PluginClassLoader(deploymentUnit.getPath());
84
85 if (loader.getResource(pluginDescriptorFileName) == null)
86 throw new PluginParseException("No descriptor found in classloader for : " + deploymentUnit);
87
88 try
89 {
90 ModuleDescriptorFactory combinedFactory = getChainedModuleDescriptorFactory(moduleDescriptorFactory);
91 pluginDescriptor = loader.getResourceAsStream(pluginDescriptorFileName);
92
93 DescriptorParser parser = descriptorParserFactory.getInstance(pluginDescriptor);
94
95 Bundle existingBundle = findBundle(parser.getKey(), parser.getPluginInformation().getVersion(), deploymentUnit);
96 Plugin osgiPlugin;
97 if (existingBundle != null)
98 {
99 osgiPlugin = new OsgiPlugin(existingBundle);
100 log.info("OSGi bundle "+parser.getKey()+" found already installed.");
101 }
102 else
103 {
104 osgiPlugin = createOsgiPlugin(deploymentUnit.getPath());
105 }
106
107 plugin = parser.configurePlugin(combinedFactory, osgiPlugin);
108 }
109 finally
110 {
111 IOUtils.closeQuietly(pluginDescriptor);
112 }
113 return plugin;
114 }
115
116
117
118
119
120
121
122 private ModuleDescriptorFactory getChainedModuleDescriptorFactory(ModuleDescriptorFactory originalFactory)
123 {
124
125 synchronized(this)
126 {
127 if (moduleDescriptorFactoryTracker == null)
128 moduleDescriptorFactoryTracker = osgi.getServiceTracker(ModuleDescriptorFactory.class.getName());
129 }
130
131
132 if (moduleDescriptorFactoryTracker != null)
133 {
134 List<ModuleDescriptorFactory> factories = new ArrayList<ModuleDescriptorFactory>();
135 Object[] serviceObjs = moduleDescriptorFactoryTracker.getServices();
136
137
138 if (serviceObjs != null)
139 {
140 for (Object fac : serviceObjs) factories.add((ModuleDescriptorFactory) fac);
141 }
142
143
144 factories.add(0, originalFactory);
145
146
147 factories.add(new UnrecognisedModuleDescriptorFallbackFactory());
148
149 return new ChainModuleDescriptorFactory(factories.toArray(new ModuleDescriptorFactory[]{}));
150 }
151 else
152 return originalFactory;
153
154
155 }
156
157 private Plugin createOsgiPlugin(File file)
158 {
159 try
160 {
161 File transformedFile = pluginTransformer.transform(file, osgi.getHostComponentRegistrations());
162 return new OsgiPlugin(osgi.installBundle(transformedFile));
163 } catch (OsgiContainerException e)
164 {
165 return reportUnloadablePlugin(file, e);
166 } catch (PluginTransformationException ex)
167 {
168 return reportUnloadablePlugin(file, ex);
169 }
170 }
171
172 private Bundle findBundle(String key, String version, DeploymentUnit deploymentUnit)
173 {
174 for (Bundle bundle : osgi.getBundles())
175 {
176 if (key.equals(bundle.getSymbolicName()) && version.equals(bundle.getHeaders().get(Constants.BUNDLE_VERSION))
177 && deploymentUnit.lastModified() < bundle.getLastModified())
178 {
179 return bundle;
180 }
181 }
182 return null;
183 }
184
185 private Plugin reportUnloadablePlugin(File file, Exception e)
186 {
187 log.error("Unable to load plugin: "+file, e);
188
189 UnloadablePlugin plugin = new UnloadablePlugin();
190 plugin.setErrorText("Unable to load plugin: "+e.getMessage());
191 return plugin;
192 }
193 }