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 *.
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