Ouertani Slim was born in Tunisia on 1981. Now he is a software engineer since 2004. 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 Client Extender With Dynamic Proxy Inside OSGi

04.14.2009
| 8662 views |
  • submit to reddit

III- Extender bundle listener

1- Listen to updated and installed bundle
2- Check the MANIFEST.MF file
3- Get the url and parse an XML resource
4- Register a proxy service

package com.jtunisie.osgi.hessian.client;

import com.jtunisie.osgi.hessian.client.Parser.Pair;
import java.net.URL;
import java.util.Dictionary;
import java.util.List;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.SynchronousBundleListener;
import static org.osgi.framework.BundleEvent.*;

/**
*
* @author slim
*/
public class BundleListner implements SynchronousBundleListener {

private static final String HESSIAN_HEADER = "Hessian-File";
private final BundleContext context;

public BundleListner(BundleContext context) {
this.context = context;
}

@Override
public void bundleChanged(BundleEvent event) {
if (event.getType() == UPDATED || event.getType() == STARTED) {

try {
addBundle(event.getBundle());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
if (BundleEvent.STOPPED == event.getType()) {
removeBundle(event.getBundle());
}
}

private void addBundle(Bundle bundle) throws ClassNotFoundException {
@SuppressWarnings("unchecked")
Dictionary<String, String> headers = bundle.getHeaders();
String indexPath = headers.get(HESSIAN_HEADER);

if (indexPath == null) {
return;
}
URL resource = bundle.getResource(indexPath);
if (resource == null) {
return;
}

List<Pair> remotes = Parser.parseRemoteconfig(resource);
if (remotes != null) {
for (Pair pair : remotes) {
pair.setServiceRegistration(new ClientExtender().registerService(context, pair));
}
}
}

private void removeBundle(Bundle bundle) {
// TODO
}
}

IV-DynamicImport-Package :


As this extender will manipulate unknown class and interfaces we must enable DynamicImport-Package to all packages. To do this, add <DynamicImport-Package>*</DynamicImport-Package> in pom file.

V- Dynamic Proxys


1 -Create generic proxy class GenericClientProxy to forward calls to remote implementation according to requested service and destination:
package com.jtunisie.osgi.hessian.client;

import com.caucho.hessian.client.HessianProxyFactory;
import com.jtunisie.osgi.hessian.client.Parser.Pair;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
*
* @author slim
*/
public class GenericClientProxy implements InvocationHandler, Serializable {

private Pair pair;

public GenericClientProxy(Pair pair) throws ClassNotFoundException {
this.pair = pair;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
HessianProxyFactory factory = new HessianProxyFactory();
Serializable service = (Serializable) factory.create(pair.getClazz(), pair.getRemoteAdress());
return method.invoke(service, args);
}
}


2- The ClientExtender class will register this proxy inside local OSGi as if it is present.
package com.jtunisie.osgi.hessian.client;

import com.jtunisie.osgi.hessian.client.Parser.Pair;
import java.lang.reflect.Proxy;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

/**
*
* @author slim
*/
public class ClientExtender {

ServiceRegistration registerService(BundleContext context, Pair pair) throws ClassNotFoundException {
String _interface = pair.getRemoteInterface();
Class[] interfaces = {pair.getClazz()};
GenericClientProxy clientProxy = new GenericClientProxy(pair);
Object newProxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, clientProxy);
return context.registerService(_interface, newProxyInstance, null);
}

void unregisterService(BundleContext context, Pair pair) {
//TODO
}
}


VI- Execution

If we run the extender bundle and a test client, we will see that our extender will register the remote service inside the local registry

osgi> b <extender-id>
........
Id=41, Status=ACTIVE Data Root=/home/slim/work/svn/hessianextender-read-only/env.client/configuration/org.eclipse.osgi/bundles/41/data
Registered Services
{com.jtunisie.osgi.hessian.IService}={service.id=47}
No services in use.
Exported packages
com.caucho.hessian.security; version="0.0.0"[exported]
com.caucho.hessian.io; version="0.0.0"[exported]
com.caucho.hessian.client; version="0.0.0"[exported]
com.caucho.hessian.server; version="0.0.0"[exported]
com.caucho.hessian.jmx; version="0.0.0"[exported]
com.caucho.hessian.mux; version="0.0.0"[exported]
com.caucho.hessian.util; version="0.0.0"[exported]
com.caucho.hessian.micro; version="0.0.0"[exported]
com.caucho.hessian; version="0.0.0"[exported]
com.caucho.hessian.test; version="0.0.0"[exported]
Imported packages
javax.crypto; version="0.0.0"<System Bundle [0]>
javax.management; version="0.0.0"<System Bundle [0]>
javax.naming; version="0.0.0"<System Bundle [0]>
javax.naming.spi; version="0.0.0"<System Bundle [0]>
javax.servlet; version="2.5.0"<initial@reference:file:plugins/web/pax-web-service-0.4.1.jar/ [37]>
javax.servlet.http; version="2.5.0"<initial@reference:file:plugins/web/pax-web-service-0.4.1.jar/ [37]>
javax.xml.namespace; version="0.0.0"<System Bundle [0]>
javax.xml.stream; version="0.0.0"<System Bundle [0]>
javax.xml.stream.events; version="0.0.0"<System Bundle [0]>
org.osgi.framework; version="1.4.0"<System Bundle [0]>
org.w3c.dom; version="0.0.0"<System Bundle [0]>
No fragment bundles
Named class space
com.jtunisie.osgi.hessian.client; bundle-version="1.0.0"[provided]
No required bundles


VII - Conclusion


Using extenders in OSGi is a powerful tool. This post outlines :
 Extender pattern.
 Bundle listener.
 Dynamic proxy for remoting.
 Stax XML parsing
 Hessian service client.

It's not for production :) but as didactic use. If you want a powerful api check Eclipse Riena.

The Source code is available under svn link : svn checkout http://hessianclient.googlecode.com/svn/trunk/ hessianclient-read-only
5
Your rating: None Average: 5 (1 vote)
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.)

Comments

Slim Ouertani replied on Wed, 2009/04/15 - 3:13am

An interesting article about proxies :http://www.osgi.org/blog/2008/08/classy-solutions-to-tricky-proxies.html

Comment viewing options

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