A CORBA-Based Protege Server Michael A. Chisholm The MITRE Corporation 202 Burlington Road, M/S K302 Bedford, MA 01730-1420 Email: chisholm@mitre.org October 2001 This README file is part of a package of Java software that implements a CORBA-Based Protege Server. The Server software enables client applications to interact with a Protege knowledge base server using the Common Object Request Broker Architecture, a mechanism for distributed object communication. The Interface Definition Language (IDL) definitions of the Protege Server's interfaces are reproduced at the end of this document, and also contained in the file KRS.IDL, included with this distribution. 0. Documentation Documentation has been provided in 3 levels of detail. This file is the most general level, and contains basic installation and usage instructions. The next level is contained in the file TechnicalIssues.txt, and contains instructions for recompiling the server, as well as discussion of architecture, concurrency, etc. The lowest level is contained in the file JavaCORBAIssues.txt, which describes technical hurdles encountered and how they were solved, alternate solutions, and more discussion of the code. 1. Installation instructions Simply unzip the distribution file to a directory of your choosing. No additional setup is required. 2. Running the server Before starting the server, you need to start the transient naming service, which comes with jre's 1.2-1.3 (the software has not been tested with jdk 1.4). You may use the -ORBInitialPort parameter to specify a port: % tnameserv -ORBInitialPort 1234 The program will respond with something like the following: Initial Naming Context: IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f 6e746578743a312e3000000000010000000000000054000101000000000d3132392e38332e392e32 343400000c9800000018afabcaff00000002608618a5000000080000000000000000000000010000 0001000000140000000000010020000000000001010000000000 TransientNameServer: setting port for initial object references to: 1234 Ready. Now, you are ready to start the Protege server. Here's an example: % java -cp protege.jar;ProtegeServer.jar;gnu-regexp-1.1.3.jar org.mitre.protegeserver.KBServer -ORBInitialHost foo -ORBInitialPort 1234 (type the above all on one line.) protege.jar is the jar file for Protege itself, ProtegeServer.jar contains the server code, and gnu-regexp-1.1.3.jar contains regular expression parsing code, used in the implementation of method findConcepts() in interface KBKnowledgeBase. There is a batch file included with the distribution, named "serv.bat", to start the server. It was written to run under Windows 2000, and you may need to tailor it for your own operating system. The parameters ORBInitialHost and ORBInitialPort specify the server and port the naming service was started on. The naming service and Protege server may run on different machines. If you omit the host, it assumes the naming service is on the localhost. The server responds with something similar to the following: Protege KB server started on Thu Oct 25 15:22:25 EDT 2001 Ready. You are now ready to use the Protege server! 3. Using the server See the example client application to see how to connect to and use the server. In a nutshell, the server registers a special object named "KBControl" with the naming service. Clients then obtain remote references to this object, which provides methods for loading and creating knowledge bases. To quit tnameserv and/or the Protege server, you must kill the processes (e.g. ctrl-C on Windows, or the 'kill' command on Unix). When you load or create a knowledge base, you specify the name without the extension. The name you give is translated by the server into a directory/name on the server computer. Currently, nothing fancy is done--the extension ".pprj" is simply appended to the name you give, and used as the project filename. Therefore, projects get saved to the same directory the server is running in. The CLIPS backend is used to save the project. Omitting the extension also masks the fact that projects are actually saved as 3 separate files (*.pprj, *.pont, and *.pins), something that should be irrelevant to clients. When a knowledge base is loaded, it is put into a list of open KBs. If you open the same KB a second time, a duplicate gets loaded into memory. Each KB will have the same data, but they are separate--changes in one will not affect the other. They will not conflict with each other, except when you try to save... and then they will each get saved to the same file, and one will overwrite the other. In order to enable sharing of KBs, there is a method getOpenKbs() which returns a list of already-open KBs. You can use this to obtain references to KBs others have already opened, so that they may be modified concurrently. One last detail which is helpful to know is that the Protege knowledge model defines two types of slots: "own" slots and "template" slots. But there are not duplicate sets of methods for slot value manipulation. The methods for adding/removing slot values are defined only in the KBInstance interface. KBConcept inherits from KBInstance, and for that interface, we have overridden those inherited methods to operate on template slots. For all other descendant interfaces, they are defined to operate on own slots. If you wish to operate on own slots of concepts, you can retrieve the concept as if it were an instance, e.g. conceptAsInstance = myKb.getInstance("MyConcept"); 4. For developers and technical discussions If you wish to delve into the source code, want to know some of the design rationale, or just are interested in more technical issues, it is highly recommended that you read the TechnicalIssues.txt and/or JavaCORBAIssues.txt files. 5. Licenses The Protege server uses gnu.regexp, a regular expression parser distributed under the terms of the GNU Lesser General Public License. See the file COPYING.LIB for the details of this license. See http://www.cacas.org/java/gnu/regexp/ for information on gnu.regexp. Protege-2000 itself is available at http://protege.stanford.edu/. It is released under the Mozilla Public License available at http://www.mozilla.org/MPL/. The Protege Server software is also covered by the Mozilla Public License: The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is the Protege Server. The Initial Developer of the Original Code is The MITRE Corporation. [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] 6. Knowledge Representation System Interface Definition Language The contents of the file KRS.idl are reproduced below. This IDL file defines the CORBA interface to the Protege Server. module KRS { //forward declarations interface KBKnowledgeBase; interface KBFrame; interface KBConcept; interface KBInstance; interface KBSlot; interface KBFacet; //new types typedef sequence ListOfConcepts; typedef sequence ListOfInstances; typedef sequence ListOfSlots; typedef sequence ListOfFacets; typedef sequence ListOfKnowledgeBases; typedef sequence ListOfStrings; typedef sequence ListOfAny; enum SlotValueType { SLOT_TYPE_ANY, SLOT_TYPE_BOOLEAN, SLOT_TYPE_CONCEPT, SLOT_TYPE_FLOAT, SLOT_TYPE_INSTANCE, SLOT_TYPE_INTEGER, SLOT_TYPE_STRING, SLOT_TYPE_SYMBOL }; //exceptions exception FileNotFoundException{}; exception FileExistsException{}; exception IoException //lower-case "o" to avoid a Java name clash. { string message; }; exception FrameNameExistsException{ string message; }; exception FrameNotFoundException{ string message; }; exception InvalidRegularExpressionException{ string message; }; interface KBControl { KBKnowledgeBase loadKb(in string kbName) raises (FileNotFoundException, IoException); KBKnowledgeBase createKb(in string kbName) raises (FileExistsException, IoException); ListOfKnowledgeBases getOpenKbs(); void closeKb(in KBKnowledgeBase kb); }; interface KBKnowledgeBase { void save() raises (IoException); void delete() raises (IoException); void clear(); KBConcept createConcept(in string name) raises (FrameNameExistsException); ListOfConcepts getConcepts(); ListOfConcepts findConcepts(in string regexp) raises (InvalidRegularExpressionException); KBConcept getRootConcept(); //This slot will implicitly be an instance of :STANDARD-SLOT, and //unattached to any concept. KBSlot createSlot(in string name) raises (FrameNameExistsException); //convenience accessors KBFrame getFrame(in string name) raises (FrameNotFoundException); KBConcept getConcept(in string name) raises (FrameNotFoundException); KBInstance getInstance(in string name) raises (FrameNotFoundException); KBSlot getSlot(in string name) raises (FrameNotFoundException); }; interface KBFrame { string getName(); //delete frame from the KB altogether void delete(); //get the KB this frame resides in. KBKnowledgeBase getKnowledgeBase(); }; interface KBInstance : KBFrame { KBConcept getDirectType(); //slot stuff ListOfSlots getSlots(); KBSlot getSlot(in string name) raises (FrameNotFoundException); void addSlotValue(in KBSlot slot, in any value) raises (FrameNotFoundException); void setSlotValues(in KBSlot slot, in ListOfAny values) raises (FrameNotFoundException); void removeSlotValue(in KBSlot slot, in any value) raises (FrameNotFoundException); ListOfAny getSlotValues(in KBSlot slot) raises (FrameNotFoundException); }; interface KBConcept : KBInstance { //class hierarchy stuff void addParents(in ListOfConcepts newParents); void reparent(in KBConcept newParent); boolean isAncestorOf(in KBConcept concept); ListOfConcepts getSuperconcepts(); ListOfConcepts getSubconcepts(); boolean isAbstract(); //instance stuff ListOfInstances getAllInstances(); ListOfInstances getDirectInstances(); KBInstance createInstance(in string name) raises (FrameNameExistsException); KBInstance getInstance(in string name) raises (FrameNotFoundException); //more slot stuff KBSlot createSlot(in string name) raises (FrameNameExistsException); void removeSlot(in KBSlot slot) raises (FrameNotFoundException); KBSlot getBrowserSlot() raises (FrameNotFoundException); void attachSlot(in KBSlot slot); void detachSlot(in KBSlot slot) raises (FrameNotFoundException); //facet stuff ListOfFacets getFacets(in KBSlot slot) raises (FrameNotFoundException); KBFacet getFacet(in KBSlot slot, in string name) raises (FrameNotFoundException); ListOfAny getFacetValues(in KBSlot slot, in KBFacet facet) raises (FrameNotFoundException); void setFacetValues(in KBSlot slot, in KBFacet facet, in ListOfAny values) raises (FrameNotFoundException); }; interface KBSlot : KBInstance { //This affects the top-level slot. I.e. unless overridden at a //particular concept, this will take effect for ALL concepts/ //instances that have this slot. void setValueType(in SlotValueType type); }; interface KBFacet : KBInstance { boolean isValidValue(in KBFrame frame, in KBSlot slot, in any value) raises (FrameNotFoundException); }; };