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 bundle.start();
112 } catch (BundleException e)
113 {
114 throw new RuntimeException("Cannot start plugin: "+getKey(), e);
115 }
116 }
117
118 public void disabled()
119 {
120 try
121 {
122 bundle.stop();
123 } catch (BundleException e)
124 {
125 throw new RuntimeException("Cannot stop plugin: "+getKey(), e);
126 }
127 }
128
129 public void close()
130 {
131 try
132 {
133 bundle.uninstall();
134 } catch (BundleException e)
135 {
136 throw new RuntimeException("Cannot uninstall bundle " + bundle.getSymbolicName());
137 }
138 }
139
140 public <T> T autowireGeneric(Class<T> clazz)
141 {
142 return autowire(clazz, AutowireStrategy.AUTOWIRE_AUTODETECT);
143 }
144
145 public <T> T autowire(Class<T> clazz, AutowireStrategy autowireStrategy)
146 {
147 if (nativeBeanFactory == null)
148 {
149
150 try
151 {
152 BundleContext ctx = bundle.getBundleContext();
153 if (ctx == null)
154 {
155 log.warn("no bundle context - we are screwed");
156 return null;
157 }
158 ServiceReference[] services = ctx.getServiceReferences("org.springframework.context.ApplicationContext", "(org.springframework.context.service.name="+bundle.getSymbolicName()+")");
159 if (services == null || services.length == 0)
160 {
161 log.warn("No spring bean factory found");
162 return null;
163 }
164
165 Object applicationContext = ctx.getService(services[0]);
166 try
167 {
168 Method m = applicationContext.getClass().getMethod("getAutowireCapableBeanFactory");
169 nativeBeanFactory = m.invoke(applicationContext);
170 } catch (NoSuchMethodException e)
171 {
172
173 throw new RuntimeException("Cannot find createBean method on registered bean factory: "+nativeBeanFactory, e);
174 } catch (IllegalAccessException e)
175 {
176 throw new RuntimeException("Cannot access createBean method", e);
177 } catch (InvocationTargetException e)
178 {
179 throw new RuntimeException("Cannot invoke createBean method", e.getCause());
180 }
181 } catch (InvalidSyntaxException e)
182 {
183
184 throw new RuntimeException("Invalid LDAP filter", e);
185 }
186
187
188 try
189 {
190 nativeCreateBeanMethod = nativeBeanFactory.getClass().getMethod("createBean", Class.class, int.class, boolean.class);
191 } catch (NoSuchMethodException e)
192 {
193
194 throw new RuntimeException("Cannot find createBean method on registered bean factory: "+nativeBeanFactory, e);
195 }
196 }
197 try
198 {
199 return (T) nativeCreateBeanMethod.invoke(nativeBeanFactory, clazz, autowireStrategy.ordinal(), false);
200 } catch (IllegalAccessException e)
201 {
202 throw new RuntimeException("Unable to access bean:" + getExceptionMessage(e), e);
203 }
204 catch (InvocationTargetException e)
205 {
206 throw new RuntimeException("Unable to call beanfactory method:" + getExceptionMessage(e), e);
207 }
208 }
209
210 private String getExceptionMessage(Exception e) {
211 return e.getMessage() == null ? e.getCause().getMessage() : e.getMessage();
212 }
213
214 public Object autowire(Class clazz) {
215 return autowireGeneric(clazz);
216 }
217
218 public Object autowire(Class clazz, int autowireStrategy) {
219 return autowire(clazz, AutowireStrategy.fromIndex(autowireStrategy));
220 }
221 }