1 package com.atlassian.plugin.osgi.factory;
2
3 import java.io.InputStream;
4 import java.net.URL;
5 import java.util.HashSet;
6 import java.util.Set;
7
8 import com.atlassian.plugin.AutowireCapablePlugin;
9 import com.atlassian.plugin.IllegalPluginStateException;
10 import com.atlassian.plugin.module.ContainerAccessor;
11 import com.atlassian.plugin.osgi.container.OsgiContainerException;
12 import com.atlassian.plugin.osgi.spring.DefaultSpringContainerAccessor;
13 import com.atlassian.plugin.osgi.spring.SpringContainerAccessor;
14 import com.atlassian.plugin.osgi.util.BundleClassLoaderAccessor;
15 import com.atlassian.plugin.osgi.util.OsgiHeaderUtil;
16 import com.atlassian.plugin.util.resource.AlternativeDirectoryResourceLoader;
17
18 import org.apache.commons.lang.Validate;
19 import org.osgi.framework.Bundle;
20 import org.osgi.framework.Constants;
21 import org.osgi.service.packageadmin.ExportedPackage;
22 import org.osgi.service.packageadmin.PackageAdmin;
23 import org.osgi.util.tracker.ServiceTracker;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27
28
29
30
31
32 class OsgiPluginInstalledHelper implements OsgiPluginHelper
33 {
34 private static final Logger log = LoggerFactory.getLogger(OsgiPluginInstalledHelper.class);
35
36 private final ClassLoader bundleClassLoader;
37 private final Bundle bundle;
38 private final PackageAdmin packageAdmin;
39
40 private volatile SpringContainerAccessor containerAccessor;
41 private volatile ServiceTracker[] serviceTrackers;
42
43
44
45
46
47 public OsgiPluginInstalledHelper(final Bundle bundle, final PackageAdmin packageAdmin)
48 {
49 Validate.notNull(bundle);
50 Validate.notNull(packageAdmin);
51 this.bundle = bundle;
52 bundleClassLoader = BundleClassLoaderAccessor.getClassLoader(bundle, new AlternativeDirectoryResourceLoader());
53 this.packageAdmin = packageAdmin;
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 throw new IllegalPluginStateException("Plugin '" + bundle.getSymbolicName() + "' has already been installed");
84 }
85
86 public void onEnable(final ServiceTracker... serviceTrackers) throws OsgiContainerException
87 {
88 Validate.notNull(serviceTrackers);
89
90 for (final ServiceTracker svc : serviceTrackers)
91 {
92 svc.open();
93 }
94
95 this.serviceTrackers = serviceTrackers;
96 }
97
98 public void onDisable() throws OsgiContainerException
99 {
100 final ServiceTracker[] serviceTrackers = this.serviceTrackers;
101 if(serviceTrackers != null)
102 {
103 for (final ServiceTracker svc : serviceTrackers)
104 {
105 svc.close();
106 }
107 this.serviceTrackers = null;
108 }
109 setPluginContainer(null);
110 }
111
112 public void onUninstall() throws OsgiContainerException
113 {
114 }
115
116 public <T> T autowire(final Class<T> clazz, final AutowireCapablePlugin.AutowireStrategy autowireStrategy) throws IllegalPluginStateException
117 {
118 assertSpringContextAvailable();
119 return containerAccessor.createBean(clazz);
120 }
121
122
123
124
125
126
127
128
129
130
131 public void autowire(final Object instance, final AutowireCapablePlugin.AutowireStrategy autowireStrategy) throws IllegalPluginStateException
132 {
133 assertSpringContextAvailable();
134 containerAccessor.autowireBean(instance, autowireStrategy);
135 }
136
137 public Set<String> getRequiredPlugins()
138 {
139
140 if (bundle.getState() == Bundle.INSTALLED)
141 {
142 log.debug("Bundle is in INSTALLED for {}", bundle.getSymbolicName());
143 packageAdmin.resolveBundles(new Bundle[]{bundle});
144 log.debug("Bundle state is now {}", bundle.getState());
145 }
146
147 final Set<String> keys = new HashSet<String>();
148 getRequiredPluginsFromExports(keys);
149
150
151
152 return keys;
153 }
154
155 private void getRequiredPluginsFromExports(Set<String> keys)
156 {
157
158 final Set<String> imports = new HashSet<String>(OsgiHeaderUtil.parseHeader((String) getBundle().getHeaders().get(Constants.IMPORT_PACKAGE)).keySet());
159
160
161 imports.addAll(OsgiHeaderUtil.parseHeader((String) getBundle().getHeaders().get(Constants.DYNAMICIMPORT_PACKAGE)).keySet());
162
163
164 for (final String imp : imports)
165 {
166
167 final ExportedPackage[] exports = packageAdmin.getExportedPackages(imp);
168 if (exports != null)
169 {
170
171 for (final ExportedPackage export : exports)
172 {
173
174 final Bundle[] importingBundles = export.getImportingBundles();
175 if (importingBundles != null)
176 {
177
178 for (final Bundle importingBundle : importingBundles)
179 {
180
181 if (getBundle() == importingBundle)
182 {
183 keys.add(OsgiHeaderUtil.getPluginKey(export.getExportingBundle()));
184 break;
185 }
186 }
187 }
188 }
189 }
190 }
191 }
192
193 public void setPluginContainer(final Object container)
194 {
195 if (container == null)
196 {
197 containerAccessor = null;
198 }
199 else
200 {
201 containerAccessor = new DefaultSpringContainerAccessor(container);
202 }
203 }
204
205 public ContainerAccessor getContainerAccessor()
206 {
207 return containerAccessor;
208 }
209
210
211
212
213 private void assertSpringContextAvailable() throws IllegalPluginStateException
214 {
215 if (containerAccessor == null)
216 {
217 throw new IllegalStateException("Cannot autowire object because the Spring context is unavailable. " +
218 "Ensure your OSGi bundle contains the 'Spring-Context' header.");
219 }
220 }
221
222 }