|
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
---|---|
ExecutorLog | A log for an Executor. |
HTMLViewer | The Nesstar HTMLViewer |
NewObjListener | A listener for creation of new objects. |
Type | A Type, for example String or Integer, used to indicate |
Class Summary | |
---|---|
AType | A Type, for example String or Integer, used to indicate |
BasicExecutorLog | A simple implementation of ExecutorLog. |
BasicObj | A basic remote object, useful as a default mapping object. |
Bookmark | A description in both human and machine understandable form of an operation. |
BooleanType | A Boolean. |
Catalog | A Catalog, a container for searchable metadata and processable data. |
CatalogHome | An API class for the CatalogHome Code automatically generated from ARGO/UML |
CatalogTest | A Test class for Catalog.java Automatically generated from ARGO/UML |
CatalogTestBase | A Base Test class for Catalog.java Automatically generated from ARGO/UML |
CollectionType | A Collection. |
Dataset | A dataset, whose metadata is defined according to the DDI standard and whose data is stored in one or more NSDSTAT files. |
DatasetEx | An extension of Dataset, adds a few convenience methods. |
DatasetHome | An API class for the DatasetHome Code automatically generated from ARGO/UML |
DatasetTest | A Test class for Dataset.java Automatically generated from ARGO/UML |
DatasetTestBase | A Base Test class for Dataset.java Automatically generated from ARGO/UML |
DBSearchEx | Perform a search on a database. |
DoubleType | A double precision float number. |
Executor | A manager for the execution of an URL. |
Explore | Explore a dataset. |
ExploreCube | |
ExploreCubeOp | |
ExploreEx | The state that has to be preserved to rebuild an Explorer Window. |
Explorer | A rapresentation of the Explorer, used by the Nesstar Explorer |
ExplorerHome | An API class for the ExplorerHome Code automatically generated from ARGO/UML |
ExplorerOp | An Explorer operation. |
ExplorerTest | A Test class for Explorer.java Automatically generated from ARGO/UML |
ExplorerTestBase | A Base Test class for Explorer.java Automatically generated from ARGO/UML |
FileType | A File. |
FloatType | A single precision floating number. |
IntegerType | An Integer. |
Learn | Acquire new information by reading the contents of the given URL. |
LearnOp | Acquire new information by applying an operation on a remote object |
Method | A Method Code automatically generated from APIMaker on Mon Dec 18 14:33:33 GMT+00:00 2000 |
MethodInvocation | A remote method invocation. |
MIMEObject | A MIME object (actually a MIME text object such as text/html). |
NetDB | A repository and cache for nesstar_rdf objects information from the internet. |
ObjectType | A generic Object. |
Operation | A generic operation. |
Parameters | A set of method parameters. |
PasswordType | A Password. |
PathIterator | An iterator on a path. |
Protocol | Client/Server protocol. |
ProtocolTest | |
Search | Perform a search in one or more catalogs. |
SearchEx | Perform a search. |
Server | A server used to publish data and metadata. |
ServerEx | A server used to publish data and metadata. |
ServerHome | An API class for the ServerHome Code automatically generated from ARGO/UML |
ServerNewObjListener | A listener for creation of new objects. |
ServerTest | A Test class for Server.java Automatically generated from ARGO/UML |
ServerTestBase | A Base Test class for Server.java Automatically generated from ARGO/UML |
StringType | A String. |
TestExploreCubeOp | |
TestTrendOp | |
Trend | |
TrendOp | |
URLType | A URL. |
User | A User. |
Version | Description of the Class |
VoidType | A void (null) result. |
Exception Summary | |
---|---|
AccessException | The exception that is returned when the user hasn't the right to execute an operation. |
TargetException | The exception that is returned when the user hasn't the right to execute an operation. |
The core classes of the Nesstar API.
If you are a Java programmers interested in developing client-side applications (Web based, Java applications, etc.) for the Nesstar system this document is the right place to start.
It describes the Nesstar API, an object-oriented interface to Nesstar that hides most of the complexity of the Nesstar HTTP/RDF network protocol.
A fuller description of the Nesstar Network Architecture can be found at http://www.nesstar.org/sdk/.
Check in particular:
As a set of Java objects. The API tries to mimic as closely as possible the way local Java objects are accessed hiding the details of the Nesstar network protocol used to access the remote Nesstar objects.
The API provides an object-oriented interface to Nesstar objects that supports:
Nesstar is a distributed object-oriented system built on top of WWW technology.
Nesstar objects are a particular kind of Web resource. Just as any other Web resource they "live" at a given URL and can be accessed by entering their URL in a Web browser.
When you access the URL of a Nesstar object what is returned is a description of the current state of the object, that's to say the value of the object properties at the time the access was performed. The information regarding the object state is coded in XML/RDF (the XML serialisation of RDF).
There are currently a number of Nesstar servers on the Net, each one of them containing thousands of Nesstar objects. To show what a Nesstar object looks like we will pick one object from the demonstration Nesstar server at http://nesstar.essex.ac.uk.
The object we are interested has the URL: http://nesstar.essex.ac.uk/obj/cServer/DEMO. If you click on this link your browser, if XML compatible, will display a short XML document that should look more or less like this:
<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:s="http://www.w3.org/TR/1999/PR-rdf-schema-19990303#" xmlns:n="http://www.nesstar.org/rdf/"
xmlns:on="http://www.nesstar.org/rdf/common/" xmlns:op="http://www.nesstar.org/rdf/common/Server#"
xmlns:ncp="http://www.nesstar.org/rdf/Server#">
<on:Server r:about="http://nesstar.essex.ac.uk:80/obj/cServer/Demo">
<s:label>Demo</s:label>
<s:comment>The Demo Server.</s:comment>
<op:homes r:resource="http://nesstar.essex.ac.uk:80/obj/cServer/Demo@homes"
/>
<op:securePort>443</op:securePort>
<ncp:debug>on</ncp:debug>
<ncp:port>80</ncp:port>
<ncp:revision>Fri Mar 14 16:47:14 GMT 2003</ncp:revision>
<ncp:version>2.16</ncp:version>
<ncp:services r:resource="http://nesstar.essex.ac.uk:80/obj/cServer/Demo@services"
/>
<ncp:catalogs r:resource="http://nesstar.essex.ac.uk:80/obj/cServer/Demo@catalogs"
/>
</on:Server>
</r:RDF>
The top level element of the returned XML document is <http://www.w3.org/1999/02/22-rdf-syntax-ns#RDF/> (in the display it appears as <r:RDF/>, with r being the XML namespace identified by the URL http://www.w3.org/1999/02/22-rdf-syntax-ns#). This element states that the document is coded according to the RDF standard.
Inside there is a <http://www.nesstar.org/rdf/common/Server/> (<on:Server/>) element that is the one the contains the actual description of the object we are accessing.
The name of the element indicates the type or class of the returned object. It tells us that we are looking at an element of type <http://www.nesstar.org/rdf/common/Server/> (from now on we will refer to it as just Server for short).
This is the first important thing to know about Nesstar objects. Just as Java objects, Nesstar objects are typed. They are always instances of a specific class that corresponds to a specific concept.
A Nesstar class is just another Nesstar object (just like a Java Class is also a Java object). As any Nesstar object its description can be found at its URL. If you point your browser to http://www.nesstar.org/rdf/common/Server you will find a description of the Server class plus a set of other objects that describe the properties and methods (the operations) of the objects that are instances of the class. |
Nesstar objects are normally hosted in specialised Nesstar servers but, if they have properties but no methods, they can also be stored in files and published using a normal Web server. |
Most Nesstar classes represent statistical concepts such as datafiles, variables, groups of variables, etc. but there are also classes, just like Server, that correspond to non-statistical concepts.
Server objects are actually a bit special and well worth knowing about. They play in Nesstar servers a role similar to that of a home page in a Web server. A Web home page contains key information about a Web site and it is the starting point from which, usually, all other Web pages on that particular site can be reached. Similarly Server objects, of which there is only one per Nesstar server, contains key information regarding the server. They are also the starting point from which it is possible to reach any other object stored in the server.
In addition to its type an object has, usually, other properties as well. Each property is coded as an XML element inside the object class element.
For example in our Server object there are a couple of properties that state the version and revision date of the Nesstar server:
<ncp:version>2.16</ncp:version>
<ncp:revision>Fri Mar 14 16:47:14 GMT 2003</ncp:revision>
Another couple of interesting properties are label and comment. They respectively contain the human readable name and a description of the object:
<s:label>Demo</s:label>
<s:comment>The Demo Server.</s:comment>
While version and revision properties are specific to Server objects label and comment are generic properties. All Nesstar objects should have a label and, whenever possible, they should also have a comment.
As we have seen the way Nesstar objects are published on the Internet is very simple: they are XML documents accessible through an HTTP GET call. Therefore they can be easily accessed and processed using standard XML and HTTP libraries that are nowadays available for any programming language.
As a Java programmer you have an even easier option. You can use the API to access Nesstar objects through an object oriented interface.
The API makes Nesstar objects easily accessible by providing, for every type of object, a corresponding 'proxy' class. All accesses to remote Nesstar objects take place through the proxy classes. The developer is therefore isolated from all the XML/HTTP protocol low level details.
So, for example, Nesstar Server objects are mapped by the API to instances of nesstar.api.common.Server
objects.
Here is an example of how we can create and use a Server proxy object using the API:
// Initialise the API Init.testInit();
// The URL of a Server object URL serverURL = new URL("http://nesstar.essex.ac.uk:80/obj/cServer/Demo");
// Retrieve the object nesstar.api.common.Server server = (nesstar.api.common.Server) Protocol.getDB().retrieve(serverURL);
// Read the object label/name // Note: out() is equivalent to System.out.println() String label = server.getLabel(); out("label=" + label);
// Read the server version String version = server.getVersion(); out("version=" + version);
The output of the program should be:
label=Demo version=2.16
The example program starts by initialising the API. To simplify this process
Init
contains a set of predefined init methods.
As part of the initialisation the API creates an in-memory default proxy object
cache. This is used to store the proxies for the Nesstar objects. The default
object cache is an instance of NetDB
and is accessed with
Protocol.getDB()
(Protocol
is one of the
API's central classes. It provides access to the basic API settings and components).
Just like any other Web resource a Nesstar object can be easily accessed through its URL.
In the example a Server object is retrieved by URL through the object cache
using RDFDB.retrieve(java.net.URL)
.
RDFDB.retrieve(java.net.URL)
first checks if the object is already cached.
If this is not the case it performs an HTTP GET operation to the object URL.
If a correct RDF description of the required object is found at the provided
URL the corresponding proxy instance is automatically created, cached and then
returned to the calling application.
If you know in advance the class of the object that you want to retrieve you can also use the retrieve method of the proxy class and avoid an explicit class cast:
Server server = Server.retrieve(serverURL);
.
One thing to remember is that proxy objects are not immediatly synchronized with the remote objects they represents. If a property of a remote object changes, or if the remote object disappears completely, this is not immediatly reflected in its proxies.
Proxies do become 'stale' though, but only after a while. If they are 'stale',
the next time that they are accessed with a getX operation they will automatically
refresh their contents by reloading their RDF description from the Net. By default
a proxy object becomes stale if it has not been explicitly refreshed for 1 hour.
You can change the defaul timeout calling Protocol.setTimeoutInSecs(long)
.
It is also possible to explicitly make all the objects in a cache 'stale' (check
RDFDB.markAllAsStale()
and RDFDB.markAsStale(String)
.
For example to make stale all the objects in the default cache:
Protocol.getDB().markAllAsStale();
Object proxies reload themselves automatically in 2 cases, when they are stale and when they are 'partial' and a property that is set to null is being requested. When an operation that returns a high number of objects is performed, e.g. a query, the Nesstar servers have the option of returning 'partial objects'. Say for example that you are performing a query that will return 1000 objects of type Study and say that a Study properties are either numerous or long or both (say for example that it has an 'abstract' property whose value is 10K bytes long). The server can decide to return only the basic properties of the requested objects (URL, type, label and comment) and leave out the rest. Now say that you are trying to get the value of the abstract property of a Study by calling a getAbstract() method. The proxy object will notice that the value of the abstract property is currently null, as it was not returned from the server. It will then reload itself (when a server is asked to return a single object it will always return all its properties) before returning the value of the property . |
To reload a proxy immediately, without waiting for a timeout, you can use the
RDFObject.reload()
method.
If you already have the object you can ask it to reload itself:
// Reload the server object to refresh its properties server.reload()
Otherwise you can ask the cache to load it in:
// Reload the object nesstar.api.common.Server server = (nesstar.api.common.Server) Protocol.getDB().reload(serverURL);
Once an application has got the proxy corresponding to the desired object it
can access its properties via normal getX accessor methods such as RDFObject.getLabel()
or Server.getVersion()
.
All proxies classes implement the RDFObj
interface and
extend RDFObject
. A couple of useful methods that all proxies
share are:
RDFObj.getID()
that returns the URL of the remote object
that the proxy object represents.RDFObj.getDB()
that returns the object cache where the
proxy is stored (normally the default cache).Properties do not have to be Strings. They can also be Integers, Floats, Doubles or Booleans, e.g.:
// Read the HTTPS port that the server is listening on (if any)
Integer securePort = server.getSecurePort();
out("HTTPS port=" + securePort);
This program should display:
HTTPS port=443
Note that the API returns an Integer, not an int. The API always returns objects rather than literals. This makes it easy to detect when a property has no value. In our example, if the server is not configured to accept HTTPS connection the value of the securePort property would be null. In your code you should always check if a property value is null and treat it accordingly.
Till now we have only seen examples of properties, such as label or version, that state a particular attribute of an object.
As you would expect there is also another kind of properties: those who are used to represent relationships among objects.
These properties have as their value either another object (1 to 1 relationship) or a List of objects (1 to n relationship).
Server
objects have both 1-1 (e.g. nesstar.api.Server#getStatEngine
that returns an object of type nesstar.api.NSDStatEngine
) and 1-N relationships
(e.g. Server.getCatalogs()
that returns a List
of Catalog
objects) as we can see in the following example:
// Traverse the 1-1 relationship from Server to NSDStatEngine NSDStatEngine engine = server.getStatEngine(); // Traverse the 1-N relationship from Server to Catalogs List catalogs = server.getCatalogs(); Iterator c = catalogs.iterator(); while (c.hasNext()) { nesstar.api.faster.Catalog catalog = (nesstar.api.faster.Catalog)c.next(); String catalogLabel = catalog.getLabel(); }
It is therefore very simple, starting from a known object, to access all related objects. Indeed starting from the a Server object you can easily access all the objects stored in a given server. These accessor functions will automatically create proxies for the objects they link to if they are not already in the default DB.
Properties are not all there is to Nesstar Objects. Again: think of the Web. The Web is not composed only by static entities, it also offers dynamic services. We can use the Web to perform operations such as buying a flight ticket or searching a library catalogue. Similarly Nesstar objects can have methods/operations.
You can perform method calls on a remote object by using the corresponding operation on the proxy object.
For example Server objects have a Server.GetReport()
operation
that will return an HTML document containing a technical report on the current
server activity. The operation can be invoked as:
// Apply a method to get a technical report on the current state of
the server
String report = server.GetReport(null);
out("Report:\n" + report);
The output of the program will be something like:
<pre>Report:
Started On=Tue Apr 15 08:06:32 BST 2003
Started Ops=6062
Completed Ops=6061
MaxConcurrent Ops=2
Threads: .....
Now, the GetReport doesn't need any parameter so why do we see a null in the parameter list?
To understand that we have to take a step back and consider that remote operations are quite different from local ones. For a start they can take quite longer (as you have to add the time needed to establish a connection and transfer the parameters and the operation result on the network) so an application might need to provide some feedback to the user on the development of the operation (think of the "Connecting/Downloading" messages displayed by WWW browsers) as well as allowing him to cancel the ongoing operation (think of the Stop button in WWW browsers). They can also fail for reasons totally unrelated to the operation itself (e.g. a network failure). Finally remote operation are executed on a remote server that is probably controlled by someone different from the person who owns the client that is asking for the operation to be performed. For this reason the server will probably enforce some kind of access control before allowing an operation to be carried out. The client might be required to provide some proof of identity, such as an user id and password, or maybe asked to pay a certain amount of money
For all these reasons remote calls need more 'management' than plain local
calls. The API provides an interface, ExecutorLog
that can
be used to provide such management. When you execute a remote operation the
execution is performed by an instance of Executor
. The Executor
is fed with a BasicExecutorLog
object (that implements the
ExecutorLog
interface) and will call this object to notify
it of any major event that it is taking place while the operation execute (e.g.
the operation failed or we are being challenged to provide some authentication
information to the server).
So, if you want to control the execution of a call, you can create your own
class that extends BasicExecutorLog
and provide an instance
of it as the last parameter of the call. If on the contrary you cannot be bothered
to explicitly manage the operation you can simply pass a null.
You might wonder how the API actually performs the operation on the remote object. To understand it again think of how the Web works: user interacts with Web applications by filling in a form and clicking on a Submit button. The Web browser then code this information and forwards it to the remote server by using the HTML Forms submit protocol. This protocol is very well proven and it is being supported by Web browser and Web applications for a decade. The Nesstar API uses the same protocol to perform remote calls. It maps object method calls to HTML forms calls.
This approach has a number of advantages: method calls can be performed using a normal web browser (and in general using programs written in any language that comes with an HTTP library) and it is easy to determine an URL that corresponds to the operation. The URL can then be used by an application to store and replay the operation.
For each operation the API provides a corresponding URL. The application can store the operation URL so that the operation can be replayed at a later time.
To see how it works let's look at another way of executing the GetReport operation.
This time we start by getting a Bookmark
representing the
operation and then we execute the bookmark:
// Get a bookmark corresponding to an operation
Bookmark reportOp = server.GetReport();
out("The URL of the report operation is:\n" + reportOp.getURL());
out("The human readable description of the report operation is:\n"
+ reportOp.getDescription());
// Execute the operation
MIMEObject result = reportOp.execute();
out("Report:\n" + result.getContent());
The output of the program will be something like:
The URL of the report operation is:
http://nesstar.essex.ac.uk:80/obj/cServer/Demo?http%3A%2F%2Fwww.nesstar.org%2Frdf%2Fmethod=http%3A%2F%2Fwww.nesstar.org%2Frdf%2FServer%2FGetReport
The human readable description of the report operation is:
GetReport
Report:
<pre>Report:
Started On=Tue Apr 15 08:06:32 BST 2003
...
The URL of the operation is just a normal Web URL. You can execute the same operation directly in your browser by clicking on it:
In order to convert the Nesstar objects to the appropriate proxy objects the cache consults an internal list of mappings. A default set of mappings is created when the API is initialised. The default settings are set in the addDefaultMappings method of nesstar/client/InitMappings.java
In some cases you might want to map Nesstar objects to your own custom proxy classes. Say for example that you want to display your objects in a tree view using a different icon for each type. You might define an interface that captures these requirements as follows:
interface TreeViewObj { Icon getIcon(); Collection getChildren(); }
You can then create new classes that extend the proxy classes and implement the new interface.
For this to work you have to tell the object cache to use your new proxy classes rather then the standard ones. Say for example if you have defined a new mypackage.Server proxy class, you can register it with:
Protocol.getDB().addMapping("http://www.nesstar.org/rdf/Server","mypackage.Server");
.
What this line says is: map any object of type Server to my custom proxy class.
Remember that the mapping has to be in place before you load any object in the DB.
Whenever a client tries to access a remote object or perform on it some operation the server that manages the object will check if the user that the client is operating on behalf of has the right to access the object or perform the operation. If the user is authorised the operation is performed and the result is returned to the client. If the user is not authorised the API will return an exception.
There is also a third case: the server might not know yet if the user is authorised or not. Say for example that the requested operation can be carried out only by the server administrator. If the user has not logged in yet the server doesn't know his identity and therefore cannot decide if the user can be authorised to carry out the required operation. In this case the server will return a challenge, that's to say an HTML form that the user will have to fill in to provide more information. The most common challenge is a login form but other challenges are possible. An user might for example be asked to agree to some condition or to pay some money.
If any time it performs an API operation the client application had to check if a challenge had been returned and perform some appropriate action the application code would become extremely complex. Luckily this is not needed. Any API operation always returns either a result or throws an exception if something went wrong (and this include the case that the user was not authorised to perform the operation).
Challenges are dealt with separately. The application provides, at setup time,
the API with a class that implements the HTMLViewer
interface.
Every time a challenge is received the API will create an instance of this class
and use the HTMLViewer.setPage(URL)
or HTMLViewer.setPage(MIMEObject)
to pass it the challenge for display. A standalone Java application might use
this mechanism to display the challenge in an embedded HTML browser or pass
it to an external browser. An example of this kind of setup can be seen in Init.testInit()
.
There are cases when more than one Nesstar application execute in the same Java VM, and therefore share the same Nesstar API, and/or when one Nesstar application operates on behalf of different users. An example of the first case is the Nesstar Server that contains many clients (object browser, study deployer, etc) all running in the same VM. An example of the second case is a web client such as the Nesstar WebView that can serve many concurrent web users.
Multi-user applications face two additional problems:
User identities are represented in the API by Protocol
objects. Multi-user applications need to create a separate Protocol object for each user and make sure that whenever they execute an operation on behalf of that user the API uses the correct Protocol object.
Protocols are created with Protocol.newProtocol()
and are associated with threads. Newly created protocols are automatically associated with the thread on which they are created. Additional threads can be associated with a given protocol by executing Protocol.setAsCurrent()
. Once a Protocol has been associated with a thread, all API operations executed thereafter on that thread will operate under the same user identity.
A good example of a Nesstar multi-user application is Nesstar WebView. When WebView receives a request from an user browser for the first time it will create a corresponding HTTPSession object and associate to it a newly created Protocol
object (e.g. using HttpSession.html.setAttribute(..)). At the beginning of the thread(s) that will be used to service the user request WebView retrieves the Protocol object associated with the user session and sets it as the current Protocol using Protocol.setAsCurrent()
.
Now to the second problem. As we have seen in the previous section an application need to provide the API with HTMLViewers that are used to display security challenges. In the case of a multi user application the HTMLViewers need to be correctly initialised to return the challenge to the correct user. For example a web client will need to initialise its HTMLViewers so that the challenge is sent back to the correct HTTP Response object.
Web applications need to customise other aspects as well. If a challenge takes place and is send to the user the web application cannot do anything else and is interrupted. Once the user has completed the challenge sequence there must be a way for the server to redirect the user browser to the web application so that the original user operation can be reapplied. This can be done by passing additional parameters to the API.
API calls are controlled by instances of classes that implement the ExecutorLog
interface. By default the API uses instances of BasicExecutorLog
but this can be changed using Protocol.setExecutorLog(BasicExecutorLog)
.
The logic needed to drive API calls for Web application is in nesstar.server.WebExecutor.
A Web client should therefore initialise the protocol, at the beginning of each thread that serves an user request, as follows:
WebHTMLViewer viewer = new WebHTMLViewer(response,...);
Protocol.setExecutorLog(new WebExecutorLog(request, response, viewer));
where WebHTMLViewer is an application specific viewer.
Some of the main things to keep in mind about Nesstar objects:
Properties are attributes of an object, there value can be either:
Methods are operation that can be applied to an object, they can take 0 to N parameters. They also have an unique URL that can be used to store and replay them.
The API supports (contains proxy classes) for the following object models:
Model |
Packages |
---|---|
Nesstar Servers 1.1.X object
model |
nesstar.api |
Nesstar Servers 2.X object
model |
nesstar.api.common and nesstar.api.faster |
Health Canada model | nesstar.api.hc |
EU Cosmos
project object
model (described in the Cosmos Architecture Document) |
nesstar.api.cosmos |
EU Madiera project model | nesstar.api.madiera |
A model is composed by one of more packages of Nesstar classes. A model defines all the classes needed for a particular Nesstar application. Classes, packages and models are formally specified in UML class diagrams.
The API proxy classes (as well as the RDF description of the classes, the server skeletons, etc.) are automatically generated from the UML class diagrams.
|
Nesstar SDK | ||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |