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