1 package com.atlassian.plugin.osgi.factory;
2
3 import com.atlassian.plugin.*;
4 import com.atlassian.plugin.event.PluginEventManager;
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 private final PluginEventManager pluginEventManager;
41
42 private ServiceTracker moduleDescriptorFactoryTracker;
43
44 public OsgiPluginFactory(String pluginDescriptorFileName, OsgiContainerManager osgi, PluginEventManager pluginEventManager)
45 {
46 Validate.notNull(pluginDescriptorFileName, "Plugin descriptor is required");
47 Validate.notNull(osgi, "The OSGi container is required");
48
49 pluginTransformer = new DefaultPluginTransformer(pluginDescriptorFileName);
50 this.osgi = osgi;
51 this.pluginDescriptorFileName = pluginDescriptorFileName;
52 this.descriptorParserFactory = new OsgiPluginXmlDescriptorParserFactory();
53 this.pluginEventManager = pluginEventManager;
54 }
55
56 public String canCreate(PluginArtifact pluginArtifact) throws PluginParseException {
57 Validate.notNull(pluginArtifact, "The plugin artifact is required");
58
59 String pluginKey = null;
60 InputStream descriptorStream = null;
61 try
62 {
63 descriptorStream = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
64
65 if (descriptorStream != null)
66 {
67 final DescriptorParser descriptorParser = descriptorParserFactory.getInstance(descriptorStream);
68 if (descriptorParser.getPluginsVersion() == 2)
69 pluginKey = descriptorParser.getKey();
70 }
71 }
72 finally
73 {
74 IOUtils.closeQuietly(descriptorStream);
75 }
76 return pluginKey;
77 }
78
79
80
81
82 public Plugin create(DeploymentUnit deploymentUnit, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
83 {
84 return create(new JarPluginArtifact(deploymentUnit.getPath()), moduleDescriptorFactory);
85 }
86
87
88
89
90
91
92
93
94
95 public Plugin create(PluginArtifact pluginArtifact, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
96 {
97 Validate.notNull(pluginArtifact, "The plugin deployment unit is required");
98 Validate.notNull(moduleDescriptorFactory, "The module descriptor factory is required");
99
100 Plugin plugin = null;
101 InputStream pluginDescriptor = null;
102 try
103 {
104 pluginDescriptor = pluginArtifact.getResourceAsStream(pluginDescriptorFileName);
105 if (pluginDescriptor == null)
106 throw new PluginParseException("No descriptor found in classloader for : " + pluginArtifact);
107
108 ModuleDescriptorFactory combinedFactory = getChainedModuleDescriptorFactory(moduleDescriptorFactory);
109
110 DescriptorParser parser = descriptorParserFactory.getInstance(pluginDescriptor);
111
112 Bundle existingBundle = findBundle(parser.getKey(), parser.getPluginInformation().getVersion(), pluginArtifact.toFile());
113 Plugin osgiPlugin;
114 if (existingBundle != null)
115 {
116 osgiPlugin = new OsgiPlugin(existingBundle, pluginEventManager);
117 log.info("OSGi bundle "+parser.getKey()+" found already installed.");
118 }
119 else
120 {
121 osgiPlugin = createOsgiPlugin(pluginArtifact);
122 }
123
124 plugin = parser.configurePlugin(combinedFactory, osgiPlugin);
125 }
126 finally
127 {
128 IOUtils.closeQuietly(pluginDescriptor);
129 }
130 return plugin;
131 }
132
133
134
135
136
137
138
139 private ModuleDescriptorFactory getChainedModuleDescriptorFactory(ModuleDescriptorFactory originalFactory)
140 {
141
142 synchronized(this)
143 {
144 if (moduleDescriptorFactoryTracker == null)
145 moduleDescriptorFactoryTracker = osgi.getServiceTracker(ModuleDescriptorFactory.class.getName());
146 }
147
148
149 if (moduleDescriptorFactoryTracker != null)
150 {
151 List<ModuleDescriptorFactory> factories = new ArrayList<ModuleDescriptorFactory>();
152 Object[] serviceObjs = moduleDescriptorFactoryTracker.getServices();
153
154
155 if (serviceObjs != null)
156 {
157 for (Object fac : serviceObjs) factories.add((ModuleDescriptorFactory) fac);
158 }
159
160
161 factories.add(0, originalFactory);
162
163
164 factories.add(new UnrecognisedModuleDescriptorFallbackFactory());
165
166 return new ChainModuleDescriptorFactory(factories.toArray(new ModuleDescriptorFactory[]{}));
167 }
168 else
169 return originalFactory;
170
171
172 }
173
174 private Plugin createOsgiPlugin(PluginArtifact pluginArtifact)
175 {
176 try
177 {
178 File transformedFile = pluginTransformer.transform(pluginArtifact, osgi.getHostComponentRegistrations());
179 return new OsgiPlugin(osgi.installBundle(transformedFile), pluginEventManager);
180 } catch (OsgiContainerException e)
181 {
182 return reportUnloadablePlugin(pluginArtifact.toFile(), e);
183 } catch (PluginTransformationException ex)
184 {
185 return reportUnloadablePlugin(pluginArtifact.toFile(), ex);
186 }
187 }
188
189 private Bundle findBundle(String key, String version, File pluginFile)
190 {
191 for (Bundle bundle : osgi.getBundles())
192 {
193 if (key.equals(bundle.getSymbolicName()) && version.equals(bundle.getHeaders().get(Constants.BUNDLE_VERSION))
194 && pluginFile.lastModified() < bundle.getLastModified())
195 {
196 return bundle;
197 }
198 }
199 return null;
200 }
201
202 private Plugin reportUnloadablePlugin(File file, Exception e)
203 {
204 log.error("Unable to load plugin: "+file, e);
205
206 UnloadablePlugin plugin = new UnloadablePlugin();
207 plugin.setErrorText("Unable to load plugin: "+e.getMessage());
208 return plugin;
209 }
210 }