Skip to topic | Skip to bottom
Grimoires
Grimoires.DesignStructure

Start of topic | Skip to actions

Design document for Grimoires registry

Needs updating

Overview

  • Internally, the registry adopts a message-passing metaphore and a component based approach. Soap messages are transformed by Axis into Java objects. Messages are handled by components we refer to as handlers. Handlers are typically designed to process messages of a same category, such as the messages of the UDDI publish interface, of the UDDI inquiry interface, or messages related to metadata. Such handlers in fact would correspond to the business logic implementing some ports of the wsdl interface of the registry. This has a number of benefits:
    • Ease of maintenance: code for a handler for a given interface will be well scoped.
    • Separate compilation and flexible deployment: we aim at being able to compile separately components, and possibly deploy only a subset of them in some specific configuration. For instance: we should be able to deploy just the uddi interfaces, or just the uddi and metadata interfaces. This obviously requires component code not to make reference to other component code!

  • Some OO patterns have been adopted: specifically, the visitor pattern is used to structure all messages and their associated handlers. Each message of a given category will implement a given interface, e.g. PublishMessage and PublishProcessable for messages of the UDDI publish interface. In particular, such messages will implement a method accept for the handler handling messages of such category. Handlers will be visitors offering a method process for each of messages in the interface.
    • Some default handlers are provided for each interface. In particular, a handler "not implemented" which will return an error for each message it is passed. When developing a new handler, it is therefore natural to subclass such a "not implemented" handler, which will ensure consistent error messages for all non implemented methods. This is far better that returning a null value since it becomes very hard to know where this value was generated.

  • We have adopted a message passing approach so that messages can be delegated to other components simply by passing them. Currently, our handling of messages is asymmetric (is this something we should revise?). A message is passed to a handler using the visitor pattern approach, i.e. by calling process on the handler, with the message as argument. However, the returned result (if any) is not passed as a message in the same way. Instead, results are stored using the setResult method (in AbstractMessage), and the input message is returned with its result field set.

  • Given this approach, when an error situation is reached in the business logic, say because an input is incorrect, we do not raise an exception in the handler, instead we said the error field, using the setError method (in AbstractMessage).

  • A source of inefficiency is copying objects (and in particular deep copies). We aim to avoid these by making sure that once an object is created by the axis container, we do not copy it again. When methods have to be added to these objects' classes, we subclass the classes generated by axis, and we need to let axis know that the class to be used when deserialing an object is the new one. (This is done by defining the entry for the data type in the config/deploy.wsdd file).

The structure explained

package comment
uk.ac.soton.ecs.grimoires the grimoires distribution
uk.ac.soton.ecs.grimoires.server the server side
uk.ac.soton.ecs.grimoires.server.impl implementation of all interfaces
uk.ac.soton.ecs.grimoires.server.impl.uddiv2 implementation of uddiv2 interfaces
uk.ac.soton.ecs.grimoires.server.impl.metadata implementation of metadata interfaces
uk.ac.soton.ecs.grimoires.server.impl.wsdl implementation of wsdl-related interface
uk.ac.soton.ecs.grimoires.server.impl.damls implementation of damls interfaces
uk.ac.soton.ecs.grimoires.server.impl.topic implementation of topics interfaces
uk.ac.soton.ecs.grimoires.server.store backend related matters
uk.ac.soton.ecs.grimoires.server.configuration configuration classes
uk.ac.soton.ecs.wstester an XML client tester

Each implementation XXX of an interface attempts to follow a same structure:

In uk.ac.soton.ecs.grimoires.server.impl. XXX comment
messages message definitions and associated visitors
datamodel data type definitions
edited name may be revised: wsdl2java generated and edited classes
handlers implementation of handlers
api implementation of APIs (currently server ties)

Saver, Loader and RDQLGenerator visitors

Grimoires uses the visitor pattern to save data objects to the RDF store, load data objects back from the store and generating RDQL queries from query data objects. Using this pattern means that we do not have to alter the data objects themselves, which are generated by Axis. Additionally, savers, loaders and query generators can be chosen to match the backend store. Currently this pattern is implemented for the metadata API implementations but the UDDIv2 APIs still use the old views design (where the data objects contain the load, save and generate RDQL methods).

The interfaces for the savers, loaders and RDQL generators are %JAVADOC{GRIM:uk.ac.soton.ecs.grimoires.server.store.Saver}%, %JAVADOC{GRIM:uk.ac.soton.ecs.grimoires.server.store.Loader}% and %JAVADOC{GRIM:uk.ac.soton.ecs.grimoires.server.rdql.RDQLGenerator}% respectively. Each has an base implementation in the same package called AbstractSaver?, AbstractLoader? and AbstractRDQLGenerator?. These throw a StoreException? (for save and load) or RDFException (for RDQL generation) reporting that the object given as parameter cannot be saved/loaded/used to generate RDQL.

The Abstract classes should be overridden in the handlers of each API. For example, there is a MetadataSaver?, MetadataLoader? and MetadataRDQLGenerator?. These override the save, load and generate methods for each type object to be saved, loaded or used in generation.

Using the save and load methods is fairly straightforward. To save, call saveToStore on a saver passing the Model to store to and the object to store. To load, call loadFromStore with an empty (default constructed) object to be initialised, the Model to load from and the Resource identifying the stored object details.

Generating RDQL is only slightly more complex. Each method for generating RDQL queries, named generateRdqlQuery, takes as arguments the object to generate the query from and a QueryDetails? object. QueryDetails? stores the list of statements, constraints, namespaces etc. that make up the query and is manipulated by the generate method. The client would usually create a new QueryDetails? using the default constructor when generating a query. The generate method returns a GenerationResults? object that contains the QueryDetails? and the name of the variable that is used to identify the object to be returned by the query. The GenerationResults? object can be processed using uk.ac..grimoires.server.impl.Jena.processQuery passing the Model to query, the GenerationResults? and the variable name that the client is interested in.

Suggested Improvements

Component-Independent Metadata

The same metadata protocol/API could be used to annotate many different types of entities without extension, by making the API more general. For example, metadata may be attached to UDDI Business Service, WSDL Message Part, Metadata (published by someone else), Virtual Topic, OWL-S Service etc. The entity to which metadata is to be attached/updated/removed could be identified by a (type, key) tuple. The type would be used to lookup the resolver class which would find the resource representing the entity with the given key. Keys could be simple or complex, as long as they are unique and interpretable by some resolver, e.g. a UUID for a Business Service, the URI namespace and local name of a message plus the local name of a message part for a WSDL message part.

Component-Independent Notifications

The independence of components from the notification component/handler could work by each component handler/API-implementation allowing the registration of listener objects. These listeners would receive the XML SOAP-Response from an operation call. A notification listener would be configured to listen on those operations for which notifications should be sent and then pass the XML on to the notification service to publish. This would maintain independence of notification component from the others.

Change-Logged File Storage

We would like to be able to store registry to file instead of database depending on configuration. Rather than regular automatic saving, every change could be saved to a change log (as well as being made to the memory model). The previous change log would be incorporated into the main registry file on startup of the service. We already effectively record change logs for the concurrency support.

Security

Once we understand this better, text to appear here.

Changes compared to latest mygrid views

  • package name changed to grimoires and I started with an empty source base! Files are copied one by one from the views repository if and when needed.

  • The views service was designed so that its business logic could be deployable in a number of containers e.g. web service and ejb. Therefore, it had adopted interfaces to define its datamodel: each data structure was defined by an interface of accessors and mutators (essentially a JavaBean). While this was a convenient/elegant way of programming a business logic, it made the hosting in a container terribly difficult. Unless we were ready to program serialisation/deserialisation ourselves, it prevented us from using tools such as wsdl2java generating the necessary stub and ties. Consequently, interfaces for data models have been abandonned.
    • Note that with Generics in java1.5, interfaces could be useful again, since a class generated automatically by wsdl2java, could be shown to implement an interface. However, without generics, this is not possible.
    • A consequence is that we may no longer be able to share the same data model for client and server, but this has only a consequence for implementers and not for users.
    • Another consequence though is that we may no longer be able to use the standalone mode for the client: this will have to be investigated!

  • Datamodel is generated automatically from WSDL file. This implies a few changes in the naming convention, and a more regular handling of sequences (with the types defined in the wsdl file). A criticism by Phil Lord was the client interface was not always compliant with Java style, and I think this is now addressed. In fact, this is now the standard way of referrring to xsd types from Java, since axis wsdl2java is jax-rpc compliant.
    • Even though data model is generated by axis, we still edit these files so that they implement the visitor pattern. Hence, they are a package "edited". Consequently, we should avoid regenerating and overwriting these files. Note that the wsdl2java target in ant generates code in another directory for this specific reason!

  • Configuration is now dynamically passed to each component instead of refering to static variable ServerConfiguration. A number of reasons justify this change:
    • handlers may be given different configurations.
    • the ServerConfiguration class referred to many different components, and was preventing separate compilation.

  • To ensure proper separate compilation, currently, there is no client and no common package, just server! Testing is done by sending raw XML (see tester ant target). When we reintroduce the client package, we will decide if a common package is necessary.

-- LucMoreau - 16 Aug 2004

-- VictorTan? - 07 Dec 2004
to top


You are here: Grimoires > DesignDocument > DesignStructure

to top

Copyright 2004 by the University of Southampton