Great. Thanks for the feedback.

Am Montag, den 21.01.2008, 15:01 +0100 schrieb Wouter de Vaal:
> Cool! Yep that does the trick. In fact, the reflection code we
> distilled from equinox does the exact same thing as the equinox
> implementation of PackageManager.
> 
> Thanks!
> 
> Wouter
> P.S: the aop stuff only gets in the way when you try to load classes
> from every bundle, because of dynamic imports, it hasn't exactly
> anything to do with aop, it was just this sepific bundle that has a
> dynamic import of *. 

ok.

Regards
Felix

> 
> On Jan 21, 2008 1:21 PM, Felix Meschberger <[EMAIL PROTECTED]> wrote:
>         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
> 
> _______________________________________________
> 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

Reply via email to