View Javadoc

1   package com.atlassian.plugin.osgi.util;
2   
3   import com.atlassian.plugin.util.resource.AlternativeResourceLoader;
4   import com.atlassian.plugin.util.resource.NoOpAlternativeResourceLoader;
5   import org.apache.commons.collections.iterators.IteratorEnumeration;
6   import org.osgi.framework.Bundle;
7   
8   import java.io.IOException;
9   import java.net.URL;
10  import java.util.Arrays;
11  import java.util.Collections;
12  import java.util.Enumeration;
13  
14  import static com.atlassian.fugue.Option.option;
15  import static com.google.common.base.Preconditions.checkNotNull;
16  
17  /**
18   * Utility methods for accessing a bundle as if it was a classloader.
19   *
20   * @since 2.3.0
21   */
22  public class BundleClassLoaderAccessor
23  {
24      /**
25       * Creates a classloader that delegates to the bundle
26       * @param bundle The bundle to delegate to
27       * @param alternativeResourceLoader An alternative resource loader to bypass bundle, can be null
28       * @return A new classloader instance
29       */
30      public static ClassLoader getClassLoader(final Bundle bundle, final AlternativeResourceLoader alternativeResourceLoader)
31      {
32          return new BundleClassLoader(bundle, alternativeResourceLoader);
33      }
34  
35      /**
36       * Loads a class from the bundle
37       * @param bundle The bundle
38       * @param name The name of the class to load
39       * @param <T> The type of the class
40       * @return The class instance
41       * @throws ClassNotFoundException If the class cannot be found in the bundle
42       */
43      public static <T> Class<T> loadClass(final Bundle bundle, final String name) throws ClassNotFoundException
44      {
45          @SuppressWarnings ({ "unchecked", "UnnecessaryLocalVariable" })
46          final Class<T> loadedClass = (Class<T>) checkNotNull(bundle, "The bundle is required").loadClass(name);
47          return loadedClass;
48      }
49  
50      ///CLOVER:OFF
51      /**
52       * Fake classloader that delegates to a bundle
53       */
54      private static class BundleClassLoader extends ClassLoader
55      {
56          private final Bundle bundle;
57          private final AlternativeResourceLoader altResourceLoader;
58  
59          public BundleClassLoader(final Bundle bundle, AlternativeResourceLoader altResourceLoader)
60          {
61              super(null);
62              this.bundle = checkNotNull(bundle, "The bundle must not be null");
63              this.altResourceLoader = option(altResourceLoader).getOrElse(new NoOpAlternativeResourceLoader());
64          }
65  
66          @Override
67          public Class<?> findClass(final String name) throws ClassNotFoundException
68          {
69              return bundle.loadClass(name);
70          }
71  
72          @SuppressWarnings("unchecked")
73          @Override
74          public Enumeration<URL> findResources(final String name) throws IOException
75          {
76              Enumeration<URL> e = bundle.getResources(name);
77  
78              if (e == null)
79              {
80                  e = new IteratorEnumeration(Collections.emptyList().iterator());
81              }
82              else
83              {
84                  // For some reason, getResources() sometimes returns nothing, yet getResource() will return one.  This code
85                  // handles that strange case
86                  if (!e.hasMoreElements())
87                  {
88                      final URL resource = findResource(name);
89                      if (resource != null)
90                      {
91                          e = new IteratorEnumeration(Arrays.asList(resource).iterator());
92                      }
93                  }
94              }
95              return e;
96          }
97  
98          @Override
99          public URL findResource(final String name)
100         {
101             URL url = altResourceLoader.getResource(name);
102             if (url == null)
103             {
104                 url = bundle.getResource(name);
105             }
106             return url;
107         }
108 
109         @Override
110         public String toString()
111         {
112             final String sym = bundle.getSymbolicName();
113             return "BundleClassLoader@" + Integer.toHexString(System.identityHashCode(this)) + "[bundle=" +
114                     ((sym != null) ? sym : "") + " [" + bundle.getBundleId() + "]]";
115         }
116     }
117 
118 }