1 package com.atlassian.plugin.osgi.factory;
2
3 import com.atlassian.plugin.IllegalPluginStateException;
4 import com.atlassian.plugin.module.ContainerAccessor;
5 import com.atlassian.plugin.osgi.container.OsgiContainerException;
6 import com.atlassian.plugin.osgi.spring.DefaultSpringContainerAccessor;
7 import com.atlassian.plugin.osgi.util.BundleClassLoaderAccessor;
8 import com.atlassian.plugin.osgi.util.OsgiHeaderUtil;
9 import com.atlassian.plugin.util.resource.AlternativeDirectoryResourceLoader;
10 import com.google.common.base.Function;
11 import org.osgi.framework.Bundle;
12 import org.osgi.framework.Constants;
13 import org.osgi.service.packageadmin.ExportedPackage;
14 import org.osgi.service.packageadmin.PackageAdmin;
15 import org.osgi.util.tracker.ServiceTracker;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import java.io.InputStream;
20 import java.net.URL;
21 import java.util.Dictionary;
22 import java.util.HashSet;
23 import java.util.Set;
24
25 import static com.atlassian.fugue.Option.option;
26 import static com.atlassian.fugue.Suppliers.alwaysFalse;
27 import static com.google.common.base.Preconditions.checkNotNull;
28
29
30
31
32
33
34 final class OsgiPluginInstalledHelper implements OsgiPluginHelper
35 {
36 private static final Logger logger = LoggerFactory.getLogger(OsgiPluginInstalledHelper.class);
37
38 private final ClassLoader bundleClassLoader;
39 private final Bundle bundle;
40 private final PackageAdmin packageAdmin;
41
42 private volatile ContainerAccessor containerAccessor;
43 private volatile ServiceTracker[] serviceTrackers;
44
45
46
47
48
49 public OsgiPluginInstalledHelper(final Bundle bundle, final PackageAdmin packageAdmin)
50 {
51 this.bundle = checkNotNull(bundle);
52 this.packageAdmin = checkNotNull(packageAdmin);
53 bundleClassLoader = BundleClassLoaderAccessor.getClassLoader(bundle, new AlternativeDirectoryResourceLoader());
54 }
55
56 public Bundle getBundle()
57 {
58 return bundle;
59 }
60
61 public <T> Class<T> loadClass(final String clazz, final Class<?> callingClass) throws ClassNotFoundException
62 {
63 return BundleClassLoaderAccessor.loadClass(getBundle(), clazz);
64 }
65
66 public URL getResource(final String name)
67 {
68 return bundleClassLoader.getResource(name);
69 }
70
71 public InputStream getResourceAsStream(final String name)
72 {
73 return bundleClassLoader.getResourceAsStream(name);
74 }
75
76 public ClassLoader getClassLoader()
77 {
78 return bundleClassLoader;
79 }
80
81 public Bundle install()
82 {
83 logger.debug("Not installing OSGi plugin '{}' since it's already installed.", bundle.getSymbolicName());
84 throw new IllegalPluginStateException("Plugin '" + bundle.getSymbolicName() + "' has already been installed");
85 }
86
87 public void onEnable(final ServiceTracker... serviceTrackers) throws OsgiContainerException
88 {
89 for (final ServiceTracker svc : checkNotNull(serviceTrackers))
90 {
91 svc.open();
92 }
93
94 this.serviceTrackers = serviceTrackers;
95 }
96
97 public void onDisable() throws OsgiContainerException
98 {
99 final ServiceTracker[] serviceTrackers = this.serviceTrackers;
100 if(serviceTrackers != null)
101 {
102 for (final ServiceTracker svc : serviceTrackers)
103 {
104 svc.close();
105 }
106 this.serviceTrackers = null;
107 }
108 setPluginContainer(null);
109 }
110
111 public void onUninstall() throws OsgiContainerException
112 {
113 }
114
115 public Set<String> getRequiredPlugins()
116 {
117
118 if (bundle.getState() == Bundle.INSTALLED)
119 {
120 logger.debug("Bundle is in INSTALLED for {}", bundle.getSymbolicName());
121 packageAdmin.resolveBundles(new Bundle[]{bundle});
122 logger.debug("Bundle state is now {}", bundle.getState());
123 }
124
125 final Set<String> keys = new HashSet<String>();
126 getRequiredPluginsFromExports(keys);
127
128
129
130 return keys;
131 }
132
133 private void getRequiredPluginsFromExports(Set<String> keys)
134 {
135
136 final Set<String> imports = new HashSet<String>(OsgiHeaderUtil.parseHeader((String) getBundle().getHeaders().get(Constants.IMPORT_PACKAGE)).keySet());
137
138
139 imports.addAll(OsgiHeaderUtil.parseHeader((String) getBundle().getHeaders().get(Constants.DYNAMICIMPORT_PACKAGE)).keySet());
140
141
142 for (final String imp : imports)
143 {
144
145 final ExportedPackage[] exports = packageAdmin.getExportedPackages(imp);
146 if (exports != null)
147 {
148
149 for (final ExportedPackage export : exports)
150 {
151
152 final Bundle[] importingBundles = export.getImportingBundles();
153 if (importingBundles != null)
154 {
155
156 for (final Bundle importingBundle : importingBundles)
157 {
158
159 if (getBundle() == importingBundle)
160 {
161 keys.add(OsgiHeaderUtil.getPluginKey(export.getExportingBundle()));
162 break;
163 }
164 }
165 }
166 }
167 }
168 }
169 }
170
171 public void setPluginContainer(final Object container)
172 {
173 if (container == null)
174 {
175 containerAccessor = null;
176 }
177 else if (container instanceof ContainerAccessor)
178 {
179 containerAccessor = (ContainerAccessor) container;
180 }
181 else
182 {
183 containerAccessor = new DefaultSpringContainerAccessor(container);
184 }
185 }
186
187 public ContainerAccessor getContainerAccessor()
188 {
189 return containerAccessor;
190 }
191
192
193
194
195 public ContainerAccessor getRequiredContainerAccessor() throws IllegalPluginStateException
196 {
197 if (containerAccessor == null)
198 {
199 throw new IllegalStateException("Cannot create object because the plugin container is unavailable.");
200 }
201 return containerAccessor;
202 }
203
204 @Override
205 public boolean isRemotePlugin()
206 {
207 return option(getBundle().getHeaders()).fold(alwaysFalse(), new Function<Dictionary, Boolean>()
208 {
209 @Override
210 public Boolean apply(Dictionary headers)
211 {
212 return headers.get(OsgiPlugin.REMOTE_PLUGIN_KEY) != null;
213 }
214 });
215 }
216 }