How can I use BundleWiring to lookup Bundle/Class relationships (previously done via PackageAdmin)? - osgi

I'm in the process of upgrading my application the latest release of Eclipse Equinox 3.7 and associated libraries. I'm excited to have the generic support in OSGi 4.3 and digging the new Bundle.adapt() concepts. I've run into one stumbling block.
Previously, I've used PackageAdmin.getBundle(Class) to find out which bundle loaded which classes. I have to do this due to some RMI object serialization usage.
QUESTION: Is there an way to accomplish the same result, mapping Class to Bundle, using the new BundleWiring API?
I realize that PackageAdmin is probably not going away anytime soon, but I hate deprecation warnings.

Kinda embarrassed that I didn't find this the first time I looked through the document. Answering my own question for completeness.
From the core specification PDF ...
Section 3.9.9 - Finding an Object’s Bundle
There are scenarios where a bundle is required in code that has no access to a Bundle Context. For this
reason, the framework provides the following methods:
Framework Util – Through the FrameworkUtil class with the getBundle(Class) method. The
framework provides this method to allow code to find the bundle of an object without having the
permission to get the class loader. The method returns null when the class does not originate from
a bundle.
Class Loader – An OSGi framework must ensure that the class loader of a class that comes from a
bundle implements the BundleReference interface. This allows legacy code to find an object’s
bundle by getting its class loader and casting it to a BundleReference object, which provides
access to the Bundle. However, this requires the code to have the permission to access the class
loader. The following code fragment shows how to obtain a Bundle object from any object.
ClassLoader cl = target.getClassLoader();
if ( cl instanceof BundleReference ) {
BundleReference ref = (BundleReference) cl;
Bundle b = ref.getBundle();
...
}
In an OSGi system, not all objects belong to the framework. It is therefore possible to get hold of a
class loader that does not implement the BundleReference interface, for example the boot class path
loader.

Related

how does system bundle has access to system packages?

I'm exploring how OSGI is implemented for the last couple of weeks. I know that each bundle uses its own class loader to load its classes. As part of my investigation, I understood that parent of every bundle's class loader is null i.e boot class loader.
System.out.println("ClassInBundle class is loaded by "+ClassInBundle.class.getClassLoader());
System.out.println("ClassInBundle parent class is "+ClassInBundle.class.getClassLoader().getParent());
Output for above code which is in bundle samplebundle is
ClassInBundle class is loaded by com.sample.bundle.samplebundle [34]
ClassInBundle parent class is null
and for imports in a bundle, it maintains a map of packagename=>classloader so that it can delegate requests to the correct class loader
Bundle SB = felix.getBundleContext().getBundle(0);
List<BundleWire> sbwires=SB.adapt(BundleWiring.class).getRequiredWires(null);
List<BundleWire> li=bundle.adapt(BundleWiring.class).getRequiredWires(null);
for(BundleWire i : li){
System.out.println(i);
}
The output for the above code is
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.wiring.package; (osgi.wiring.package=com.test.packag) -> [org.apache.felix.framework [0](R 0)]
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework)(version>=1.8.0)(!(version>=2.0.0))) -> [org.apache.felix.framework [0](R 0)]
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework.wiring)(version>=1.2.0)(!(version>=2.0.0))) -> [org.apache.felix.framework [0](R 0)]
[com.sample.bundle.samplebundle [34](R 34.0)] osgi.ee; (&(osgi.ee=JavaSE)(version=1.6)) -> [org.apache.felix.framework [0](R 0)]
As you can see in the first line of above output, the package com.test.packag is added as FelixConstants.FRAMEWORK_SYSTEMPACKAGES and the bundle samplebundle is wired to system bundle[0] for com.test.packag.
So, I wanted to understand how system bundle[0] can access system packages which are loaded by different class loader(App class loader). Not only that all the core classes of OSGI like Bundle, BundleActivator, Felix are also loaded by App class loader. So, I tried debugging the Felix code to understand whether the system bundle is delegating the loadClass() requests to App class loader. Unfortunately, while debugging I observed m_wiring variable of BundleWiringImpl class, I noticed that classloader of system bundle is null(which is not possible because boot class loader only loads java.* packages).
please correct my understanding if I'm wrong.
My questions here are
what is the class loader of system_bundle[0] and what is its parent class loader?
if the parent of the system_bundle class loader is not App class loader, is system bundle also maintaining the map of package=>classloader to load classes which are loaded by app class loader?
what exactly is the hierarchy of class loaders(bundle class loaders, system class loader, boot class loader, and app class loader)?
Thank you.
Normally the OSGi Framework (aka the System Bundle) is loaded by the application loader and therefore has visibility of everything else on the application loader, and its parents i.e. the extension loader and the boot loader.
It actually depends on how you write your launcher. You can embed OSGi into any standard Java application simply by instantiating a FrameworkFactory and using it to launch a Framework. When you do this, the OSGi framework is just another library on the classpath and it has visibility of the same set of classes as your own code.
You can make things as simple or as fancy as you like. For example you could embed an OSGi Framework into a Servlet deployed in a J2EE application server... in that case the system bundle will have visibility to all the types available in the Web Application, as controlled by the contents of WEB-INF. You could even embed an OSGi Framework into a bundle deployed to another OSGi Framework... OSGi inception!
In all these cases, the Framework can choose what set of packages to export. These packages become available to be imported by bundles inside that Framework. By default the packages exported are the standard set of JavaSE packages for the relevant JavaSE version, but you can augment with additional application-level packages.

Deploying BEAN in OSGi plugin

I am currently deploying my custom controls as OSGi plugins and I wanted to do the same thing with my beans. I have tried putting them into the OSGi plugin and it works fine but the only problem I have is the faces-config.
It seems it has to be called faces-config in the OSGi plugin to work but that means i can't use beans in the NSF anymore because it seems to ignore the local faces-config.
Is there a way to change the name of the faces-config in the OSGi plugin?
Something like FEATURE-faces-config.xml?
In the class in your plugin that extends AbstractXspLibrary, you can override "getFacesConfigFiles", which should return an array of strings representing paths within the plugin to additional files of any name to load as faces-config additions. For example:
#Override
public String[] getFacesConfigFiles() {
return new String[] {
"com/example/config/beans.xml"
};
}
Then you can put the config file in that path within your Java source folder (or another folder that is included in build.properties) and it will be loaded in addition to your app's normal faces-config, beans and all.
The NSFs are running as separate, distinct Java applications. The OSGi plugin is running in the OSGi layer, above all those distinct Java applications, as a single code base. Consequently, the faces-config is only at that level.
It's possible to load them dynamically, by using an ImplicitObjectFactory, loaded from an XspContributor. That's what is done in OpenNTF Domino API for e.g. userScope (which is a bean stored in applicationScope of an NSF). See org.openntf.domino.xsp.helpers.OpenntfDominoImplicitObjectFactory, which is referenced in OpenntfDominoXspContributor, loaded via the extension point of type "com.ibm.xsp.library.Contributor".
A few caveats:
You have no control over what happens if you try to register your bean with a name the developer also uses for a different variable in that scope.
Unless you add code to check if the library is enabled, as we do, you'll be adding the bean to every database on the server.
You still need to add the library to the NSF. Unless you also provide a component that those databases will all use, there's no way you can programmatically add it, as far as I know.
It might be easier to skip the bean approach and just add an instance of the Java class in beforePageLoad, page controller class, or however you're managing the backing to the relevant XPage (if viewScope) or application (if sessionScope / applicationScope).

How do I access HttpContext.Current.Session in a class library?

So, I am creating a class library that handles user information like username, password, etc. I want to do this so that I can just reference this library with any of my web apps and not have to continuously rewrite the user information part.
In, the user information class library, I want to handle the login. I've done this before in app_code that was a part of the web project by using HttpContext.Current.Session. But, when I try to use it in my class library (even while using System.Web) it throws a compile error saying that HttpContext does not exist in this context. How can I get access to it?
When creating a utility type class that works with a dependency like HttpContext, your best bet is to pass the context or the session into the class either via a constructor or the method call. That way, it is explicit to the consumers of your class that it requires this object to function. This also allows you to test your class in isolation.
Even better, if you are working with a few specific properties that have basic types then you can accept those properties as inputs. That way, you are not creating any dependencies on a UI framework for your utility library.

Why imported classes take precedence over bundle classes?

I know that the specification exactly defines it but cannot get what is the reason for this:
A class space is then all classes reachable from a given bundle’s class loader.
Thus, a class space for a given bundle can contain classes from:
• The parent class loader (normally java.* packages from the boot class path)
• Imported packages
• Required bundles
• The bundle's class path (private packages)
• Attached fragments
Let's assume:
A bundle declares "import-package: a"
There is a local class a.X in this bundle
There is a class a.X in another bundle
new a.X() would load the class from another bundle.
What is the reason that imported classes take precedence over bundle classes? Is it just a consequent continuation of java hierarchical class loading policy?
This is actually a core aspect of OSGi.
Sharing classes
The whole import/export mechanism is intended to let different bundles use the same class when communicating. Same in this case means not only binary equal, but loaded by the same class loader (recall that every bundle has its own class loader). If the bundle's own classes would be favored over imported ones, bundles would not be able to 'agree' on which copy of a class to use.
But... why?
Why would you have a copy of a class, which you also intend to import?
Consider a situation in which you want to do some logging, so you import org.osgi.service.log, but it's not a vital aspect, you can happily run without a LogService present. Now,
if you would only import the package, your bundle would fail to resolve, and thus fail to start, and
if you would only include the class, you would never use the other bundle's LogService class, so you cannot use the service (this is the agreeing part).
In this situation, you both import and include the class, so you can run in either situation, using your own copy when no one else has one, and sharing a copy if someone else does. You can even choose to export your copy, and let the framework decide.
As a sidenote, this is exactly the reason you should (almost) always import what you export.

Singletons in Cocoa Plugins

How would I get a hold of a singleton in the main application from a SIMBL plugin? When I try to call something like [ProcessControl sharedInstance], I get an error that ProcessControl is undefined (even though it is declared in a header file).
Use NSClassFromString to look up the class at run time, then send it the sharedInstance message as normal.
Be prepared for NSClassFromString to return Nil or for the message to the class to fail. Either one will happen if the application developer removes or renames the class or its singleton method. You assume this risk whenever you write a plug-in for an application that doesn't have a documented, supported plug-in API.
Your “plug-in” will be most robust if all of your code that interacts with the application's classes and instances thereof looks thoroughly paranoid.

Resources