Servent user guide

Javier Noguera


Chapter 1.  Versioning

version

release Date

Author, Organisation

0.1

May 09, 2005

Javier Noguera, Sun Microsystems

0.2

June 01,2005

Javier Noguera, Sun Microsystems

0.3

July 20,2005

Javier Noguera, Sun Microsystems

Chapter 2.  Introduction

This document is addressed to Servent users, Servent administrators and service developers, not to Servent developers. We will learn how to install a new Servent, how to make and deploy applications in it and how the communication is performed.

Other information about the Servent implementation and about the core itself is not explained here. Because the Servent is under construction this implementation information changes quickly and there is not a formal document at the moment.

The Servent can be seen as a service container. Something similar to any J2EE or Tomcat but made for service deployment, not servlets, beans, JSPs or HTML.

The main function of the servent is to make the remote communication easy as well as the deployment and creation of services, trying to make the development process simple. The servent itself also must provide different communication protocols and different ways to communicate (UserInterfaces, ProtocolAdaptre, DynamicProxy...)

Chapter 3.  Servent

The Servent is a piece of code written in Java, what means that a Java VM must be installed in order to run the Servent. The full Servent release will be decompressed in one directory ($HOME/servent by default). This directory can be deleted to unistall the Servent because there are no more dependencies outside this directory (no information is saved in any kind of registry or whatever).

Servent directories

The servent follows an strictly directories structure:

/-- servent/
  |- bin/
  |- lib/
  |- common/
  |- shared/
  |- deploy/
  \- servent.props

  

servent:

This is the rootPath where the servent is deployed. By default it is the $HOME/servent directory, but user can change it while installation.

bin:

This directory contains some scripts useful for the servent. At the moment it contains the run.sh script (that runs the servent) and the client.sh script (that test one service deployed within the servent)

lib:

Libraries directory. It contains different libraries that are useful to start the service but are specific of the Servent implementation. Services must not use none of these libraries

common:

Libraries directory. It contains some common libraries that will normally used by all services

shared:

Libraries directory. It contains specific libraries that will be loaded for each services, so services will all have a different copy of these libraries.

deploy:

All services (DAR files) will be deployed here.

servent.props

Configuration file for the servent

Many operations related with the sevent startup use these directories and try to find it with the only acknowledge of the rootPath so, it is a bad idea to modify the name or the location of these directories. This can seem very restrictive but, in fact it is not. Maintaining this strict structure allow us to have less configuration (only rootPath is needed). By the way there is no reason for changing it.

servent.props

This is a very simple properties file with only the more basic configuration options. These configuration parameters can be specified while installing or can be changed directly by the user editing the servent.props file. If the servent.props file is changed the servent must restart.

hostName

The name of the machine. It must be the name of the machine to be accessible by others. Names as “localhost”, “192...”, “127...” must be avoid.

rootPath

The directory where the servent is installed. Some processes depends of this directory. If the value is not correct needed libraries will not be found.

fadaURL

The node where the FADA node is running. It can be local or remote.

adminPort

The private port for administration calls (deployment) and services search. This port is usually only accessible by users in the same LAN.

clientPort

This is the publicPort where services are visible. This port must be accessible for users outside the LAN.

log4java

The full path where the log4java properties can be found

Chapter 4.  Services

A DBEService (aka. Adapter or Service) is a very simple or a more complex class written in Java. DBEServices must be deployed in the Servent in order to run and become accessible by other DBEServices or DBEClients.

A DBEService is simply a class implementation that, of course, can use other classes or interfaces. Actually the DBEService is also named Adapter because we though the most of them will be used to adapt the brand new DBE business model to old fashioned legacy systems already running in the most of the companies.

The DBEService can also implement all the service logic if there is not another remote system or if we can do a new application. Threads and Tasks can be used at the moment, but we can not promise this will be allowed in later versions because of security restrictions.

DBEServices must not implement a special communication method for the remote invocation process. Public DBEservice methods will be extracted at runtime and a new endpoint will be created in the servent to attend remote invocations. DBEClients will be able to communicate with this DBEService automatically.

Methods, then, will run in where deployed and they must be though and implemented as simple methods.

DBEService class

DBEService class has not strong implementation restrictions (it must not extend any special class) but it must implement an interface called org.dbe.servent.Adapter. The DBEService implementation must extend at leas a DBEService interface too. All methods from this interface will be parsed so, can be accessible. All public methods declared in the DBEService implementation class that are not declared in the DBEService interface will not be parsed and will not public accessible. Because of serialization needs we must assure all parameters implement the java.io.Serializable class.

Usually in a DBE development this DBEService interface will be obtained directly form the SDL definition. User will only need to implement that interface. Using this SDL2Java process we can (must) be sure the org.dbe.servent.Adapter class will be implemented and the parameters will be serializable.

The org.dbe.servent.Adapter interface has only two methods: init and destroy. The init method is called by the Servent just after instantiate the DBEService and is useful for initialization task.

<algorithm><title> org.dbe.servent.Adapter interface </title>

public interface Adapter {

    /**

    * Initializes the adapter. The "server provider" can initialize any

    * resource here.

    * @param props The Properties with the initialization parameters

    */

    void init(ServiceContext context);

    /**

    * Executed just before destroy the adapter. The "server provider" can

    *destroy any resource here.

    *

    */ void destroy();

}

</algorithm>

ServiceContext

The ServiceContext object is passed to the DBEService while initialized. It contains many information related to the service as:

  • homeDirectory: path where the service is deployed and very useful to access some resources

  • id: service identifier

  • endpoint: external endpoint (URL) used by others to talk with the service

By means the ServiceContext it is also possible to access to specific parameters needed by the service. These parameters can be written in the deployment.props file???.

ServiceContext can be used also to get some other needed service deployed within the DBE network. The getService method can be used to retrieve any well known service proxy. If the service is not deployed null will be returned.

Example

This example shows a very simple service that returns the actual Date. Notice three files are necessaries to write the service: ServiceInterface, ServiceImplementation and deployment.props??? file.

ServiceInterface

The service interface shows the public methods that will be accessible for others[1]. In this case there will be only one method named getDate.

package demo.date
public interface DateInterface {
    Date getDate ();
}

   

ServiceImplementation

Remember that the implementation is instantiated in the Servent where deployed and it will run in the same Servent. Remote clients will call this DBEServices as RPCs.

Our service implementation must implement the org.dbe.servrent.Adapter interface so two more methods (init and destroy) must be implemented. We have nothing to do in the initialization not in the destroy so will leave these methods in blank.

package demo.date
import org.dbe.servent.Adapter
public class DateServiceImpl implements DateInterface, Adapter {
    public Date getDate () {
        return new Date ();
    }
    public void init (ServiceContext context) {
        /* nop */
    }
    public void destroy () {
        /* nop */
    }
}

   

Deployment file

Finally we only need to write the deployment file???. One one parameter is really needed (adapter), but it is also useful to indicate the applicationName.

applicationName=Simple Date Service
adapter=demo.date.DateServiceImpl

   



[1] When DBE service factory is used this interface is created automatically from SDL

Chapter 5.  Deployment

Two methods can be employed for deploying a service:

  1. HTTP Post method sending a DAR file as a parameter.

  2. Decompress a DAR file directly in the Serventdeploy directory.

DAR file

A DAR file is, in fact, a ZIP file which contains libraries and information (something similar to the usual JAR, WAR or EAR file).

The information inside the DAR file must be organized in a specific way to be understood by the Servent at deployment time. The only mandatory file inside the DAR file is the deployment.props file which specify the Adapter (DBEService) to be used.

/-- deployment.props 
  |- service-impl/
  |     |- classes/
  |     \- lib/
  |- META-INF/
  |     \- ServiceManifest
  \- service-chain/ 

  

deployment.props:

This is the properties file where there is the information about the service and the deployment issues

classes:

In this directory usually there are, extended, the classes that are part of the DBEService (the service itself)

lib:

This directory contains any extra or third party libraries needed by the DBEService

ServiceManifest:

Is a document containing the BML definition + SDL definition + specific data (about the company, I guess). The ServiceManifest is also known as SM

service-chain :

This directory will be used, in short, to store .BPR files needed by composed services

deployment.props

The deployment.props file contains some useful configuration needed by the servent at deployment time and also the parameters useful for the service itself. The service can access to these parameters at any time while executing (???).

The most important parameter is named adapter. It specify the name of the class the servent must instantiate and deploy: the service itself. Because this class is instantiated in runtime by the servent, an empty constructor is needed. Notice that other constructors can be provided, by they will not be used by the servent.

When the service is deployed, some filters can also be specified to run before and after its execution.

These are some of the most significative prameters we can use in the deployment.props file:

applicationName

This is a descriptive name for the application

adapter

Full name for the DBEService interface class (Adapter class). Full name includes the package.

codebase

The relative name to the codebase JAR file. The codebase or anotation is a JAR file that contains different classes not included in the standard Java distribution. This codebase is needed by FADA and the GUI [???] in order to know the classes to use

proxy

Full name for the UIFactory [???] that implements the GUI. It is not needed if there is no GUI

Deploy using a HTTP POST call

The DAR file can be deployed programmatic sending a POST method to the servent or using a HTML file with multipart/form-data encode type. The ServiceFactory will use the programmatic method but we can use the more easy HTML file for our examples[2].

Because the servent is still very bound to the DBE, if this method is used, one more parameter is needed in the deployment.props??? file. This parameter is named smid and this will be the service identifier (a number o small word).

As a result of the deployment, a new directory will be create in the Servent deployment directory. The name of the directory will be the smid value. The DAR file will be decompressed in this directory.

<algorithm><title> Deployment HTML file </title>

<h1>Deployment</h1>

  <form action="http://<servent_ip>:<private_port>/DBE/upload"

    method="post" enctype="multipart/form-data">

  <input type="file" name="file">

  <input type="submit" value="go!">

</form>

You need to change the <servent_ip> and <private_port> with the real servent values.

</algorithm>

Deploy directly in the deployment directory

It is also possible to deploy a service decompressing the DAR file directly in the deployment directory. The service must be deployed within a directory.

The service identifier will be the name of the directory. Notice that if we use this method, the service must be restarted.

Example

If we want to deploy our previous example (DateInterface) we must create a tree structure like the following:

/-- deployment.props 
  \- service-impl/
       \- classes/
            \- demo/
                \- date/
                     |- DateInterface.class
                     \- DateServiceImpl.class

  

If we are not going to use extra information like SM[3], service-chain of libraries, these directories do not need to be present while deployment.




[2] This file is already included in the servent release (deploy.html) but it will be changed in short to be part of the servent automatically.

[3] We are not developing now using the DBE ServiceFactory, so we haven't ServiceManifest. The Servent can run with or without it. Evidently its better to work with it if we want to work within the DBE network but it's more easy to understand if we work without while teaching the Servent itself.

Chapter 6.  Filters

Filters are services without endpoint deployed in the Servent. All we have told about services [???] and deployment [???] is also valid for filers. There are only small differences:

  1. The applicationName in the deployment.props [???] file is needed. This will be the way to find an specific filter

  2. Filters do not implement the org.dbe.servent.Adapter interface but org.dbe.servent.filters.ServiceFilter that is basically the same as adapter but it contains one more method named doFilter.

  3. It is not necessary to implement any specific Service interface because only the doFilter method will be called. (Methods will not be parsed as done with DBEServices)

<algorithm><title> org.dbe.servent.filter.ServiceFilter interface </title>

public interface ServiceFilter {
    /** 
    * Init the filter
    */ 
    public void init(ServiceContext context);
    /** 
    * Destroy the filter,
    */ 
    public void destroy();
    /** 
    * Executes the filter. Some action can be done before and after the Real 
    * Service execution. 
    */ 
    void doFilter(InvokationRequest request, InvokationResponse response, 
        FilterContext context, ServiceFilterChain chain) 
        throws ServiceFilterException;
}

</algorithm>

Filters are deployed in the Servent and services can specify which filter must be used before call the service code. Filters can execute actions before and after the the service execution to save information, change parameters, abort execution... Notice that if a service specify that one filter must be executed and this filter is not deployed in the Servent, the execution is aborted[4].

Services filter specification

A DBEService can specify in its deployment.props file the filter(s) it want to use before and after execution. Unser can specify in a new parameter named filters all the filters to be used. These names must be separated by coma.

When a filter is used by a service, some parameters must be needed. The filters can access to the service paramters (using the init method) but it has also some specific filter parameters. These parameters can be specified in the deployment.props file using the <name_of_the_filter>.<name_of_the_paramter>. Next you can find a deployment.props file where two filters are specified (one of then with some parameters).

# filters
filters= one, two
# here we can specify paramteres for filter “one”
one.name=nombre 
one.count=8080

  

In previous example the filter one have two paramters: named and count.

Special parameters

There is one special parameters named method. When a filter is specified to run with a service, this filter will be executed for all service methods. With the method parameter we can specify this filter will only run for a detemined method. If no parameter named method is specified yn the deployment.props file, it will be executed by default for all methods.

We can modify the previous example to allow filter one to run with methods “getName” and “getAll” and filter two to run with method “getName”. Notice that other methods in the DBEService will run without filters.

# filters
filters= one, two
# here we can specify paramteres for filter “one”
one.name=nombre 
one.count=8080
# We specify filter “one” must only run with getName and getAll methods
one.method=getAll, getName
# We specify filter “two” must only run with getName method
two.method=getAll

  



[4] It is better to abort execution than execute a possible service with an insecure user. It is possible service uses filters to authenticate a user or receive by its services.

Chapter 7.  GUI

At this point DBEServices can be called programatically by others using a generic adapter called ProtocolAdpater or using an DynamicProxy that implement its interface remotely. It is also possible to code an interface for the service so users can call the service an get this DBESeervice interface.

The creation of a GUI is not very complicated, but is necessary to have some knowledge about the proxyframework and the proxytoolkit.

We pretend the user can make the GUI (usually JFrame) without worry about the communiation protocol. We need then to know something more about org.dbe.toolkit.proxyframework.ui.UIFactory, org.dbe.toolkit.proxyframework.ui.ServiceUI and org.dbe.toolkit.proxyframework.Workspace

Workspace

The workspace class is the communication protocol itself. The user have nothing to do with this, he can assume this will be deliver to him directly by the servent. He will use this to inkoke the remote service without matter about the protocol or the endpoint the service is deployed.

UIFactory

User must implement this interface that publish only two methods. One service can have been implemented in many ways (JFrame, Frame, Applet, JPanel...) this UIFactory will store the different UITypes (String[] getUITypes ()) and instantiane one of them in the best way only know by the programer (ServiceUI createServiceUI (String type, Workspace workspace)).

These methods will be called directly by the client or by the servent, so the porgramer only needs to make a very simple UIFactory that return the valid UITypes and that initailize each one of them when the createServiceUI is called.

<algorithm><title> Very simple UIFactory implementation </title>

public class DateUIFActory implements UIFActory {
    public String [] getUITypes () {
        return new String [] {”JFrame”}
    }
    public ServiceUI getServiceUI (String type, Workspace workspace) {
        if (“JFrame”.equals(type)) {
            return new DateServiceUI (workspace);
        }
        else {
            throw new UnsoportedUIException (type + “ was not found”);
        }
}

</algorithm>

ServiceUI

User must also implement this interface that publish only one method (void startUI ()). This method is in charge of create the real JFrame, Frame, Applet... or whatever and invoke its show() method. As we have seen before, the ServiceUI has been created by the UIFactory and, in our example, we passed the Workspace object to this ServiceUI. Usually the ServiceUI implemetation will pass this Workspace to the real GUI implementation to allow comunication with the real endpoint.

The programer then assume this Workspace objec will be passed in the contructor an he will use it to perform communication.

<algorithm><title> Very simple ServiceUI implementation </title>

public class DateServiceUI implements ServiceUI {

    private Workspace w;

    public DataServiceUI (Workspace w) {

        this.w = w;

    }

    public void startUI () {

        // init the real JFrame

        new DateJFrame (w).show();

}

</algorithm>

Chapter 8.  CoreServices

There is also a special kind of services named CoreServices. These services has total access to the servent Core functionalities as Deployer, Configuration, P2PRegisterer, P2PDirectory... Whit these CoreServices it is possible to make more powerful services.

Security

Because those services can access to the Servent core functionallity, they must not be deployed by anyone and it's is possible the service itself must contain some kind of certificate or hash wich authenticate itself within the servent.

This is not done and will not be done in short so anyone that can access to the ADMIN port can deploy CoreServices.

Creating a CoreService

Creating a CoreService is pretty easy. We only need to follow the same steps as when we are creating a Service only with one small difference. It is necessary to extend the inteface org.dbe.servent.tools.CoreAdapter.

This interface provides only one new method wich allows to store as a member variable the ServentContext. There is also a special kind of services named CoreServices. These services has total access to the servent Core functionalities as Deployer, Configuration, P2PRegisterer. Whit these CoreServices it is possible to make more powerful services. These special DBEServices are not explained here but we hope they will be finished in short.

<algorithm><title> org.dbe.servent.tools.CoreAdapter interface </title>

public interface CoreAdapter extends Adapter {

    /**

    * Initializes the Adapter with the ServentContext. The "service provider"

    * can store this object

    *

    * @param context ServentContext

    */

    void init(ServentContext context);

}

</algorithm>

ServentContext

The ServentContext is an interface that allows the user to get some configuration parameters used during the servent StartUP and some components used by the servent to deploy/undeploy services, register/unregister proxies...

<algorithm><title> org.dbe.servent.ServentContext definition </title>

/**

* Context of the Servent application. With the context we

* can access to the Logger, the ServentConfiguration, ...

*

*/

public class ServentContext {

    public ServentConfiguration getConfig() ;

    public void setConfig(ServentConfiguration config) ;

    public ServiceWrapperRepository getRepository() ;

    public ServiceWrapperRepository getServiceFilterRepository();

    public void setRepository(ServiceWrapperRepository repository);

    public void setServiceFilterRepository(ServiceWrapperRepository repository);

    public Deployer getDeployer() ;

    public void setDeployer(Deployer deployer) { this.deployer = deployer; }

    public ClassLoader getCommonClassLoader ();

    public void setCommonClassLoader (ClassLoader common)

    public void setHttpServer(ServentServer server)

    public ServentServer getHttpServer()

    public void setConnectionManager(ConnectionManager connectionManager);

    public ConnectionManager getConnectionManager() ;

    public void setPublicHandler(ServentHandler handler) ;

    public ServentHandler getPublicHandler() ;

    public P2PDirectory getDirectory();

    public void setDirectory(P2PDirectory directory);

}

</algorithm>

Deployment and more

The deployment process and all other things are done as if it is a Service???

Chapter 9.  Testing services

If you have created and deployed a service maybe you want to test it. You can do it directly from your navigator (firefox, opera, explorer...) if your service has beed deployed with an UserInterface (JFrame)

If your service doen't have UserInterface or simply you want to integrate it within another bigger service you cant est using a simple Java class with main method.

Testing from browser

This can be only done by services that have been deployed with an UserInterface

You only need to write in your browser this URL:

http://_servent_ip_:_servent_port_/CLIENT/show?entries=_entry_

Where _servent_ip_ is localhost, _servent_port_ is tipically 2728 and _entry_ is the service smid

Testing from a Java class

We will use the ClientHelper to test the new service. ClientHelper is a simple class that communicates with the servent, get the information needed and return to the user the interface of the remote service or the Workspace (protocolAdapter)

The ClienHelper gets as consturctor the Servent CSS URL, (usually http://localhost:2727).

There are two methods we can use: getProxy (Class, String[]) and getProxy (String[]). The first one returns the Class (Class is the serviceInterface) and the second one returns the Workspace.

  	// Get proxy
  	ClientHelper ch = new ClientHelper (new URL ("http://localhost:2728"));
  	DateService service = (DateService) cl.getProxy (DateService.class, new String [] {"date"});
  	
  	// Execute service
  	service.getDate ();
  

If you don't know the DataService interface but you know the methods and parameters (this is basically helpful for computers, that can parse the SDL to know this information), you can get directly the Workspace (ProtocolAdaoter) and make invokations to it.

  	// Get proxy
  	ClientHelper ch = new ClientHelper (new URL ("http://localhost:2728"));
  	Workspace pa = (Workspace) cl.getProxy ( new String [] {"date"});
  	
  	// Execute service
  	pa.invoke ("getDate", null, null);