Thursday, January 11, 2007

Jini Network Technology : A short preview.

What is Jini?

Jini™ technology is a service oriented architecture that defines a programming model which both exploits and extends Java™ technology to enable the construction of secure, distributed systems consisting of federations of well-behaved network services and clients. Jini technology can be used to build adaptive network systems that are scalable, evolvable and flexible as typically required in dynamic computing environments.

Steps to contact the Jini World

There are three basic steps to first contact in the Jini network.

  • Discovery
  • Join
  • Lookup

Discovery

The process of discovery occurs when a service is searching for a registration point in the Jini network. This registration point or service is referred to as the Lookup Service (LUS). The Lookup Service is fundamental to the Jini network. It allows us to manage the life cycle of services. Services must register with a LUS in order for other services and clients to find and use them.The net.jini.discovery.LookupDiscovery class implements the net.jini.discovery.DiscoveryManagement interface. This interface defines operations related to the discovery of a lookup service. An instance of the LookupDiscovery class acts as a mediator between devices and services and the LUS supporting the network.

You can construct an instance of this class by passing an array of groups that you want the discovered lookup service to support. For instance public groups or groups identified by specific department or geographic region could be used to construct the LookupDiscovery class.

String[] groups = new String[] { "" };

try {

LookupDiscovery lookup = new LookupDiscovery(groups);

} catch (IOException ioe) {}

In the previous code fragment the empty string value is used to indicate all public groups.
This instance then multicasts a request on the local network for any lookup services that support the groups requested to identify themselves. The LookupDiscovery instance listens for replies and, if there are any, passes to the service (JOS) an array of objects that are proxies for the discovered lookup services. These proxies are what the service will use to register with the LUSes discovered.
Reggie, the Jini supplied LUS, is one of the services that you start when you establish your Jini network. You may start one or more lookup services on your network. The following batch file provides an example start-up script. The environment variable JINI_HOME points to your installation of Jini.

java -jar -Djava.security.policy=%JINI_HOME%\policy.file %JINI_HOME%\lib\reggie.jar

http://%IP_ADDRESS%:8080/reggie-dl.jar %JINI_HOME%\example\lookup\policy.all %JINI_HOME%\tmp\reggie_log public

Join

The process of Join occurs when a service has located a lookup service through discovery and now wishes to register a service with it. The Join protocol is implemented by another Jini technology infrastructure software class, net.jini.lookup.JoinManager. This class actually combines discovery, the first step, with LUS registration. There are five parameters required to construct a JoinManager.

1)java.lang.Object -- The object or service to be registered

2)net.jini.core.entry.Entry[] -- An array of attributes associated with the object

3)net.jini.lookup.ServiceIDListener or net.jini.core.lookup.ServiceID -- Every service receives a unique service identifier. If the service has already received the identifier from the LUS, then it uses the id as a parameter; otherwise it supplies an id listener to receive the id. The id listener would store the id for subsequent registration.

4)net.jini.discovery.DiscoveryManagement -- This is an interface that defines the discovery operations as outlined in the previous section. The LookupDiscovery class implements this interface. In addition the LookupLocatorDiscovery class implements this interface using unicast instead of the multicast protocol.


5)net.jini.lease.LeaseRenewalManager -- The lease renewal manager is responsible for renewing your lease with the LUS. This is how resources are managed across the Jini network, e.g. time allocation management.

public class MyServer implements ServiceIDListener, DiscoveryListener

{// register with any LUS supporting

public groupsString[] groups = new String[] { "" };// define specific LUS locations for unicast discovery

LookupLocators[] locs = { "jini://%HOST_NAME%:4159" };// define specific service attributes e.g. Name and ServiceInfoprivate

Entry[] entries = { new Name("MyInterface"),new ServiceInfo("My Service Description","","","1.0","", "") };
// supply a lease manager for our serviceLeaseRenewalManager

lrm = new LeaseRenewalManager();// we don't have a service id yet

ServiceID id = null;// table to save service items

private Hashtable lookups = new Hashtable();// the service to register

MyServiceObject obj;

public MyServer() {

try {

if (System.getSecurityManager() == null) {System.setSecurityManager(new RMISecurityManager());}

// the service that you are registering

obj = new MyServiceObject ();

// we will use a unicast and multicast discovery process

LookupDiscoveryManager ldm = new LookupDiscoveryManager(groups, locs, this);

if(id != null)

{// we have a service id

JoinManager jm = new JoinManager(obj, entries, id, ldm, lrm);

} else {

// we will have a service id assigned

JoinManager jm = new JoinManager(obj, entries, this, ldm, lrm);

}

} catch (Exception e) {

e.printStackTrace();

System.out.println("Unable to initialize service...exiting!");

System.exit(1);

}


The code fragment above demonstrates use of JoinManager. This is our DiscoveryListener implementation. It receives notification of LUSes discovered and discarded. Our implementation creates a new thread to handle the event.

net.jini.discovery.DiscoveryListener Interface

public void discovered(DiscoveryEvent de) {
new Thread(new DiscoveryNotifier(de)).start();
}
public void discarded(DiscoveryEvent de) {
// removes the LUS from the lookup table
// and may generate additional event notifications
}
Our DiscoveryEvent thread interfaces with the LUS proxy (ServiceRegistrar) to register our service with the LUSes returned.class

class DiscoveryNotifier implements Runnable {

DiscoveryEvent de;

DiscoveryNotifier(DiscoveryEvent de) {

this.de = de;

}

public synchronized void run() {

try {

// get the LUS's returned

ServiceRegistrar registrars[] = de.getRegistrars();

for(int i=0; i <>

if(lookups.containsKey(registrars[i]) == false) {

// create a ServiceItem

ServiceItem si = new ServiceItem(id, obj, entries);

// register the service with the LUS

ServiceRegistration sr = registrars[i].register(si,Long.MAX_VALUE);

System.out.println("registered on " +registrars[i].getLocator() + " as " + sr.getServiceID()); // delegate lease management

lrm.renewUntil(sr.getLease(), Long.MAX_VALUE, null);

// update our LUS table

lookups.put(registrars[i], sr);

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

Lookup

The process of Lookup occurs when a client or user needs to locate and invoke a service described by its interface type and option service attributes. A lookup service maps interfaces indicating the functionality provided by a service to sets of objects that implement the service. In addition, descriptive entries associated with a service allow more fine-grained selection of services based on properties. If you look back at the parameters to the JoinManager you will notice an array of attributes as the second parameter. These attributes implement the Entry interface and are used to qualify or augment the object that has been registered. When lookups are performed users can supply attributes to limit the matching services. Entry attributes can be user defined; however, the Jini implementation provides some default attribute classes. The net.jini.lookup.entry package defines the Address, Comment, Location, Name, ServiceInfo, Status, and ServiceType attributes. The LookupLocator class is responsible for performing unicast discovery. A hostname is all that is required to discover the LUS at a specific location. Optionally a port number can be provided to the LookupLocator. Otherwise it will default to port 4160. The LookupLocator constructor takes a URL of the form:

jini://host:port/.

Unicast discovery was used as opposed to multicast because the multicast protocol is restricted by network configurations. The multicast protocol is only used on local network segments. Typically routers block multicast packets across network defined boundaries. This is often a source of confusion with new developers to Jini. The basic pattern of communication involves a combination of multicast and unicast. This enables the best of both worlds: dynamic discovery of local peers and directed or trusted discovery of distant peers.

Objects in a lookup service may include other lookup services; this provides hierarchical lookup. Further, a lookup service may contain objects that encapsulate other naming or directory services, providing a way for bridges to be built between a Jini lookup service and other forms of lookup service.

In step 3 the HTTP server running on the server-side of the Jini network supplies the code to the client requesting the service. This movement of code from machine-to-machine is critical to the differentiation of Jini from other distributed object technologies. The codebase parameter supplied to the HTTP daemon at start-up determines the location of the jar and class files that are available for download distribution.
The following script starts the http server.

java -jar %JINI_HOME%\lib\tools.jar -port 8080 -dir %JINI_HOME%\download\lib -trees -verbose

In step 4 the client invokes methods on the service. Some methods may be invoked locally while others may be invoked remotely. The flexibility provided in the implementation of the service will determine the best invocation approach. Jini uses the Java Remote Method Invocation (RMI) framework to enable communication between services and clients. The infrastructure to support communication between services is not itself a service that is discovered and used but is, rather, a part of the Jini technology infrastructure. RMI provides mechanisms to find, activate, and garbage collect object groups.


RMI allows
data and code to be passed from object to object around the network. The simplicity and dynamic capabilities of the Jini system are enabled by this ability to move code around the network in a form that is encapsulated as an object. The RMI daemon is another service that must be started to enable your Jini environment.
The following script starts the RMI

daemon.rmid -J-Djava.security.policy=%JINI_HOME%\policy.file


We now have the basis of a Jini environment in place.

  • An HTTP server running with a defined codebase for downloading files.
  • An RMI daemon running to activate services
  • An LUS (Reggie) running to register and lookup services



Sunday, January 7, 2007

Resource Management and JMX : preview of Standard MBeans

Overview Of JMX Technology:

The JMX technology provides a simple, standard way of managing resources such as applications, devices, and services. Because the JMX technology is dynamic, you can use it to monitor and manage resources as they are created, installed and implemented. You can also use the JMX technology to monitor and manage the Java Virtual Machine (Java VM).

The Java Management Extensions (JMX) technology is a standard part of the Java Platform, Standard Edition (Java SE platform). The JMX technology was added to the platform in the Java 2 Platform, Standard Edition (J2SE) 5.0 release.

The JMX specification defines the architecture, design patterns, APIs, and services in the Java programming language for management and monitoring of applications and networks.
Using the JMX technology, a given resource is instrumented by one or more Java objects known as Managed Beans, or MBeans. These MBeans are registered in a core-managed object server, known as an MBean server. The MBean server acts as a management agent and can run on most devices that have been enabled for the Java programming language.
The specifications define JMX agents that you use to manage any resources that have been correctly configured for management. A JMX agent consists of an MBean server, in which MBeans are registered, and a set of services for handling the MBeans. In this way, JMX agents directly control resources and make them available to remote management applications.

Architecture of the JMX Technology:

The JMX technology can be divided into three levels, as follows:

Instrumentation : Contains MBeans and their manageable resources.

JMX agent : Contains the JMX agents used to exposed the MBeans.

Remote management : Contains components that enable management
applications to communicate with JMX agents.


Standard MBeans :

A standard MBean is defined by writing a Java interface called MBean and a Java class that implements that interface. Every method in the interface defines either an attribute or an operation in the MBean. By default, every method defines an operation. Attributes and operations are methods that follow certain design patterns. A standard MBean is composed of an MBean interface and a class. The MBean interface lists the methods for all exposed attributes and operations. The class implements this interface and provides the functionality of the instrumented resource.

MBean Interface:

package com.example;

public interface HelloWorldMBean{

public void setGreeting(String greetings);
public String getGreeting();
public void print();

}

By convention, an MBean interface takes the name of the Java class that implements it, with the suffix MBean added. In this case, the interface is called HelloWorldMBean. The HelloWorld class that implements this interface is described in the next section.

According to the JMX specification, an MBean interface consists of named and typed attributes that are readable and possibly writable, in addition to the named and typed operations that can be invoked by the applications that are managed by the MBean.

MBean Implementation

The HelloWorld Java class that follows implements the HelloWorldMBean MBean interface:

package com.example;

public class HelloWorld implements HelloWorldMBean {

String greetings = null;

public HelloWorld(){
this.greeting = "Hello World! I am a Standard MBean";
}

public HelloWorld(String greeting){
this.greeting = greeting;
}
public void setGreeting(String greetings){
this.greetings = greetings;
}

public String getGreeting(){
return greetings;
}
public void print(){
System.out.println("Wish you " + greetings);
}

And with that, we have created first MBean. Now, in order to test the MBean, you need to create a JMX agent to contain it. The next section discusses the creating of the HelloAgent class. After creating your agent, you can begin using the MBean.

Creating the JMX Agent:

Now that we have the first MBean we need to make it avialable for use. To do so, you must register it in a JMX Agent. We will create the HelloWorldAgent class, which is a simple JMX agent class.

As described before, JMX agents are JMX components in the Agent layer of JMX and are containers for MBeans.
The Agent class performs 3 tasks.
  • It creates an MBeanServer instance to contain MBeans.
  • It creates an adapter to handle connections from clients .(In our case we will use HTML Adapter.
  • It registers a new instance of the (HelloWorld) MBean.

Writing the HelloAgent class

package com.examples;

import javax.management.*;

import com.sun.jdmk.com.*;

public class HelloAgent{

public MBeanServer mbs = null;

public HelloAgent(){

mbs = MBeanServerFactory.createMBeanServer("HelloAgent");

HtmlAdaptorServer adaptor = new HtmlAdaptorServer();

HelloWorld hw = new HelloWorld();

ObjectName adapterName = null;

ObjectName helloWorldName = null;

try{

helloWorldName = new ObjectName("HelloWorldAgent:name=helloWorld");

mbs.registerMBean(hw,helloWorldName);

adapterName = new ObjectName("HelloAgent:name=htmladapter,port=9092");

adaptor.setPort(9092);

mbs.registerMBean(adaptor,adapterName);

}catch(Exception ex){

e.printStackTrace();

}

}

public static void main(String args[]){

HelloAgent agent = new HelloAgent();

System.out.println(" Agent is started");

}

}

Now that the agent is running and the MBean and the HtmlAdapter is regitered to it, it is exposed for invocation through http request. Using your webbrowser, type http://localhost:9092.

You will be listed with all the MBean registered and running in local host at port 9092.
You can invoke the methods on HelloWorld directly from the browser.


JMX Notifications:
JMX notifications are Java objects used to send information from MBean and agents to other objects that have registered to recieve them.Objects interested in recieving events are notification listeners - they implement the javax.management.NotificationListener interface.

Adding Notification to HelloWorld MBean

For the HelloWorld MBean to send notifications, it needs to allow objects interested in receiving notifications to register them. JMX supports 2 mechanisms for MBeans to provide listeners to register for notifications:

  • Implement the javax.management.NotificationBroadcaster interface.
  • Extend the javax.management.NotificationBroadcasterSupport class.

Let us change our HelloWorld MBean to support for notificatoins extending NotificationBroadcasterSupport class.

package com.example;

public class HelloWorld extends NotificationBroadcasterSupport implements HelloWorldMBean {

String greetings = null;

public HelloWorld(){

this.greeting = "Hello World! I am a Standard MBean";

}

public HelloWorld(String greeting){

this.greeting = greeting;

}

public void setGreeting(String greetings){

this.greetings = greetings;

Notification notification = new Notification(" test notification" ,this, -1,System.currentMillis (),greeting); // creating the notification object.

sendNotification(notification); // sending the notification

}

public String getGreeting(){

return greetings;

}

public void print(){

System.out.println("Wish you " + greetings);

}

}

Creating the NotificatoinListener class : HelloWorldListener.java

import javax.management.*;

public class HelloWorldListener implements NotificationListener{

public HelloWorldListener(){

}

public void handleNotification(Notification notif,Object handle){

System.out.println("Receiving notifications .....);

System.out.println(notif.getType());

System.out.println(notif.getMessage());

}

}

Enabling the Agent to register Listeners to send notifications:

package com.examples;


import javax.management.*;
import com.sun.jdmk.com.*;

public class HelloAgent{
public MBeanServer mbs = null;
public HelloAgent(){
mbs = MBeanServerFactory.createMBeanServer("HelloAgent");
HtmlAdaptorServer adaptor = new HtmlAdaptorServer();
HelloWorld hw = new HelloWorld();
ObjectName adapterName = null;
ObjectName helloWorldName = null;
try{
helloWorldName = new ObjectName("HelloWorldAgent:name=helloWorld");

hw.addNotificatioListener(new HelloWorldListener(),null,null); //enabling listeners
mbs.registerMBean(hw,helloWorldName);
adapterName = new ObjectName("HelloAgent:name=htmladapter,port=9092");
adaptor.setPort(9092);
mbs.registerMBean(adaptor,adapterName);
}catch(Exception ex){
e.printStackTrace();
}
}
public static void main(String args[]){
HelloAgent agent = new HelloAgent();
System.out.println(" Agent is started");
}
}

Run we have added the capability of listening notificatoins when property of HelloWorld changes. Using your browser navigate to http://localhost:9092/ and invoke the setGreetings method. In the console of your program running HelloWorldAgent, you would see the notifications messages.

Summary :

This article will help to understand the basics of JMX and standard MBean with a working example. Other than StandardMBean we also have :

Dynamic MBeans
Open MBeans
Model MBeans
MXBeans

We will see in later articles more upon the other types of MBean.

If you have any questions/suggestions please mail at pritam.dewan@gmail.com

-----------------------------------***----------------------------------