View Javadoc

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   * Plugin that wraps an OSGi bundle that does contain a plugin descriptor.
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       * This plugin is dynamically loaded, so returns true.
64       * @return true
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                     // Should never happen
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                 // should never happen
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                 // Should never happen
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 }