Jump to content
Excelsior Forums
sba

OSGi bundles and Windows service

Recommended Posts

Hi.

I'm would like to compile a number of OSGi bundles (providing among other things: a web site and some web services) into a single Windows service.

Does JET support this?

If it does, I assume the way to go about it is to implement a class that extends WinService and wraps the EclipseStarter class. But how do I get JET to protect both the starter class and the bundles (or at least the bundles I have written)?

- Sba

Share this post


Link to post
Share on other sites

I'm would like to compile a number of OSGi bundles (providing among other things: a web site and some web services)

So you have an Eclipse Equinox application, haven't you?

into a single Windows service.

Does JET support this?

In short, no.

More details:

Currently we do not support arbitrary Eclipse Equinox applications (based on Equinox OSGi runtime). However, as far as we know, it is possible to convert an Equinox application into Eclipse RCP (note that using Eclipse RCP framework does not imply that the application must have SWT GUI).

Excelsior JET does support Eclipse RCP, so you would be able to compile it with Excelsior JET thus protecting your OSGi bundles. However we did not have in mind the use of our Windows Service API in conjunction with Eclipse RCP.

But I have just found that we did not forbid to use it with Eclipse RCP actually (but did not test this possibility either). I have just compiled an RCP app specifying "servicemain" and "servicename" equations and it has effectively turned into a Windows Service. I cannot promise that it will work flawlessly but you may try:

1. Convert your application into Eclipse RCP

2. Wrap  Eclipse RCP launcher class into WinService

3. Compile your application as Eclipse RCP specifying "servicemain" and "servicename" equations

Please share your results, if you try :)

PS Another way is to convert your application into plain Tomcat web-application that is fully supported by Excelsior JET along with Windows services :)

Share this post


Link to post
Share on other sites

Currently we do not support arbitrary Eclipse Equinox applications (based on Equinox OSGi runtime). However, as far as we know, it is possible to convert an Equinox application into Eclipse RCP (note that using Eclipse RCP framework does not imply that the application must have SWT GUI).

Do you have any links/further material explaining this; my Google-fu seems to be too weak to find any.

But I have just found that we did not forbid to use it with Eclipse RCP actually (but did not test this possibility either). I have just compiled an RCP app specifying "servicemain" and "servicename" equations and it has effectively turned into a Windows Service. I cannot promise that it will work flawlessly but you may try:

1. Convert your application into Eclipse RCP

2. Wrap  Eclipse RCP launcher class into WinService

3. Compile your application as Eclipse RCP specifying "servicemain" and "servicename" equations

The custom startup class should be part of the RCP project, wight?

Wrt "servicemain" and "servicename" then I should manually add these two options to the .prj file?

"servicemain" should be assigned the FQCN of the class extending WinService?

Please share your results, if you try :)

Will do :)

- sba

Share this post


Link to post
Share on other sites

Currently we do not support arbitrary Eclipse Equinox applications (based on Equinox OSGi runtime). However, as far as we know, it is possible to convert an Equinox application into Eclipse RCP (note that using Eclipse RCP framework does not imply that the application must have SWT GUI).

Do you have any links/further material explaining this; my Google-fu seems to be too weak to find any.

We would like to create such a material, since Eclipse community seems not paying much attention to this subject. I have just converted Hello Equinox application into Eclipse RCP by myself and can share some "tips and tricks" about it. Honestly speaking, since the process is not automated by Eclipse, unexpected pitfalls and problems could arise during the process. I overcame them once, but today have spent another 2 hours to make things work. Here the instructions  (possibly incomplete):

1. Prerequisite: all your code must be OSGi bundles.

2. The main difference between RCP application and Equinox application that Eclipse RCP provides uniform way to launch an application. This is done via "Application" extension point. So the next requirement:

  a) You have to choose a bundle (let us call it "main bundle" or "entry point") that would provide the "org.eclipse.core.runtime.applications" extension.

  B) To add this extension, you open plugin.xml file for the main bundle (or manifest.mf)

  c) Go to the "Extensions" tab

  d) Add "org.eclipse.core.runtime.applications" extension

  e) Fill it. Remember Id.

  f)  Click Save

  g) Add "run" element (right click on "application" element of "org.eclipse.core.runtime.applications" extension and then click "New/run" in context menu)

  h) Create class for the element (must implements IApplication). This class will be an entry point of your application

  i) Click Save again

  j) Move the logic of your main class to the just created entry point class. Note, that OSGi framework is already initialized by Eclipse Runtime at this point, so you do not need to do it manually if you did.

3. Another feature of Eclipse RCP is so called "Product" extension point. Product has branding for instance. To add Product extension, you have to create a "Product Configuration" file:

 a) Click "File/New/Product Configuration"

 B) Choose a bundle where you have just added the "Application" extension.

 c) Click "New" in the product selection line of "Overview" tab of just created .product file

 d)  In the appeared dialog, you have to link created application with created product providing remembered Id (see "e" in 2.) in Product Application section of the dialog and fill other info as well.

4. Once you have "Application" and "Product" extensions in your main bundle you may call your application as Eclipse RCP. For instance, you may launch and export your application (as Eclipse RCP application) at "Overview" tab of your ".product" file. But unfortunately, your application may fail to run at this point. To overcome this, you have to fill "Dependencies tab" of ".product" file correctly:

  a). Add all your bundles to the dependencies list first

  B)  Click "Add Required Plug-ins"

  c) Ensure that "org.eclipse.core.runtime" appeared in the list. If not, you have to add it manually and click "Add Required Plug-ins" again.

5. At this point, my Hello Equinox application starts working as Eclipse RCP. But you may encounter other problems at startup of your application  because bundle initialization may go in a different way that was normally when you launch your application as Equinox application. To overcome this you should properly configure "Configuration" tab of ".product" file. At this tab you specify start properties of the bundles.

6. Once your application works as expected via "Launch an application" action of "Overview" tab, you may export your application in Eclipse RCP form via "Eclipse Product export wizard" of "Overview" tab of ".product" file. And a directory that would be created after exporting process is eligible for compilation with Excelsior JET!

The custom startup class should be part of the RCP project, wight?

Wrt "servicemain" and "servicename" then I should manually add these two options to the .prj file?

"servicemain" should be assigned the FQCN of the class extending WinService?

yes. FQCN must use "/" delimiter though. And as the service main class must be in application classpath, you have to add application classpath entry containing the class to the project as well (also manually). You may do it via

"!classpathentry" or "!classloaderentry app" directives.

Please share your results, if you try :)

Will do :)

Thanks for attention :)

Share this post


Link to post
Share on other sites

I have to say that this guide is not very comprehensible. We have an RCP desktop application which needs to be run as a windows service. The problem is that I don't know how to implement the method run in com.excelsior.service.WinService. It would need to start the RCP application using equinox launcher, but how do I do that the simple way?

This is probably the only problem we have with Excelsior JET, so the resolution of this problem will determine whether we will buy it or not.

Thank you for any tips.

Mirage

Share this post


Link to post
Share on other sites

I have to say that this guide is not very comprehensible. We have an RCP desktop application which needs to be run as a windows service. The problem is that I don't know how to implement the method run in com.excelsior.service.WinService. It would need to start the RCP application using equinox launcher, but how do I do that the simple way?

Have you got a GUI application or command line? Do you want to launch your application only as windows service or as standard RCP application too?

Share this post


Link to post
Share on other sites

Have you got a GUI application or command line? Do you want to launch your application only as windows service or as standard RCP application too?

It's not a GUI application (no interaction with desktop required). We don't even use command line (no console). It's just an RCP application which should start as a service only. It is controlled by clients connected to it using RMI.

Share this post


Link to post
Share on other sites

It's not a GUI application (no interaction with desktop required). We don't even use command line (no console). It's just an RCP application which should start as a service only. It is controlled by clients connected to it using RMI.

Ok, you would need the following steps:

1. You may use the following code snippet for Windows Service

import java.io.*;
import java.lang.reflect.Method;

public class RCPService extends com.excelsior.service.WinService {

   public boolean init () {
       return false; // pause/resume are not supported
   }

   public void run () {
       try {
           Class bootstrap = Class.forName("org.eclipse.equinox.launcher.Main");
           Method main = bootstrap.getDeclaredMethod("main", String[].class);
           main.invoke(null, (Object) new String[] {});
       } catch (Exception e) {
           StringWriter sw = new StringWriter();
           PrintWriter pw = new PrintWriter(sw);
           e.printStackTrace(pw);
           logErrorEvent("RCP Service failed: " + sw);
       }
   }

}

2. Compile the code above with javac and put it to a jar (say RCPService.jar) using the following command line

javac -cp <JetInstallDir>/lib/WinService.jar RCPService.java

jar -cf RCPService.jar RCPService.class

3. As JET Control Panel does not support the combination of Eclipse RCP and Windows Service you need to create JET project file as Eclipse RCP project first and then manually modify it in the following way:

a) add

-servicemain=RCPService

-servicename=ServiceNameOfYourChoice

to the equations section of the project

B) and add

!classloaderentry app RCPService.jar
 -pack=noncompiled
 -protect=nomatter
 -optimize=all
!end

to the end of the project.

Please let us know if you succeed with this instructions.

Share this post


Link to post
Share on other sites

- using org.eclipse.equinox.launcher.Main is not the recommended solution

- no need to use reflection

- you cannot just pass an empty array with no properties to equinox (it requires hundreds of properties to be specified combining system properties, config.ini properties, and native launcher properties)

- currently, we are trying to use EclipseStarter class, which is the recommended way of starting an RCP application, but you need to pass some special properties as well

- we already have a working solution using srvany.exe service wrapper, but the problem is that it doesn't call the shutdown hook when we exit the application (it just kills it)

Share this post


Link to post
Share on other sites

- using org.eclipse.equinox.launcher.Main is not the recommended solution

Who does not recommend this? Eclipse itself starts Eclipse RCP applications using this class with JNI code that can be decoded as "new Main().run(args);"

This is exactly what main method of org.eclipse.equinox.launcher.Main does.

- no need to use reflection

This is just code snippet, you may modify it as you want. Reflection allows not statically import the launcher jar.

- you cannot just pass an empty array with no properties to equinox (it requires hundreds of properties to be specified combining system properties, config.ini properties, and native launcher properties)

Only <YourAppLauncherName>.ini will not be read in this mode. When you use Excelsior WinService API, your application is linked with special startup library that differs from startup library used for Eclipse RCP launching (where <YourAppLauncherName>.ini is read). To set required VM properties, you have to specify them in "jetvmprop" equation of JET project file. Required ordinary arguments have to be passed to the main of launcher.Main. You can also parse <YourAppLauncherName>.ini by yourself to extract ordinary arguments. Other properties that Eclipse Runtime needs (not listed in <YourAppLauncherName>.ini, f.i. config.ini properties) are set by Java code that is invoked from launcher.Main.

Share this post


Link to post
Share on other sites

I'm sorry. Your solution really works. My colleague has been trying this with org.eclipse.core.launcher.Main instead of org.eclipse.equinox.launcher.Main. That approach really requires to specify hundreds of properties.

We now have another problem. We use a shutdown hook to make cleanup procedures. We need to somehow exit the framework (either using EclipseStarter.shutdown or by calling System.exit). The problem is that methods stop or shutdown on WinService never get called. We use Win7 x64. We tried running the application in a separate thread to avoid blocking the control thread, but it seems you already do that (according to your documentation). Do you have any idea what could cause this?

Share this post


Link to post
Share on other sites

If your application exits normally the "stop" method of WinService is not called but Java shutdown hooks must be executed in this case. "stop" method is called when the user stops the service from Windows Services Control Panel. In this case Windows terminates the process by its own and Java shutdown hooks are not executed. So you need to place application finalization manually to "stop" method for this case.

Share this post


Link to post
Share on other sites

If your application exits normally the "stop" method of WinService is not called but Java shutdown hooks must be executed in this case. "stop" method is called when the user stops the service from Windows Services Control Panel. In this case Windows terminates the process by its own and Java shutdown hooks are not executed. So you need to place application finalization manually to "stop" method for this case.

Yes, I understand this, but when I stop the service using the Stop button, the method stop or shutdown doesn't get called. This is tested very well, and I just don't see the message "RCP Service Stopping...", but I do see "RCP Service Starting...":

public class WindowsService extends WinService {

@Override
public boolean init() {
	return false; // pause/resume are not supported
}

@Override
public void run() {
	logInfoEvent("RCP Service Starting...");
	System.out.println("RCP Service Starting...");
	try {
       		Class bootstrap = Class.forName("org.eclipse.equinox.launcher.Main");
		Method main = bootstrap.getDeclaredMethod("main", String[].class);
		main.invoke(null, (Object) new String[] {});
       	} catch (Exception e) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		e.printStackTrace(pw);
		logErrorEvent("RCP Service failed: " + sw);
	}
}

@Override
public void stop() {
	logInfoEvent("RCP Service Stopping...");
	System.out.println("RCP Service Stopping...");
	try {
		Class starter = Class.forName("org.eclipse.core.runtime.adaptor.EclipseStarter");
		Method shutdown = starter.getDeclaredMethod("shutdown");
		shutdown.invoke(null);
	} catch (Exception e) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		e.printStackTrace(pw);
		logErrorEvent("RCP Service Stop failed: " + sw);
	}
	super.stop();
}

@Override
public void shutdown() {
	logInfoEvent("RCP Service Shutdown");
	System.out.println("RCP Service Shutdown");
	super.shutdown();
}
}

Share this post


Link to post
Share on other sites

We have tried your code snippet on our RCP sample and the stop method is called in our environment (according to Event Viewer).

the Stop button

Do we understand the same by "the Stop button"? We stop the service going Windows Control Panel/Administrative tools/Services -- choosing the service, and use either Stop from context menu or "Stop the service" link on the left of the panel.

Share this post


Link to post
Share on other sites

We have tried your code snippet on our RCP sample and the stop method is called in our environment (according to Event Viewer).

Do we understand the same by "the Stop button"? We stop the service going Windows Control Panel/Administrative tools/Services -- choosing the service, and use either Stop from context menu or "Stop the service" link on the left of the panel.

Yes, indeed, Windows Control Panel/Administrative tools/Services.

Share this post


Link to post
Share on other sites
On 4/23/2012 at 4:16 PM, kit said:

Ok, you would need the following steps:

1. You may use the following code snippet for Windows Service

 


import java.io.*;
import java.lang.reflect.Method;

public class RCPService extends com.excelsior.service.WinService {

   public boolean init () {
       return false; // pause/resume are not supported
   }

   public void run () {
       try {
           Class bootstrap = Class.forName("org.eclipse.equinox.launcher.Main");
           Method main = bootstrap.getDeclaredMethod("main", String[].class);
           main.invoke(null, (Object) new String[] {});
       } catch (Exception e) {
           StringWriter sw = new StringWriter();
           PrintWriter pw = new PrintWriter(sw);
           e.printStackTrace(pw);
           logErrorEvent("RCP Service failed: " + sw);
       }
   }

}
 

 

2. Compile the code above with javac and put it to a jar (say RCPService.jar) using the following command line

javac -cp <JetInstallDir>/lib/WinService.jar RCPService.java

jar -cf RCPService.jar RCPService.class

3. As JET Control Panel does not support the combination of Eclipse RCP and Windows Service you need to create JET project file as Eclipse RCP project first and then manually modify it in the following way:

a) add

-servicemain=RCPService

-servicename=ServiceNameOfYourChoice

to the equations section of the project

B) and add

 


!classloaderentry app RCPService.jar
 -pack=noncompiled
 -protect=nomatter
 -optimize=all
!end
 

 

to the end of the project.

Please let us know if you succeed with this instructions.

 

Hi friend,

Please give  more information above step-3 and where is put "step-3 (a)".

RCP application bundle create successfully then JET required or not? 

Share this post


Link to post
Share on other sites
On 30.11.2016 at 1:46 PM, LalitSolanki said:

Hi friend,

Please give  more information above step-3 and where is put "step-3 (a)".

 

In the begining of the project file created by Excelsior JET Control Panel.

 

Quote

RCP application bundle create successfully then JET required or not? 

JET is not required for application to run after compilation and packaging the application with Excelsior JET.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×