Ouertani Slim was born in Tunisia in 1981. Now he is a software engineer since 2004 and he is Java 6 and Spring certified with 100% and 94% respectively. He is very interested in Java technology, Scala and open source projects. He believes that programming is one of the hardest jobs and most beautiful in the world. Slim has posted 32 posts at DZone. You can read more from them at their website. View Full User Profile

Hessian Service and Client on an OSGi Container : Part 2

07.29.2008
| 7714 views |
  • submit to reddit

In my last post, I introduced hessian extender. Now, I will show  how to create service that will be registered by the last extender, and a Java application that will communicate with it.

First, we create a simple service interface witch is inspired here :

package com.jtunisie.osgi.hessian;  
 
import com.jtunisie.osgi.hessian.exceptions.ServiceException;  
 
public interface IService {  
 public String execute() throws ServiceException;  
}  

Next, we create a service implementation that will extend HessianServlet and implement and old interface:

package com.jtunisie.osgi.hessian.impl;

import com.caucho.hessian.server.HessianServlet;
import com.jtunisie.osgi.hessian.IService;

import com.jtunisie.osgi.hessian.exceptions.ServiceException;


public class Service extends HessianServlet implements IService {

public void publish() {
this.setAPIClass(IService.class);
}

@Override
public String execute() throws ServiceException {
return "jTunisie";
}
}
 

We use Spring DM to register this service as com.caucho.hessian.server.HessianServlet name and we note that publish method will be called as default init method after all spring IoC
service reference injection.
 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">

<bean id="serviceDebug" class="com.jtunisie.osgi.hessian.impl.Service"/>

<osgi:service interface="com.caucho.hessian.server.HessianServlet" ref="serviceDebug">
<osgi:service-properties>
<entry key="url" value="/jtunisie"/>
</osgi:service-properties>
</osgi:service>
</beans>

 

 

Service will be registred under /jtunisie url.


At the client side, we need only the api bundle and hessian library :

 

package com.jtunisie.osgi.debug.test;

import com.caucho.hessian.client.HessianProxyFactory;
import com.jtunisie.osgi.hessian.IService;
import com.jtunisie.osgi.hessian.exceptions.ServiceException;
import java.net.MalformedURLException;

public class Main {

public static void main(String[] args) throws MalformedURLException, ServiceException {
HessianProxyFactory factory = new HessianProxyFactory();
IService service = (IService) factory.create(IService.class, "http://localhost:8080/jtunisie");
System.out.println(service.execute());
}

At the end, I want to thank Roman who let me share his work and my team that helped me to have and accomplish this work.
The full source code is available here as 2 maven projects:
svn checkout http://hessianextender.googlecode.com/svn/trunk/ hessianextender-read-only

 

Published at DZone with permission of its author, Slim Ouertani.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

jon hopper replied on Fri, 2008/08/01 - 5:51am

Hi,

I am trying to do this, and having an issue. I start everything up, and that is ok, but my beans seem to startup, and then die before I have a chance to connect to them.  The web service is still running, but the beans  destroy-method has been called, and the connection to the hessian interface fails ( I assume because the bean behind it has gone)

 

 

Any idea as to why this is happening?  I have been unable to find documentation about the lifecycle of the osgi-spring beans, and why they live and die.

 

Thanks

Slim Ouertani replied on Fri, 2008/08/01 - 7:37am in response to: jon hopper

@jhop

Have you installed api bundle ? You shouldn't install it because the impl bundle expose the same interfaces.

Be sure that spring extender is up and turn on spring logging. 

 

Jeffry Hidayat replied on Mon, 2009/07/06 - 5:54pm

Hi Slim Ouertani,

I have been trying to implement this material (Hessian Service and Client on OSGI container) for a simple example to understand this process. Basically this is what I am trying to do:
1. Creating dummy Calculator service (which does adding, multiplying, addition, and substraction)
2. I would like to deploy this dummy Calculator Service into Spring DM Server
3. With the bundle available in server, I am thinking about the Hessian Service and Client solution to expose the service outside the Spring DM server through HTTP
4. I will have my client sittting outside the Spring DM Server and tried to use the service through http extended by Hessian

I really need your help since I am really newbie in OSGI field, please look at my codes below:

On service sides, I am creating:
- iCalculator class
package test.osgi.calculator;

public interface iCalculator {
public double add(double x, double y);
public double substract(double x, double y);
public double multiply(double x, double y);
public double divide(double x, double y);
}


- Calculator class
package test.osgi.calculator.impl;

import com.caucho.hessian.server.HessianServlet;
import test.osgi.calculator.iCalculator;

public class Calculator extends HessianServlet implements iCalculator{

public void publish() {
this.setAPIClass(iCalculator.class);
}
public double add(double x, double y) {
return x + y;
}
public double substract(double x, double y) {
return x - y;
}
public double multiply(double x, double y) {
return x * y;
}
public double divide(double x, double y) {
return x / y;
}
}


- the same CustomTracker class as given in the example
package test.osgi.calculator.extender;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;

public abstract class CustomTracker extends ServiceTracker {

public CustomTracker(BundleContext context, String clazz) {
super(context, clazz, null);
}

@Override
public Object addingService(ServiceReference reference) {
try {
serviceRegistered(reference);
} catch (Exception e) {
e.printStackTrace();
}
return super.addingService(reference);
}

public abstract void serviceRegistered(ServiceReference reference) throws Exception;

@Override
public void removedService(ServiceReference reference, Object service) {
try {
serviceUnregistered(reference, service);
} catch (Exception e) {
e.printStackTrace();
}
super.removedService(reference, service);
}

public abstract void serviceUnregistered(ServiceReference reference, Object service) throws Exception;
}


- and HessianListener class as well
package test.osgi.calculator.extender;

import com.caucho.hessian.server.HessianServlet;
import javax.servlet.Servlet;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.util.tracker.ServiceTracker;


public class HessianListener {

private HttpService httpService;
private ServiceTracker servletsTracker;

public HessianListener(BundleContext context) {
this.servletsTracker = new CustomTracker(context, HessianServlet.class.getName()) {

@Override
public void serviceRegistered(ServiceReference reference) throws Exception {
Servlet servlet = (Servlet) context.getService(reference);
String url = (String) reference.getProperty("url");
httpService.registerServlet(url, servlet, null, null);
System.out.println("we get servlet");
}
@Override
public void serviceUnregistered(ServiceReference reference, Object service) throws Exception {
System.out.println("Unregister " + reference);
httpService.unregister((String) reference.getProperty("url"));
}
};
}

public void setHttpService(HttpService httpService) throws Exception {
this.httpService = httpService;
this.servletsTracker.open();
}

public void unsetHttpService(ServiceReference reference) {
this.servletsTracker.close();
}
}



- calculator-osgi.xml in META-INF/spring/
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
<osgi:service id="CalculatorOSGIService" ref="CalculatorService" interface="test.osgi.calculator.iCalculator">
<osgi:service-properties>
<entry key="url" value="/Calculator"/>
</osgi:service-properties>
</osgi:service>

<!-- reference to HttpService -->
<osgi:reference id="httpService" interface="org.osgi.service.http.HttpService">
<osgi:listener ref="hessianListener" unbind-method="unsetHttpService" />
</osgi:reference>
<!-- configure the JettyListener -->
<bean name="hessianListener" class="test.osgi.calculator.extender.HessianListener"> <constructor-arg ref="bundleContext"/>
<property name="httpService" ref="httpService"/>
</bean>
</beans>


- and calculator-service.xml in META-INF/spring/
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="CalculatorService" class="test.osgi.calculator.impl.Calculator"/>
</beans>

- while the MANIFEST.MF looks like:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Calculator Plug-in
Bundle-SymbolicName: test.osgi.Calculator
Bundle-Version: 1.0.0
Bundle-ClassPath: ., WEB-INF/hessian-3.2.1.jar, WEB-INF/WEB-INF/classes/, WEB-INF/servlet-api.jar
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework;version="1.3.0", org.osgi.service.http;version="1.2.0", org.osgi.util.tracker;version="1.3.3"
Export-Package: test.osgi.calculator


I have been able to export the bundle as plugin and deploy it into Spring DM Server, but in the console, it's continuously throwing :
"service-monitor-thread-1 Mandatory reference '&httpService' in bundle 'test.osgi.Calculator' version '1.0.0' is waiting for service with filter '(objectClass=org.osgi.service.http.HttpService)'."

Any help will be appreciated. Thank you.

Slim Ouertani replied on Tue, 2009/07/07 - 8:00am in response to: Jeffry Hidayat

Hi,

Happy to help you.

Your source code is correct, but I remark that you use WEB-INF/servlet-api.jar inside your class path ... do you manually write your manifest file? The source code of your service will be a simple jar file and extender will contain hessain. I did some enhancement according to this example to be like SCA spec : http://www.jroller.com/ouertani/entry/hessian_declarative_extender_as_sca : so service and implementation aren't related to hessain.

Jeffry Hidayat replied on Wed, 2009/07/08 - 4:42pm

Hi Slim, I have got the solution to the problem above by importing the package directly from eclipse's javax.servlet(2.5.0) package instead of using servlet-api.jar that I manually move to inside WEB-INF/ and added it in Bundle-Classpath.

So at this point, I have removed servlet-api.jar from my java build path and Bundle-Classpath and added it in Import-Package in MANIFEST.MF (javax.servlet;version="2.5.0"). But the MANIFEST.MF still has WEB-INF/hessian-3.2.1.jar and in the java build path.
But here comes another problem: Everytime I deploy the bundle into Spring DM and start the bundle, I always encounter this error:

2009-07-08 14:24:44.323] server-dm-13 Application context creation failure for bundle 'test.osgi.Calculator'.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hessianListener' defined in URL [bundleentry://133/META-INF/spring/calculator-service.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [test.osgi.calculator.extender.HessianListener]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: com/caucho/hessian/server/HessianServlet
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:254)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:925)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:835)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:440)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)




But if I comment out the "import com.caucho.hessian.server.HessianServlet" and commenting out others, which are dependent to HessianServlet class in HessianListener class, and redeploy the bundle, starting the bundle will be completed successfully.

I have been thinking that we need a OSGI-fied (or plugin) Hessian jar bundle, which contains com.caucho.hessian.server.HessianServlet, so that I can just import it just like javax.servlet;version="2.5.0" mentioned above.

Any pointer for this? Thank you for your reply.

Jeffry Hidayat replied on Thu, 2009/07/09 - 12:23am in response to: Jeffry Hidayat

Anyway, I have figured out all the dependency issues above by manually putting the hessian jar in /WEB-INF inside the exported Calculator service jar.

Currently when I start the bundle, it seems that it already tries to register the service (I can see from all the printed comments from System.out), but the HTTP POST seems to return me 404, so whenever I access http://localhost:8080/Calculator, it still returns 404. Any idea about this from my code above (in HessianListener.java and CustomTracker.java, which I basically copied and pasted from your example) ? Thanks.

127.0.0.1 - - [08/Jul/2009:17:47:43 -0700] "POST /Calculator HTTP/1.1" 404 - "null" "Java/1.6.0_13"

Slim Ouertani replied on Thu, 2009/07/09 - 3:43am in response to: Jeffry Hidayat

These are my manifest files :

this one for the simple extender :

Manifest-Version: 1.0
Export-Package: com.caucho.hessian.server;uses:="javax.servlet,javax.s
 ervlet.http"
Private-Package: com.caucho.burlap.client,com.caucho.burlap.io,com.cau
 cho.burlap.server,com.caucho.hessian,com.caucho.hessian.client,com.ca
 ucho.hessian.io,com.caucho.hessian.jmx,com.caucho.hessian.micro,com.c
 aucho.hessian.mux,com.caucho.hessian.security,com.caucho.hessian.test
 ,com.caucho.hessian.util,com.caucho.services.client,com.caucho.servic
 es.message,com.caucho.services.name,com.caucho.services.server,
 extender.package
Bundle-Version: 1.0
Tool: Bnd-0.0.249
Bnd-LastModified: 1210332330440
Bundle-Name: hessian.extender
Bundle-ManifestVersion: 2
Created-By: 1.6.0_04 (Sun Microsystems Inc.)
Import-Package: com.caucho.hessian.server,javax.crypto,javax.managemen
 t,javax.naming,javax.naming.spi,javax.servlet,javax.servlet.http,org.
 osgi.framework,org.osgi.service.http,org.osgi.util.tracker,org.w3c.do
 m,the.api.package
Include-Resource: resources
Bundle-SymbolicName: hessian.extender

and 

 

this one for impl :

Manifest-Version: 1.0
Export-Package: api;uses:="....exceptions.ServiceLayerExceptions"
Private-Package: ....ressources,impl
Built-By: sst
Tool: Bnd-0.0.255
Bundle-Name: impl
Created-By: Apache Maven Bundle Plugin
Bundle-Version: 1.0.0.SNAPSHOT
Build-Jdk: 1.6.0_10-beta
Bnd-LastModified: 1227859891561
Bundle-ManifestVersion: 2
Import-Package: com.caucho.hessian.server,....,org.apache.comm
 ons.logging,org.osgi.framework
Bundle-SymbolicName: impl

 

Next,

 

I using the basic equinox with jetty server  and not ssap. I ityou havealready problem I will prepare for you bundled jar with your source code. (send to me your email please).

 

Thanks.

 

Jeffry Hidayat replied on Thu, 2009/07/09 - 11:59pm

I have sent you my email address in a private message. Beside that, do we have to modify web.xml (registering the servlet and its mapping) for Spring DM server in for httpService.RegisterServlet to work properly?

Jeffry Hidayat replied on Mon, 2009/07/20 - 12:05pm

Hi Slim,
I really appreciate your help and replies.
Anyway, by far, I have solved and managed all the examples above to work successfully and properly. But I am really interested to find out:
1. How to use the Spring DM's embed Tomcat server instead of Eclipse's Jetty Server? Do we have to modify the HttpService usage in the code (referencing httpService.RegisterServlet)?

2. If I don't want the service to extend HessianServlet, is there anyway that I can have 1 Bundle for HessianListener and another bundle for the service and publish the service bean over http using the HessianListener bundle?

I am looking forward to your reply. Thanks.

Jeff,

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.