As Felix mentions you should have a look at
org.osgi.service.packageadmin.PackageAdmin#getBundle(Class clazz)

The hack you did in Equinox is similar to the code behind the
PackageAdmin#getBundle method.

Tom




                                                                       
  From:       Felix Meschberger <[EMAIL PROTECTED]>                   
                                                                       
  To:         OSGi Developer Mail List <[email protected]>        
                                                                       
  Date:       01/21/2008 06:26 AM                                      
                                                                       
  Subject:    Re: [osgi-dev] How to get bundle for an arbitrary class  
                                                                       





Hi Walter,

Not sure, but PackageAdmin.getBundle(Class clazz) (of the Package Admin
Service) comes to my mind ... I am not sure, though, how this would
react to your AOP stuff, you are also referring to.

Regards
Felix

Am Montag, den 21.01.2008, 12:29 +0100 schrieb Wouter de Vaal:
> Hi,
>
> The following mail is about an issue we have and we have already
> discussed this with Peter Kriens on the JavaPolis
> in december and he suggested posted this on the osgi-dev, it is a bit
> belated, but here goes.
>
> To sum it all up, we did not find a way to get the bundle information
> for an arbitray class. The long version, see below.
>
> We are using a project that uses wicket as a front end and we have our
> components separated using bundles. The
> classes that comprise the wicket components are not know forehand, but
> are configured by user action and the
> classnames are stored in a database, together with their bundle
> symbolic name and version (there can be multiple
> versions of the same bundle running in 1 environment, so versioning is
> crucial). Our problem is that wicket
> serializes these objects using ObjectOutputStream and then reloads
> them at a later date. The problem is that
> these classes are not wired, but dynamically loaded using exact
> bundle/version matching, which ObjectInput/OutputStream
> has no notion of. What we could do is plug in our own subclasses of
> ObjectInput/OutputStream. What we are
> doing is writing extra version/bundle information into the byte stream
> and reading it back in. For reading
> in the class we can just iterate through the bundles until we have a
> match, however finding the bundle
> and version on an arbitrary class, now that's a whole different
> story.
>
> There is a lot of information here, so I hope you bear with me.
>
> The outputstream class just writes out a flag that we have a versioned
> class and after that the information.
> public class MultiVersionObjectOutputStream extends ObjectOutputStream
> {
>
>     private final IClassVersionStringProvider
> classVersionStringProvider;
>
>     public MultiVersionObjectOutputStream(final OutputStream out,
> final IClassVersionStringProvider classVersionStringProvider) throws
> IOException {
>         super(out);
>         this.classVersionStringProvider = classVersionStringProvider;
>     }
>
>     @Override
>     protected void writeClassDescriptor(final ObjectStreamClass desc)
> throws IOException {
>         final String versionString =
> classVersionStringProvider.getClassVersionString(desc.forClass());
>         writeBoolean(versionString != null);
>         if (versionString != null) {
>             writeUTF(versionString);
>         }
>         super.writeClassDescriptor(desc);
>     }
>
> }
>
> The information is delivered by this interface
> public interface IClassVersionStringProvider {
>
>     String getClassVersionString(Class<?> clazz);
>
> }
>
> Now here is the problem, how do we get the specific bundle for a
> class? First thoughts, just get skip
> through the bundles and do a reference check on the class object.
>
> Our specific implementation looks like this
>     public String getClassVersionString(Class<?> clazz) {
>         // locate correct bundle, reads our database
>         Bundle foundBundle = Activator.getBundleForClass(clazz);
>         String symName = foundBundle.getSymbolicName();
>         String version = (String)
> foundBundle.getHeaders().get(Constants.BUNDLE_VERSION);
>         return symName + "%" + version;
>     }
>
> in activator:
>
>     public static Bundle getBundleForClass(Class clazz) {
>         // find bundle
>         Bundle[] bundles = instance.context.getBundles();
>         // locate correct bundle
>         for (Bundle bundle : bundles) {
>             try {
>                 Class clazz2 = bundle.loadClass(clazz.getName());
>                 if (clazz2 == clazz){
>                     return bundle;
>                 }
>             } catch (ClassNotFoundException e) {
>                 continue;
>             }
>         }
>         return null;
>     }
>
> Problem is, this doesn't work for us. In our specific case, we get two
> hits, one of the real bundle and one
> on the spring-aop bundle, so other bundles that dynamically load
> classes and incidentally have loaded
> our class, also match the criteria, but the information got from that
> bundle is no good, as when loading
> the class from that bundle, which it does so dynamically, will give
> the class from the bundle with the
> highest version number, but we need exact version matching.
>
> Up until know we did not find an good solution for this, however we
> managed to hack an equinox specific
> solution to our problem:
>     @Override
>     public String getClassVersionString(Class<?> clazz) {
>         // locate correct bundle
>         ClassLoader cl = clazz.getClassLoader();
>         if (cl != null &&
>
cl.getClass().getName().equals("org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader"))
 {
>             Bundle foundBundle = null;
>             try {
>                 Method m =
> cl.getClass().getDeclaredMethod("getDelegate");
>                 Object classLoaderDelegate = m.invoke(cl);
>                 Method m2 =
> classLoaderDelegate.getClass().getDeclaredMethod("getBundle");
>                 m2.setAccessible(true);
>                 foundBundle = (Bundle) m2.invoke(classLoaderDelegate);
>             } catch (Exception e) {
>                 throw new IllegalArgumentException(e);
>             }
>             String symName = foundBundle.getSymbolicName();
>             String version = (String)
> foundBundle.getHeaders().get(Constants.BUNDLE_VERSION );
>             return symName + "%" + version;
>         }
>         return null;
>     }
>
> <sarcasm>nice eh?</sarcasm>. What we really would like to see and
> perhaps this is a good addition for the r5 specs, is
> a generic way to get bundle information when you only have a Class
> object.
>
>
> For completeness, here follows the input part of the process.
>
> public class MultiVersionObjectInputStream extends ObjectInputStream
> {
>
>     private final IMultiVersionClassResolver classResolver;
>
>     private String versionString;
>
>     public MultiVersionObjectInputStream(final InputStream in, final
> IMultiVersionClassResolver classResolver) throws IOException {
>         super(in);
>         this.classResolver = classResolver;
>     }
>
>     @Override
>     protected ObjectStreamClass readClassDescriptor() throws
> IOException, ClassNotFoundException {
>         final boolean hasVersionString = readBoolean();
>         versionString = hasVersionString ? readUTF() : null;
>         return super.readClassDescriptor();
>     }
>
>     @Override
>     protected Class<?> resolveClass(final ObjectStreamClass desc)
> throws IOException, ClassNotFoundException {
>         if (versionString != null) {
>             return classResolver.resolveClass(desc.getName(),
> versionString);
>         }
>         return super.resolveClass(desc);
>     }
>
> }
>
> public interface IMultiVersionClassResolver {
>
>     Class<?> resolveClass(String className, String versionString)
> throws ClassNotFoundException;
>
> }
>
> and our implementation
> public class LayoutBundleClassResolver implements
> IMultiVersionClassResolver{
>
>     @Override
>     public Class<?> resolveClass(final String className, final String
> versionString) throws ClassNotFoundException {
>         int sepIndex = versionString.indexOf('%');
>         String bundleSymname = versionString.substring(0, sepIndex);
>         String bundleVersion = versionString.substring(sepIndex + 1);
>         Class<?> clazz = Activator.loadClass(className, bundleSymname,
> bundleVersion);
>         if (clazz == null) {
>             throw new ClassNotFoundException("Could not find bundle
> for bundle symbolic name " + bundleSymname + " and version "
>                     + bundleVersion + " for class " + className);
>         }
>         return clazz;
>
>     }
>
> }
>
> and in activator (here we use a utility class from Spring DM):
>     public static Class<?> loadClass(String className, String
> bundleSymbolicName, String version) throws ClassNotFoundException{
>         // find bundle
>         Bundle[] bundles = instance.context.getBundles();
>         // locate correct bundle
>         for (Bundle bundle : bundles) {
>             String symName = foundBundle.getSymbolicName ();
>             String foundVersion = (String)
> bundle.getHeaders().get(Constants.BUNDLE_VERSION);
>
>             if (symName.startsWith(bundleSymbolicName) &&
> version.equals(foundVersion)) {
>                 // got the bundle, load the class
>                 BundleDelegatingClassLoader cl =
> BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle);
>                 return cl.loadClass(className);
>             }
>         }
>         return null;
>     }
>
> Regards,
> Wouter de Vaal
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> http://www2.osgi.org/mailman/listinfo/osgi-dev

_______________________________________________
OSGi Developer Mail List
[email protected]
http://www2.osgi.org/mailman/listinfo/osgi-dev

<<inline: graycol.gif>>

<<inline: ecblank.gif>>

_______________________________________________
OSGi Developer Mail List
[email protected]
http://www2.osgi.org/mailman/listinfo/osgi-dev

Reply via email to