public void start(BundleContext context) throws Exception { super.start(context); plugin = this; System.out.println(PLUGIN_ID + ":Activator::start invoked"); try { System.out.println(PLUGIN_ID + ":Activator::start installing bundle"); Bundle b = context.installBundle("file:///home/beyonddc/workspace/deployed_plugin/plugins/dc_buddypolicy_plugin1_1.0.0.jar"); System.out.println(PLUGIN_ID + ":Activator::start installed bundle"); b.start(); System.out.println("Invoking Class.forName()"); Class lc = Class.forName("dc_buddypolicy_plugin1.Logger"); } catch (Throwable th) { th.printStackTrace(); } }
dc_buddypolicy_plugin3:Activator::start invoked dc_buddypolicy_plugin3:Activator::start installing bundle dc_buddypolicy_plugin3:Activator::start installed bundle dc_buddypolicy_plugin3:Activator::start dc_buddypolicy_plugin1 INSTALLED dc_buddypolicy_plugin1:Activator - start - invoked [08272012] dc_buddypolicy_plugin1::logger - dc_buddypolicy_plugin1:Activator::start invoked [08272012] Invoking Class.forName() java.lang.ClassNotFoundException: dc_buddypolicy_plugin1.Logger
Bundle b = context.installBundle(...); b.loadClass("dc_buddypolicy_plugin1.Logger")
<!-- dc_buddypolicy_plugin1 --> Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Buddy Policy Plugin 1 Bundle-SymbolicName: dc_buddypolicy_plugin1; singleton:=true Bundle-Version: 1.0.0 Bundle-Activator: dc_buddypolicy_plugin1.Activator Bundle-Vendor: David Chu Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: dc_buddypolicy_plugin1 Eclipse-RegisterBuddy: dc_buddypolicy_plugin3
<!-- dc_buddypolicy_plugin3 --> Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Buddy Policy Plugin3 Bundle-SymbolicName: dc_buddypolicy_plugin3; singleton:=true Bundle-Version: 1.0.0 Bundle-Activator: dc_buddypolicy_plugin3.Activator Bundle-Vendor: David Chu Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: dc_buddypolicy_plugin3 Eclipse-BuddyPolicy: registered
Classname is dc_buddypolicy_plugin1.Logger java.lang.NoClassDefFoundError: dc_buddypolicy_plugin1/Logger at dc_buddypolicy_plugin3.Activator.start(Activator.java:70) b.start(); Class<dc_buddypolicy_plugin1.Logger> logclass = b.loadClass("dc_buddypolicy_plugin1.Logger"); System.out.println("Classname is " + logclass.getName()); dc_buddypolicy_plugin1.Logger.logMsg(PLUGIN_ID + ":Activator", "start", "invoked")
Bundle-ClassPath: ., pathToJarThatContainsTheClass/jarThatContainsTheClass.jar
Class<dc_buddypolicy_plugin1.Logger> logclass = b.loadClass("dc_buddypolicy_plugin1.Logger"); "System.out.println("Classname is " + logclass.getName());"
Class<dc_buddypolicy_plugin1.Logger> logclass = b.loadClass("dc_buddypolicy_plugin1.Logger"); System.out.println("Classname is " + logclass.getName()); dc_buddypolicy_plugin1.Logger.logMsg(PLUGIN_ID + ":Activator", "start", "invoked");
Class<dc_buddypolicy_plugin1.Logger> logclass = b.loadClass("dc_buddypolicy_plugin1.Logger"); System.out.println("Classname is " + logclass.getName()); Class[] argTypes = new Class[] { String.class, String.class, String.class }; java.lang.reflect.Method logMsg = logclass.getDeclaredMethod("logMsg", argTypes); String[] msgArgs = new String[] { "test1", "test2", "test3" }; logMsg.invoke(null, msgArgs);
Sorry but there is a little missunderstanding. You should certainly not add /home/beyonddc/workspace/deployed_plugin/plugins/dc_buddypolicy_plugin1_1.0.0.jarto the classpath of plugin3. First of all it is an absolute path which has nothing to do in a manifest. What if you decide to give the plugin to someone else? And then if you add it to plugin3 what is the need of plugin1 anyway?
You need to add the Bundle-ClassPath to the manifest if the classes are located in a jar. So for example if your logger is packed in a jar logger.jar and you place the jar into a lib folder located in your plugin, then you should add logger.jar to the classpath. In that case the classpath would be:
Bundle-ClassPath: ., lib/logger.jar
Where lib is a folder located in your plugin1.
If on the other hand your class is located in a folder dc_buddypolicy_plugin1/Logger.class and the folder itself is located in the root of dc_buddypolicy_plugin1_1.0.0.jar, then
Bundle-ClassPath: .
Is sufficient. I am not sure whether Bundle-ClassPath can be neglected in that case. At least it does not harm.
You definetly have to remove /home/beyonddc/workspace/deployed_plugin/plugins/dc_buddypolicy_plugin1_1.0.0.jar from the classpath of plugin3!!!
May I ask why you want to use the buddy policy to resolve the class from plugin1? As far as I know the buddy policy was introduced to overcome class loading issues when bundles cannot make use of the normal OSGI delegation model. Since you have a simple OSGI bundle with one class, why don't you just import the package or the bundle into plugin3? And what is the use of loading the plugin programmatically? Why don't you just add it to your configuration? Is this just a proof of concept?
Regarding your reflection question: Why would you load the class other than to use it for reflection? If you were already able to load the class before modifying the Bundle-ClassPath then go back to that point and use the class with reflection.
Regards,
Thorsten
public void start(BundleContext context) throws Exception { super.start(context); plugin = this; System.out.println(PLUGIN_ID + ":Activator::start invoked"); try { System.out.println(PLUGIN_ID + ":Activator::start installing bundle"); Bundle b = context.installBundle("reference:file:///home/beyonddc/workspace/exported_plugins/plugins/dc_buddypolicy_plugin1_1.0.0.jar"); System.out.println(PLUGIN_ID + ":Activator::start installed bundle"); b.start(); dc_buddypolicy_plugin1.Logger.logMsg(PLUGIN_ID + ":Activator", "start", "invoked"); } catch (Throwable th) { th.printStackTrace(); }
recap: You want to install bundle1 at runtime from bundle3 and then use it from bundle3.
bundle3 can't see your bundle1 classes by default. You'd either have to require the bundle bundle1 or import the packages from bundle1 into bundle3. But then bundle1 would have to be there at compile time for sure, and (even if optional) you would not be able to load a class that references anything from bundle3 (until after it had been installed and PackageAdmin or Wiring had been updated).
The OSGi pattern to do this would be to provide a service interface (something that will allow you to start using the bundle1 functionality). Then you have bundle1 provide the service (preferably through Declarative Services) and bundle3 would consume the service (use a ServiceTracker, for example).
Then when bundle1 is installed the service it provides (a logger?) would become available to bundle3.
PW