1 package com.atlassian.plugin.osgi.factory;
2
3 import com.atlassian.plugin.PluginArtifact;
4 import com.atlassian.plugin.PluginArtifactBackedPlugin;
5 import com.atlassian.plugin.PluginException;
6 import com.atlassian.plugin.PluginInformation;
7 import com.atlassian.plugin.PluginPermission;
8 import com.atlassian.plugin.PluginState;
9 import com.atlassian.plugin.impl.AbstractPlugin;
10 import com.atlassian.plugin.osgi.util.BundleClassLoaderAccessor;
11 import com.atlassian.plugin.util.resource.AlternativeDirectoryResourceLoader;
12 import com.google.common.collect.ImmutableSet;
13 import org.osgi.framework.Bundle;
14 import org.osgi.framework.BundleEvent;
15 import org.osgi.framework.BundleException;
16 import org.osgi.framework.Constants;
17 import org.osgi.framework.SynchronousBundleListener;
18
19 import java.io.InputStream;
20 import java.net.URL;
21 import java.util.Date;
22
23 import static com.google.common.base.Preconditions.checkNotNull;
24
25
26
27
28 public final class OsgiBundlePlugin extends AbstractPlugin implements PluginArtifactBackedPlugin
29 {
30
31 private final Bundle bundle;
32 private final Date dateLoaded;
33 private final ClassLoader bundleClassLoader;
34 private final SynchronousBundleListener bundleStartStopListener;
35 private final PluginArtifact pluginArtifact;
36
37 public OsgiBundlePlugin(final Bundle bundle, final String key, final PluginArtifact pluginArtifact)
38 {
39 this.bundle = checkNotNull(bundle);
40 this.pluginArtifact = checkNotNull(pluginArtifact);
41 this.bundleClassLoader = BundleClassLoaderAccessor.getClassLoader(bundle, new AlternativeDirectoryResourceLoader());
42 bundleStartStopListener = new SynchronousBundleListener()
43 {
44 public void bundleChanged(final BundleEvent bundleEvent)
45 {
46 if (bundleEvent.getBundle() == bundle)
47 {
48 if (bundleEvent.getType() == BundleEvent.STOPPING)
49 {
50 setPluginState(PluginState.DISABLED);
51 }
52 else if (bundleEvent.getType() == BundleEvent.STARTED)
53 {
54 setPluginState(PluginState.ENABLED);
55 }
56 }
57 }
58 };
59 PluginInformation pluginInformation = new PluginInformation();
60 pluginInformation.setDescription((String) bundle.getHeaders().get(Constants.BUNDLE_DESCRIPTION));
61 pluginInformation.setVersion((String) bundle.getHeaders().get(Constants.BUNDLE_VERSION));
62 pluginInformation.setVendorName((String) bundle.getHeaders().get(Constants.BUNDLE_VENDOR));
63 pluginInformation.setPermissions(ImmutableSet.of(PluginPermission.EXECUTE_JAVA));
64
65 dateLoaded = new Date();
66 setPluginsVersion(2);
67 setName((String) bundle.getHeaders().get(Constants.BUNDLE_NAME));
68 setKey(key);
69 setPluginInformation(pluginInformation);
70 setSystemPlugin(false);
71 }
72
73
74 @Override
75 public Date getDateLoaded()
76 {
77 return dateLoaded;
78 }
79
80 @Override
81 public Date getDateInstalled()
82 {
83 long date = getPluginArtifact().toFile().lastModified();
84 if (date == 0)
85 {
86 date = getDateLoaded().getTime();
87 }
88 return new Date(date);
89 }
90
91 public boolean isUninstallable()
92 {
93 return true;
94 }
95
96 public boolean isDeleteable()
97 {
98 return true;
99 }
100
101 public boolean isDynamicallyLoaded()
102 {
103 return true;
104 }
105
106 public <T> Class<T> loadClass(final String clazz, final Class<?> callingClass) throws ClassNotFoundException
107 {
108 return BundleClassLoaderAccessor.loadClass(bundle, clazz);
109 }
110
111 public URL getResource(final String name)
112 {
113 return bundleClassLoader.getResource(name);
114 }
115
116 public InputStream getResourceAsStream(final String name)
117 {
118 return bundleClassLoader.getResourceAsStream(name);
119 }
120
121 @Override
122 protected void uninstallInternal()
123 {
124 try
125 {
126 if (bundle.getState() != Bundle.UNINSTALLED)
127 {
128 bundle.uninstall();
129 }
130 }
131 catch (final BundleException e)
132 {
133 throw new PluginException(e);
134 }
135 }
136
137 @Override
138 protected PluginState enableInternal()
139 {
140 getLog().debug("Enabling OSGi bundled plugin '{}'", getKey());
141 try
142 {
143 if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
144 {
145 getLog().debug("Plugin '{}' bundle is NOT a fragment, starting.", getKey());
146 bundle.start();
147 bundle.getBundleContext().addBundleListener(bundleStartStopListener);
148 }
149 else
150 {
151 getLog().debug("Plugin '{}' bundle is a fragment, not doing anything.", getKey());
152 }
153 return PluginState.ENABLED;
154 }
155 catch (final BundleException e)
156 {
157 throw new PluginException(e);
158 }
159 }
160
161 @Override
162 protected void disableInternal()
163 {
164 try
165 {
166 if (bundle.getState() == Bundle.ACTIVE)
167 {
168 bundle.stop();
169 }
170 }
171 catch (final BundleException e)
172 {
173 throw new PluginException(e);
174 }
175 }
176
177 public ClassLoader getClassLoader()
178 {
179 return bundleClassLoader;
180 }
181
182 public PluginArtifact getPluginArtifact()
183 {
184 return pluginArtifact;
185 }
186 }