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
