Wednesday, September 9, 2009

RMI client callbacks

In a project that I have worked for in the past, the RMI clients could call asynchronous methods on the RMI server. After making these calls the client could return to whatever it is doing. The RMI server would run the method/tasks on seperate threads which would take a long time to complete. Once finished the RMI server would send back the reponse to the RMIClient. In order to send the response, the RMI server needs to make remote calls to its clients. So the RMI client has to act like a RMI server. To accomplish this, a RMI client must be a remote object and it must be able to accept incoming calls from others. This is achieved on the RMI client by calling the following static method:


UnicastRemoteObject.exportObject (remote_object)

The exportObject() method returns a stub which can be cast to the remote interface that the client implements. Here is an example which simulates this.

I have the following pieces of code:

  • AttractionListener.java - The remote interface which the client will implement. It has a callback method attractionAdded() which the RMI server will invoke on completion of a long running task.
  • CallbackClient.java - The client code which invokes the long running method addAttraction() on the RMI server.
  • Attractions.java - The remote interface which will be implemented by the RMI Server. It has a method addAttractionListener() which lets the client register itself with the server.
  • AttractionsImpl.java - The RMI server which implements Attractions interface. It runs the long running task on a seperate thread.
  • ServerRMI.java - The code which binds the RMI server to the rmi registry.
AttractionListener .java


import java.rmi.Remote;
import java.rmi.RemoteException;

public interface AttractionListener extends Remote {
public void attractionAdded(String attraction) throws RemoteException;
}


CallbackClient.java


import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Scanner;


public class CallbackClient implements AttractionListener {


public void attractionAdded(String attraction)
throws RemoteException {
System.out.println("Attraction Added:" + attraction);
}

public static void main(String args[]) {
try {
AttractionListener client = new CallbackClient();
System.out.println("Exporting the client");
UnicastRemoteObject.exportObject(client);
String serverURL = "rmi://127.0.0.1:1099/ServerRMI";
Attractions server =
(Attractions)Naming.lookup(serverURL);
server.addAttractionListener(client);
String s;
while (true) {
System.out.println("Enter new attraction:");
Scanner sc = new Scanner(System.in);
s = sc.next();
if (s != null) {
server.addAttraction(s);
}
}

} catch (Exception e) {
System.out.println("Exception occured " +
"while adding attraction: " +
"\n" + e.getMessage());
}
}
}



Attractions.java

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;


public interface Attractions extends Remote {
public void addAttraction(String name) throws RemoteException;
public List<String> showAttractions() throws RemoteException;
public void addAttractionListener(AttractionListener listener) throws RemoteException;
}



AttractionsImpl.java

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;


public class AttractionsImpl extends UnicastRemoteObject implements Attractions {

private static final long serialVersionUID = 1L;
private List<String> attractions = new ArrayList<String>();
private AttractionListener listener;

protected AttractionsImpl() throws RemoteException {
super();
}

@Override
public void addAttraction(String name) throws RemoteException {
if (name != null) {
verifyAttraction(name);
}
}

@Override
public List<String> showAttractions() throws RemoteException {
List<String> a = new ArrayList<String>();
a.addAll(attractions);
return attractions;
}

@Override
public void addAttractionListener(
AttractionListener listener) throws RemoteException {
this.listener = listener;
}

private void verifyAttraction(String name) {
Runnable t = new VerifyThread(name);
new Thread(t).start();
System.out.println("Verify Thread started");
}

private class VerifyThread implements Runnable {

private String name;

VerifyThread(String name) {
this.name = name;
}

@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println("Finished verifying");
attractions.add(name);
if (listener!= null)
listener.attractionAdded(name);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}

}


}

}



ServerRMI.java


import java.rmi.Naming;


public class ServerRMI {

public static void main (String args[] ) {
try {
Attractions attractions = new AttractionsImpl();
Naming.rebind("ServerRMI", attractions);
System.out.println("Server started!");
}
catch (Exception e) {
System.out.println("Exception: " + e);
}
}

}




Here are steps for getting the code working:

Compile the code
run rmic on the CallbackClient
start the rmiregistry
start the server
start the client

Here is a sample output:

Running the client:
Exporting the client
Enter new attraction:
tt
Enter new attraction:
rr
Attraction Added:tt
Attraction Added:rr

Server Output:
Server started!
Verify Thread started
Finished verifying
Verify Thread started
Finished verifying

I have kept the code simple to illustrate RMI callbacks. Usually the server has a List of listeners as there will be multiple clients. Also since RMI server handles each request in separate thread for calls originating from different connections, you will need to synchronize the code i.e. make the server-side code thread-safe.

Thursday, September 3, 2009

InetAddress and Factory Design Pattern

I was recently working on a project which required me to check if a server is reachable or not. I started looking at java.net.InetAddress.isReachable(int) to solve my problem. The javadoc was not very clear and so I went in to see how it was actually implemented. In the java file I came across Factory design pattern for creating Internet address(InetAddress), so I decided to blog about it.

One cannot create the InetAddress objects by invoking the constructor. One has to use static methods like getLocalHost() etc. Based on the type of IP address of the host i.e. whether it is version4 or version6 IP address, a Inet4Address or Inet6Address is returned by the factory. Both these classes extend InetAddress. This is transparent to the client, so the client need not worry about which type of InetAddress to create.

In brief, the factory design pattern delegates the responsibility of creating the correct object to the factory. The factory makes the decision of which class of object to construct based on the user input or some other implicit criteria(here it was IP address type).

Here is the snippet from the code in InetAddress.java which uses Factory Design Pattern to acheive it. In this code the factory is InetAddressImplFactory which makes the decision to either load(call constructor of) the Inet4Address class or Inet6Address class.

public class InetAddress implements java.io.Serializable {

............
static {

...............
impl = (new InetAddressImplFactory()).create();
...........
}

.........
}


class InetAddressImplFactory {

//create v6 or v4 address
static InetAddressImpl create() {
Object o;
if (isIPv6Supported()) {
o = InetAddress.loadImpl("Inet6AddressImpl");
} else {
o = InetAddress.loadImpl("Inet4AddressImpl");
}
return (InetAddressImpl)o;
}

............

}



Thursday, August 27, 2009

Java EE and Cloud Computing

I would like to share this interesting article on Java EE and Cloud Computing.

Monday, August 10, 2009

JUnit 4.0

Junit 4.0 is very different from its previous versions. I present the features followed by examples.


JUnit 4.0 features:

  • Uses annotations and makes life very easy.
  • Test Class DOES NOT have to extend TestCase.
  • Need to manually do "import static org.junit.Assert.*" to get all the methods like AssertFalse and AssertTrue as the Test class does not extend TestCase.
  • All methods that needed to be tested should be decorated with @org.junit.Test annotation and you can use any method name.
  • @Test notatation takes an expected parameter which can be used to specify the exception the method should throw.eg: @Test(expected=IndexOutOfBoundsException.class) The test fails if the expected exception is not thrown.
  • To not test a particular method , decorate it with the annotation @org.junit.Ignore
  • Can specify a timeout for a method, if the method runs for a longer time, it fails. eg: @Test(timeout=1)- AssertEquals can test arrays, so we don't need to iterate over contents of array.
  • Can use annotations to specify test fixtures.
  • There are 2 Class level fixtures: @BeforeClass and @AfterClass. These are run only once before or after the tests in the class are run. Note: Can create multiple @BeforeClass fixtures though the order of running them cannot be currently
    specified.
  • There are 2 Method level fixtures: @Before and @After. These are run before or after running every test (method) in the class.
  • Can use annotations to specify test suites.
    @RunWith(Suite.class)
    @Suite.SuiteClasses( { <YourTestClass1>.class,[<YourTestClass2>.class] })
    public class <SuiteName> {
    }
  • Introduces a new runner called Parameterized. It allows the same tests to be run with different data. One of the examples below shows how to run Parameterized test. To enable this do the following:
    • Have the annotation @RunWith(value = Parameterized.class) for the Test Class
    • Have a public static method that returns a Collection for data. Each element of the collection must be an Array of the various paramters used for the test.
    • Provide a public constructor for the test class that uses the parameters.

Examples:

Java code on which the tests have to be run


import java.util.HashMap;
import java.util.Map;

public class SimpleExample {

private Map<Integer, Employee> emp;

public SimpleExample() {
emp = new HashMap<Integer, Employee>();
}

public void addEmployee(String name, int id) {
Employee e = new Employee(name,id);
emp.put(id, e);
}

public String getEmployeeName(int id) throws EmployeeException{
if (!emp.containsKey(id)) {
throw new EmployeeException("No Employee with the id " + id);
}
return emp.get(id).getEmpName();
}

public int getNumberofEmployees(){
return emp.size();
}


}

class Employee {
private String empName;
private int empID;

Employee(String name, int id) {
empName = name;
empID = id;
}

public String getEmpName() {
return empName;
}

public int getEmpID() {
return empID;
}
}

public class EmployeeException extends Exception {

private static final long serialVersionUID = 1L;

EmployeeException(String ex) {
super(ex);
}

}


Example 1: JUnit 4.0 test cases for the above class


import static org.junit.Assert.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;

public class SimpleExampleJUnitTest {

private static SimpleExample se;
private static final String NAME1 = "foo";
private static final String NAME2 = "bar";

@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("setUpBeforeClass: run only once");
se = new SimpleExample();
se.addEmployee(NAME1, 1);
}

@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("tearDownAfterClass: run only once");
se = null;
}

@Before
public void setUp() throws Exception {
}

@After
public void tearDown() throws Exception {
}

@Test
public void addEmployeetTest() {
se.addEmployee(NAME2, 2);
assertEquals(se.getNumberofEmployees(),2);
}

@Test
public void getExisitingEmployeeNameTest()
throws EmployeeException {
assertEquals(se.getEmployeeName(1),NAME1);
}

@Test(expected=EmployeeException.class)
public void getNonExisitngEmployeeNameTest() throws EmployeeException {
se.getEmployeeName(10);
}

@Ignore
public void getAllEmployeesTest() {
//Not yet implemented.
}
}


Example 2: Parameterized JUnit 4.0 test case


import static org.junit.Assert.*;

import java.util.Arrays;
import java.util.Collection;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(value = Parameterized.class)
public class SimpleExampleParameterizedJUnitTest {

private SimpleExample se;
private String name;
private int id;

public SimpleExampleParameterizedJUnitTest(String name,int id) {
this.name = name;
this.id = id;
}

@SuppressWarnings("unchecked")
@Parameters
public static Collection data() {
Object[][] data = new Object[][] {
{ "foo", 1}, {"bar",2},{"foobar",3}};
return Arrays.asList(data);
}

@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("setUpBeforeClass: run only once");
}

@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("tearDownAfterClass: run only once");
}

@Before
public void setUp() throws Exception {
System.out.println("setUp: run before every test");
se = new SimpleExample();
}

@After
public void tearDown() throws Exception {
System.out.println("teatDown: run after every test");
se = null;
}

@Test
public void addEmployeetTest() {
se.addEmployee(name,id);
assertEquals(se.getNumberofEmployees(),1);
}

@Test
public void getExisitingEmployeeNameTest()
throws EmployeeException {
se.addEmployee(name,id);
assertEquals(se.getEmployeeName(id),name);
}

@Test(expected=EmployeeException.class)
public void getNonExisitngEmployeeNameTest() throws EmployeeException {
se.getEmployeeName(id+1);
}

@Ignore
public void getAllEmployeesTest() {
//Not yet implemented.
}
}