Protege 5 Development Environment

From Protege Wiki
Jump to: navigation, search

Introduction

The Protege 5 client server allows multiple Protege 5 clients (such as the desktop application) to browse and edit concurrently an ontology stored on a Protege 5 server.

The Protege 5 client server works in a way similar to SVN (update, commit, resolve conflicts). The conflict resolution mechanism is pluggable. You can read more about the client-server implementation (as a generic OWL-API server) in this paper. Here is the first of several videos that I am going to make to demonstrate server features:

I have also created a new page Protege Server design to explain how the Protege Server works for the Protege developers.

Status

We are working on an alpha release. Most of the things that would block an alpha release are relatively easy to do. Here are some things that need doing:

  • Figure out how to setup the Protege server as windows service. The startup scripts are now working on linux and on os x.
  • Develop a security policy for server access. We have a policy mechanism but it is not quite ready yet.
  • Don't expose passwords as plaintext. We can live with this for a bit and eventually use the fix in Protege 3.
  • Branching. This shouldn't be too difficult and we plan to permit branches to go across server boundaries (e.g. git-like).
  • Update backwards to a previous revision. The underlying server implementation now supports this but it has not yet been exposed.

Many things already work including

  • Basic Client-Server interaction
  • Conflict management
  • Authentication (password is sent as plaintext)
  • Firewall compatibility
  • Extended sessions where a user logs out with uncommitted changes and commits them in a later session

Setting Up the Protege 5 Server Development Environment

Prerequisites

  • Java 6 or above. We test this with Oracles java more but openjdk should work.
  • Maven 2.
  • ant is nice as is some useful development environment such as Eclipse or IntelliJ.

Install and Run From Svn

First checkout the development tree

     svn checkout https://smi-protege.stanford.edu/repos/protege/protege4/libraries/org.protege.owl.server/trunk org.protege.owl.server
     cd org.protege.owl.server

To build the server and run the unit and integration tests type:

    mvn verify

If you want to do this without running the tests type:

   mvn verify -DskipTests

Note mvn package will build the main artifact target/org.protege.owl.server-*.jar. In addition, mvn verify will build a working server in the target/server/server-distribution directory. This working server is needed for the integration tests but is made even if the tests are not run.

In addition to the maven lifecycle, this project has an ant build file to add some scripts that are not naturally part of the maven build lifecycle. The ant targets are

  • usage which will give a complete listing of the ant targets with some additional documentation.
  • run which will run the server, assuming that mvn verify has already been run. This server will listen for client requests on port 5100.
  • debug which will run the server as above but will allow debugging by waiting for a debugger to connect on port 8100. I believe that most reasonable ide's will have a facility for debugging in this manner and the eclipse capability can be configured with the menu Debug→Debug Configurations→Remote Java Application.
  • install which will install the Protege server library into the copy of a Protege distribution pointed to by the PROTEGE_HOME environment variable. This target assumes that maven has been previously run with a lifecycle goal of package or better (e.g., verify works). In order for this to be useful, you will also need to install the protege client. The client installation is described below. Information about the PROTEGE_HOME environment variable and the Protege build scripts can be found here.

The server that is started in this way is preconfigured with the following usernames and passwords:

fergerson ncbo
redmond bicycle
vendetti protege
guest guest


After installing a copy of the server library into PROTEGE_HOME, you may want to install the Protege client so that you can use Protege to connect to the server. To do this first checkout the client code:

        svn checkout https://smi-protege.stanford.edu/repos/protege/protege4/plugins/org.protege.editor.owl.client/trunk org.protege.editor.owl.client

Then you can compile and install it as follows:

       cd org.protege.editor.owl.client
       ant install

Setting up Eclipse

To configure the org.protege.owl.server project follow the following steps:

  1. first check the project out from svn (e.g., svn checkout https://smi-protege.stanford.edu/repos/protege/protege4/libraries/org.protege.owl.server/trunk org.protege.owl.server). This can be done using the eclipse tools but don't worry about how the project gets configured. Then, after making sure that the META-INF/MANIFEST.MF file has not been modified when eclipse checked out the org.protege.owl.server.
  2. make the maven call mvn eclipse:clean eclipse:eclipse.
  3. in eclipse either refresh the org.protege.owl.server project, if it is already visible there, or import the project using the File→Import→Existing Projects Into Workspace menu.


This has changed and will be updated shortly.


To set up eclipse,

  1. run "ant install". This step ensures that the built sources will be included in the org.protege.owl.server project.
  2. unzip the ide-eclipse.zip file.
  3. start eclipse using protege.server as the workspace.
  4. import the projects (File -> Import -> General -> Existing Projects Into Workspace).

The next part doesn't work yet but should be coming soon. This eclipse workspace will come with a couple of runnables:

  • Client starts the Protege OWL Client.
  • Server starts the Protege OWL Sever
  • ConnectToAntServer connects to the "ant debug.server" script for debugging.

Programatic access to the server

Some of the key classes used to access the OWL server are:

  • the Client which provides a low level api for server access. A Client object can also be used by classes such as the ClientUtilities to provide easy higher level operations such as uploading, downloading and updating ontologies.
  • the VersionedOntologyDocument is an object representing an open ontology corresponding to a server document at a particular document revision. An instantiation of the Client and VersionedOntologyDocument are sufficient to do many operations on a checked out ontology including update, commit and save.

Connecting to the server programatically

Connecting to the Protege server involves two steps, authentication and connection. Both the authentication protocol and the connection protocol are fully pluggable on the server, so the exact method of connecting to the server depends on how the server is configured. However currently we only support one authentication mechanism, a very simple username/password mechanism, and two connection protocols, the rmi protocol for accessing the server remotely and the local protocol for accessing a server running on the same jvm.

Accessing the server through rmi

Accessing the server with standard authentication and rmi can be done with the following steps:

        String host = "171.65.32.14";
        int rmiPort = 4875;
        AuthToken tim = RMILoginUtility.login(host, rmiPort, "redmond", "troglodyte");
        RMIClient client = new RMIClient(tim, host, rmiPort);

The first step authenticates the user "redmond" on to a server running on the same machine but in a different process. This authentication step results in a AuthToken object (tim) that can then be used to connect to the server. The result of the above steps is an object that implements the Client interface.

Accessing the server from the same jvm

The best way to access the server when running on the same jvm is to use a local transport. This transport bypasses all network protocols such as rmi and makes a direct connection to the server through java function calls. The manner in which the local transport object is obtained depends on how the server is started. The normal case will be the standard Protege server installation where the code accessing the server is run from a plugin. In this case the LocalTransport object can be obtained from OSGi declarative services. An example of this approach can be found here. This example can be run by

  • checking out the project from the svn location.
  • copying the local.properties.template to local.properties and changing the server.home to the appropriate location of the Protege server.
  • running ant install to install the plugin to the Protege server plugin directory.
  • (re)starting the Protege server so that it will pick up the new plugin.

To obtain the LocalTransport object through declarative services, create a server component declaration like this one:

<?xml version="1.0"?>
<scr:component name="org.protege.owl.server.example.component" 
               immediate="true"
			   xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
	<implementation class="org.protege.owl.server.example.EntryImpl"/>
	<service>
		<provide interface="org.protege.owl.server.example.Entry"/>
	</service>
	<reference name="LOCALTRANSPORT"
	    interface="org.protege.owl.server.connect.local.LocalTransport"
	    bind="initialise"
	    cardinality="1..1"/>
</scr:component>

This declaration tells OSGi declarative services that if it sees a new LocalTransport service then it should instantiate an EntryImpl class and send the new LocalTransport to the EntryImpl's initialise method.

Once the LocalTransport object has been obtained, the client can easily be obtained after authenticating as follows:

        AuthToken token = Authenticator.localLogin(transport, "redmond", "troglodyte");
        Client client = transport.getClient(token);

This client can be used just as any ordinary client. In the example plugin it is used to list the contents of the root directory of the server:

        RemoteServerDirectory serverRoot = (RemoteServerDirectory) client.getServerDocument(localRoot);
        boolean isEmpty = true;
        for (RemoteServerDocument doc : client.list(serverRoot)) {
            logger.info("Found doc : " + doc);
            isEmpty = false;
        }
        if (isEmpty) {
            logger.info("Server root is empty");
        }

In a more realistic plugin, the bioportal import plugin for instance, it is used to copy and update ontologies from the NCBO BioPortal into a directory on the Protege server.


Alternatively, if you start the server without OSGi (see manual setup) then you can arrange to register the LocalTransport somehow so that classes that need it can find it.

Navigating the server file system

Documents on the Protege server are identified by an IRI. Thus for example, the root directory for the server at 171.65.32.14:4875 would look like this:

        rmi-owl2-server://localhost:5100

This IRI can be construced programatically as follows:

        String host = "171.65.32.14";
        int rmiPort = 4875;
        IRI serverIRI = IRI.create(RMIClient.SCHEME + "://" + host + ":" + rmiPort);

If you know the name for a server document (the root directory, for example, should always exist) then you can retrieve it directly:

        client.getServerDocument(serverIRI);

This server document (RemoteOntologyDocument) can either be a directory (RemoteServerDirectory) or an ontology document RemoteOntologyDocument).

In particular, in the case of the server root directory, the server document is guaranteed to be a directory so it can be directly cast to that type. So if serverIRI represents the server root as described above then we can use the following code:

        RemoteServerDirectory dir = (RemoteServerDirectory) client.getServerDocument(serverIRI);

The contents of a directory can then be listed:

        for (RemoteServerDocument doc : client.list(dir)) {
            System.out.println("found: " + doc.getServerLocation());
        }

Uploading an ontology document to the server

The pre-requisites for uploading an ontology to a Protege server are a valid client to the server and an open (e.g. instantiation of the OWL api OWLOntology interface) ontology. The ClientUtilities class provides a convenience method for uploading an ontology to the server and a typical invocation looks something like this:

  VersionedOntologyDocument versionedOntology = ClientUtilities.createServerOntology(client, pizzaLocation, new ChangeMetaData("A tasty pizza"), ontology);

where

  • client is the Client
  • pizzaLocation is an IRI for the ontology document on the server,
  • ChangeMetaData is a class containing a commit timestamp and a commit comment.
  • ontology is the ontology that you wish to save.

Downloading an ontology document from the server

Again the ClientUtilities class is the key. The ClientUtilities class has a loadOntology method that takes three arguments: a Client, an ontology manager and a RemoteOntologyDocument to be downloaded. The following code demonstrates how this works:

        RemoteOntologyDocument doc = (RemoteOntologyDocument) client.getServerDocument(IRI.create(RMIClient.SCHEME + "://" + host + ":" + rmiPort 
                                                                                                                   + "/Pizza.history"));
        VersionedOntologyDocument vont = ClientUtilities.loadOntology(client, OWLManager.createOWLOntologyManager(), doc);
        OWLOntology ontology = vont.getOntology();
        System.out.println("Axiom count = " + ontology.getAxiomCount());

The caller knows that there is a server-side ontology document representing the pizza ontology and requests a RemoteOntologyDocument pointing to that location.

Saving a server ontology locally along with server metadata

Loading a server ontology and server meta data from a local file

Uploading an ontology onto the server

Extending the server with a plugin

Here I will talk about the metaproject and server components.

Starting the server manually

In its standard installation, the Protege server is automatically configured based on a configuration file using a dependency injection strategy. However it is possible to start the server programmatically and this approach to starting and running the server is demonstrated in a unit test. The key code in this test is the code that starts the server:

        Server core = new ServerImpl(TestUtilities.ROOT_DIRECTORY, TestUtilities.CONFIGURATION_DIRECTORY);
        server = new Authenticator(new ConflictManager(core));
        
        List<ServerTransport> transports = new ArrayList<ServerTransport>();
        ServerTransport rmiTransport = new RMITransport(rmiPort, rmiPort);
        rmiTransport.start(server);
        transports.add(rmiTransport);
        localTransport = new LocalTransportImpl();
        localTransport.start(server);
        transports.add(localTransport);
        
        server.setTransports(transports);

The first two lines:

        Server core = new ServerImpl(TestUtilities.ROOT_DIRECTORY, TestUtilities.CONFIGURATION_DIRECTORY);
        server = new Authenticator(new ConflictManager(core));

initialize a new server and configure two filters for the server which provide a simple authentication mechanism and basic conflict management.