1 package com.atlassian.plugin.osgi.loader;
2
3 import com.atlassian.plugin.impl.AbstractPlugin;
4 import com.atlassian.plugin.impl.DynamicPlugin;
5 import com.atlassian.plugin.StateAware;
6 import com.atlassian.plugin.AutowireCapablePlugin;
7
8 import java.net.URL;
9 import java.io.InputStream;
10 import java.lang.reflect.Method;
11 import java.lang.reflect.InvocationTargetException;
12
13 import org.osgi.framework.*;
14 import org.apache.commons.logging.Log;
15 import org.apache.commons.logging.LogFactory;
16
17
18
19
20 public class OsgiPlugin extends AbstractPlugin implements StateAware, AutowireCapablePlugin, DynamicPlugin
21 {
22 private Bundle bundle;
23 private static final Log log = LogFactory.getLog(OsgiPlugin.class);
24 private boolean deletable = true;
25 private boolean bundled = false;
26 private Object nativeBeanFactory;
27 private Method nativeCreateBeanMethod;
28
29 public OsgiPlugin(Bundle bundle) {
30 this.bundle = bundle;
31 }
32
33 public Bundle getBundle() {
34 return bundle;
35 }
36
37 public Class loadClass(String clazz, Class callingClass) throws ClassNotFoundException
38 {
39 return BundleClassLoaderAccessor.loadClass(bundle, clazz, callingClass);
40 }
41
42 public boolean isUninstallable()
43 {
44 return true;
45 }
46
47 public URL getResource(String name)
48 {
49 return BundleClassLoaderAccessor.getResource(bundle, name);
50 }
51
52 public InputStream getResourceAsStream(String name)
53 {
54 return BundleClassLoaderAccessor.getResourceAsStream(bundle, name);
55 }
56
57 public ClassLoader getClassLoader()
58 {
59 return BundleClassLoaderAccessor.getClassLoader(bundle);
60 }
61
62
63
64
65
66 public boolean isDynamicallyLoaded()
67 {
68 return true;
69 }
70
71
72 public boolean isDeleteable()
73 {
74 return deletable;
75 }
76
77 public void setDeletable(boolean deletable)
78 {
79 this.deletable = deletable;
80 }
81
82 public boolean isBundledPlugin()
83 {
84 return bundled;
85 }
86
87 public void setBundled(boolean bundled)
88 {
89 this.bundled = bundled;
90 }
91
92 public boolean isEnabled()
93 {
94 return Bundle.ACTIVE == bundle.getState();
95 }
96
97 public void setEnabled(boolean enabled)
98 {
99 if (enabled) {
100 enabled();
101 }
102 else {
103 disabled();
104 }
105 }
106
107 public void enabled()
108 {
109 try
110 {
111 if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.INSTALLED)
112 bundle.start();
113 } catch (BundleException e)
114 {
115 throw new RuntimeException("Cannot start plugin: "+getKey(), e);
116 }
117 }
118
119 public void disabled()
120 {
121 try
122 {
123 if (bundle.getState() == Bundle.ACTIVE)
124 bundle.stop();
125 } catch (BundleException e)
126 {
127 throw new RuntimeException("Cannot stop plugin: "+getKey(), e);
128 }
129 }
130
131 public void close()
132 {
133 try
134 {
135 if (bundle.getState() != Bundle.UNINSTALLED)
136 bundle.uninstall();
137 } catch (BundleException e)
138 {
139 throw new RuntimeException("Cannot uninstall bundle " + bundle.getSymbolicName());
140 }
141 }
142
143 public <T> T autowireGeneric(Class<T> clazz)
144 {
145 return autowire(clazz, AutowireStrategy.AUTOWIRE_AUTODETECT);
146 }
147
148 public <T> T autowire(Class<T> clazz, AutowireStrategy autowireStrategy)
149 {
150 if (nativeBeanFactory == null)
151 {
152
153 try
154 {
155 BundleContext ctx = bundle.getBundleContext();
156 if (ctx == null)
157 {
158 log.warn("no bundle context - we are screwed");
159 return null;
160 }
161 ServiceReference[] services = ctx.getServiceReferences("org.springframework.context.ApplicationContext", "(org.springframework.context.service.name="+bundle.getSymbolicName()+")");
162 if (services == null || services.length == 0)
163 {
164 log.warn("No spring bean factory found");
165 return null;
166 }
167
168 Object applicationContext = ctx.getService(services[0]);
169 try
170 {
171 Method m = applicationContext.getClass().getMethod("getAutowireCapableBeanFactory");
172 nativeBeanFactory = m.invoke(applicationContext);
173 } catch (NoSuchMethodException e)
174 {
175
176 throw new RuntimeException("Cannot find createBean method on registered bean factory: "+nativeBeanFactory, e);
177 } catch (IllegalAccessException e)
178 {
179 throw new RuntimeException("Cannot access createBean method", e);
180 } catch (InvocationTargetException e)
181 {
182 throw new RuntimeException("Cannot invoke createBean method", e.getCause());
183 }
184 } catch (InvalidSyntaxException e)
185 {
186
187 throw new RuntimeException("Invalid LDAP filter", e);
188 }
189
190
191 try
192 {
193 nativeCreateBeanMethod = nativeBeanFactory.getClass().getMethod("createBean", Class.class, int.class, boolean.class);
194 } catch (NoSuchMethodException e)
195 {
196
197 throw new RuntimeException("Cannot find createBean method on registered bean factory: "+nativeBeanFactory, e);
198 }
199 }
200 try
201 {
202 return (T) nativeCreateBeanMethod.invoke(nativeBeanFactory, clazz, autowireStrategy.ordinal(), false);
203 } catch (IllegalAccessException e)
204 {
205 throw new RuntimeException("Unable to access bean:" + getExceptionMessage(e), e);
206 }
207 catch (InvocationTargetException e)
208 {
209 throw new RuntimeException("Unable to call beanfactory method:" + getExceptionMessage(e), e);
210 }
211 }
212
213 private String getExceptionMessage(Exception e) {
214 return e.getMessage() == null ? e.getCause().getMessage() : e.getMessage();
215 }
216
217 public Object autowire(Class clazz) {
218 return autowireGeneric(clazz);
219 }
220
221 public Object autowire(Class clazz, int autowireStrategy) {
222 return autowire(clazz, AutowireStrategy.fromIndex(autowireStrategy));
223 }
224 }