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             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                     // Should never happen
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                 // should never happen
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                 // Should never happen
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 }