Posts tagged ‘jboss’

Writing a jboss - webservices client using python suds

I was experimenting with writing a secured web services client in python and I was surprised how easy it was using python suds.

First write your webservice in java:

@Remote
public interface TestService {
public String echo(String s);

public int add(int a, int b);
}

and the implementation:

@WebService
@Stateless
public class TestServiceImpl implements TestService {
public String echo(String s) {
return s;
}

public int add(int a, int b) {
return a+b;
}
}

Expose it using a webapp and configure security using web.xml:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>project-name-war</display-name>
<description></description>
<servlet>
<servlet-name>WS</servlet-name>
<servlet-class>net.ahlawat.TestServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WS</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>web service</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<description>Known users of the Foobar service</description>
<role-name>user</role-name>
</security-role>
</web-app>

and configure it to a jboss login module using jboss-web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>java:/jaas/tws</security-domain>
</jboss-web>

Basically that is it - you can then code up your python clinet like this:

from suds.client import Client

url = "https://127.0.0.1:8080/webServiceTest-war?wsdl"

client = Client(url, username="user", password="userPassword2010!")

#print client

result = client.service.add(1,2)

print result

result = client.service.echo("Hello world")

print result

And not surprisingly the result:

C:\cygwin\home\deepti\python-suds-0.4>python client.py
3
Hello world

C:\cygwin\home\deepti\python-suds-0.4>

Its amazing how easy this was. I think this is where you think programming in java sucks - putting out a simple client using basic auth would have taken 5 pages of code. Suds is an excellent library to write a quick web service client. Great tool to have in your programmers arsenal.

JBoss JMX extensions to EJB3

I don’t particularly like developing on JBoss - I think its bloated and slow. But with EJB3 the platform has become more viable. The turn around time to get a relatively complex application with web services etc. done is great.

One thing I like about JBoss 5.x are the JMX extensions to EJB3. Its really amazing how simple installing a JMX MBean is. Let’s say I have to write  a CalculatorService represented by this interface:

package net.ahlawat.cricket;

import javax.ejb.Remote;

import org.jboss.ejb3.annotation.Management;

@Management
@Remote
public interface CalculatorService {
	public double add(double a, double b);
	public double subtract(double a, double b);
	public double performOperation(double a, double b);
	public String getDefaultOperation();
	public void setDefaultOperation(String operation);
}

The interesting annotations here are @Management which tells JBoss deployer that the interface is to be bound as a JMX MBean. The implementation of this bean can be simple pojo - listed here.

package net.ahlawat.cricket;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.ejb3.annotation.Service;

@Service(objectName = "ahlawat:service=CalculatorService")
public class CalculatorServiceImpl implements CalculatorService {
	static Log logger = LogFactory.getLog(CalculatorServiceImpl.class);

	Method defaultOperation;

	@Override
	public double add(double a, double b) {
		return a+b;
	}

	@Override
	public String getDefaultOperation() {
		return defaultOperation.getName();
	}

	@Override
	public double performOperation(double a, double b) {
		try {
			BigDecimal bd = (BigDecimal) defaultOperation.invoke(new BigDecimal(a), new BigDecimal(b));
			return bd.doubleValue();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		return Double.NaN;
	}

	@Override
	public void setDefaultOperation(String operation) {
		try {
			Method m = BigDecimal.class.getMethod(operation, BigDecimal.class);
			logger.info("Setting default operation to " + operation);
			defaultOperation = m;
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}

	}

	@Override
	public double subtract(double a, double b) {
		return a-b;
	}

	//lifecycle methods
	public void create() throws Exception {
		logger.info("Creating service");
	}

	public void start() throws Exception {
		logger.info("Starting service");
		setDefaultOperation("add");
	}
}

The only interesting thing here is @Service - which tells Jboss that this is a singleton bean. And the fact that MBean lifecycle methods like create() and start() are available to be implemented here.

The complete list of life cycle methods are:

   void create() throws Exception;
   void start() throws Exception;
   void stop();
   void destroy();

Once this is jar’d up and deployed to Jboss - you can go to jmx-console and see that the service is visible:

jmx-console

jmx-console

You can also look up the bean using the default JNDI name CalculatorServiceImpl/remote

public class Main {
	public static void main(String[] args) throws Exception {
		InitialContext ctx = new InitialContext();

		CalculatorService cs = (CalculatorService)ctx.lookup("CalculatorServiceImpl/remote");

		System.out.println(cs.add(2.1, 3.2));
	}
}

Here is the jndi.properties:

#jboss JNDI properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jnp.interfaces

And you can also inject the referece to another EJB using the @EJB annotation like this:

@Stateless
public class PlayerServiceImpl implements PlayerService {
	static Log logger = LogFactory.getLog(PlayerServiceImpl.class);

	@PersistenceContext(unitName = "default")
	EntityManager entityManager;

	@EJB
	CalculatorService calculatorService;

	@PostConstruct
	public void gotCalculator() {
		System.out.println(">>>>>>>>>>>>>>>>>> " + calculatorService.add(1.0, 1.0));
	}

...
}

Really small amount of code and guess what - no XML. I really like it.