Equinox (the Eclipse OSGi runtime) can be launched via a Java process if you have an existing Java application that needs integration. You can of course run it by putting
startup.jar
on the classpath, and running
org.eclipse.core.launcher.Main
's
main
or
run
methods.
It also installs the HelloWorld.jar from the EclipseZone demo on
OSGi at JSIG
, as well as starting the bundle. You can
telnet localhost 1234
in order to interact with the framework.
Of course, this a trivial example, but the Java application could be a servlet, GUI client (including Swing) or middleware in a message oriented application; the principle is the same. The only tricky part will be ensuring that any place this is used manages a single instance of the OSGi engine; Equinox uses a number of paths (e.g. the
osgi.configuration.area
and
osgi.instance.area
) that need to be customised on a per-OSGi instance.
Alex,
Thanks for posting this code. How would you go about:
Configuring for local bundle store
Configure to not use a console, the reason is I would like to use the frame work in a infrastructure application.
This is a good start an exposing people to the OSGI framework. I have the older versions of the Equinox examples that watch a local location for new bundles then the framework automatically loads the bundle. That example does not seem to work with this version or it just could be the framework is not configured for the local bundle store.
Any help to get the wrinkles worked out would be appreciated.
Regards
richwt
You don't have to specify the -console arg if you don't want to; I merely presented that so that you could see what was happening if you wanted to.
You can set the osgi.bundles property to show what comes up automatically; in Eclipse, it's usually org.eclipse.update.configurator (which doesn't watch a location, but scans it once on startup AFAIK). You're almost certainly not starting that. Of course, you don't need to specify that; you can add it at run-time too.
You might also want to check out Peter's FileInstall which does watch a location:
Of course, you'd need to make sure you install/start that bundle before it will do its thing, but you have plenty of control over that as I've noted here.
Does this Method only work using a .jar - file? Is it possible to start a RCP from another class in the same project?
Would you please explain me how I can choose the parameters in the variable equinoxArgs?
I tried your example and it worked.
Then I generated (using the launcher of the rcp.product) a jar file of my RCP and replaced the part "http:... " with "file//..." as absolute path to the .jar- file (inside my workspace). I get a lot error messages (file cannot be found ...), and think that I m using the wrong equinoxArgs (?).
In a java application, how would you call a service provided by a bundle? I've tried obtaining the service using the Service Reference and ServiceTracker method but I get a ClassCastException when I try to cast the service to the interface. The debugger shows me the service is a implementation of the interface I'm trying to cast but I still get the exception. I can call the service from another OSGi bundle but not from my host java application.
I was able to call the service from my java app by setting the argument osgi.parentClassloader=app. I read somewhere that it could have been a class loader problem so I tried setting this argument which I think by default is set to boot and it didn't give me a class cast exception. I'm not exactly sure why it works but it did. Do you have any insights on why it worked?
It's really not a good idea to call stuff inside the OSGi framework from outside the framework; even with mucking around with boot delegation, it's still hit or miss as to whether it works.
So is there a good way for a host application to utilize the services the bundles provide. The example would be if the application only wanted to use OSGi as a plugin system and have the core application interact with the plugins.
No; the whole point of OSGi is to control the classpaths of bundles. You can't do that if your top-level app is in a state where that classpath can't be managed.
On the other hand, it's relatively trivial to convert your existing app into one big bundle. and run it as an IApplication, from which it will be able to participate in OSGi:
Thanks for the article. I have some questions (I also posted these questions in Equinox forums):
1. I need to send parameter to org.eclipse.equinox.http.jetty_1.0.0.20071010-2241.jar bundle that tells it to open at the specified port. When I launch Equinox from Eclipse I only have to put "-Dorg.osgi.service.http.port=8080" at the VM arguments section. How do I pass this ?
Also when I start the bundle it throws the following exception:
org.osgi.framework.BundleException: Exception in org.eclipse.equinox.http.jetty.internal.Activator.start() of bundle org.eclipse.equinox.http.jetty.
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:1010)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:966)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:317)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:256)
at com.farbeyond.core.test.TestCore.startTest(TestCore.java:80)
Caused by: java.lang.ExceptionInInitializerError
at org.eclipse.equinox.http.jetty.internal.HttpServerManager.updated(HttpServerManager.java:78)
at org.eclipse.equinox.http.jetty.internal.Activator.start(Activator.java:52)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:991)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:985)
... 26 more
Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed. (Caused by org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed.) (Caused by org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed. (Caused by org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed.))
at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:543)
at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:235)
at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:209)
at org.mortbay.log.LogFactory.getLog(LogFactory.java:28)
at org.mortbay.util.Container.<clinit>(Container.java:39)
... 31 more
Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed. (Caused by org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed.)
at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:397)
at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529)
... 35 more
Caused by: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed.
at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:385)
... 36 more
... Removed 22 stack frames
2. One of my bundles actually points to an Eclipse plugin project that's not jarred yet. Since installBundle method apparently expects url that points to jar files, how do I tell Equinox to install this bundle ?
I've tried the following code:
bundle = context.installBundle("reference:file:<path to my project folder>");
bundle.start;
but then it throws ClassNotFoundException exception stating that it can not find my activator class.
3. Since starting this Equinox takes place on startup method of a TestCase class, do I have to call each bundle's stop method on teardown method or will just calling EclipseStarter.shutdown do the job ?
Sorry for the lengthy questions since I'm new to this great stuff.
Using -D on the command line is equivalent to System.setProperty("port","8888")
The exception clearly states the problem:
"Caused by: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed."
You can't run and install the bundle from the project location, since the layout is not in OSGi format (and the PDE does weird'n'wonderful things to make it so at runtime). You have to Jar it.
You can just call EclipseStarter.shutdown() to take the system down. All bundles will be stopped.
> Using -D on the command line is equivalent to
> System.setProperty("port","8888")
Thanks. It works.
> The exception clearly states the problem:
>
> "Caused by:
> org.apache.commons.logging.LogConfigurationException:
> Invalid class loader hierarchy. You have more than
> one version of 'org.apache.commons.logging.Log'
> visible, which is not allowed."
> You can't run and install the bundle from the project
> location, since the layout is not in OSGi format (and
> the PDE does weird'n'wonderful things to make it so
> at runtime). You have to Jar it.
Ah, this is a showstopper to me. Since the plugin I'm testing is under development there's no way I have to jar it first to be testable.
> You can just call EclipseStarter.shutdown() to take
> the system down. All bundles will be stopped.
Starting Equinox from a Java application
At 6:33 PM on Apr 30, 2007, Alex Blewitt
wrote:
startup.jaron the classpath, and runningorg.eclipse.core.launcher.Main'smainorrunmethods.Alternatively, you can use
org.eclipse.core.runtime.adaptor.EclipseStarter, which is in theorg.eclipse.osgiJar. It hasmainandrunmethods as well, so either of these can be used. The parsing of the arguments is the same as launching from the command line .Here's an example of bringing code up in a Java app to start a console on a networked socket inside a Java application:
// Run with java -cp org.eclipse.osgi_3.2.x.x.jar;. Demo import org.osgi.framework.*; import org.eclipse.core.runtime.adaptor.*; public class Demo { public static void main(String args[]) throws Exception { String[] equinoxArgs = {"-console","1234","-noExit"}; BundleContext context = EclipseStarter.startup(equinoxArgs,null); Bundle bundle = context.installBundle( "http://www.eclipsezone.com/files/jsig/bundles/HelloWorld.jar"); bundle.start(); } }It also installs the HelloWorld.jar from the EclipseZone demo on OSGi at JSIG , as well as starting the bundle. You can
telnet localhost 1234in order to interact with the framework.Of course, this a trivial example, but the Java application could be a servlet, GUI client (including Swing) or middleware in a message oriented application; the principle is the same. The only tricky part will be ensuring that any place this is used manages a single instance of the OSGi engine; Equinox uses a number of paths (e.g. the
osgi.configuration.areaandosgi.instance.area) that need to be customised on a per-OSGi instance.Alex.
14 replies so far (
Post your own)
Re: Starting Equinox from a Java application
Hmm. Can I start two? Those static methods are so NOT embeddable...Re: Starting Equinox from a Java application
Embeddable != can run multiple instancesAlex.
Re: Starting Equinox from a Java application
Alex,Thanks for posting this code. How would you go about:
Configuring for local bundle store
Configure to not use a console, the reason is I would like to use the frame work in a infrastructure application.
This is a good start an exposing people to the OSGI framework. I have the older versions of the Equinox examples that watch a local location for new bundles then the framework automatically loads the bundle. That example does not seem to work with this version or it just could be the framework is not configured for the local bundle store.
Any help to get the wrinkles worked out would be appreciated.
Regards
richwt
Re: Starting Equinox from a Java application
You don't have to specify the -console arg if you don't want to; I merely presented that so that you could see what was happening if you wanted to.You can set the osgi.bundles property to show what comes up automatically; in Eclipse, it's usually org.eclipse.update.configurator (which doesn't watch a location, but scans it once on startup AFAIK). You're almost certainly not starting that. Of course, you don't need to specify that; you can add it at run-time too.
You might also want to check out Peter's FileInstall which does watch a location:
http://www.aqute.biz/Blog/2007-05-25
Of course, you'd need to make sure you install/start that bundle before it will do its thing, but you have plenty of control over that as I've noted here.
Alex.
Re: Starting Equinox from a Java application
Does this Method only work using a .jar - file? Is it possible to start a RCP from another class in the same project?Would you please explain me how I can choose the parameters in the variable equinoxArgs?
I tried your example and it worked.
Then I generated (using the launcher of the rcp.product) a jar file of my RCP and replaced the part "http:... " with "file//..." as absolute path to the .jar- file (inside my workspace). I get a lot error messages (file cannot be found ...), and think that I m using the wrong equinoxArgs (?).
I look forward to your answer
Greetings,
Miriam K.
http://www.duentscheidest.com
http://www.renshishen.com
Re: Starting Equinox from a Java application
In a java application, how would you call a service provided by a bundle? I've tried obtaining the service using the Service Reference and ServiceTracker method but I get a ClassCastException when I try to cast the service to the interface. The debugger shows me the service is a implementation of the interface I'm trying to cast but I still get the exception. I can call the service from another OSGi bundle but not from my host java application.Has anyone encountered this before?
thanks.
Re: Starting Equinox from a Java application
You'll have to do that from within an OSGi environment, not the Java App. The ClassCast is because the classes are incompatible with each other.Alex.
Re: Starting Equinox from a Java application
Alex,I was able to call the service from my java app by setting the argument osgi.parentClassloader=app. I read somewhere that it could have been a class loader problem so I tried setting this argument which I think by default is set to boot and it didn't give me a class cast exception. I'm not exactly sure why it works but it did. Do you have any insights on why it worked?
Bryant
Re: Starting Equinox from a Java application
It's really not a good idea to call stuff inside the OSGi framework from outside the framework; even with mucking around with boot delegation, it's still hit or miss as to whether it works.Alex.
Re: Starting Equinox from a Java application
So is there a good way for a host application to utilize the services the bundles provide. The example would be if the application only wanted to use OSGi as a plugin system and have the core application interact with the plugins.-Bryant
Re: Starting Equinox from a Java application
No; the whole point of OSGi is to control the classpaths of bundles. You can't do that if your top-level app is in a state where that classpath can't be managed.On the other hand, it's relatively trivial to convert your existing app into one big bundle. and run it as an IApplication, from which it will be able to participate in OSGi:
http://www.eclipsezone.com/eclipse/forums/t99762.html
Alex.
Re: Starting Equinox from a Java application
Hi Alex,Thanks for the article. I have some questions (I also posted these questions in Equinox forums):
1. I need to send parameter to org.eclipse.equinox.http.jetty_1.0.0.20071010-2241.jar bundle that tells it to open at the specified port. When I launch Equinox from Eclipse I only have to put "-Dorg.osgi.service.http.port=8080" at the VM arguments section. How do I pass this ?
Also when I start the bundle it throws the following exception:
2. One of my bundles actually points to an Eclipse plugin project that's not jarred yet. Since installBundle method apparently expects url that points to jar files, how do I tell Equinox to install this bundle ?
I've tried the following code:
bundle = context.installBundle("reference:file:<path to my project folder>"); bundle.start;but then it throws ClassNotFoundException exception stating that it can not find my activator class.
3. Since starting this Equinox takes place on startup method of a TestCase class, do I have to call each bundle's stop method on teardown method or will just calling EclipseStarter.shutdown do the job ?
Sorry for the lengthy questions since I'm new to this great stuff.
Thanks and regards.
Setya
Re: Starting Equinox from a Java application
Using -D on the command line is equivalent to System.setProperty("port","8888")The exception clearly states the problem:
"Caused by: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed."
You can't run and install the bundle from the project location, since the layout is not in OSGi format (and the PDE does weird'n'wonderful things to make it so at runtime). You have to Jar it.
You can just call EclipseStarter.shutdown() to take the system down. All bundles will be stopped.
Alex.
Re: Starting Equinox from a Java application
> Using -D on the command line is equivalent to> System.setProperty("port","8888")
Thanks. It works.
> The exception clearly states the problem:
>
> "Caused by:
> org.apache.commons.logging.LogConfigurationException:
> Invalid class loader hierarchy. You have more than
> one version of 'org.apache.commons.logging.Log'
> visible, which is not allowed."
After adding the following :
System.setProperty("osgi.parentClassloader","app");The problem is gone.
> You can't run and install the bundle from the project
> location, since the layout is not in OSGi format (and
> the PDE does weird'n'wonderful things to make it so
> at runtime). You have to Jar it.
Ah, this is a showstopper to me. Since the plugin I'm testing is under development there's no way I have to jar it first to be testable.
> You can just call EclipseStarter.shutdown() to take
> the system down. All bundles will be stopped.
Thank you for the information.
Best Regards,
Setya