SMD's Ontology Widget

Beauheim et al, 2007

Date:  January 26, 2007

Revised:  July 7th, 2007

Introduction

The Ontology Widget is a javascript/html application that utilizes AJAX (Asyncronous Javascript And Xml) to rapidly find and select ontology terms on a web page.  The widget is intended to be used in a larger context, such as an experiment annotation page.  The javascript functions query the SMD Ontology Service to retrieve and navigate ontology terms quickly and easily.  The first part of this document, Widget Context and Architecture, briefly describes the environment in which the widget works.  The next section,  Behavior of the Ontology Widget, describes what the widget does.  The third part explains how to construct an html page to use the widget.  Appendix 1 is an example html page.  Appendix 2 describes how to deploy the widget and Appendix 3 describes SMD Ontology Services in detail.  Appendix 4 shows more detail on how an OntologyWidget is initialized, and Appendix 5 describes how to change your Apache web server settings to set up a proxy pass and proxy pass reverse.

The home page for the widget project is http://smd.stanford.edu/ontologyWidget/.  Here you can find the complete gzipped package that includes this document, the war file required to deploy the servlet stub (see below), and an example html file, ExampleToEdit.html.  There is also an example html file (Example_8080.html) in the war file that is configured to run at localhost:8080, the default Tomcat location.  Please see the instructions in Appendix 2 for deploying the war file.  A working demonstration of the widget can be accessed at http://smd.stanford.edu/js/ontology/v1/ExampleProduction.html.  Finally, the javascript files are available at this site in the tar file OntologyWidgetSrc.tar.

Widget Context and Architecture

The Ontology Widget depends on three levels of service: the client user-interface in the browser, a Tomcat servlet stub and http server provided by the implementor, and the backend SMD Ontology Service and ontology database.  In Figure 1, the browser interface is shown in gray, the implementor's Tomcat server is shown in green and the SMD OntologyService is shown in blue.  The browser displays an html file that includes javascript code that interprets user actions, which then generate queries to the SMD Ontology Web Services through a servlet stub.  The SMD Ontology Service uses Java servlets to construct sql queries and direct the queries to our ontology database.  The response from the database is packaged in an xml document that is passed back through the servlet stub to the javascript code.  The javascript code  interprets the xml document and draws html in the client's browser. 

 

Figure 1. System Architecture.  The widget currently supports 43 of the OBO ontologies listed at http://obo.sourceforge.net/cgi-bin/table.cgi.  A current list of our ontologies can be retrieved by directly querying our SMD Ontology Service at http://smd.stanford.edu/smd/OntologyService?func=getOntologyList.  Queries to the SMD OntologyService are described in Appendix 3.

Behavior of the Ontology Widget

The widget is composed of a title, a label, a text field, a search button and a tree display.  The tree display is an area reserved to display the ontology as a tree.  Figure 2 shows an example single widget, as displayed on a web page.  In the text field, the user can type in characters to search for matching terms.  The text field is connected to an auto-complete list of terms queried through the SMD Ontology Service.  As the user types into the text field, the ontology database searches for terms that match the typed-in characters.  The SMD Ontology Service returns a matching term list up to 50 terms. When the user selects a term from the list, it is written to the text field.  Figure 3 shows the list that matches the characters 'res'.

Figure 2.  Ontology Widget with the Gene Ontology term Physiological Process selected as the root term in the html file.

Figure 3.  Auto-complete list of terms matching 'res'

 

The tree display area shows the ontology as a hierarchical tree.  Figure 4 shows the tree display for the children of Physiological Process, a term within the Biological Process branch of the Gene Ontology.  Clicking on a term in the tree will highlight the term and write it to the text field.  Figure 4 shows the homeostasis term highlighted in the tree and written to the text field. We also show paths in the tree from a selected term to the ontology root.   llTo display a path, select a term from the auto-suggest list (as in Figure 3) or directly from the tree (as in Figure 4) and click the Search button.  

 

Figure 4.  Selecting a term in the tree writes it to the text area

 

The tree display is navigated using the common collapse and expand icons shown in Figure 5.  The plus sign indicates that there are children of this term that are not displayed.  Clicking the plus sign expands the tree node and shows the children.  The minus sign collapses the tree at this node and hides the children.

                      

Figure 5.  Tree Navigation Icons

The icon with three dots is displayed when we show the path from the tree root to the selected node, highlighted in yellow.  Only the nodes along the path of interest are shown.  The icon with three dots indicates that there are additional child nodes for a parent that are not being displayed. When the dot icon is clicked, the hidden children of the term are displayed and the icon disappears.  Figure 6 shows the ontology tree for Physiological Process when the term 'response to pheromone' has been selected from the auto-complete list.  Notice that the term, 'response to pheronome', is highlighted in the tree and that the term occurs in the tree two times.  The dots icon here shows that all the terms along the path from the root, physiological process, to  'response to pheromone ...' have more child terms that are not displayed.

 

 

Figure 6.  Tree from selected term to root, showing the dots icon at multiple places

 

The widget is designed to report five fields of data when a button of <input type=submit> is included on the form.  The action method that is called must be supplied by the user of the widget.  Each widget will report its ontology name, the label, title, term name and term accession number through hidden input fields.  We provide a sample action for Submit which reports the values in a simple table.  In the section below we describe how to construct a web page with an ontology widget and a Submit button.

How To Construct a Webpage with Ontology Widgets

 

In the downloadable files (and as shown in Appendix 1), we have created an html file which can be used as a template for widget creation.  The basic outline of widget creation is that the html file must initialize the SMDService by calling a javascript function, SMDService().  The SMDService  handles all the queries to the SMD Ontology Service through a proxy servlet and XMLHttpRequests and responses.  Then the html file defines the widget parameters in JSON format (javascript object notation).  When the widgets are configured, they are dynamically placed on the page at user-specified locations.  Each widget will report five fields in hidden input fields when the form is submitted.  Appendix 1 gives a full listing of an example html file.  The html file is  described in detail below.

HTML File Format:

The <head> section

Ontology Widget is constructed using seven javascript files plus icon image files and a cascading style sheet (css).  The tree in the annotation widget is built using YAHOO!'s public domain user interface code for widgets  (http://developer.yahoo.com/yui ).  It is not necessary to download the javascript files, as they can simply be included as shown in Figure 7; of course, they can be downloaded from our web site using those same urls, if you are interested in the actual code.  In Figure 7, the javascript and css files are imported into the html file by referencing the files on our web server.  Improvements we make are automatically available through these urls.

 

 

<link rel="stylesheet" type="text/css" href="http://smd.stanford.edu/js/ontology/v1/treeview/assets/tree.css">

 

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/Widget.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/SMDService.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/Ontology.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/OntologyTreeBrowser.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/Term.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/Hashtable.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/treeview/yahoo.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/treeview/treeview.js'></script>

<script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/treeview/MyNode.js'></script>

 

Figure 7.  Including the required files in the html document

 

Initialization of a web page containing one or more widgets proceeds as follows.  The window.onload() function is used to set up some flags and create the SMDService() (see Figure 8 for code listing; a more detailed indication of the process of flag setting and database queries is shown in Appendix 4).  During the set up phase, we query the database for the currently available ontologies.  This query is done in the new SMDService() function.  The javascript  interval checker, setInterval ('checkFlag()', 100) in the window.onload() function checks for the value of the variable 'flag' in the function checkFlag().  checkFlag() is called every 100 ms by the javascript function setInterval() until it is cleared.  When the value of 'flag' changes to 2, the initial database query has returned, thus clearing the interval checker, and the function buildWidgets() is  called.  buildWidgets() also  queries the database and these queries must return before we can continue.  When the value of the variable 'flag' changes to 3, we are ready to continue and the interval checker is cleared again.  The two functions shown in Figure 8 must be included verbatim in the html file.  Other javascript commands may be included in the window.onload() function as required by the application, such as calling other javascript functions which lay-out other parts of the html page or making database queries for previously selected values.


 

 

window.onload = function() {

document.getElementById ('init').setAttribute ('flag', 1 );

doneYet = setInterval ('checkFlag()', 100 );

smdService = new SMDService();

}

 

function checkFlag() {

//query for ontology ids has completed

if ( document.getElementById ('init').getAttribute ('flag') == 2 ) {

buildWidgets();

}

else if  (document.getElementById ('init').getAttribute ('flag') == 3 ) {

clearInterval (doneYet);

}

}

 

Figure 8.  Javascript functions for initializing form

 

The second part of the <head> section of the html file defines each widget in JSON notation.  A widget needs six pieces of data:

á      title to be shown on the form (string)

á      ontology id (database identifier, supplied by function call) 

á      ontology name (string)

á      term name (string)

á      label (string)

á      unique identifier (string or number )

 

Figure 9 shows the listing for a function called buildWidgets(), which is an example of how to create widgets.  When defining a widget, the code must first get the database identifier for the ontology name.  This is done by calling smdService.getOntologyId (ontologyName).  The code below is creating an array of objects where each object will be one widget.  Because javascript uses associative arrays to reference data fields and because it is not typed, care must be taken to use the identifiers exactly as defined below.  The fields are title, ontId, ontName, termName, label, and uid.  The values for title, label, and uid are user-specified.  The label defines the context of the annotation to the page.  The uid is a unique identifier, important when there are several widgets on one page.  The uid can be a string or an integer; it just must be unique for each widget on the page.  The termName allows the user to specify a root from which the ontology descends.  If termName is the empty string, that is “ ” or ‘ ’ or 0, the root of the ontology will be the root of the tree.  If termName is a term name in this ontology, then that term will be the root.  In this way, the scope of the terms can be restricted to the context of the annotation.  For both the ontology name and the subroot term, we require an exact string match with the name and the term as defined in the ontology.  In Appendix 3, we explain how you can check these names against our database. 

The buildWidgets() function, shown in Figure 9, creates three widgets:  one for The MGED Ontology, one for Gene Ontology and one for NCBI_Taxonomy.  The first widget is limited to search for terms which are children of the term BiologicalProperty.  The second widget is limited to those terms that are descendents of biological_process in the Gene Ontology.  The third widget displays all the terms in the NCBI Taxonomy ontology.  Below the widget descriptions, the function loadWidgets() is called.  Optionally, we have preselected the term growth in the Gene Ontology.  The preselection feature can be used to display the term selected in a previous session or a default value. 

 

<script type='text/javascript'>

               var smdService;

               var doneYet;

               var termNames;

               function buildWidgets() {

               

 

          //Set up for "The MGED ONTOLOGY", rooted at the term "BiologicalProperty"

                   var id1 = smdService.getOntologyId ("The MGED Ontology");

                   termNames = { "lookups": [

                         {"title" : "Biological Samples ",

                          "ontId" : id1,

                        "ontName" : "The MGED Ontology",

                       "termName" : "BiologicalProperty",

                          "label" : "Biological Samples",

                            "uid" : '1' }]};

                  //---------------------End of biological samples

 

          //Set up for "The Gene Ontology", rooted at the term "biological_process"

                   var id2 = smdService.getOntologyId ("Gene Ontology");

                   termNames.lookups[termNames.lookups.length] =

                        {"title" : "Biological Process ",

                         "ontId" : id2,

                       "ontName" : "Gene Ontology",

                      "termName" : "biological_process",

                         "label" : "Biological Process",

                           "uid" :'2'};

                  //---------------------End of biological process

 

                   //Set up for "NCBI_Taxonomy", rooted at the root

                   id3 = smdService.getOntologyId ("NCBI_Taxonomy");

                   termNames.lookups[termNames.lookups.length] =

                       { "title" : "Taxonomy",

                         "ontId" : id3,

                       "ontName" : "NCBI_Taxonomy",

                      "termName" : "",

                         "label" : "Taxonomy",

                           "uid" : '3'};

                   //---------------------end of ncbi taxonomy

 

                //call the smdService to load the widgets on the page

               smdService.loadWidgets (termNames );

               //preselect a term for each widget (optional)

               smdService.preSelectTerm (id2, ÒgrowthÓ, 2);

              

              }

</script>

Figure 9.  Example:  Building three data objects

 

The <body> section

The last part of the html file is the body.  In the body we define the <div> elements that hold a place for each widget on the page and define the five hidden inputs.  The <div> elements for the widgets are named by the string id =' widget' + uid.  Similarly the four hidden fields have ids in the form of:  'ontology' + uid, 'label' + uid, 'termName' + uid, 'accession' + uid.  The fifth hidden input names the uid for this widget.  In Figure 10, notice that the id of the form is ' MainForm ' as passed to SMDService(' MainForm').

 

<body>

      <form name='ExperimentalInfo'

            id = 'MainForm' method=POST onsubmit = "validateForm()">

          <fieldset>

             <legend>Design of the Investigation </legend>

                 <table border cellpadding=4 >

                     <!-- widget with unique id = 1.  hidden fields are required for submission -->

                     <tr valign=top>

                     <td> <div id='widget1'>

                          <input type='hidden' id='ontology1' name='ontology1' value="">

                          <input type='hidden' id='label1' name='label1' value="">

                          <input type='hidden' id='termName1' name='termName1' value="">

                          <input type='hidden' id='accession1' name='accession1' value="">

                          <input type='hidden' id='uid' name='uid' value="1">

                     </td>

                     </tr>

                     <!-- widget with unique id = 2.  hidden fields are required for submission -->

                     <tr valign=top>

                     <td> <div id='widget2'>

                          <input type='hidden' id='ontology2' name='ontology2' value="">

                          <input type='hidden' id='label2' name='label2' value="">

                          <input type='hidden' id='termName2' name='termName2' value="">

                          <input type='hidden' id='accession2' name='accession2' value="">

                          <input type='hidden' id='uid' name='uid' value="2">

                     </td>

                     </tr>

                     <!-- widget with unique id = 3.  Hidden fields are requires for submission -->

                     <tr>

                     <td> <div id='widget3'>

                          <input type='hidden' id='ontology3' name='ontology3' value="">

                          <input type='hidden' id='label3' name='label3' value="">

                          <input type='hidden' id='termName3' name='termName3' value="">

                          <input type='hidden' id='accession3' name='accession3' value="">

                          <input type='hidden' id='uid' name='uid' value="3">

                     </td>

                     </tr>

                 </table>

                 <table  border cellpadding=4 >

                     <tr> <td> <input type='submit' ></td></tr>

                 </table>

          </fieldset>

        

          <!-- init flags required for query synchronization -->

          <div id='init' flag='0'></div>

          <!-- url for our service

          <div id='url' server='http://localhost:8080/OntologyWidgetProxy/OntologySvs'></div>

          </form>

</body>

Figure 10.  Body and form for three widgets

 

 

The last requirement is two divÕs for initialization purposes.  The ÔinitÕ flag we saw above for synchronization. The URL div exposes the address of the ontology service proxy.  Because of browser security issues, the proxy is necessary to avoid the Òcross-domainÓ problem.  This is because browsers do not allow an html file to call a service URL in another domain.  In your html file, the URL must point to the ontology service proxy in your local tomcat installation.

 

These instructions describe how to use SMDÕs Ontology Widget with our OntologyService.  Figure 11 shows what this example html page looks like.  The first time our service is accessed, there will be a security alert from Firefox.  Figure 12 shows this alert.  Check the box “Remember this decision” and click the “Allow” button.

 

 

Figure 11.  Browser rendering of Example_8080.html

 

Figure 12.  Security Alert from Firefox


Appendix 1:  Example html file

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

 

 <head>

    <meta http-equiv="content-type" content="text/html/charset=iso-8859-1">

       <link rel="stylesheet" type="text/css" href="http://smd.stanford.edu/js/ontology/v1/treeview/assets/tree.css">

 

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/Widget.js'></script>

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/SMDService.js'></script>

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/OntologyTreeBrowser.js'></script>

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/Hashtable.js'></script>

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/treeview/yahoo.js'></script>

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/treeview/treeview.js'></script>

        <script type='text/javascript' src='http://smd.stanford.edu/js/ontology/v1/treeview/MyNode.js'></script>

 

 

        <script type='text/javascript'>

               var smdService;

               var doneYet;

               var termNames;

 

               /*  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *

                *  buildWidgets supplies the basic data for each instance of an ontology annotator.*

                *  smdService looks up the ontology name against our database as the widgets are   *

                *  built.                                                                          *

                *  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

               function buildWidgets() {

 

                 //Set up for "The MGED ONTOLOGY", rooted at the term "BiologicalProperty"

                   var id1 = smdService.getOntologyId ("The MGED Ontology");

                   termNames = { "lookups": [

                         {"title" : "Biological Samples ",

                          "ontId" : id1,

                        "ontName" : "The MGED Ontology",

                       "termName" : "BiologicalProperty",

                          "label" : "Biological Samples",

                            "uid" : '1' }]};

                  //---------------------End of biological samples

 

                   var id2 = smdService.getOntologyId ("Gene Ontology");

                   termNames.lookups[termNames.lookups.length] =

                        {"title" : "Biological Process ",

                         "ontId" : id2,

                       "ontName" : "biological_process",

                      "termName" : "biological_process",

                         "label" : "Biological Process",

                           "uid" :'2'};

                  //---------------------End of biological process

 

                   //Set up for "NCBI_Taxonomy", rooted at the root

                   id3 = smdService.getOntologyId ("NCBI_Taxonomy");

                   termNames.lookups[termNames.lookups.length] =

                       { "title" : "Taxonomy",

                         "ontId" : id3,

                       "ontName" : "NCBI_Taxonomy",

                      "termName" : "",

                         "label" : "Taxonomy",

                           "uid" : '3'};

                   //---------------------end of ncbi taxonomy

 

 

 

                   //call the smdService to load the widgets on the page.

                   smdService.loadWidgets (termNames );

                   smdService.preSelectTerm (id2, "growth", 2);

               }

 

               /*  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *

                *  window.onload sets up the SMDService which is doing some preliminary queries.   *

                *  the 'init' flag is synchronizing the setup queries with building the widgets.   *

                *  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

               window.onload = function() {

                  document.getElementById('init').setAttribute ('flag', 1 );

                  doneYet = setInterval ('checkFlag()', 100 );

                  smdService = new SMDService('MainForm');

               }

 

 

               /*  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *

                *  when smdService finishes its setup, it changes the init flag and calls

                *  buildWidgets.

                *  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

               function checkFlag() {

                 //query for ontology ids has completed

                 if ( document.getElementById ('init').getAttribute ('flag') == 2 ) {

                     buildWidgets();

                 }

                 else if  (document.getElementById('init').getAttribute ('flag') == 3 ) {

                     clearInterval (doneYet);

                 }

               }

 

               /*  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *

                *  validateForm is called when the submit button is clicked and performs necessary

                *  form validation.  It returns false when validation fails.

                *  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

               function validateForm () {

                   return true;

               }

 

               /*  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *

                *  for debugging purposes.  Remove the comments if debugging message desired.      *

                *  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

               function doDebug(str) {

                /***

                  var console = getElement ('console') ;

                  newline = document.createElement ('div');

                  console.appendChild (newline);

                  text = document.createTextNode(str);

                  newline.appendChild (text); ***/

               }

          </script>

      </head>

 

 

 

   <body>

      <form name='ExperimentalInfo'

              id='MainForm'  method=POST onsubmit = "validateForm()">

          <fieldset>

             <legend>Design of the Investigation </legend>

                 <table border cellpadding=4 >

                     <!-- widget with unique id = 1.  hidden fields are required for submission -->

                     <tr valign=top>

                     <td> <div id='widget1'></div>

                          <input type='hidden' id='ontology1' name='ontology1' value=""/>

                          <input type='hidden' id='label1' name='label1' value=""/>

                          <input type='hidden' id='termName1' name='termName1' value=""/>

                          <input type='hidden' id='accession1' name='accession1' value=""/>

                          <input type='hidden' id='uid' name='uid' value="1"/>

                     </td>

                     </tr>

                     <!-- widget with unique id = 2.  hidden fields are required for submission -->

                     <tr valign=top>

                     <td> <div id='widget2'></div>

                          <input type='hidden' id='ontology2' name='ontology2' value=""/>

                          <input type='hidden' id='label2' name='label2' value=""/>

                          <input type='hidden' id='termName2' name='termName2' value=""/>

                          <input type='hidden' id='accession2' name='accession2' value=""/>

                          <input type='hidden' id='uid' name='uid' value="2"/>

                     </td>

                     </tr>

                     <!-- widget with unique id = 3.  hidden fields are required for submission -->

                     <tr valign=top>

                     <td> <div id='widget3'></div>

                          <input type='hidden' id='ontology3' name='ontology3' value=""/>

                          <input type='hidden' id='label3' name='label3' value=""/>

                          <input type='hidden' id='termName3' name='termName3' value=""/>

                          <input type='hidden' id='accession3' name='accession3' value=""/>

                          <input type='hidden' id='uid' name='uid' value="3"/>

                     </td>

                     </tr>

                 </table>

                 <table  border cellpadding=4 >

                     <tr> <td> <input type='submit' ></td></tr>

                 </table>

          </fieldset>

        

          <!-- init flags required for query synchronization -->

          <div id='init' flag='0'></div>

 

          <div flag='0'></div>

 

          <!-- for debugging purposes only -->

          <div id='console'></div>

 

          <!-- url for our service -->

          <div id='url' server='http://smd.stanford.edu/smd/OntologyService'></div>

          </form>

   </body>

</html>

 

 

 


Appendix 2:  Deploying the Ontology Service Proxy

The OntologyWidgetProxy is a simple servlet that passes HTTP requests and responses between the Ontology Widget client that runs in your browser, and the OntologyService that runs on Stanford 's server and that queries Stanford 's SMD ontology database.  With this pass-through arrangement, the Widget client need not connect directly to the Stanford OntologyService.  Most browsers prohibit such a connection, which would cross web service security domains.  The download file, ontologyWidget.tar.gz, contains a sample html file, called ExampleToEdit.html, this document, and the OntologyWidgetProxy.war.  Inside the war file is another html file, Example_8080.html, which is configured to run at Tomcat's default url, localhost:8080. 

The OntologyWidgetProxy is packaged as a war file (OntologyWidgetProxy.war) that you  deploy in an Apache Tomcat (or other) servlet container.  To do this for Tomcat:

¯    Make sure that a local Tomcat server is running (that is, a Tomcat server in your local security domain).  If, for example, Tomcat is installed on your local machine using the default port 8080, then you can check by entering the address http://localhost:8080 in your browser.  When Tomcat is running, you will see Tomcat's default welcome page.

¯    Copy the OntologyWidgetProxy.war file into a directory that is the appbase for a <Host> object in TomcatÕs configuration.  If TomcatÕs installation directory is CATALINA_HOME, then its configuration file is ${CATALINA_HOME}/config/server.xml.  In a default Tomcat configuration, that file defines one <Host> object with appBase= 'webapps'.  For such an installation, copy OntologyWidgetProxy.war into ${CATALINA_HOME}/webapps.

¯    If (as by default) the Tomcat configuration declares unpackWARs="true" autoDeploy="true" for the Host being used, then Tomcat automatically deploys the OntologyWidgetProxy in the directory webapps/OntologyWidgetProxy.

¯    To run the widgets in the example in Appendix 1, edit the file webapps/OntologyWidgetProxy/Example_8080.html:  Near the end, there is a line that defines a <div> element with the attribute id=ÕurlÕ:

<div id='url' server='http://localhost:8080/OntologyWidgetProxy/OntologySvs'></div>

     You may need special permissions to edit this file in the webapps location.

¯    If tomcat is running on localhost:8080 and the Example_8080.html file is located at webapps/OntologyWidgetProxy, then  Example_8080.html is called by http://localhost:8080/OntologyWidgetProxy/Example_8080.html.  The html file must be visible to the web service.   Usually there is a location in the web services directories for html files.  Please check with your system administration or web master for the correct file placement.

¯    To test the proxy, try the url http://localhost:8080/OntologyWidgetProxy/OntologySvs?func=getOntologyList. Please substitute the url for your server for Òlocalhost:8080Ó.  If the proxy is correctly placed, the result should be a list of Ontologies in xml. 

This works Ôas isÕ for the default Tomcat installation described above.  However, localhost:8080 may need to be changed for your Tomcat instance.  You may need super user permissions.
Appendix 3:  SMD Ontology Services

 

SMD Ontology Service is a set of seven services that return ontology data.  The services are written as Java servlets and query our ontology database.  All of the services return an xml string, which is either  an OntologyList or a TermList.  The seven services are:

 

            * getOntologyList

            * getChildren

            * getParents

            * getRootTerms

            * getTermsByName

            * getAncestors

            * getDescendents

 

Because we allow our services to be used outside of our domain, we have had to add the proxy servlet, which runs in the implementor's server, and is described in Appendix 2.  All the services are available directly using the url http://smd.stanford.edu/smd/OntologyService in conjunction with the appropriate query strings described below.

 

The list of ontologies is returned by the query string ?func=getOntologyList.  This url can be used to check the names of the ontologies that we support.  An  OntologyList contains name and identifier values for the ontologies managed by this host.  An example OntologyList, in xml, is:

 

<OntologyList uid="null">

<Ontology name="Mouse Anatomy Ontology" id="18"/>

<Ontology name="Disease Ontology" id="17"/>

<Ontology name="The MGED Ontology" id="5"/>

</OntologyList>

 

 

The TermList returns the identifier of the term that originated the query and the UID of the ontology widget.  Some of the child elements of a Term in a TermList may be omitted,  due to what data is captured in the database.  Only the <name> item is always returned. When the term has multiple parents, the parent ids are represented as a comma separated list.  A TermList element is returned for the six services listed below.

 

An example of a  TermList is:

 

<TermList sourceId="5913092" uid="12">

                   <Term id="5913736">

                          <accession>MAE:0000813</accession>

                          <name>brain meninges</name>

                          <def>some definition</def>

                          <comment>a comment</comment>

                          <scientificName>some name, if

                                         any</scientificName>

                          <synonym>synonym if any</synonym>

                          <synonymAccession>MAE:0000xxx

                               </synonymAccession>

                         <nChildren>6</nChildren>

                         <parentIds>5913092</parentIds>

                   </Term>

              </TermList>

 

 

getOntologyList

query: ?func=getOntologyList

servlet api:  public String getOntologyList()

                        no parameters

           Returns: String ontologyList  // xml list of ontologies

 

getChildren

query:  ?func=getChildren&ontologyId=21&term=hand

query:  ?func=getChildren&termId=6687717

A list of child terms of the indicated term is returned. There are two forms of this function: one taking an ontology identifier and a term name  as a string and the other taking a term as an identifier. Both forms have equivalent function.

 

servlet api:  public String getChildren (String ontologyId, String uid, String term)

            Parameters:      String ontologyId  // database identifer

                                    String uid             // identifies the widget that made this query

                                    String term           //  name of the term to query for its children

            Returns            String termList      //  xlm list of terms which match query

 

            public String getChildren (String uid, long id)

            Parameters:      String uid            // identifies the widget that made this query

                                    long id                // database identifier for the term to query for its

                                                               // children

            Returns:           String termList   // xml list of terms which match query

 

getParents

query:  ?func=getParents&ontologyId=21&term=hand

query:  ?func=getParents&termId=6687714

A list of parent terms of the indicated term is returned. There are two forms of this function:   one taking an ontology identifier and a term name as a string and the second form takes the term identifier.  Both forms have equivalent function.  The sourceId in the TermList is the identifier of the term that originated the query.

 

servlet api:  public String getParents (String ontologyId, String uid, String term)

Parameters:      String ontologyId  // database identifer

                                    String uid             // identifies the widget that made this query

                                    String term           //  name of the term to query for its parents

           Returns:            String termList      //  xml list of terms which match query

 

servlet api:  public String getParents (String uid, long id )

Parameters:      String uid             // identifies the widget that made this query

                                    long id                // database identifier for term that queries for its

                                                              // parents

           Returns:            String termList    //  xml list of terms which match query

 

 

 

getTermsByName

query:  ?func=getTermsByName&ontologyId=21&term=bra

A list of terms matching the indicated partial term is returned. The partial term is interpreted as the term followed by a wildcard character matching zero or more characters. The wildcard character '*' may be included at the beginning of the partial term or embedded in the partial term.  At this time, we only support that '*' wildcard.  This url can be used to lookup the exact term name to be used as a pre-selected term or root term.

 

servlet api:  public String getTermsByName (String ontologyId, String uid, String partialName )

Parameters:      String ontologyId   // database identifier for ontology

                        String uid              // identifies the widget that made this query

                                    String partialName //  partial term name to query for matching terms

           Returns:            String termList      // xlm list of terms which match query

 

servlet api:  public String getTermsByName (String ontologyId, String uid,

                                                                  String partialName, String rootId )

Parameters:      String ontologyId     // database identifier for ontology

                        String uid                 // identifies the widget that made this query

                                    String partialName  //  partial term name to query for matching terms

                                    String rootId           // limit results to terms which are descendents of

                                                               this term

           Returns:            String termList       //  xml list of terms which match query

 

getRootTerms

query:  ?func=getRootTerms&ontologyId=21

Returns a list of terms that are the root(s) of specified ontology. 

  

servlet api:  public String getRootTerms (String ontologyId, String uid)

Parameters:      String ontologyId  // database identifier for ontology

                        String uid             // identifies the widget that made this query

           Returns:            String termList     //  xml list of terms which match query

 

getAncestors

query:  ?func=getAncestors&termId=6687845

Returns a list of terms that are the ancestors of the indicated term up to the root(s).  When a term has multiple parents, all of the ancesters are returned.

 

servlet api:  public String getAncestors (String uid, long id)

            Parameters:      String uid          // used internally to identify the widget that made

                                                            // the call

                                    long id              // database identifier of term from which to find ancestors

Returns:           String termList  // xml list of terms which match the query

 

getDescendents

query:  ?func=getDescendents&termId=6687845

Returns a list of terms that are all the descendents of the indicated term. The parent identifiers of each term are returned so that the caller may reassemble the terms into a DAG.

 

servlet api:  public String getDescendents (String uid, long id)

            Parameters:      String uid             // identifies the widget that made this query

long id                 // database identifier of term from which to

                                                    // find descendents           

Returns:           String termList     // xml list of terms which match query


Appendix 4:  Sequence of Events During Widget Initialization

 

 

 

 

 

 

 


                     


Appendix 5:  Implementing the Proxy Pass and ReverseProxy Pass in Tomcat

An alternative to deploying the OntologyWidgetProxy.war file in Tomcat is to change your Apache web server settings for ProxyPass and ProxyPassReverse.  The typical use of a proxy pass is to enable internet access to internal clients that are restricted by a firewall.  Apache.org warns that opening your web server is dangerous to your network and that your server must be secured before the proxy settings are changed.  Please see http://httpd.apache.org/docs/2.2/mod/mod_proxy.html for detailed instructions.  Please note that this reference is for version 2.2 of Apache.

            The ProxyPass and ProxyPassReverse directives are in the httpd.conf file of your web server.  This file will require 'superuser' permission to change.  There are many details and various settings discussed on the web site above.  The basic setting for the OntologyService is :

 

ProxyPass /yourpathtoyourService http://smd.stanford.edu/smd/OntologyService

ProxyPassReverse /yourpathtoyourService http://smd.stanford.edu/smd/OntologyService

 

            In addition to setting the proxy pass and proxy pass reverse, the mod_proxy (mod_proxy.c) module must be compiled into your apache version.  Then in the httpd.conf file, the line

LoadModule proxy_module    must be uncommented and apache restarted.

 

            The OntologyWidget is also looking for the url to our service through your server.  The url that you need to supply is your url + yourpathtoyourService that you defined in the ProxyPass and ProxyPassReverse.  See Figure 10 of this document.