Sunday, March 22, 2009

RMI

Here is a short summary about RMI. A simple example can be found in my post here.

A RMI based application has the following minimum pieces:

1. RemoteInterface (import java.rmi.*;)

- Defines the interface.
- The interface extends java.rmi.Remote and declares remote methods.
- Each remote method throws java.rmi.RemoteException.


public interface RemoteInterface extends Remote {
public String concat(String s1, String s2) throws RemoteException;
}



2. Implementation of the RemoteInterface (import java.rmi.*;)

- Implements all methods of remote interface.
- Has a constructor which throws RemoteException


public class RemoteInterfaceImpl implements RemoteInterface{
//Has constructor which throws RemoteException
public RemoteInterfaceImpl() throws RemoteException{
}
//Implements all methods of the RemoteInterface
public String concat(String s1, String s2) throws RemoteException{
.....
}
}



3. The server (import java.rmi.registry.*; import java.rmi.*;)

- Creates and exports the remote objects.
- Gets handle to the RMI registry. (It runs at default port 1099.
if you start at a different port specify port when trying to get registry).
- Bind/register the remote object stubs with the registry.


public class Server {
public static void main(String[] args) {
try {
RemoteInterfaceImpl rii = new RemoteInterfaceImpl();
RemoteInterface stub = UnicastRemoteObject.exportObject(rii, 0);

Registry registry = LocateRegsitry.getRegistry();
registry.bind("concat", stub);

catch(RemoteException e) {
.....
}
}
}



4. Client (import java.rmi.registry.*;)

- Do following:

1. Get the stub to the registry on the remote host.If registry running on different port provide it too.
Registry registry = LocateRegistry.getRegistry(host);


2. Lookup the remote object's stub using its name in the registry.
ri = (RemoteInterface)registry.lookup("concat");

3. Invoke the methods on the remote object using the stub.
String c = ri.concat("1","2");

where

concat is a method defined in the RemoteInterface
The object returned or method parameters must be Serializable (Remember: String class implements Seriableable)
RemoteException must be caught and do something valuable with it.




5.Running them

- Compile source files using javac.
- start the rmiregistry. (uses port 1099 by default).
- start the server.
- start the client.


More on RMI:


Here are a few high level things to remember about RMI:

Passing parameters in RMI

RMI deals with 3 types of parameters:

- Primitive paramters: Always passed by value. Copy is made and sent across.
- Object parameters: A copy of the object itself is made and sent across. Note, the reference to the object is not passed the object itself is passed. The object should be Serializable. If the object is composed of other objects, they are also sent across, so they must also be Serializable.
- Remote Object parameters: The remote object parameter is substituted with the remote proxy/stub and sent across.

 

Garbage collection of remote objects:

- It is done using Distributed Garbage Collection and reference counting.
- When the client creates a remote reference, it lets the server side know this by calling dirty() on the Distributed Garbage Collector(DGC) of the server.
- The client keeps renewing the lease periodically on the remote reference by calling dirty().
- Once the client is done with the remote reference(GCed on the client), the client calls clean() on th server-side DGC, indicating that the server-side DGC no longer needs to keep the remote object alive for this client
- The server-side DGC keeps track of all its remote references and does not GC them and if they are being used.


rmiregistry:

- RMIRegistry is purely for bootstraping purposes, so that clients can get a remote object stub. If the client can get a remote object stub through another mechanism then the rmiregistry is not needed.
- rmiregistry and server can run on different machines but sometimes the registry may give AccessException if you try to bind from non local host.I have never tried this, so cannot provide more insight on this.
- You can also create the registry from within your code using createRegistry() API.If you do this, you dont have to explicity start the rmiregistry, it is started when the server is started.
Registry registry = LocateRegistry.createRegistry(port);



Exporting Objects:

- UnicastRemoteObject.exportObject(), exports the remote object receive incoming remote invocation by making it listen on an anonymous TCP port in the machine.
- It returns a stub to the remote object which has the info on the port on which the remote object is listening.
- This remote object stub is returned to the client when it does a lookup on the rmiregistry. Now the client through the remote stub knows how to contact and call methods on the remote object.


RMI stubs:

- rmic is no longer required to generate stub post 1.5. stub classes are generated at runtime.
- When a stub's method is invoked, it does the following:

- initiates a connection with the remote JVM containing the remote object,
- marshals (writes into byte stream and transmits) the parameters to the remote JVM,
- waits for the result of the method invocation,
- unmarshals (reads) the return value or exception returned, and
- returns the value to the caller.


 

Wednesday, March 11, 2009

Nesting Java enums in an interface

Continuing on my post about enums from yesterday...

Just like a class can be nested inside an interface, an enum can also be nested inside an interface. Nested enums in an interface are implicitly static and public. Here is an example.

interface SoundInterface {
public void makeSound();

//nested enum
enum WesternStringInstruments implements SoundInterface {
PIANO("Piano"), GUITAR("Guitar"),
VIOLIN("Violin"), VIOLA, BASE, CELLO;

private String name;
WesternStringInstruments(){
name = null;
}

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

@Override public String toString() {
if (name != null) {
return name;
}
return this.name();
}
public void makeSound(){
System.out.println("String sound");
}
}

}

public class InterfaceWithEnum {

//Using the nested enum
public static void main(String[] args) {
for( SoundInterface.WesternStringInstruments st:
SoundInterface.WesternStringInstruments.values()) {
System.out.println(st);
}
SoundInterface.WesternStringInstruments.PIANO.makeSound();
}
}


Here is the output:
Piano
Guitar
Violin
VIOLA
BASE
CELLO
String sound

Monday, March 9, 2009

Java enums

Listed below are a few highlights about Java enums. It is followed by an example.
- enum is a type in Java
- used to represent a fixed set of constants. so the enum constants are implicitly public static final.
- is Serializable
- implements Comparable
- is NOT Cloneable
- implicitly extends the class java.lang.Enum so they cannot extend any other class or enum. So is implicitly final.
- cannot be abstract
- can have the access modifiers public or default.
- can be defined outside the class or as a class member. They cannot be defined inside methods. Enums defind inside a class are implicitly static.
- can have one or more constructors but they cannot be called explicitly. So better declare them private.
- cannot be instantiated using new operator.
- can have methods including abstract methods. An enum constant can override any number of available methods. Abstract methods have to be implemented by each and every constant of that enum.
- name(), valueOf() and defualt implementation of the toString() methods is to return the name of the enum constant. The enum constants can override toString() method to return something else.
- can be used as an operand in the instanceof operator
- enum constants can be used in switch statements.
- '==' and equals yield the same results for enum constants.
- natural order of the enum constants is the way they are defined and is used by compareTo(), values(), EnumSet.range().
- ordinal() returns the natural ordering of the enum constants starting at the index at 0 for the first constant.
- cannot be generic

public class MyEnumType {

  //Simple enum
  public enum TrainType {
    STEAM,DIESEL //; is optional
  }
  
  //Complex enum
  public enum ThomasAndFriends {
    
    //Enums can have constructors
    THOMAS(1,"blue"), EDWARD(2,"blue"),GORDON(4,"blue"),
    DAISY(9,"black"){
      //Can override method
      @Override public TrainType getTrainType() {
        return TrainType.DIESEL;
      }
    },
    JAMES(5,"red"),PERCY(6,"green");
    
    private int engineNumber;
    private String color;
    
    //Constructor's access can be private or default.
    ThomasAndFriends(int engineNumber, String color) {
      this.engineNumber = engineNumber;
      this.color = color;
    }
    
    public int getEngineNumber(){
      return engineNumber;
    }
    
    public String getColor(){
      return color;
    }
    
    public TrainType getTrainType(){
      return TrainType.STEAM;
    }
    
  }
  
  public static void main(String[] args) {
    
    //Walk through the enumeration and print values
    for (ThomasAndFriends tf: ThomasAndFriends.values()) {
      //Enums have ordinals but do not use them. Code dosent 
      //scale, instead use constructors to specify values.
      System.out.println("Name: " + tf + 
              " EngineNumber: " + tf.getEngineNumber() +
              " Enum Ordinal: " + tf.ordinal() +
              " Color: " + tf.getColor() +
              " TrainType: " + tf.getTrainType());  
    }
    
  }

}

OUTPUT:
Name: THOMAS EngineNumber: 1 Enum Ordinal: 0 Color: blue TrainType: STEAM
Name: EDWARD EngineNumber: 2 Enum Ordinal: 1 Color: blue TrainType: STEAM
Name: GORDON EngineNumber: 4 Enum Ordinal: 2 Color: blue TrainType: STEAM
Name: DAISY EngineNumber: 9 Enum Ordinal: 3 Color: black TrainType: DIESEL
Name: JAMES EngineNumber: 5 Enum Ordinal: 4 Color: red TrainType: STEAM
Name: PERCY EngineNumber: 6 Enum Ordinal: 5 Color: green TrainType: STEAM

Saturday, March 7, 2009

Configuring MySQL for the Sun App Server

Last winter, I took a course on "Designing J2EE Enterprise Applications" at UC Berkeley Extension. While doing the course, though not required, I ended up installing MySQL server and configuring it for the Sun App server. Due to lack of documentation on the configuration, I went through some trial and error but finaly figured out the configuration. Here are the steps:

Installing database server and setting up
Install mysql server
Create a database
Create tables, users as suitable
Install j connector JDBC driver
Add the connector to your system classpath (computer->system->advanced->env variables)
Open admin console of server
Add the jdbc driver (jar fle) to the JVM settings->path settings.

Configuring connection resource in appserver
Open admin console of server
add a new connection pool under resources->connectionPool.
Select new.
Name: enter any name to identify this connection pool. Select javax.sql.DataSource
for resource type. Database Vendor see mysql and select it or select your vendor or leave blank if your vendor do not appear. click next.
Data Source Class Name: enter your class name i.e. Find your database driver name and enter here. For mysql 5.0, it is com.mysql.jdbc.jdbc2.optional.MysqlDataSource
Scroll down to add Properties. Add the following:
user, password, databaseName, port(3306:default), serverName(localhost)
Save.
Now connection pool is created for the database.

Now create the resource
In admin console go to resources->jdbc resources
Add a new jndi name for jdbc resources
Go back to connection pool and ping
Click new.
Enter the JNDI Name you will use to identify the connection pool in your application i.e ejb/customer or anything you want . Select the Pool Name you just configured from the list and click save.
Go back to Connection Pools navaigational link and select your database you configured.
Click ping. If you get errors that means it is not yet working. So try again.