spacer spacer spacer
spacer spacer spacer
spacer
NASA Jet Propulsion Laboratory, California Institute of Technology + View the NASA Portal

+ NASA en Español

+ Contact NASA
Search the API    

Developing a Profile Handler

Profiles describe resources. But where do profiles come from? From profile handlers. Profile handlers are interchangeable components of a profile server that accept queries for profiles and return matching profiles. Profile handlers take a static or a dynamic collection of information and serve an equivalent set of profiles. Developing a new profile handler is as simple as writing a Java class that implements a specific interface or two.

If you're not already familiar with the XMLQuery class, go ahead and take its tutorial now . We'll wait!

Introduction

Profile handlers handle queries for profiles. They're the interchangeable part of a profile server that you can develop for special needs. Profile servers delegate all incoming requests to zero or more profile handlers, as shown in the following class diagram:

Delegation model

Developing, testing, and deploying a new profile handler involves:

  1. Creating a class that implements (however indirectly) the jpl.eda.profile.handlers.ProfileHandler interface.
  2. Creating a new process that runs either the RMI or CORBA ProfileServiceImpl class, specifying the name of your handler class.
  3. Starting the server and sending in queries.

This document describes each of these steps in detail.

Writing the Handler Class

Writing the class that handles profile queries and delivers profile results is easily the hardes t part in developing a new kind of profile server. Profile servers' handlers can serve profiles describing static resources, can synthesize profile on the fly to describe resources, and can create profile metadata for resources that change all the time.

Understanding the resources you're trying to describe with profiles is the most important thing you can do before beginning to write your profile handler:

  • Do you always have the same set of static resources? If so, you can write a static profile document to describe them and use the LightweightProfileHandler , thus avoiding having to write a new handler at all.
  • Do you have resources that never change, but may add to or remove from that set? If so, you can use the OracleProfileImpl handler which uses an Oracle database to store a set of profiles that you can update.
  • Do you have resources that do change, or that come from a dynamic set of data? If so, you'll have to write a handler.

Choosing the Handler Interface to Implement

The OODT Framework provides two handler interfaces (one is an extension of the other):

  • jpl.eda.profile.handlers.ProfileHandler is the basic profile handler. It defines methods for handling searches for profiles.
  • jpl.eda.profile.handlers.ProfileManager is an extension that not just handles profile queries but also manages the set of profiles maintained by the server, by providing methods for adding to, removing from, and updating the set of managed profiles.

For nearly all applications, the ProfileHandler interface is sufficient. If you need to provide profile management capabilities, it still may be handy to start with the Profile Handler interface, implement and test its methods, and then change to the ProfileManager .

The ProfileHandler Interface

The ProfileHandler interface is as follows:

package jpl.eda.profile.handlers;

import java.util.List;
import jpl.eda.profile.Profile;
import jpl.eda.profile.ProfileException;
import jpl.eda.xmlquery.XMLQuery;

public interface ProfileHandler {
  List findProfiles(XMLQuery query) throws ProfileException;
  Profile get(String profID) throws ProfileException;
}

The two methods are described in detail below.

findProfiles
This method accepts a query in the form of an XMLQuery object and returns a Java List of Profile objects that match. If there are no matches, this method must return an empty list. If an error occurs, it should throw the ProfileException .

This is by far the most used and most important method, and really is the raison d'etre for profile servers. It's what the OODT Framework uses to allow clients to ask your server for resources based on metadata .

get
This method accepts the ID of a profile in the form of a Java String and returns either a Profile object with that ID or null if the ID is unknown. This method enables a client to retrieve a profile using a priori knowledge of the profile's ID (perhaps from a previous search).

The ProfileManager Interface

The ProfileManager interface builds on the ProfileHandler , and is listed below:

package jpl.eda.profile.handlers;

import java.util.Collection;
import java.util.Iterator;
import jpl.eda.profile.Profile;
import jpl.eda.profile.ProfileException;
import jpl.eda.xmlquery.XMLQuery;

public interface ProfileManager extends ProfileHandler {
  void add(Profile profile) throws ProfileException;
  void addAll(Collection collection) throws ProfileException;
  void clear() throws ProfileException;
  boolean contains(Profile profile) throws ProfileException;
  boolean containsAll(Collection collection) throws ProfileException;
  Collection getAll() throws ProfileException;
  boolean isEmpty() throws ProfileException;
  Iterator iterator() throws ProfileException;
  boolean remove(String profID, String version) throws ProfileException;
  boolean remove(String profID) throws ProfileException;
  int size() throws ProfileException;
  void replace(Profile profile) throws ProfileException;
}

If you choose to implement a profile manager, please see the API documentation for the ProfileManager class for the expectations of each method.

Our First Profile Handler

Although not terribly useful, a “ null ” profile handler is a good example to start with because it is small and will make sure your environment is in good working order before proceeding to a real profile handler.

What's a “ null ” profile handler? It's one that serves no profiles. That is, for any query with findProfiles and any retrieval with get it never returns any profiles.

Directory Layout

For these examples, we'll work on a kind of Unix system with a csh shell. Other shell users or Windows users will need to adjust. We'll also use the J2SDK command-line tools. If you're using an Integrated Development Environment of some sort, please adjust accordingly.

We'll create a "home" directory for our profile ser vers with subdirectories to hold specific components like source code, jar files, and scripts. We'll call this home directory by an environment variable, PS_HOME (PS for Profile Server), so that scripts won't have to refer to things by relative paths:

% mkdir ps
% cd ps
% setenv PS_HOME `pwd`
% mkdir bin classes lib src

Source File

One of the easier parts is the source itself for the ‘ null ’ profile handler. Here it is:

import java.util.Collections;
import java.util.List;
import jpl.eda.profile.Profile;
import jpl.eda.profile.handlers.ProfileHandler;
import jpl.eda.xmlquery.XMLQuery;

public class NullHandler implements ProfileHandler {
  public List findProfiles(XMLQuery query) {
    return Collections.EMPTY_LIST;
  }
  public Profile get(String id) {
    return null;
  }
}

Note that for every query, the findProfiles method returns an empty list (meaning that no profiles matched), and that for any retrieval the get method returns null, meaning that the handler believes there's no such profile.

This class should be compiled into a file named $PS_HOME/src/NullHandler.java since it is a public class.

Note: Profile handler classes must be public and provide a no-arguments constructor. You should retrieve any initialization settings through the System Properties or by other means specific to your profile handler.

Compiling the Handler

Compiling this profile handler requires the following dependent components:

  • Profile Service . This defines the entire profile model, handler interfaces, servers, clients, and so forth.
  • Query Expression . This defines the XMLQuery and related classes.

Download the binary distributions of the above two packages and copy the jar file from each into the $PS_HOME/lib directory. Then you can compile the NullHandler.java file.

% ls
bin   classes   lib    src
% ls -l lib
total 244
-rw-r--r--  1 kelly  kelly   43879 28 Feb 07:05 edm-query-2.0.2.jar
-rw-r--r--  1 kelly  kelly  201453 28 Feb 07:01 grid-profile-3.0.2.jar
% javac -extdirs lib -d classes src/NullHandler.java
% ls -l classes
total 4
-rw-r--r--  1 kelly  kelly  511 28 Feb 07:07 NullHandler.class
% jar -cf lib/my-handler.jar -C classes NullHandler.class
% jar -tf lib/my-handler.jar
META-INF/
META-INF/MANIFEST.MF
NullHandler.class

We now have a new jar file, my-handler.jar which contains our ‘ null ’ profile handler, compiled and ready to go.

Starting an RMI Registry

Clients access profile servers with an open-ended set of network protocols. We currently have implementations for RMI and CORBA. For this tutorial, we'll use RMI, since it's enormously less complex. Clients of RMI systems first contact an RMI registry and look up a server object's network address. The registry maintains mappings from a server object's name to its network address. When servers start up, they register with the RMI registry so clients can later find them.

To start an RMI Registry, you'll need the following components:

Download each component's binary distribution, unpack each one , and take collect the jar files into the lib directory. The RMI Registry will also need the grid-profile jar file, which we've already got.

% ls -l $PS_HOME/lib
total 404
-rw-r--r--  1 kelly  kelly  149503 28 Feb 07:28 edm-commons-2.2.5.jar
-rw-r--r--  1 kelly  kelly   43879 28 Feb 07:05 edm-query-2.0.2.jar
-rw-r--r--  1 kelly  kelly  201453 28 Feb 07:01 grid-profile-3.0.2.jar
-rw-r--r--  1 kelly  kelly     796 28 Feb 07:07 my-handler.jar
-rw-r--r--  1 kelly  kelly    8055 28 Feb 07:28 rmi-registry-1.0.0.jar

Now all we need is a convenient script to start the RMI registry. We'll call it rmi-reg and stick it in the bin directory. Here's the rmi-reg script:

#!/bin/sh
exec java -Djava.ext.dirs=$PS_HOME/lib \
    gov.nasa.jpl.oodt.rmi.RMIRegistry

This script tells the Java virtual machine to find extension jars in the directory $PS_HOME/lib . It then says that the main class to execute is gov.nasa.jpl.oodt.rmi.RMIRegistry .

Go ahead and make this script executable and start the RMI Registry. In another window (with the appropriate setting of PS_HOME ), run $PS_HOME/bin/rmi-reg . You should see output similar to the following:

% chmod 755 $PS_HOME/bin/rmi-reg
% $PS_HOME/bin/rmi-reg
Mon Feb 28 07:30:13 CST 2005: no objects registered

The RMI Registry is now running. Every two minutes it will display an update of all registered objects. Naturally, we don't have any profile service running right now, so it will say no objects registered . Go ahead and ignore this window for now. It's time to start our profile server.

Starting the Profile Server

With our handler compiled and our RMI registry running, we're ready t o start our profile server. As said before, profile servers delegate to zero or more profile handlers to actually handle all incoming requests. You tell the profile server what handlers to instantiate by naming their classes in a system property. That property is called handlers , and its value is a comma-separated list of fully qualified class names, including the package name prefixes. Since our NullHandler is just in the default package, NullHandler is its fully-qualified class name.

Profile server processes require the following components in addition to the ones we've downloaded so far:

Copy these two other jars to the $PS_HOME/lib directory. You should now have seven jars there:

% ls -l $PS_HOME/lib
total 1580
-rw-r--r--  1 kelly  kelly   149503 28 Feb 07:28 edm-commons-2.2.5.jar
-rw-r--r--  1 kelly  kelly    43879 28 Feb 07:05 edm-query-2.0.2.jar
-rw-r--r--  1 kelly  kelly   201453 28 Feb 07:01 grid-profile-3.0.2.jar
-rw-r--r--  1 kelly  kelly  1144107 28 Feb 09:23 jena-1.6.1.jar
-rw-r--r--  1 kelly  kelly      796 28 Feb 07:07 my-handler.jar
-rw-r--r--  1 kelly  kelly     8055 28 Feb 07:28 rmi-registry-1.0.0.jar
-rw-r--r--  1 kelly  kelly    53978 28 Feb 09:20 xmlrpc-1.1.jar

Now, create a second shell script to make starting the profile server convenient and call it $PS_HOME/bin/ps . It should look like this:

#!/bin/sh
exec java -Djava.ext.dirs=$PS_HOME/lib \
    -Dhandlers=NullHandler \
    jpl.eda.ExecServer \
    jpl.eda.profile.rmi.ProfileServiceImpl \
    urn:eda:rmi:MyProfileService

Make the script executable and start the profile server:

% chmod 755 $PS_HOME/bin/ps
% $PS_HOME/bin/ps
Object context ready; delegating to: [jpl.eda.object.jndi.RMIContext@dec8b3]

The profile server will start, check its handlers property, and create an object of each class named by it. Then it'll register itself with the RMI registry and wait for requests to come in from profile clients.

What's in a Name?

The profile server registers itself using a name provided on the command-line, in this case, urn:eda:rmi:MyProfileService . Let's take apart the name and see how it works.

If you're familiar with web standards, you can see that the name is a Uniform Resource Name (URN), since it starts with urn: . The OODT Framework uses URNs to identify services and other objects. The eda: tells that the name is part of the Enterprise Data Architecture (EDA) namespace. (EDA was the name of a project related to OODT that was merged with OODT. For now, just always use eda: in your URNs.)

Next comes rmi: . This is a special flag for the OODT services that tells that we're using a name of an RMI-accessible object. The OODT framework will know to use an RMI registry to register the server.

Finally is MyProfileService . This is the actual name used in the RMI registry. You can call your profile server anything you want. For example, suppose you have three profile servers; one in the US, one in Canada, and one in Australia. You might name them:

  • urn:eda:rmi:US
  • urn:eda:rmi:Canada
  • urn:eda:rmi:Australia

Or you might prefer to use ISO country codes. Or you might name them according to the kinds of profiles they serve, such as urn:eda:rmi:BiomarkerMetadata or urn:eda:rmi:BusniessForecastMetadata .

The RMI registry will happily re-assign a name if one's already in use, so when deploying your own profile (and other) servers, be sure to give each one a unique name.

Querying the Profile Server

To query a profile server, you use the ProfileClient class. It provides methods to contact a named profile server, performing the lookup in the RMI registry, contacting the profile server, and passing in queries and profile retrievals. The ProfileClient class is also an executable class, making it perfect for testing a new profile server from the command-line.

Still, we'll make a script, called $PS_HOME/bin/pc (for "profile client") to execute it, though, to save from having to type hugely long Java command-lines:

#!/bin/sh
if [ $# -ne 1 ]; then
   echo "Usage: `basename $0` <query-expression>" 1>&2
   exit 1
fi
exec java -Djava.ext.dirs=$PS_HOME/lib \
     jpl.eda.profile.ProfileClient \
     urn:eda:rmi:MyProfileService \
     "$1"

Make this script executable and then run it:

% chmod 755 $PS_HOME/bin/pc
% $PS_HOME/bin/pc "temperature = 37"
Object context ready; delegating to: [jpl.eda.object.jndi.RMIContext@dec8b3]
[]

Although it may not look spetacular, this is a success! The two square brackets, [ ] , indicates the list of matching profiles to our query expression, temperature = 37 . In this case, there were no matches, which is exactly what we wanted.

Conclusion

The Null Profile Server made sure our development environment worked from end to end for creating, deploying, and testing a profile handler. Now you're ready to implement a real profile handler:

  • Instead of returning an empty list, create a Profile object and return it as a singleton list. See the API documentation for Profile as well as other articles for manipulating this class.
  • Analyze the methods of the XMLQuery class to determine the query passed in from the user. Use that information to synthesize the correct Profile object. See the API documentation for class XMLQuery for more information.
  • Connecting to an external data source (such as the local filesystem or a database), synthesize appropriate profiles in response to queries and profile retrieval with the get method.
FirstGov - Your First Click to the US Governmnet

+ Freedom of Information Act

+ NASA Privacy Statement, Disclaimer,

and Accessibility Certification


+ Freedom to Manage
NASA

Editor: Sean Kelly

NASA Official: Dan Crichton

Last Published: 07 July 2006

+ Contact NASA
spacer
spacer spacer spacer
spacer spacer spacer