<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.opendap.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dan</id>
	<title>OPeNDAP Documentation - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.opendap.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dan"/>
	<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php/Special:Contributions/Dan"/>
	<updated>2026-07-12T20:42:53Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.38.4</generator>
	<entry>
		<id>https://docs.opendap.org/index.php?title=DMR%2B%2B&amp;diff=13052</id>
		<title>DMR++</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=DMR%2B%2B&amp;diff=13052"/>
		<updated>2021-07-26T19:01:12Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* DAP representations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;How to build &amp;amp; deploy dmr++ files for Hyrax&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==What? Why?== &lt;br /&gt;
&lt;br /&gt;
It is a fast and flexible way to serve data stored in S3.&lt;br /&gt;
The dmr++ encodes the location of the data content residing in a binary data file/object (e.g., an hdf5 file) so that it can be directly accessed, without the need for an intermediate library API, by using the file with the location information. The binary data objects may be on a local filesystem, or they may reside across the web in something like an S3 bucket.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==How Does It Work?==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;dmr++&#039;&#039; ingest software reads a data file (see &#039;&#039;&#039;note&#039;&#039;&#039;) and builds a document that holds all of the file&#039;s metadata (the names and types of all of the variables along with any other information bound to those variables). This information is stored in a document we call the Dataset Metadata Response (DMR). The &#039;&#039;dmr++&#039;&#039; adds some extra information to this (that&#039;s the &#039;++&#039; part) about where each variable can be found and how to decode those values. The &#039;&#039;dmr++&#039;&#039; is simply an special annotated DMR document.&lt;br /&gt;
&lt;br /&gt;
This effectively decouples the annotated DMR (&#039;&#039;dmr++&#039;&#039;) from the location of the granule file itself. Since dmr++ files are typically significantly smaller than the source data granules they represent, they can be stored and moved for less expense. They also enable reading all of the file&#039;s metadata in one operation instead of the iterative process that many APIs require.&lt;br /&gt;
&lt;br /&gt;
If the dmr++ contains references to the source granules location on the web, the location of the the dmr++ file itself does not matter.&lt;br /&gt;
&lt;br /&gt;
Software that understands the dmr++ content can directly access the data values held in the source granule file, and it can do so without having to retrieve the entire file and work on it locally, even when the file is stored in a Web Object Store like S3. &lt;br /&gt;
&lt;br /&gt;
If the granule file contains multiple variables and only a subset of them are needed, the dmr++ enabled software can retrieve just the bytes associated with the desired variables values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;note:&#039;&#039;&#039; The OPeNDAP software currently supports HDF5 and NetCDF4. Other formats can be supported, such as zarr.&lt;br /&gt;
&lt;br /&gt;
==Supported Data Formats==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;dmr++&#039;&#039; software currently works with &#039;&#039;hdf5&#039;&#039; and &#039;&#039;netcdf-4&#039;&#039; files. (The &#039;&#039;netcdf-4&#039;&#039; format is a subset of &#039;&#039;hdf5&#039;&#039; so &#039;&#039;hdf5&#039;&#039; tools are utilized for both.) Other formats like &#039;&#039;zarr&#039;&#039;, &#039;&#039;hdf4&#039;&#039;, &#039;&#039;netcdf-3&#039;&#039; are not currently supported by the &#039;&#039;dmr++&#039;&#039; software, but support could be added if needed.&lt;br /&gt;
&lt;br /&gt;
===&#039;&#039;hdf5&#039;&#039;===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hdf5&#039;&#039; data format is quite complex and many of the options and edge cases are not currently supported by the &#039;&#039;dmr++&#039;&#039; software. &lt;br /&gt;
&lt;br /&gt;
These limitations and how to quickly evaluate an &#039;&#039;hdf5&#039;&#039; or &#039;&#039;netcdf-4&#039;&#039; file for use with the &#039;&#039;dmr++&#039;&#039; software are explained below.&lt;br /&gt;
&lt;br /&gt;
====&#039;&#039;hdf5&#039;&#039; filters====&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hdf5&#039;&#039; format has several filter/compression options used for storing data values. &lt;br /&gt;
The &#039;&#039;dmr++&#039;&#039; software currently supports data that utilize the  H5Z_FILTER_DEFLATE and H5Z_FILTER_SHUFFLE filters.&lt;br /&gt;
[https://support.hdfgroup.org/HDF5/doc/RM/RM_H5Z.html You can find more on hdf5 filters here.]&lt;br /&gt;
&lt;br /&gt;
====&#039;&#039;hdf5&#039;&#039; storage layouts====&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hdf5&#039;&#039; format also uses a number of &amp;quot;storage layouts&amp;quot; that describe various structural organizations of the data values associated with a variable in the granule file.&lt;br /&gt;
The &#039;&#039;dmr++&#039;&#039; software currently supports data that utilize the  H5D_COMPACT, H5D_CHUNKED, and H5D_CONTIGUOUS storage layouts. These are all of the storage layouts defined by the &#039;&#039;hdf5&#039;&#039; library, but others can be added.&lt;br /&gt;
[https://support.hdfgroup.org/HDF5/doc1.6/Datasets.html You can find more on hdf5 storage layouts here.]&lt;br /&gt;
&lt;br /&gt;
====Is my &#039;&#039;hdf5&#039;&#039; or &#039;&#039;netcdf-4&#039;&#039; file suitable for &#039;&#039;dmr++&#039;&#039;?====&lt;br /&gt;
&lt;br /&gt;
To determine the &#039;&#039;hdf5&#039;&#039; filters, storage layouts, and chunking scheme used in an &#039;&#039;hdf5&#039;&#039; or &#039;&#039;netcdf-4&#039;&#039; file you can use the command:&lt;br /&gt;
 &amp;lt;code&amp;gt;h5dump -H -p &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
To get a human readable assessment of the file that will show the storage layouts, chunking structure, and the filters needed for each variable (aka DATASET in the &#039;&#039;hdf5&#039;&#039; vocabulary) [https://support.hdfgroup.org/HDF5/doc/RM/Tools.html#Tools-Dump h5dump info can be found here.]&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;h5dump example output:&#039;&#039;&lt;br /&gt;
 $ h5dump -H -p chunked_gzipped_fourD.h5&lt;br /&gt;
 HDF5 &amp;quot;chunked_gzipped_fourD.h5&amp;quot; {&lt;br /&gt;
 GROUP &amp;quot;/&amp;quot; {&lt;br /&gt;
   DATASET &amp;quot;d_16_gzipped_chunks&amp;quot; {&lt;br /&gt;
      DATATYPE  H5T_IEEE_F32LE&lt;br /&gt;
      DATASPACE  SIMPLE { ( 40, 40, 40, 40 ) / ( 40, 40, 40, 40 ) }&lt;br /&gt;
      STORAGE_LAYOUT {&lt;br /&gt;
         CHUNKED ( 20, 20, 20, 20 )&lt;br /&gt;
         SIZE 2863311 (3.576:1 COMPRESSION)&lt;br /&gt;
      }&lt;br /&gt;
      FILTERS {&lt;br /&gt;
         COMPRESSION DEFLATE { LEVEL 6 }&lt;br /&gt;
      }&lt;br /&gt;
      FILLVALUE {&lt;br /&gt;
         FILL_TIME H5D_FILL_TIME_ALLOC&lt;br /&gt;
         VALUE  H5D_FILL_VALUE_DEFAULT&lt;br /&gt;
      }&lt;br /&gt;
      ALLOCATION_TIME {&lt;br /&gt;
         H5D_ALLOC_TIME_INCR&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Is my netcdf file &#039;&#039;netcdf-3&#039;&#039; or &#039;&#039;netcdf-4&#039;&#039;?====&lt;br /&gt;
&lt;br /&gt;
It is an unfortunate state of affairs that the file suffix &amp;quot;.nc&amp;quot; is the commonly used naming convention for both &#039;&#039;netcdf-3&#039;&#039; and &#039;&#039;netcdf-4&#039;&#039; files. &lt;br /&gt;
You can use the command:  &lt;br /&gt;
 &amp;lt;code&amp;gt;ncdump -k &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
to determine if a &#039;&#039;netcdf&#039;&#039; file is either classic &#039;&#039;netcdf-3&#039;&#039; (classic) or &#039;&#039;netcdf-4&#039;&#039; (netCDF-4).&lt;br /&gt;
* The &#039;&#039;netcdf&#039;&#039; library must be installed on the system upon which the command is issued.&lt;br /&gt;
&lt;br /&gt;
[http://www.bic.mni.mcgill.ca/users/sean/Docs/netcdf/guide.txn_79.html You can learn more in the NetCDF documentation here.]&lt;br /&gt;
&lt;br /&gt;
==Building &#039;&#039;dmr++&#039;&#039; files with get_dmrpp==&lt;br /&gt;
&lt;br /&gt;
The application that builds the &#039;&#039;dmr++&#039;&#039; files is a command line tool called &#039;&#039;get_dmrpp&#039;&#039;. It in turn utilizes other executables such as &#039;&#039;build_dmrpp&#039;&#039;, &#039;&#039;reduce_mdf&#039;&#039;, &#039;&#039;merge_dmrpp&#039;&#039; (which rely in turn on the &#039;&#039;hdf5_handler&#039;&#039; and the &#039;&#039;hdf5&#039;&#039; library), along with a number of UNIX shell commands.&lt;br /&gt;
&lt;br /&gt;
All of these components are install with each recent version of the Hyrax Data Server&lt;br /&gt;
&lt;br /&gt;
You can see the &#039;&#039;get_dmrpp&#039;&#039; usage statement with the command: &amp;lt;code&amp;gt;get_dmrpp -h&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using &#039;&#039;get_dmrpp&#039;&#039;===&lt;br /&gt;
&lt;br /&gt;
The way that &#039;&#039;get_dmrpp&#039;&#039; is invoked controls the way that the data are ultimately represented in the resulting &#039;&#039;dmr++&#039;&#039; file(s). &lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;get_dmrpp&#039;&#039; application utilizes software from the Hyrax data server to produce the base DMR document which is used to construct the &#039;&#039;dmr++&#039;&#039; file. &lt;br /&gt;
&lt;br /&gt;
The Hyrax server has a long list of configuration options, several of which can substantially alter the the structural and semantic representation of the dataset as seen in the dmr++ files generated using these options.&lt;br /&gt;
&lt;br /&gt;
===Command line options===&lt;br /&gt;
&lt;br /&gt;
The command line switches provide a way to control the output of the tool. In addition to common options like verbose output or testing modes, the tool provides options to build extra (aka &#039;sidecar&#039;) data files that hold information needed for CF compliance if the original HDF5 data files lack that information (see the &#039;&#039;missing data&#039;&#039; section ). In addition, it is often desirable to build &#039;&#039;dmr++&#039;&#039; files before the source data files are uploaded to a cloud store like S3. In this case, the URL to the data may not be known when the &#039;&#039;dmr++&#039;&#039; is built. We support this by using placeholder/template strings in the &#039;&#039;dmr++&#039;&#039; and which can then be replaced with the URL at runtime, when the &#039;&#039;dmr++&#039;&#039; file is evaluated. See the &#039;-u&#039; and &#039;-p&#039; options below.&lt;br /&gt;
&lt;br /&gt;
====Inputs====&lt;br /&gt;
&lt;br /&gt;
; -b&lt;br /&gt;
: The fully qualified path to the top level data directory. Data files read by &#039;&#039;get_dmrpp&#039;&#039; must ride in the directory tree rooted at this location and their names expressed as a path relative to this location. The value may not be set to &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;/etc&amp;lt;/code&amp;gt; The default value is /tmp if a value is not provided. All the data files to be processed must be in this directory or one of its subdirectories. If &#039;&#039;get_dmrpp&#039;&#039; is being executed from same directory as the data then &amp;lt;code&amp;gt;-b `pwd`&amp;lt;/code&amp;gt; works as well.&lt;br /&gt;
;-u&lt;br /&gt;
: This option is used to specify the location of the binary data object. It’s value must be an http, https, or file (file://) URL. This URL will be injected into the dmr++ when it is constructed. If option -u is not used; then the template string &amp;lt;code&amp;gt;OPeNDAP_DMRpp_DATA_ACCESS_URL&amp;lt;/code&amp;gt; will be used and the dmr++ will substitute a value at runtime.&lt;br /&gt;
;-c&lt;br /&gt;
:The path to an alternate bes configuration file to use.&lt;br /&gt;
;-s&lt;br /&gt;
:The path to an optional addendum configuration file which will be appended to the default BES configuration. Much like the site.conf file works for the full server deployment it will be loaded last and the settings there-in will have an override effect on the default configuration.&lt;br /&gt;
&lt;br /&gt;
====Output====&lt;br /&gt;
&lt;br /&gt;
; -o&lt;br /&gt;
: The name of the file to create.&lt;br /&gt;
&lt;br /&gt;
====Verbose Output Modes====&lt;br /&gt;
&lt;br /&gt;
; -h&lt;br /&gt;
: Show help/usage page.&lt;br /&gt;
; -v:&lt;br /&gt;
: verbose mode, prints the intermediate DMR.&lt;br /&gt;
; -V&lt;br /&gt;
: Very verbose mode,  prints the DMR, the command and the configuration file used to build the DMR, and does not remove temporary files.&lt;br /&gt;
; -D&lt;br /&gt;
: Just print the DMR that will be used to build the DMR++&lt;br /&gt;
&lt;br /&gt;
====Tests====&lt;br /&gt;
&lt;br /&gt;
; -T&lt;br /&gt;
: Run ALL hyrax tests on the resulting dmr++ file and compare the responses the ones generated by the source hdf5 file.&lt;br /&gt;
; -I&lt;br /&gt;
: Run hyrax inventory tests on the resulting dmr++ file and compare the responses the ones generated by the source hdf5 file.&lt;br /&gt;
; -F&lt;br /&gt;
: Run hyrax value probe tests on the resulting dmr++ file and compare the responses the ones generated by the source hdf5 file.&lt;br /&gt;
&lt;br /&gt;
====Missing Data Creation====&lt;br /&gt;
&lt;br /&gt;
; -M&lt;br /&gt;
: Build a &#039;sidecar&#039; file that holds missing information needed for CF compliance (e.g., Latitude, Longitude and Time coordinate data).&lt;br /&gt;
; -p&lt;br /&gt;
: Provide the URL for the Missing data sidecar file. If this is not given (but -M is), then a template value is used in the dmr++ file and a real URL is substituted at runtime.&lt;br /&gt;
; -r&lt;br /&gt;
: The path to the file that contains missing variable information for sets of input data files that share common missing variables. The file will be created if it doesn&#039;t exist and the result may be used in subsequent invocations of get_dmrpp (using -r) to identify the missing variable file.&lt;br /&gt;
&lt;br /&gt;
===&#039;&#039;hdf5_handler&#039;&#039; Configuration===&lt;br /&gt;
&lt;br /&gt;
Because &#039;&#039;get_dmrpp&#039;&#039; uses the &#039;&#039;hdf5_handler&#039;&#039; software to build the &#039;&#039;dmr++&#039;&#039; the software must inject the &#039;&#039;hdf5_handler&#039;&#039;&#039;s configuration. &lt;br /&gt;
&lt;br /&gt;
The default configuration is large, but any valued may be altered at runtime.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here are some of the commonly manipulated configuration parameters with their default values:&lt;br /&gt;
 H5.EnableCF=true&lt;br /&gt;
 H5.EnableDMR64bitInt=true&lt;br /&gt;
 H5.DefaultHandleDimension=true&lt;br /&gt;
 H5.KeepVarLeadingUnderscore=false&lt;br /&gt;
 H5.EnableCheckNameClashing=true&lt;br /&gt;
 H5.EnableAddPathAttrs=true&lt;br /&gt;
 H5.EnableDropLongString=true&lt;br /&gt;
 H5.DisableStructMetaAttr=true&lt;br /&gt;
 H5.EnableFillValueCheck=true&lt;br /&gt;
 H5.CheckIgnoreObj=false&lt;br /&gt;
&lt;br /&gt;
====&#039;&#039;Note to DAACs with existing Hyrax deployments.&#039;&#039;====&lt;br /&gt;
&lt;br /&gt;
If your group is already serving data with Hyrax and the data representations that are generated by your Hyrax server are satisfactory, then a careful inspection of the localized configuration, typically held in /etc/bes/site.conf, will help you determine what configuration state you may need to inject into &#039;&#039;get_dmrpp&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===The &#039;&#039;H5.EnableCF&#039;&#039; option===&lt;br /&gt;
&lt;br /&gt;
Of particular importance is the &#039;&#039;H5.EnableCF&#039;&#039; option, which instructs the &#039;&#039;get_dmrpp&#039;&#039; tool to produce [https://cfconventions.org/ Climate Forecast convention (CF)] compatible output based on metadata found in the granule file being processed. &lt;br /&gt;
&lt;br /&gt;
Changing the value of &#039;&#039;H5.EnableCF&#039;&#039; to &#039;&#039;&#039;&#039;&#039;false&#039;&#039;&#039;&#039;&#039; will have (at least) two significant effects.&lt;br /&gt;
&lt;br /&gt;
It will:&lt;br /&gt;
&lt;br /&gt;
* Stop &#039;&#039;get_dmrpp&#039;&#039; from attempting to make the results CF compliant.&lt;br /&gt;
* Make visible the Group hierarchies (if any) in the underlying data granule as these would have been suppressed otherwise, as CF does not yet support Groups.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
By default &#039;&#039;get_dmrpp&#039;&#039; the &#039;&#039;H5.EnableCF&#039;&#039; option is set to true:&lt;br /&gt;
 H5.EnableCF = true&lt;br /&gt;
&lt;br /&gt;
===Missing data, the CF conventions and &#039;&#039;hdf5&#039;&#039;===&lt;br /&gt;
&lt;br /&gt;
Many of the &#039;&#039;hdf5&#039;&#039; files produced by NASA and others do not contain the domain coordinate data (such as latitude, longitude, time, etc.) as a collection of explicit values. Instead information contained in the dataset metadata can used to reproduce these values. &lt;br /&gt;
&lt;br /&gt;
In order for a dataset to be Climate Forecast (CF) compatible it must contain these domain coordinate data values.&lt;br /&gt;
&lt;br /&gt;
The Hyrax &#039;&#039;hdf5_handler&#039;&#039; software, utilized by the &#039;&#039;get_dmrpp&#039;&#039; application, can create this data from the dataset metadata.  The &#039;&#039;get_dmrpp&#039;&#039; application places these generated data in a “sidecar” file for deployment with the source &#039;&#039;hdf5/netcdf&#039;&#039;-4 file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hyrax - Serving data using dmr++ files==&lt;br /&gt;
&lt;br /&gt;
There are three fundamental deployment scenarios for using dmr++ files to serve data with the Hyrax data server.&lt;br /&gt;
&lt;br /&gt;
This can be simple categorized as follows:&lt;br /&gt;
The dmr++ file(s) are XML files that contain a root &amp;lt;tt&amp;gt;dap4:Dataset&amp;lt;/tt&amp;gt; element with a &amp;lt;tt&amp;gt;dmrpp:href&amp;lt;/tt&amp;gt; attribute whose value is one of:&lt;br /&gt;
# An http(s):// URL referencing to the underlying granule files via http.&lt;br /&gt;
# A file:// URL that references the granule file on the local filesystem in a location that is inside the BES&#039; data root tree.&lt;br /&gt;
# The template string &amp;lt;tt&amp;gt;OPeNDAP_DMRpp_DATA_ACCESS_URL&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each will discussed in turn below. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: By default Hyrax will automatically associate files whose name ends with &amp;quot;.dmrpp&amp;quot; with the dmr++ handler.&lt;br /&gt;
&lt;br /&gt;
===Using dmr++ with http(s) URLs===&lt;br /&gt;
&lt;br /&gt;
If the dmr++ files that you wish to serve contain &amp;lt;tt&amp;gt;dmrpp:href&amp;lt;/tt&amp;gt; attributes whose values are http(s) URLs then there are 2+1 steps to serve the data:&lt;br /&gt;
# Place the dmr++ files on the local disk inside of the directory tree identified by the &amp;lt;tt&amp;gt;BES.Catalog.catalog.RootDirectory&amp;lt;/tt&amp;gt; in the BES configuration&lt;br /&gt;
# Ensure that the Hyrax AllowedHosts list is configured to allow Hyrax to access those target URLs. This can be accomplished by adding new regex entires to the AllowedHosts list in /etc/bes/site.conf, creating that file as need be.&lt;br /&gt;
# If the data URLs require authentication to access then you&#039;ll need to configure Hyrax for that too.&lt;br /&gt;
&lt;br /&gt;
===Using dmr++ with file URLs===&lt;br /&gt;
&lt;br /&gt;
Using dmr++ files with locally held files can be useful for verifying that dmr++ functionality is working without relying on network access that may have data rate limits, authenticated access configuration, or security access constraints. Additionally, in many cases the dmr++ access to the locally held data may be significantly faster than through the native netcdf-4/hdf5 data handlers.&lt;br /&gt;
&lt;br /&gt;
In order to use dmr++ files that contain file:// URLs:&lt;br /&gt;
# Place the dmr++ files on the local disk inside of the directory tree identified by the &amp;lt;tt&amp;gt;BES.Catalog.catalog.RootDirectory&amp;lt;/tt&amp;gt; in the BES configuration&lt;br /&gt;
# Ensure the the dmr++ files contain only file:// URLs that refer to data granule files inside of the directory tree identified by the &amp;lt;tt&amp;gt;BES.Catalog.catalog.RootDirectory&amp;lt;/tt&amp;gt; in the BES configuration.&lt;br /&gt;
&lt;br /&gt;
Note: For Hyrax, a correctly formatted file URL must start with the protocol &amp;lt;tt&amp;gt;file://&amp;lt;/tt&amp;gt; followed by the full qualified path to the data granule, for example:  &lt;br /&gt;
 /usr/share/hyrax/ghrsst/some_granule.h5&lt;br /&gt;
so the the completed URL will have three slashes after the first colon:&lt;br /&gt;
 file:///usr/share/hyrax/ghrsst/some_granule.h5&lt;br /&gt;
&lt;br /&gt;
===Using dmr++ with the template string.===&lt;br /&gt;
&lt;br /&gt;
Another way to server dmr++ files with Hyrax is to build the dmr++ files &#039;&#039;&#039;without&#039;&#039;&#039; valid URLs but with a template string that is replaced at runtime. If no target URL is supplied to get_drmpp at the time that the dmr++ is generated the template string: &amp;lt;tt&amp;gt; OPeNDAP_DMRpp_DATA_ACCESS_URL&amp;lt;/tt&amp;gt; will added to the file in place of the URL. The at runtime it can be replaced withe the correct value.&lt;br /&gt;
&lt;br /&gt;
Currently the only implementation of this is Hyrax&#039;s NGAP service which, when deployed in the NASA NGAP cloud, will accept &amp;quot;restified path&amp;quot; URLs that are defined as&lt;br /&gt;
having a URL path component with two mandatory and one optional parameters:&lt;br /&gt;
 MANDATORY: &amp;quot; /collections/UMM-C:{concept-id} &amp;quot;&lt;br /&gt;
 OPTIONAL:  &amp;quot;/UMM-C:{ShortName} &#039;.&#039; UMM-C:{Version} &amp;quot;&lt;br /&gt;
 MANDATORY: &amp;quot;/granules/UMM-G:{GranuleUR}&amp;quot;&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039; &amp;lt;tt&amp;gt;https://opendap.earthdata.nasa.gov/collections/C1443727145-LAADS/MOD08_D3.v6.1/granules/MOD08_D3.A2020308.061.2020309092644.hdf.nc&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When encountering this type of URL Hyrax will decompose it and use the content to formulate a query to the NASA CMR in order to retrieve the data access URL for the granule and for the dmr++ file. It then retrieves the dmr++ file and injects the data URL so that data access can proceed as described above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://wiki.earthdata.nasa.gov/display/DUTRAIN/Feature+analysis%3A+Restified+URL+for+OPENDAP+Data+Access More on the Restified Path can be found here],&lt;br /&gt;
&lt;br /&gt;
== Recipe: Building and testing dmr++ files using Hyrax docker containers ==&lt;br /&gt;
Prerequisites: &lt;br /&gt;
* Docker daemon running on a system that also supports a shell (the examples use &amp;lt;tt&amp;gt;bash&amp;lt;/tt&amp;gt; in this section)&lt;br /&gt;
=== Recipe: Building dmr++ files using a Hyrax docker container.===&lt;br /&gt;
# Acquire representative granule files for the collection your wish to import. Put them on the system that is running the Docker daemon. For this recipe we will assume that these files have been placed in the directory:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;/tmp/dmrpp&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Get the most up to date Hyrax docker image:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;docker pull opendap/hyrax:snapshot&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Start docker container, mounting your data directory on to the docker image at &amp;lt;tt&amp;gt;/usr/share/hyrax&amp;lt;/tt&amp;gt;:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;docker run -d -h hyrax -p 8080:8080 --volume /tmp/dmrpp:/usr/share/hyrax --name=hyrax opendap/hyrax:snapshot&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Login to the docker container:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;docker exec -it hyrax /bin/bash&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Change working dir to data dir:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;cd /usr/share/hyrax&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Get a first view of your data using the default &amp;lt;tt&amp;gt;get_dmrpp&amp;lt;/tt&amp;gt;. This script assumes your ingestable data files end with &amp;lt;tt&amp;gt;.h5&amp;lt;/tt&amp;gt;, and the resulting dmr++ files will contain &amp;lt;tt&amp;gt;file://&amp;lt;/tt&amp;gt; URLs so that they may be easily tested with the docker instance.&lt;br /&gt;
#: &amp;lt;tt&amp;gt;#!/bin/bash&amp;lt;/tt&amp;gt;&lt;br /&gt;
#: &amp;lt;tt&amp;gt;for file in *.h5&amp;lt;/tt&amp;gt;&lt;br /&gt;
#: &amp;lt;tt&amp;gt;do&amp;lt;/tt&amp;gt;&lt;br /&gt;
#:: &amp;lt;tt&amp;gt;dmrpp_file=&amp;quot;${file}.dmrpp&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
#:: &amp;lt;tt&amp;gt;get_dmrpp -b `pwd` -o &amp;quot;${dmrpp_file}&amp;quot; -u &amp;quot;file://&amp;quot;`pwd`&amp;quot;/${file}&amp;quot; &amp;quot;${file}&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
#: &amp;lt;tt&amp;gt;done&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Use the running Hyrax server to look at the dmrpp files you just created by pointing your browser at:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;http://localhost:8080/opendap/&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testing and qualifying dmr++ files ===&lt;br /&gt;
In the previous section/step we created some initial dmr++ files using the default configuration. It is crucial to make sure that they provide the representation of the data that you and your users are expecting, and that they will work correctly with the Hyrax server. (See the following sections for details). If the generated dmr++ files do not match expectations then the default configuration of the &amp;lt;tt&amp;gt;get_dmrpp&amp;lt;/tt&amp;gt; may need to be amended using the &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
If the data are currently being served by your DAAC&#039;s on-prem team this is where understanding exactly what the localizations made to the configurations of the on-prem Hyrax instances deployed for the collection is important. These localization will probably need to be injected into &amp;lt;tt&amp;gt;get_drmpp&amp;lt;/tt&amp;gt; in order to produce the correct data representation in the dmr++ files.&lt;br /&gt;
&lt;br /&gt;
=== Flattening Groups ===&lt;br /&gt;
By default &amp;lt;tt&amp;gt;get_dmrpp&amp;lt;/tt&amp;gt; will preserve and show group hierarchies. If this is not desired, say for CF-1.0 compatibility, then you can change this by creating a small amendment to &amp;lt;tt&amp;gt;get_dmrpp&amp;lt;/tt&amp;gt;&#039;s default configuration. &lt;br /&gt;
First create the amending configuration file:&lt;br /&gt;
 echo &amp;quot;H5.EnableCF=true&amp;quot; &amp;gt; site.conf&lt;br /&gt;
Then, change the invocation of &amp;lt;tt&amp;gt;get_dmrpp&amp;lt;/tt&amp;gt; in the above example by adding the &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; switch:&lt;br /&gt;
 get_dmrpp -s site.conf -b `pwd` -o &amp;quot;${dmrpp_file}&amp;quot; -u &amp;quot;file://&amp;quot;`pwd`&amp;quot;/${file}&amp;quot; &amp;quot;${file}&amp;quot;&lt;br /&gt;
And re-run the dmr++ production as shown above.&lt;br /&gt;
&lt;br /&gt;
==== Unwanted Side Effects ====&lt;br /&gt;
A side effect of setting &amp;lt;tt&amp;gt;H5.EnableCF=true&amp;lt;/tt&amp;gt; is that some data types that are not represented in the DAP2 (and possibly early CF conventions) will be promoted to a different type, as is the case with signed bytes which are promoted to signed 16bit integers. Or, as in the case of 64bit integers, they may be elided from the dataset. &lt;br /&gt;
&lt;br /&gt;
The promotion of variables in the creation of the dmr++ will create runtime problems and must, at least for now, be studiously avoided. Much of the legacy data being ripped to dmr++ may benefit from the default configuration of &amp;lt;tt&amp;gt;H5.EnableCF=true&amp;lt;/tt&amp;gt; and the variable promotion behavior will not be an issue. However, for many of the more recently developed datasets this promotion must be carefully avoided.&lt;br /&gt;
&lt;br /&gt;
How does one tell this is an issue for a particular dataset/collection? &lt;br /&gt;
: &#039;&#039;By using either the &amp;lt;tt&amp;gt;ncdump&amp;lt;/tt&amp;gt; or the &amp;lt;tt&amp;gt;h5dump&amp;lt;/tt&amp;gt; command one can see the native datatypes on the file.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Example (&#039;&#039;semantic metadata elided for readability/compactness&#039;&#039;):&lt;br /&gt;
 ncdump -h 20020601090000-JPL-L4_GHRSST-SSTfnd-MUR-GLOB-v02.0-fv04.1.nc&lt;br /&gt;
 netcdf \20020601090000-JPL-L4_GHRSST-SSTfnd-MUR-GLOB-v02.0-fv04.1 {&lt;br /&gt;
 dimensions:&lt;br /&gt;
     time = 1 ;&lt;br /&gt;
      lat = 17999 ;&lt;br /&gt;
      lon = 36000 ;&lt;br /&gt;
 variables:&lt;br /&gt;
      int time(time) ;&lt;br /&gt;
      float lat(lat) ;&lt;br /&gt;
      float lon(lon) ;&lt;br /&gt;
      short analysed_sst(time, lat, lon) ;&lt;br /&gt;
      short analysis_error(time, lat, lon) ;&lt;br /&gt;
      byte mask(time, lat, lon) ;&lt;br /&gt;
      byte sea_ice_fraction(time, lat, lon) ;&lt;br /&gt;
We can see two variables, &amp;lt;tt&amp;gt;mask&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;sea_ice_fraction&amp;lt;/tt&amp;gt;, whose type is signed byte. The default setting of &amp;lt;tt&amp;gt;H5.EnableCF=true&amp;lt;/tt&amp;gt; will cause these two variables to be promoted in the resulting dmr++ to &amp;lt;tt&amp;gt;short&amp;lt;/tt&amp;gt; (aka &amp;lt;tt&amp;gt;Int16&amp;lt;/tt&amp;gt;) and that spells trouble for the dmr++ service. In &amp;quot;normal/legacy&amp;quot; server operations the promotion and subsequent type casting of the data values are handled in a single operation by either the &#039;&#039;netcdf_handler&#039;&#039; or the &#039;&#039;hdf5_handler&#039;&#039;. But in the dmr++ operation these activities happen at separate times, and the downstream code knows not of the promotion which will cause data corruption issues in the servers responses. The fix is easy, rerun &amp;lt;tt&amp;gt;get_dmrpp&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; switch and inject &amp;lt;tt&amp;gt;H5.EnableCF=false&amp;lt;/tt&amp;gt; to quell this behavior.&lt;br /&gt;
&lt;br /&gt;
=== DAP representations ===&lt;br /&gt;
We have test and assurance procedures for DAP4 and DAP2 protocols below. Both are important. For legacy datasets the DAP2 request API is widely used by an existing client base and should continue to be supported. Since DAP4 subsumes DAP2 (but with somewhat different API semantics) It should be checked for legacy datasets as well. For more modern datasets that content DAP4 types such as Int64 that are not part of the DAP2 specification or implementations we will need to relying eliding the instances of unmapped types, or return an error when this is encountered.&lt;br /&gt;
 # Test Constants:&lt;br /&gt;
 GRANULE_FILE=&amp;quot;some_name.h5&amp;quot;&lt;br /&gt;
 # Granule URL&lt;br /&gt;
 gf_url=&amp;quot;http://localhost:8080/opendap/${GRANULE_FILE}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Inspect the dmr++ files====&lt;br /&gt;
# Do the dmr++ files have the expected dmrpp:href URL(s)?&lt;br /&gt;
#: &amp;lt;tt&amp;gt;head -2 ${GRANULE_FILE}.dmrpp&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Check DAP4 DMR Response ====&lt;br /&gt;
Inspect &amp;lt;tt&amp;gt;${gf_url}.dmrpp.dmr&amp;lt;/tt&amp;gt; &lt;br /&gt;
# Get the document, save as &amp;lt;tt&amp;gt;foo.dmr&amp;lt;/tt&amp;gt;:&lt;br /&gt;
#: &amp;lt;tt&amp;gt;curl -L -o foo.dmr &amp;quot;${gf_url}.dmr&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Is each variable&#039;s data type correct and as expected? &lt;br /&gt;
# Are the associated dimensions correct?&lt;br /&gt;
&lt;br /&gt;
==== DAP4 Check binary data response ====&lt;br /&gt;
&lt;br /&gt;
For a particular granule GRANULE_FILE and a particular variable VARIABLE_NAME (Where [https://docs.opendap.org/index.php?title=DAP4:_Specification_Volume_1#Fully_Qualified_Names VARIABLE_NAME is a full qualified DAP4 name.]):&lt;br /&gt;
:&amp;lt;tt&amp;gt; curl -L -o dap4_subset_file &amp;quot;${gf_url}.dap?dap4.ce=VARIABLE_NAME&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
:&amp;lt;tt&amp;gt; curl -L -o dap4_subset_dmrpp &amp;quot;${gf_url}.dmrpp.dap?dap4.ce=VARIABLE_NAME&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
:&amp;lt;tt&amp;gt; cmp dap4_subset_file dap4_subset_dmrpp&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== DAP4 UI test ====&lt;br /&gt;
* View and exercise the DAP4 Data Request Form &amp;lt;tt&amp;gt;{gf_url}.dmr.html&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== DAP2 Check DDS Response ====&lt;br /&gt;
&lt;br /&gt;
# Inspect &amp;lt;tt&amp;gt;${gf_url}.dds&amp;lt;/tt&amp;gt;&lt;br /&gt;
## Is each variable&#039;s data type correct and as expected? &lt;br /&gt;
## Are the associated dimensions correct?&lt;br /&gt;
# Compare DMR++ DDS with granule file DDS. &lt;br /&gt;
#:For a particular granule GRANULE_FILE and a particular variable VARIABLE_NAME (Where [https://cdn.earthdata.nasa.gov/conduit/upload/512/ESE-RFC-004v1.1.pdf VARIABLE_NAME is a DAP2 name.]):&lt;br /&gt;
#::&amp;lt;tt&amp;gt; curl -L -o dap2_dds_file &amp;quot;${gf_url}.dds&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
#::&amp;lt;tt&amp;gt; curl -L -o dap2_dds_dmrpp &amp;quot;${gf_url}.dds&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
#::&amp;lt;tt&amp;gt; cmp dap2_dds_file dap2_dds_dmrpp &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== DAP2 Check binary data response ====&lt;br /&gt;
&lt;br /&gt;
For a particular granule GRANULE_FILE and a particular variable VARIABLE_NAME (Where [https://cdn.earthdata.nasa.gov/conduit/upload/512/ESE-RFC-004v1.1.pdf VARIABLE_NAME is a DAP2 name.]):&lt;br /&gt;
:&amp;lt;tt&amp;gt; curl -L -o dap2_subset_file &amp;quot;${gf_url}.dods?VARIABLE_NAME&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
:&amp;lt;tt&amp;gt; curl -L -o dap2_subset_dmrpp &amp;quot;${gf_url}.dmrpp.dods?VARIABLE_NAME&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
:&amp;lt;tt&amp;gt; cmp dap2_subset_file dap2_subset_dmrpp&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: One might consider doing this with two or more variables.&lt;br /&gt;
&lt;br /&gt;
==== DAP2 UI Test ====&lt;br /&gt;
* View and exercise the DAP2 Data Request Form located here: &amp;lt;tt&amp;gt;{gf_url}.html&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Try it in Panoply!&lt;br /&gt;
** Open Panoply.&lt;br /&gt;
** From the &#039;&#039;&#039;File&#039;&#039;&#039; menu select &#039;&#039;&#039;Open Remote Dataset...&#039;&#039;&#039;&lt;br /&gt;
** Paste the &amp;lt;tt&amp;gt;{gf_url}.html&amp;lt;/tt&amp;gt; into the resulting dialog box.&lt;br /&gt;
---&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=File:Winter-ESIP-2015_Web-Services-Performance-Panel.pdf&amp;diff=11628</id>
		<title>File:Winter-ESIP-2015 Web-Services-Performance-Panel.pdf</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=File:Winter-ESIP-2015_Web-Services-Performance-Panel.pdf&amp;diff=11628"/>
		<updated>2015-03-05T19:13:00Z</updated>

		<summary type="html">&lt;p&gt;Dan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Meetings&amp;diff=11627</id>
		<title>Meetings</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Meetings&amp;diff=11627"/>
		<updated>2015-03-05T19:12:29Z</updated>

		<summary type="html">&lt;p&gt;Dan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--&lt;br /&gt;
* [[Developer&#039;s Meeting|Fall 2008 Developer&#039;s Meeting]] &amp;lt;font size=&amp;quot;-2&amp;quot;&amp;gt;Tentatively scheduled for early Fall 2008&amp;lt;/font&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
* [[OPeNDAP Developer&#039;s Workshop 2010]]&lt;br /&gt;
* [[OPeNDAP Developer&#039;s Workshop 2007]]&lt;br /&gt;
* [[OPeNDAP Workshops at APAC and the Australian BOM, Oct. 2007.]]&lt;br /&gt;
* 2015 ESIP Winter Meeting - Panel Discussion: [[Media:Winter-ESIP-2015 Web-Services-Performance-Panel.pdf | Improving Performance for Data Access Web Services]]&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11626</id>
		<title>Hyrax WMS</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11626"/>
		<updated>2015-03-05T16:18:02Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* Theory of Operation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hyrax now works with [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
With the recent addition of the Dynamic Services feature in the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS WMS Server] from [http://www.resc.reading.ac.uk/ Reading e-Science Centre] Hyrax can now provide WMS services for all of it&#039;s appropriate holdings.&lt;br /&gt;
&lt;br /&gt;
=== Theory of Operation ===&lt;br /&gt;
In an instance of the ncWMS a Dynamic Service is configured that points to a Hyrax server. This allows the ncWMS instance to access all of the holdings of the DAP server. However, the ncWMS does not &amp;quot;crawl&amp;quot; or &amp;quot;discover&amp;quot; or in any other way catalog or inventory the DAP server. Instead the user configures the Hyrax server to add the WMS service to its catalogs and services content. Hyrax then directs WMS traffic to the ncWMS. The ncWMS in turn retrieves the data directly from Hyrax and services the request.&lt;br /&gt;
 &lt;br /&gt;
The ncWMS instance may be hosted anywhere, however for a significant performance improvement we suggest you host your own ncWMS running in the same Tomcat instance as Hyrax. With such a configuration the WMS response performance for datasets backed by the DAP service is nearly as fast as the ncWMS response performance using direct file access.&lt;br /&gt;
&lt;br /&gt;
=== Evaluating Candidate Datasets ===&lt;br /&gt;
&lt;br /&gt;
In order for ncWMS to recognize your dataset as valid for service your data must:&lt;br /&gt;
* Contain gridded data (as DAP Grid objects or DAP Array objects utilizing shared dimensional coordinate arrays) &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/v4.3/netcdf-java/tutorial/GridDatatype.html as described by the Unidata Common Data Model]&#039;&#039;&#039;.&lt;br /&gt;
* The NetCDF-Java library (which is what provides data access services for ncWMS) utilizes the Common Data Model and must be able to identify the coordinates system used. You can test this by using the &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/current/netcdf-java/documentation.htm Unidata ToolsUI application]&#039;&#039;&#039; (which is also based on the NetCDF-Java library). Open your dataset with &#039;&#039;&#039;ToolsUI&#039;&#039;&#039;, and in the &#039;&#039;&#039;Feature Types -&amp;gt; Grid Panel&#039;&#039;&#039; there should be one or more variables shown with some kind of coordinate system.&lt;br /&gt;
[[File:ToolsUI-GridView.png|left|frame|ToolsUI Grid View]]&lt;br /&gt;
 &amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 &#039;&#039;Note that &#039;&#039;&#039;ToolsUI&#039;&#039;&#039; supports opening both local files and remote (http accessible) datasets.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== WMS Installation (suggested) ==&lt;br /&gt;
&lt;br /&gt;
The ncWMS web application is easy to install. &lt;br /&gt;
&lt;br /&gt;
Simply:&lt;br /&gt;
&lt;br /&gt;
* Go to the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS web site] and download the WAR (Web ARchive) file for the latest version of ncWMS. &lt;br /&gt;
&lt;br /&gt;
* Place the WAR file in the  &#039;&#039;$CATALINA_HOME/webapps&#039;&#039; directory&lt;br /&gt;
&lt;br /&gt;
* Restart Tomcat&lt;br /&gt;
&lt;br /&gt;
== OLFS/Hyrax Installation ==&lt;br /&gt;
&lt;br /&gt;
As of the release of Hyrax 1.10.0 (and in particular OLFS 1.12.0) the support for WMS will be built into the server. All that is required is a (collocated) ncWMS instance and then the configuration steps as detailed below. So - get the latest Hyrax (1.10.0 or later) install and configure using the normal methods and then follow the configuration steps detailed below.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The following sub sections assume that you have installed both Hyrax and the ncWMS on your server in a single Tomcat instance running on port 8080. If your arrangement is otherwise you will need to adjust accordingly. &lt;br /&gt;
&lt;br /&gt;
For the following example sections we will use the following URLs:&lt;br /&gt;
* Your Tomcat server: http://servername.org:8080/&lt;br /&gt;
* Top level of DAP server:  http://servername.org:8080/opendap&lt;br /&gt;
* Top Level of ncWMS: http://servername.org:8080/ncWMS&lt;br /&gt;
* WMS Service: http://servername.org:8080/ncWMS/wms&lt;br /&gt;
* Godiva: http://servername.org:8080/ncWMS/godiva2.html&lt;br /&gt;
&lt;br /&gt;
=== ncWMS configuration ===&lt;br /&gt;
&lt;br /&gt;
==== Authenticate as the Administrator ====&lt;br /&gt;
Go to the ncWMS administration page:  http://servername.org:8080/ncWMS/admin/&lt;br /&gt;
&lt;br /&gt;
This page requires a simple authentication step where the default username is &#039;admin&#039; and the default password is &#039;ncWMS&#039; . &lt;br /&gt;
&lt;br /&gt;
If you are deploying your server in a publicly accessible environment we strongly recommend that you:&lt;br /&gt;
# Change that default password.&lt;br /&gt;
# If you are using Apache httpd as the authentication engine for your service you should add a security constraint for the location &amp;lt;Location /ncWMS/admn&amp;gt; that limits the access to a select group of administrators.&lt;br /&gt;
&lt;br /&gt;
==== Configure a Dynamic Service ====&lt;br /&gt;
Once you have authenticated and can view the ncWMS admin page, scroll down to the Dynamic Services section:&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
[[File:Screen_Shot_2014-08-11_at_12.34.19_PM.png|border|ncWMS Admin Page - Partial Screen Grab]]&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a new Dynamic Service for Hyrax:&lt;br /&gt;
* Choose and enter a unique ID. (Write it down, you&#039;ll need it later) The screen shot shows &#039;lds&#039; for &#039;local dap service&#039; which we will use for the rest of these examples.&lt;br /&gt;
* The value of the &#039;&#039;Service URL&#039;&#039; field will be the URL for the top level of the Hyrax server. &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running together in a single Tomcat instance then this URL &#039;&#039;&#039;should&#039;&#039;&#039; be expressed as: http://localhost:8080/opendap  &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running on separate systems this URL &#039;&#039;&#039;must&#039;&#039;&#039; be a DAP server top level URL, and not a localhost URL.&lt;br /&gt;
** &#039;&#039;&#039;Best WMS response performance will be achieved by running ncWMS and Hyrax on the same server and providing the &#039;&#039;localhost&#039;&#039; URL here.&#039;&#039;&#039;&lt;br /&gt;
* The Dataset Match Regex should be a regex that matches of all of the data files you have for which WMS can prove services. If that&#039;s too cumbersome then just use &#039;.*&#039; (as in the example) which matches everything.&lt;br /&gt;
* Scroll to the bottom of the page and save the configuration.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary&#039;&#039;&#039;&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&lt;br /&gt;
! Unique ID&lt;br /&gt;
! Service URL&lt;br /&gt;
! Dataset Match Regex&lt;br /&gt;
! Disabled?&lt;br /&gt;
! Remove&lt;br /&gt;
! Data Reading Class&lt;br /&gt;
! Link to more info&lt;br /&gt;
! Copyright Statement&lt;br /&gt;
|-&lt;br /&gt;
|lds&lt;br /&gt;
|http://localhost:8080/opendap&lt;br /&gt;
|.*&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hyrax Configuration ===&lt;br /&gt;
&lt;br /&gt;
The Hyrax WMS configuration is contained in the file  &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;. This file identifies data viewers and Web Services that Hyrax can provide for datasets. There are two relevant sections, the first defines Hyrax&#039;s view of the WMS service and the second enables Hyrax to provide access to the Godiva service that is part of ncWMS.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Edit the file &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Uncomment the following sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;http://YourServersNameHere:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== NcWmsServce ====&lt;br /&gt;
&lt;br /&gt;
In the first section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
* NB: The &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the ncWMS service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== GodivaWebService ====&lt;br /&gt;
&lt;br /&gt;
In the second section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;http://yourNcWMSserver:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
* The value of the &#039;&#039;href&#039;&#039; attribute is the fully qualified URL for public access to your WMS service. The server name in this &#039;&#039;href&#039;&#039; will &#039;&#039;&#039;never&#039;&#039;&#039; be &#039;&#039;localhost&#039;&#039; - Godiva won&#039;t work. (Well OK, if your browser is running on the same system as the ncWMS instance then it would but it won&#039;t work for anybody else)&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Godiva&#039;&#039; element&#039;s &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the Godiva service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
== Start and Test ==&lt;br /&gt;
&lt;br /&gt;
* Once the configuration steps are complete restart your Tomcat server.&lt;br /&gt;
* Point your browser at the Hyrax sever and navigate to a WMS-suitable dataset. &lt;br /&gt;
* Clicking the dataset&#039;s &#039;&#039;&#039;Viewers&#039;&#039;&#039; link should return a page with both WMS and Godiva links.&lt;br /&gt;
* Try &#039;em.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Issues ==&lt;br /&gt;
&lt;br /&gt;
=== Logging Issue ===&lt;br /&gt;
&lt;br /&gt;
There is a small issue with deploying this configuration onto some Linux system in which everything has been installed from RPM (except maybe Tomcat and it&#039;s components including the ncWMS and Hyrax applications)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== The Symptom ====&lt;br /&gt;
&lt;br /&gt;
The issue appears in the Tomcat log as a failure to lock files associated with the java.util.prefs.FileSystemPreferences:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;systemverilog&amp;quot;&amp;gt;&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And is logged every 30 seconds or so. So the problem is the logs fill up with this issue and not stuff we care about. The problem is that the files/directories in question either don&#039;t exist, or, if they do exist the Tomcat user does not have read/write permissions on them.&lt;br /&gt;
&lt;br /&gt;
==== The Fix ====&lt;br /&gt;
&lt;br /&gt;
I looked around and discovered that a number of people (including TDS deployers) had experienced this issue. It&#039;s a Linux problem and involves the existence and permissions of a global system preferences directory. I think this is only an issue on Linux systems in which everything is installed via yum/rpm, which may be why we only see this problem on certain systems, but I not 100% confident that the issue is limited only to this type of installation.&lt;br /&gt;
&lt;br /&gt;
I found and tested these two ways to solve it:&lt;br /&gt;
&lt;br /&gt;
; 1) Create the global System Preference directory and set the owner to the Tomcat user&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   sudo mkdir -P /etc/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /etc/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: This could also be accomplished by changing the group ownership to the tomcat-group and setting the group read/write flags.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2) Create your own java System Preference directory and then set the JAVA_OPTS environment variable so that the systemRoot value is set the new directory&lt;br /&gt;
Create the directory&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   mkdir -P /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then, in each shell that launches Tomcat:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   export JAVA_OPTS=&amp;quot;-Djava.util.prefs.systemRoot=/home/tomcat-user/.java&amp;quot;&lt;br /&gt;
   $CATALINA_HOME/bin/startup.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11625</id>
		<title>Hyrax WMS</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11625"/>
		<updated>2015-03-05T16:14:05Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* Configure a Dynamic Service */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hyrax now works with [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
With the recent addition of the Dynamic Services feature in the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS WMS Server] from [http://www.resc.reading.ac.uk/ Reading e-Science Centre] Hyrax can now provide WMS services for all of it&#039;s appropriate holdings.&lt;br /&gt;
&lt;br /&gt;
=== Theory Of Operation ===&lt;br /&gt;
In an instance of the ncWMS a Dynamic Service is configured that points to a Hyrax server. This allows the ncWMS instance to access all of the holdings of the DAP server. However, the ncWMS does not &amp;quot;crawl&amp;quot; or &amp;quot;discover&amp;quot; or in any other way catalog or inventory the DAP server. Instead the user configures the Hyrax server to add the WMS service to its catalogs and services content. Hyrax then directs WMS traffic to the ncWMS. The ncWMS in turn retrieves the data directly from Hyrax and services the request.&lt;br /&gt;
 &lt;br /&gt;
The ncWMS instance may be hosted anywhere, however for a significant performance improvement we suggest you host your own ncWMS running in the same Tomcat instance as Hyrax. With such a configuration the WMS response performance for datasets backed by the DAP service is nearly as fast as the ncWMS response performance using direct file access.&lt;br /&gt;
&lt;br /&gt;
=== Evaluating Candidate Datasets ===&lt;br /&gt;
&lt;br /&gt;
In order for ncWMS to recognize your dataset as valid for service your data must:&lt;br /&gt;
* Contain gridded data (as DAP Grid objects or DAP Array objects utilizing shared dimensional coordinate arrays) &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/v4.3/netcdf-java/tutorial/GridDatatype.html as described by the Unidata Common Data Model]&#039;&#039;&#039;.&lt;br /&gt;
* The NetCDF-Java library (which is what provides data access services for ncWMS) utilizes the Common Data Model and must be able to identify the coordinates system used. You can test this by using the &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/current/netcdf-java/documentation.htm Unidata ToolsUI application]&#039;&#039;&#039; (which is also based on the NetCDF-Java library). Open your dataset with &#039;&#039;&#039;ToolsUI&#039;&#039;&#039;, and in the &#039;&#039;&#039;Feature Types -&amp;gt; Grid Panel&#039;&#039;&#039; there should be one or more variables shown with some kind of coordinate system.&lt;br /&gt;
[[File:ToolsUI-GridView.png|left|frame|ToolsUI Grid View]]&lt;br /&gt;
 &amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 &#039;&#039;Note that &#039;&#039;&#039;ToolsUI&#039;&#039;&#039; supports opening both local files and remote (http accessible) datasets.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== WMS Installation (suggested) ==&lt;br /&gt;
&lt;br /&gt;
The ncWMS web application is easy to install. &lt;br /&gt;
&lt;br /&gt;
Simply:&lt;br /&gt;
&lt;br /&gt;
* Go to the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS web site] and download the WAR (Web ARchive) file for the latest version of ncWMS. &lt;br /&gt;
&lt;br /&gt;
* Place the WAR file in the  &#039;&#039;$CATALINA_HOME/webapps&#039;&#039; directory&lt;br /&gt;
&lt;br /&gt;
* Restart Tomcat&lt;br /&gt;
&lt;br /&gt;
== OLFS/Hyrax Installation ==&lt;br /&gt;
&lt;br /&gt;
As of the release of Hyrax 1.10.0 (and in particular OLFS 1.12.0) the support for WMS will be built into the server. All that is required is a (collocated) ncWMS instance and then the configuration steps as detailed below. So - get the latest Hyrax (1.10.0 or later) install and configure using the normal methods and then follow the configuration steps detailed below.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The following sub sections assume that you have installed both Hyrax and the ncWMS on your server in a single Tomcat instance running on port 8080. If your arrangement is otherwise you will need to adjust accordingly. &lt;br /&gt;
&lt;br /&gt;
For the following example sections we will use the following URLs:&lt;br /&gt;
* Your Tomcat server: http://servername.org:8080/&lt;br /&gt;
* Top level of DAP server:  http://servername.org:8080/opendap&lt;br /&gt;
* Top Level of ncWMS: http://servername.org:8080/ncWMS&lt;br /&gt;
* WMS Service: http://servername.org:8080/ncWMS/wms&lt;br /&gt;
* Godiva: http://servername.org:8080/ncWMS/godiva2.html&lt;br /&gt;
&lt;br /&gt;
=== ncWMS configuration ===&lt;br /&gt;
&lt;br /&gt;
==== Authenticate as the Administrator ====&lt;br /&gt;
Go to the ncWMS administration page:  http://servername.org:8080/ncWMS/admin/&lt;br /&gt;
&lt;br /&gt;
This page requires a simple authentication step where the default username is &#039;admin&#039; and the default password is &#039;ncWMS&#039; . &lt;br /&gt;
&lt;br /&gt;
If you are deploying your server in a publicly accessible environment we strongly recommend that you:&lt;br /&gt;
# Change that default password.&lt;br /&gt;
# If you are using Apache httpd as the authentication engine for your service you should add a security constraint for the location &amp;lt;Location /ncWMS/admn&amp;gt; that limits the access to a select group of administrators.&lt;br /&gt;
&lt;br /&gt;
==== Configure a Dynamic Service ====&lt;br /&gt;
Once you have authenticated and can view the ncWMS admin page, scroll down to the Dynamic Services section:&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
[[File:Screen_Shot_2014-08-11_at_12.34.19_PM.png|border|ncWMS Admin Page - Partial Screen Grab]]&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a new Dynamic Service for Hyrax:&lt;br /&gt;
* Choose and enter a unique ID. (Write it down, you&#039;ll need it later) The screen shot shows &#039;lds&#039; for &#039;local dap service&#039; which we will use for the rest of these examples.&lt;br /&gt;
* The value of the &#039;&#039;Service URL&#039;&#039; field will be the URL for the top level of the Hyrax server. &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running together in a single Tomcat instance then this URL &#039;&#039;&#039;should&#039;&#039;&#039; be expressed as: http://localhost:8080/opendap  &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running on separate systems this URL &#039;&#039;&#039;must&#039;&#039;&#039; be a DAP server top level URL, and not a localhost URL.&lt;br /&gt;
** &#039;&#039;&#039;Best WMS response performance will be achieved by running ncWMS and Hyrax on the same server and providing the &#039;&#039;localhost&#039;&#039; URL here.&#039;&#039;&#039;&lt;br /&gt;
* The Dataset Match Regex should be a regex that matches of all of the data files you have for which WMS can prove services. If that&#039;s too cumbersome then just use &#039;.*&#039; (as in the example) which matches everything.&lt;br /&gt;
* Scroll to the bottom of the page and save the configuration.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary&#039;&#039;&#039;&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&lt;br /&gt;
! Unique ID&lt;br /&gt;
! Service URL&lt;br /&gt;
! Dataset Match Regex&lt;br /&gt;
! Disabled?&lt;br /&gt;
! Remove&lt;br /&gt;
! Data Reading Class&lt;br /&gt;
! Link to more info&lt;br /&gt;
! Copyright Statement&lt;br /&gt;
|-&lt;br /&gt;
|lds&lt;br /&gt;
|http://localhost:8080/opendap&lt;br /&gt;
|.*&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hyrax Configuration ===&lt;br /&gt;
&lt;br /&gt;
The Hyrax WMS configuration is contained in the file  &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;. This file identifies data viewers and Web Services that Hyrax can provide for datasets. There are two relevant sections, the first defines Hyrax&#039;s view of the WMS service and the second enables Hyrax to provide access to the Godiva service that is part of ncWMS.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Edit the file &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Uncomment the following sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;http://YourServersNameHere:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== NcWmsServce ====&lt;br /&gt;
&lt;br /&gt;
In the first section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
* NB: The &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the ncWMS service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== GodivaWebService ====&lt;br /&gt;
&lt;br /&gt;
In the second section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;http://yourNcWMSserver:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
* The value of the &#039;&#039;href&#039;&#039; attribute is the fully qualified URL for public access to your WMS service. The server name in this &#039;&#039;href&#039;&#039; will &#039;&#039;&#039;never&#039;&#039;&#039; be &#039;&#039;localhost&#039;&#039; - Godiva won&#039;t work. (Well OK, if your browser is running on the same system as the ncWMS instance then it would but it won&#039;t work for anybody else)&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Godiva&#039;&#039; element&#039;s &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the Godiva service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
== Start and Test ==&lt;br /&gt;
&lt;br /&gt;
* Once the configuration steps are complete restart your Tomcat server.&lt;br /&gt;
* Point your browser at the Hyrax sever and navigate to a WMS-suitable dataset. &lt;br /&gt;
* Clicking the dataset&#039;s &#039;&#039;&#039;Viewers&#039;&#039;&#039; link should return a page with both WMS and Godiva links.&lt;br /&gt;
* Try &#039;em.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Issues ==&lt;br /&gt;
&lt;br /&gt;
=== Logging Issue ===&lt;br /&gt;
&lt;br /&gt;
There is a small issue with deploying this configuration onto some Linux system in which everything has been installed from RPM (except maybe Tomcat and it&#039;s components including the ncWMS and Hyrax applications)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== The Symptom ====&lt;br /&gt;
&lt;br /&gt;
The issue appears in the Tomcat log as a failure to lock files associated with the java.util.prefs.FileSystemPreferences:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;systemverilog&amp;quot;&amp;gt;&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And is logged every 30 seconds or so. So the problem is the logs fill up with this issue and not stuff we care about. The problem is that the files/directories in question either don&#039;t exist, or, if they do exist the Tomcat user does not have read/write permissions on them.&lt;br /&gt;
&lt;br /&gt;
==== The Fix ====&lt;br /&gt;
&lt;br /&gt;
I looked around and discovered that a number of people (including TDS deployers) had experienced this issue. It&#039;s a Linux problem and involves the existence and permissions of a global system preferences directory. I think this is only an issue on Linux systems in which everything is installed via yum/rpm, which may be why we only see this problem on certain systems, but I not 100% confident that the issue is limited only to this type of installation.&lt;br /&gt;
&lt;br /&gt;
I found and tested these two ways to solve it:&lt;br /&gt;
&lt;br /&gt;
; 1) Create the global System Preference directory and set the owner to the Tomcat user&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   sudo mkdir -P /etc/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /etc/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: This could also be accomplished by changing the group ownership to the tomcat-group and setting the group read/write flags.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2) Create your own java System Preference directory and then set the JAVA_OPTS environment variable so that the systemRoot value is set the new directory&lt;br /&gt;
Create the directory&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   mkdir -P /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then, in each shell that launches Tomcat:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   export JAVA_OPTS=&amp;quot;-Djava.util.prefs.systemRoot=/home/tomcat-user/.java&amp;quot;&lt;br /&gt;
   $CATALINA_HOME/bin/startup.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11624</id>
		<title>Hyrax WMS</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11624"/>
		<updated>2015-03-05T16:09:18Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* Evaluating Candidate Datasets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hyrax now works with [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
With the recent addition of the Dynamic Services feature in the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS WMS Server] from [http://www.resc.reading.ac.uk/ Reading e-Science Centre] Hyrax can now provide WMS services for all of it&#039;s appropriate holdings.&lt;br /&gt;
&lt;br /&gt;
=== Theory Of Operation ===&lt;br /&gt;
In an instance of the ncWMS a Dynamic Service is configured that points to a Hyrax server. This allows the ncWMS instance to access all of the holdings of the DAP server. However, the ncWMS does not &amp;quot;crawl&amp;quot; or &amp;quot;discover&amp;quot; or in any other way catalog or inventory the DAP server. Instead the user configures the Hyrax server to add the WMS service to its catalogs and services content. Hyrax then directs WMS traffic to the ncWMS. The ncWMS in turn retrieves the data directly from Hyrax and services the request.&lt;br /&gt;
 &lt;br /&gt;
The ncWMS instance may be hosted anywhere, however for a significant performance improvement we suggest you host your own ncWMS running in the same Tomcat instance as Hyrax. With such a configuration the WMS response performance for datasets backed by the DAP service is nearly as fast as the ncWMS response performance using direct file access.&lt;br /&gt;
&lt;br /&gt;
=== Evaluating Candidate Datasets ===&lt;br /&gt;
&lt;br /&gt;
In order for ncWMS to recognize your dataset as valid for service your data must:&lt;br /&gt;
* Contain gridded data (as DAP Grid objects or DAP Array objects utilizing shared dimensional coordinate arrays) &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/v4.3/netcdf-java/tutorial/GridDatatype.html as described by the Unidata Common Data Model]&#039;&#039;&#039;.&lt;br /&gt;
* The NetCDF-Java library (which is what provides data access services for ncWMS) utilizes the Common Data Model and must be able to identify the coordinates system used. You can test this by using the &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/current/netcdf-java/documentation.htm Unidata ToolsUI application]&#039;&#039;&#039; (which is also based on the NetCDF-Java library). Open your dataset with &#039;&#039;&#039;ToolsUI&#039;&#039;&#039;, and in the &#039;&#039;&#039;Feature Types -&amp;gt; Grid Panel&#039;&#039;&#039; there should be one or more variables shown with some kind of coordinate system.&lt;br /&gt;
[[File:ToolsUI-GridView.png|left|frame|ToolsUI Grid View]]&lt;br /&gt;
 &amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 &#039;&#039;Note that &#039;&#039;&#039;ToolsUI&#039;&#039;&#039; supports opening both local files and remote (http accessible) datasets.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== WMS Installation (suggested) ==&lt;br /&gt;
&lt;br /&gt;
The ncWMS web application is easy to install. &lt;br /&gt;
&lt;br /&gt;
Simply:&lt;br /&gt;
&lt;br /&gt;
* Go to the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS web site] and download the WAR (Web ARchive) file for the latest version of ncWMS. &lt;br /&gt;
&lt;br /&gt;
* Place the WAR file in the  &#039;&#039;$CATALINA_HOME/webapps&#039;&#039; directory&lt;br /&gt;
&lt;br /&gt;
* Restart Tomcat&lt;br /&gt;
&lt;br /&gt;
== OLFS/Hyrax Installation ==&lt;br /&gt;
&lt;br /&gt;
As of the release of Hyrax 1.10.0 (and in particular OLFS 1.12.0) the support for WMS will be built into the server. All that is required is a (collocated) ncWMS instance and then the configuration steps as detailed below. So - get the latest Hyrax (1.10.0 or later) install and configure using the normal methods and then follow the configuration steps detailed below.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The following sub sections assume that you have installed both Hyrax and the ncWMS on your server in a single Tomcat instance running on port 8080. If your arrangement is otherwise you will need to adjust accordingly. &lt;br /&gt;
&lt;br /&gt;
For the following example sections we will use the following URLs:&lt;br /&gt;
* Your Tomcat server: http://servername.org:8080/&lt;br /&gt;
* Top level of DAP server:  http://servername.org:8080/opendap&lt;br /&gt;
* Top Level of ncWMS: http://servername.org:8080/ncWMS&lt;br /&gt;
* WMS Service: http://servername.org:8080/ncWMS/wms&lt;br /&gt;
* Godiva: http://servername.org:8080/ncWMS/godiva2.html&lt;br /&gt;
&lt;br /&gt;
=== ncWMS configuration ===&lt;br /&gt;
&lt;br /&gt;
==== Authenticate as the Administrator ====&lt;br /&gt;
Go to the ncWMS administration page:  http://servername.org:8080/ncWMS/admin/&lt;br /&gt;
&lt;br /&gt;
This page requires a simple authentication step where the default username is &#039;admin&#039; and the default password is &#039;ncWMS&#039; . &lt;br /&gt;
&lt;br /&gt;
If you are deploying your server in a publicly accessible environment we strongly recommend that you:&lt;br /&gt;
# Change that default password.&lt;br /&gt;
# If you are using Apache httpd as the authentication engine for your service you should add a security constraint for the location &amp;lt;Location /ncWMS/admn&amp;gt; that limits the access to a select group of administrators.&lt;br /&gt;
&lt;br /&gt;
==== Configure a Dynamic Service ====&lt;br /&gt;
Once you have authenticated and can view the ncWMS admin page, scroll down to the Dynamic Services section:&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
[[File:Screen_Shot_2014-08-11_at_12.34.19_PM.png|border|ncWMS Admin Page - Partial Screen Grab]]&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a new Dynamic Service for Hyrax:&lt;br /&gt;
* Choose and enter a unique ID. (Write it down, you&#039;ll need it later) The screen shot shows &#039;lds&#039; for &#039;local dap service&#039; which we will use for the rest of these examples.&lt;br /&gt;
* The value of the &#039;&#039;Service URL&#039;&#039; field will be the URL for the top level of the Hyrax server. &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running together in a single Tomcat instance then this URL &#039;&#039;&#039;should&#039;&#039;&#039; be expressed as: http://localhost:8080/opendap  &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running on separate systems this URL &#039;&#039;&#039;must&#039;&#039;&#039; be a DAP server top level URL, and not a localhost URL.&lt;br /&gt;
** &#039;&#039;&#039;Best WMS response performance will be achieved by running ncWMS and Hyrax on the same server and providing the &#039;&#039;localhost&#039;&#039; URL here.&#039;&#039;&#039;&lt;br /&gt;
* The Dataset Match Regex should be a regex that matches of all of the data files you have for which WMS can prove services. If that&#039;s a drag, then just do like the example and use &#039;.*&#039; which matches everything.&lt;br /&gt;
* Scroll to the bottom of the page and save the configuration.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary&#039;&#039;&#039;&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&lt;br /&gt;
! Unique ID&lt;br /&gt;
! Service URL&lt;br /&gt;
! Dataset Match Regex&lt;br /&gt;
! Disabled?&lt;br /&gt;
! Remove&lt;br /&gt;
! Data Reading Class&lt;br /&gt;
! Link to more info&lt;br /&gt;
! Copyright Statement&lt;br /&gt;
|-&lt;br /&gt;
|lds&lt;br /&gt;
|http://localhost:8080/opendap&lt;br /&gt;
|.*&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hyrax Configuration ===&lt;br /&gt;
&lt;br /&gt;
The Hyrax WMS configuration is contained in the file  &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;. This file identifies data viewers and Web Services that Hyrax can provide for datasets. There are two relevant sections, the first defines Hyrax&#039;s view of the WMS service and the second enables Hyrax to provide access to the Godiva service that is part of ncWMS.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Edit the file &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Uncomment the following sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;http://YourServersNameHere:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== NcWmsServce ====&lt;br /&gt;
&lt;br /&gt;
In the first section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
* NB: The &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the ncWMS service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== GodivaWebService ====&lt;br /&gt;
&lt;br /&gt;
In the second section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;http://yourNcWMSserver:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
* The value of the &#039;&#039;href&#039;&#039; attribute is the fully qualified URL for public access to your WMS service. The server name in this &#039;&#039;href&#039;&#039; will &#039;&#039;&#039;never&#039;&#039;&#039; be &#039;&#039;localhost&#039;&#039; - Godiva won&#039;t work. (Well OK, if your browser is running on the same system as the ncWMS instance then it would but it won&#039;t work for anybody else)&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Godiva&#039;&#039; element&#039;s &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the Godiva service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
== Start and Test ==&lt;br /&gt;
&lt;br /&gt;
* Once the configuration steps are complete restart your Tomcat server.&lt;br /&gt;
* Point your browser at the Hyrax sever and navigate to a WMS-suitable dataset. &lt;br /&gt;
* Clicking the dataset&#039;s &#039;&#039;&#039;Viewers&#039;&#039;&#039; link should return a page with both WMS and Godiva links.&lt;br /&gt;
* Try &#039;em.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Issues ==&lt;br /&gt;
&lt;br /&gt;
=== Logging Issue ===&lt;br /&gt;
&lt;br /&gt;
There is a small issue with deploying this configuration onto some Linux system in which everything has been installed from RPM (except maybe Tomcat and it&#039;s components including the ncWMS and Hyrax applications)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== The Symptom ====&lt;br /&gt;
&lt;br /&gt;
The issue appears in the Tomcat log as a failure to lock files associated with the java.util.prefs.FileSystemPreferences:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;systemverilog&amp;quot;&amp;gt;&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And is logged every 30 seconds or so. So the problem is the logs fill up with this issue and not stuff we care about. The problem is that the files/directories in question either don&#039;t exist, or, if they do exist the Tomcat user does not have read/write permissions on them.&lt;br /&gt;
&lt;br /&gt;
==== The Fix ====&lt;br /&gt;
&lt;br /&gt;
I looked around and discovered that a number of people (including TDS deployers) had experienced this issue. It&#039;s a Linux problem and involves the existence and permissions of a global system preferences directory. I think this is only an issue on Linux systems in which everything is installed via yum/rpm, which may be why we only see this problem on certain systems, but I not 100% confident that the issue is limited only to this type of installation.&lt;br /&gt;
&lt;br /&gt;
I found and tested these two ways to solve it:&lt;br /&gt;
&lt;br /&gt;
; 1) Create the global System Preference directory and set the owner to the Tomcat user&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   sudo mkdir -P /etc/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /etc/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: This could also be accomplished by changing the group ownership to the tomcat-group and setting the group read/write flags.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2) Create your own java System Preference directory and then set the JAVA_OPTS environment variable so that the systemRoot value is set the new directory&lt;br /&gt;
Create the directory&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   mkdir -P /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then, in each shell that launches Tomcat:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   export JAVA_OPTS=&amp;quot;-Djava.util.prefs.systemRoot=/home/tomcat-user/.java&amp;quot;&lt;br /&gt;
   $CATALINA_HOME/bin/startup.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11623</id>
		<title>Hyrax WMS</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Hyrax_WMS&amp;diff=11623"/>
		<updated>2015-03-05T16:03:51Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* Therory Of Operation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hyrax now works with [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
With the recent addition of the Dynamic Services feature in the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS WMS Server] from [http://www.resc.reading.ac.uk/ Reading e-Science Centre] Hyrax can now provide WMS services for all of it&#039;s appropriate holdings.&lt;br /&gt;
&lt;br /&gt;
=== Theory Of Operation ===&lt;br /&gt;
In an instance of the ncWMS a Dynamic Service is configured that points to a Hyrax server. This allows the ncWMS instance to access all of the holdings of the DAP server. However, the ncWMS does not &amp;quot;crawl&amp;quot; or &amp;quot;discover&amp;quot; or in any other way catalog or inventory the DAP server. Instead the user configures the Hyrax server to add the WMS service to its catalogs and services content. Hyrax then directs WMS traffic to the ncWMS. The ncWMS in turn retrieves the data directly from Hyrax and services the request.&lt;br /&gt;
 &lt;br /&gt;
The ncWMS instance may be hosted anywhere, however for a significant performance improvement we suggest you host your own ncWMS running in the same Tomcat instance as Hyrax. With such a configuration the WMS response performance for datasets backed by the DAP service is nearly as fast as the ncWMS response performance using direct file access.&lt;br /&gt;
&lt;br /&gt;
=== Evaluating Candidate Datasets ===&lt;br /&gt;
&lt;br /&gt;
In order for ncWMS to recognize your dataset as valid for service your data must:&lt;br /&gt;
* Contain gridded data (Either as DAP Grid objects or as data arrays utilizing shared dimensional coordinate arrays) &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/v4.3/netcdf-java/tutorial/GridDatatype.html as described by the Unidata Common Data Model]&#039;&#039;&#039;.&lt;br /&gt;
* The NetCDF-Java library (which is what provides data access services for ncWMS) utilizes the Common Data Model and must be able to identify the coordinates system used. You can test this by using the &#039;&#039;&#039;[http://www.unidata.ucar.edu/software/thredds/current/netcdf-java/documentation.htm Unidata ToolsUI application]&#039;&#039;&#039; (which is also based on the NetCDF-Java library). Open your dataset with &#039;&#039;&#039;ToolsUI&#039;&#039;&#039;, and in the &#039;&#039;&#039;Feature Types -&amp;gt; Grid Panel&#039;&#039;&#039; there should be one or more variables shown with some kind of coordinate system.&lt;br /&gt;
[[File:ToolsUI-GridView.png|left|frame|ToolsUI Grid View]]&lt;br /&gt;
 &amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 &#039;&#039;Note that &#039;&#039;&#039;ToolsUI&#039;&#039;&#039; supports opening both local files and remote (http accessible) datasets.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== WMS Installation (suggested) ==&lt;br /&gt;
&lt;br /&gt;
The ncWMS web application is easy to install. &lt;br /&gt;
&lt;br /&gt;
Simply:&lt;br /&gt;
&lt;br /&gt;
* Go to the [http://www.resc.rdg.ac.uk/trac/ncWMS/ ncWMS web site] and download the WAR (Web ARchive) file for the latest version of ncWMS. &lt;br /&gt;
&lt;br /&gt;
* Place the WAR file in the  &#039;&#039;$CATALINA_HOME/webapps&#039;&#039; directory&lt;br /&gt;
&lt;br /&gt;
* Restart Tomcat&lt;br /&gt;
&lt;br /&gt;
== OLFS/Hyrax Installation ==&lt;br /&gt;
&lt;br /&gt;
As of the release of Hyrax 1.10.0 (and in particular OLFS 1.12.0) the support for WMS will be built into the server. All that is required is a (collocated) ncWMS instance and then the configuration steps as detailed below. So - get the latest Hyrax (1.10.0 or later) install and configure using the normal methods and then follow the configuration steps detailed below.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The following sub sections assume that you have installed both Hyrax and the ncWMS on your server in a single Tomcat instance running on port 8080. If your arrangement is otherwise you will need to adjust accordingly. &lt;br /&gt;
&lt;br /&gt;
For the following example sections we will use the following URLs:&lt;br /&gt;
* Your Tomcat server: http://servername.org:8080/&lt;br /&gt;
* Top level of DAP server:  http://servername.org:8080/opendap&lt;br /&gt;
* Top Level of ncWMS: http://servername.org:8080/ncWMS&lt;br /&gt;
* WMS Service: http://servername.org:8080/ncWMS/wms&lt;br /&gt;
* Godiva: http://servername.org:8080/ncWMS/godiva2.html&lt;br /&gt;
&lt;br /&gt;
=== ncWMS configuration ===&lt;br /&gt;
&lt;br /&gt;
==== Authenticate as the Administrator ====&lt;br /&gt;
Go to the ncWMS administration page:  http://servername.org:8080/ncWMS/admin/&lt;br /&gt;
&lt;br /&gt;
This page requires a simple authentication step where the default username is &#039;admin&#039; and the default password is &#039;ncWMS&#039; . &lt;br /&gt;
&lt;br /&gt;
If you are deploying your server in a publicly accessible environment we strongly recommend that you:&lt;br /&gt;
# Change that default password.&lt;br /&gt;
# If you are using Apache httpd as the authentication engine for your service you should add a security constraint for the location &amp;lt;Location /ncWMS/admn&amp;gt; that limits the access to a select group of administrators.&lt;br /&gt;
&lt;br /&gt;
==== Configure a Dynamic Service ====&lt;br /&gt;
Once you have authenticated and can view the ncWMS admin page, scroll down to the Dynamic Services section:&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
[[File:Screen_Shot_2014-08-11_at_12.34.19_PM.png|border|ncWMS Admin Page - Partial Screen Grab]]&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a new Dynamic Service for Hyrax:&lt;br /&gt;
* Choose and enter a unique ID. (Write it down, you&#039;ll need it later) The screen shot shows &#039;lds&#039; for &#039;local dap service&#039; which we will use for the rest of these examples.&lt;br /&gt;
* The value of the &#039;&#039;Service URL&#039;&#039; field will be the URL for the top level of the Hyrax server. &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running together in a single Tomcat instance then this URL &#039;&#039;&#039;should&#039;&#039;&#039; be expressed as: http://localhost:8080/opendap  &lt;br /&gt;
** If the Hyrax server and the ncWMS server are running on separate systems this URL &#039;&#039;&#039;must&#039;&#039;&#039; be a DAP server top level URL, and not a localhost URL.&lt;br /&gt;
** &#039;&#039;&#039;Best WMS response performance will be achieved by running ncWMS and Hyrax on the same server and providing the &#039;&#039;localhost&#039;&#039; URL here.&#039;&#039;&#039;&lt;br /&gt;
* The Dataset Match Regex should be a regex that matches of all of the data files you have for which WMS can prove services. If that&#039;s a drag, then just do like the example and use &#039;.*&#039; which matches everything.&lt;br /&gt;
* Scroll to the bottom of the page and save the configuration.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary&#039;&#039;&#039;&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&lt;br /&gt;
! Unique ID&lt;br /&gt;
! Service URL&lt;br /&gt;
! Dataset Match Regex&lt;br /&gt;
! Disabled?&lt;br /&gt;
! Remove&lt;br /&gt;
! Data Reading Class&lt;br /&gt;
! Link to more info&lt;br /&gt;
! Copyright Statement&lt;br /&gt;
|-&lt;br /&gt;
|lds&lt;br /&gt;
|http://localhost:8080/opendap&lt;br /&gt;
|.*&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hyrax Configuration ===&lt;br /&gt;
&lt;br /&gt;
The Hyrax WMS configuration is contained in the file  &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;. This file identifies data viewers and Web Services that Hyrax can provide for datasets. There are two relevant sections, the first defines Hyrax&#039;s view of the WMS service and the second enables Hyrax to provide access to the Godiva service that is part of ncWMS.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Edit the file &#039;&#039;$CATALINA_HOME/content/opendap/viewers.xml&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Uncomment the following sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
        &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
        &amp;lt;NcWmsService href=&amp;quot;http://YourServersNameHere:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== NcWmsServce ====&lt;br /&gt;
&lt;br /&gt;
In the first section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.NcWmsService&amp;quot; serviceId=&amp;quot;ncWms&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Web Mapping Service&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
* NB: The &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the ncWMS service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== GodivaWebService ====&lt;br /&gt;
&lt;br /&gt;
In the second section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;WebServiceHandler className=&amp;quot;opendap.viewers.GodivaWebService&amp;quot; serviceId=&amp;quot;godiva&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;applicationName&amp;gt;Godiva WMS GUI&amp;lt;/applicationName&amp;gt;&lt;br /&gt;
    &amp;lt;NcWmsService href=&amp;quot;http://yourNcWMSserver:8080/ncWMS/wms&amp;quot; base=&amp;quot;/ncWMS/wms&amp;quot; ncWmsDynamicServiceId=&amp;quot;lds&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;Godiva href=&amp;quot;/ncWMS/godiva2.html&amp;quot; base=&amp;quot;/ncWMS/godiva2.html&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/WebServiceHandler&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the &#039;&#039;NcWmsService&#039;&#039; element so that:&lt;br /&gt;
* The value of the &#039;&#039;href&#039;&#039; attribute is the fully qualified URL for public access to your WMS service. The server name in this &#039;&#039;href&#039;&#039; will &#039;&#039;&#039;never&#039;&#039;&#039; be &#039;&#039;localhost&#039;&#039; - Godiva won&#039;t work. (Well OK, if your browser is running on the same system as the ncWMS instance then it would but it won&#039;t work for anybody else)&lt;br /&gt;
* The value of the &#039;&#039;ncWmsDynamicServiceId&#039;&#039; matches the &#039;&#039;Unique ID&#039;&#039; of the Dynamic Service you defined in ncWMS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;Godiva&#039;&#039; element&#039;s &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes both use relative URL paths to locate the Godiva service. If the ncWMS instance is NOT running on the same host as Hyrax then  the values of the &#039;&#039;href&#039;&#039; and &#039;&#039;base&#039;&#039; attributes must be converted to fully qualified URLs.&lt;br /&gt;
&lt;br /&gt;
== Start and Test ==&lt;br /&gt;
&lt;br /&gt;
* Once the configuration steps are complete restart your Tomcat server.&lt;br /&gt;
* Point your browser at the Hyrax sever and navigate to a WMS-suitable dataset. &lt;br /&gt;
* Clicking the dataset&#039;s &#039;&#039;&#039;Viewers&#039;&#039;&#039; link should return a page with both WMS and Godiva links.&lt;br /&gt;
* Try &#039;em.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Issues ==&lt;br /&gt;
&lt;br /&gt;
=== Logging Issue ===&lt;br /&gt;
&lt;br /&gt;
There is a small issue with deploying this configuration onto some Linux system in which everything has been installed from RPM (except maybe Tomcat and it&#039;s components including the ncWMS and Hyrax applications)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== The Symptom ====&lt;br /&gt;
&lt;br /&gt;
The issue appears in the Tomcat log as a failure to lock files associated with the java.util.prefs.FileSystemPreferences:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;systemverilog&amp;quot;&amp;gt;&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:28 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences checkLockFile0ErrorCode&lt;br /&gt;
WARNING: Could not lock System prefs. Unix error code 32612.&lt;br /&gt;
Dec 12, 2014 1:17:58 PM java.util.prefs.FileSystemPreferences syncWorld&lt;br /&gt;
WARNING: Couldn&#039;t flush system prefs: java.util.prefs.BackingStoreException: Couldn&#039;t get file lock.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And is logged every 30 seconds or so. So the problem is the logs fill up with this issue and not stuff we care about. The problem is that the files/directories in question either don&#039;t exist, or, if they do exist the Tomcat user does not have read/write permissions on them.&lt;br /&gt;
&lt;br /&gt;
==== The Fix ====&lt;br /&gt;
&lt;br /&gt;
I looked around and discovered that a number of people (including TDS deployers) had experienced this issue. It&#039;s a Linux problem and involves the existence and permissions of a global system preferences directory. I think this is only an issue on Linux systems in which everything is installed via yum/rpm, which may be why we only see this problem on certain systems, but I not 100% confident that the issue is limited only to this type of installation.&lt;br /&gt;
&lt;br /&gt;
I found and tested these two ways to solve it:&lt;br /&gt;
&lt;br /&gt;
; 1) Create the global System Preference directory and set the owner to the Tomcat user&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   sudo mkdir -P /etc/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /etc/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: This could also be accomplished by changing the group ownership to the tomcat-group and setting the group read/write flags.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2) Create your own java System Preference directory and then set the JAVA_OPTS environment variable so that the systemRoot value is set the new directory&lt;br /&gt;
Create the directory&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   mkdir -P /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
   sudo chown -R tomcat-user /home/tomcat-user/.java/.systemPrefs&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then, in each shell that launches Tomcat:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
   export JAVA_OPTS=&amp;quot;-Djava.util.prefs.systemRoot=/home/tomcat-user/.java&amp;quot;&lt;br /&gt;
   $CATALINA_HOME/bin/startup.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Development&amp;diff=6151</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Development&amp;diff=6151"/>
		<updated>2011-01-04T18:18:36Z</updated>

		<summary type="html">&lt;p&gt;Dan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Current Development==&lt;br /&gt;
* [[Hyrax Development]] This page contains several designs, both completed and ongoing, for parts of Hyrax. They include the NCML handler, DAP4 implementation, THREDDS XSLT implementation, The BES XML interface, NetCDF File Response, ...&lt;br /&gt;
* [[IOOS Gateway]]&lt;br /&gt;
* [[DAP3/4]]&lt;br /&gt;
* [[DAP 4.0 Design]]&lt;br /&gt;
* [[WCS]]&lt;br /&gt;
* [[NC-DAP]]&lt;br /&gt;
* [[REAP Cataloging and Searching]]&lt;br /&gt;
* [[AMQP Support in Hyrax]]&lt;br /&gt;
* [[libdap refactor]]&lt;br /&gt;
* [[HowTo: Adding to the Dataset List]]&lt;br /&gt;
* [[Dataset List]]&lt;br /&gt;
* [[Javascript Data Request Form]]&lt;br /&gt;
* [[Hyrax Customization user manual]]&lt;br /&gt;
* [[Hyrax-1.6.2_Packages_for_OS-X]]&lt;br /&gt;
&lt;br /&gt;
==Project Ideas==&lt;br /&gt;
* [[Server side processing]] Some of these ideas could be part of DAP4, some could be additional services Hyrax performs.&lt;br /&gt;
* [[Image Service]]&lt;br /&gt;
* [[Hyrax Admin Interface]]&lt;br /&gt;
* [[Relational Database Handler | RDH]]&lt;br /&gt;
* [[GeoDAP]]&lt;br /&gt;
* [[THREDDS Catalog Metadata]]&lt;br /&gt;
* [[DAP Capabilities]]&lt;br /&gt;
* OGC Web Services Framework&lt;br /&gt;
** [[Sensor Observation Service]]&lt;br /&gt;
* [[Google Summer of Code 2010 Ideas]]&lt;br /&gt;
*[[Hyrax Metadata Management]]&lt;br /&gt;
*[[ASCII Data DDX]]&lt;br /&gt;
&lt;br /&gt;
==Completed Projects==&lt;br /&gt;
* [[NetCDF Translation]]&lt;br /&gt;
* [[CheapStix]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Development]]&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Development&amp;diff=6150</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Development&amp;diff=6150"/>
		<updated>2011-01-04T18:17:21Z</updated>

		<summary type="html">&lt;p&gt;Dan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Current Development==&lt;br /&gt;
* [[Hyrax Development]] This page contains several designs, both completed and ongoing, for parts of Hyrax. They include the NCML handler, DAP4 implementation, THREDDS XSLT implementation, The BES XML interface, NetCDF File Response, ...&lt;br /&gt;
* [[WCS Gateway]]&lt;br /&gt;
* [[DAP3/4]]&lt;br /&gt;
* [[DAP 4.0 Design]]&lt;br /&gt;
* [[WCS]]&lt;br /&gt;
* [[NC-DAP]]&lt;br /&gt;
* [[REAP Cataloging and Searching]]&lt;br /&gt;
* [[AMQP Support in Hyrax]]&lt;br /&gt;
* [[libdap refactor]]&lt;br /&gt;
* [[HowTo: Adding to the Dataset List]]&lt;br /&gt;
* [[Dataset List]]&lt;br /&gt;
* [[Javascript Data Request Form]]&lt;br /&gt;
* [[Hyrax Customization user manual]]&lt;br /&gt;
* [[Hyrax-1.6.2_Packages_for_OS-X]]&lt;br /&gt;
&lt;br /&gt;
==Project Ideas==&lt;br /&gt;
* [[Server side processing]] Some of these ideas could be part of DAP4, some could be additional services Hyrax performs.&lt;br /&gt;
* [[Image Service]]&lt;br /&gt;
* [[Hyrax Admin Interface]]&lt;br /&gt;
* [[Relational Database Handler | RDH]]&lt;br /&gt;
* [[GeoDAP]]&lt;br /&gt;
* [[THREDDS Catalog Metadata]]&lt;br /&gt;
* [[DAP Capabilities]]&lt;br /&gt;
* OGC Web Services Framework&lt;br /&gt;
** [[Sensor Observation Service]]&lt;br /&gt;
* [[Google Summer of Code 2010 Ideas]]&lt;br /&gt;
*[[Hyrax Metadata Management]]&lt;br /&gt;
*[[ASCII Data DDX]]&lt;br /&gt;
&lt;br /&gt;
==Completed Projects==&lt;br /&gt;
* [[NetCDF Translation]]&lt;br /&gt;
* [[CheapStix]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Development]]&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Relational_Database_Handler&amp;diff=4191</id>
		<title>Relational Database Handler</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Relational_Database_Handler&amp;diff=4191"/>
		<updated>2009-05-06T19:33:11Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* Sending DAP2 Data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In order to provide support for a [http://www.opengeospatial.org/standards/sos Sensor Observation Service (SOS)] implementation Hyrax will need a handler that allows it to access data in a Relational Database Management System (RDBMS). (This requirement stems from the observation that many of our stake holders store their in situ measurement data in RDBMSs)&lt;br /&gt;
&lt;br /&gt;
It is anticipated RDBMS handler will have a much broader application than just SOS related data sets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
# [[Adding the RDH to the BES]]&lt;br /&gt;
# [[RDH handles bes:showCatalog request ]]&lt;br /&gt;
# [[RDH handles a DDX request ]]&lt;br /&gt;
# [[RDH handles a DDS request ]]&lt;br /&gt;
# [[RDH handles a DAS request ]]&lt;br /&gt;
# [[RDH handles a DAP2 data request ]]&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; row set&lt;br /&gt;
: A &#039;&#039;row set&#039;&#039; is an object which encapsulates a set of [http://en.wikipedia.org/wiki/Row_(database) rows]. [http://en.wikipedia.org/wiki/Database_table Database tables] are &#039;&#039;row sets&#039;&#039;.  A database &#039;&#039;[http://en.wikipedia.org/wiki/View_(database) view]&#039;&#039; is a &#039;&#039;row set&#039;&#039;. [http://en.wikipedia.org/wiki/SQL_query SQL queries] return &#039;&#039;row sets&#039;&#039;. [http://en.wikipedia.org/wiki/Join_(SQL) SQL JOIN] operations take &#039;&#039;row sets&#039;&#039; as input and produce &#039;&#039;row sets&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
; Constraint Expression (CE)&lt;br /&gt;
: The DAP constraint expression string as described in the [http://www.opendap.org/pdf/ESE-RFC-004v1.1.pdf DAP2 Specification].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
In the past a Java servlet called the DODS Relational Database Server (DRDS)  was used to provide DAP access to RDBMS holdings. However this older implementation has a number of shortcomings that preclude it&#039;s direct use in our current server architecture:&lt;br /&gt;
* No longer supported.&lt;br /&gt;
* Uses the Java DAP implementation &lt;br /&gt;
* Not a BES module&lt;br /&gt;
* Significant memory limitations&lt;br /&gt;
* Difficult to configure/localize&lt;br /&gt;
&lt;br /&gt;
Although there has been continuing interest in a DRDS replacement within the OPeNDAP community, no funding has been available to develop a soution until recently. The IOOS project has a need to provide a [http://www.opengeospatial.org/standards/sos Sensor Observation Service (SOS)] interface for Hyrax. Since much of the sensor data is already held in RDBMSs it is a natural and necessary time to develop a DRDS replacement.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
There are a number of client/server interactions that can take place in the DAP protocol. However, from a programatic viewpoint, pretty much all of the activities involved in these interactions take place when a client requests DAP2 data from the server. In order for the server to respond to a DAP2 data request it must:&lt;br /&gt;
* Build a DDS instance in memory.&lt;br /&gt;
* Populate it with instances of DAP variables (typically from a custom class factory)&lt;br /&gt;
* Parse the DAP2 Constraint Expression.&lt;br /&gt;
* Read data from the underlying data source and apply the CE to the data.&lt;br /&gt;
* Send the constrained data back to the client.&lt;br /&gt;
In order to illuminate the design of the RDH we will examine each component of this interaction in some detail.&lt;br /&gt;
&lt;br /&gt;
The RDH will be a BES module/plug-in. It will use an implementation of the ODBC (most likely [http://www.unixodbc.org/ unixODBC]) to access the RDMS(s). ODBC Data Sources will be defined at the system level as usual.&lt;br /&gt;
[http://www.unixodbc.org/odbcinst.html][http://msdn.microsoft.com/en-us/library/ms188681.aspx]&lt;br /&gt;
[http://support.adobe.com/devsup/devsup.nsf/docs/53765.htm]&lt;br /&gt;
[http://www.internet-webhosting.com/pleskfaq/ch03s77.html]&lt;br /&gt;
&lt;br /&gt;
As with other DAP service implementations, the abstract data type classes in the [[http://www.opendap.org/api/pref/html/index.html libdap library]] get sub-classed and data source specific read methods are implemented. Because of the nature of the RDBMS data sources some data types (such as Sequence) will need to have other methods (such as serialize()) overridden.&lt;br /&gt;
&lt;br /&gt;
[[Image:RDH StaticClasses.png|thumb|640px|center|Data type classes for RDH]]&lt;br /&gt;
&lt;br /&gt;
==== New Class Methods ====&lt;br /&gt;
&lt;br /&gt;
; SqlDDS&lt;br /&gt;
: method01 - explain...&lt;br /&gt;
: method02 - explain...&lt;br /&gt;
&lt;br /&gt;
; SqlSequence&lt;br /&gt;
: method01 - explain...&lt;br /&gt;
&lt;br /&gt;
There may be more...&lt;br /&gt;
&lt;br /&gt;
===Building the DDS object in memory.===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The RDH will load (and cache) from it&#039;s specific configuration section of the BES configuration file a list of ODBC Data Sources that it will serve as DAP data sets (See Use Case  [[Adding the RDH to the BES]]).&lt;br /&gt;
When the RDH receives a request for content (such as a DDS, DDX, DAP2 data etc.) it will identify the DAP dataset from the request, and determine which ODBC Data Source it must interact with to fulfill the request. &lt;br /&gt;
Then, using ODBC (or SQL) introspection methods in the [http://msdn.microsoft.com/en-us/library/ms714177.aspx ODBC API], the RDH will identify the collection of tables and views available in the ODBC Data Source and use them to construct a specialized DDS instance in memory.&lt;br /&gt;
&lt;br /&gt;
[[Image:RDH ActivityDiagram.png|thumb|400px|center| Activity diagram for the RDH]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The RDH will traverse the available tables and views in the ODBC Data Source and it will build a representation of each one as a DAP Sequence object.  The columns in each  table and view will represented by a DAP variable in the corresponding Sequence instance. &lt;br /&gt;
Each of these Sequence instances  will be added to the DDS instance. &lt;br /&gt;
When building  the Sequences and their variables the RDH will use a custom class factory to build instances of DAP objects that can utilize the ODBC API to extract data from the Result Set of an ODBC brokered database query.  Each of the data types generated by the custom factory will have implemented read methods able to read data from the row set returned through the ODBC API. The Sequence instances will each hold the information about their associated ODBC Data Source for use during the data serialization activity.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:BuildingDDS.png|thumb|640px|center|Building a DDS instance from an ODBC Data Source]]&lt;br /&gt;
&lt;br /&gt;
==== Special Metadata for Sequences ====&lt;br /&gt;
&lt;br /&gt;
;Table Relationships&lt;br /&gt;
: Explain...&lt;br /&gt;
&lt;br /&gt;
;ODBC Datasource&lt;br /&gt;
: Explain...&lt;br /&gt;
&lt;br /&gt;
;SQL Query String&lt;br /&gt;
:Explain...&lt;br /&gt;
&lt;br /&gt;
=== Handling the DAP Constraint Expression===&lt;br /&gt;
&lt;br /&gt;
Once an instance of SqlDDS has been created the Constraint Expression can be parsed and applied to it. This process is normally handled in 2 steps: First the CE is parsed and all of the projected variables in the DDS are marked as such. Second, during the reading of the data (which takes place during the serialization process), each data value is checked against the collection of Clauses in the CE. If it meets the CE criteria it is serialized back to the client. In the RDH the process is somewhat more complex because the RDBMS system can (and should) be used to apply most f the relational constraints. Thus in the RDH applying the CE works more like this:&lt;br /&gt;
# Create the DDX in memory&lt;br /&gt;
# Parse the CE&lt;br /&gt;
# Mark all of the projected variables in the DDS.&lt;br /&gt;
# Use the CE to create an SQL query for each Sequence (which represents a table in the RDBMS) in the DDS.&lt;br /&gt;
## Projected variables should be &amp;quot;SELECT&amp;quot;ed in the SQL query.&lt;br /&gt;
## Where possible convert all the clauses in the CE to SQL WHERE clauses.&lt;br /&gt;
## [[RDH: Creating an SQL query from a DAP2 Constraint Expression | More details here.]]&lt;br /&gt;
# When each Sequence variable in the DDS is serialized, the Sequence.serialize() method should first connect to the ODBC Data Source and issue the (previoulsy constructed) SQL query.&lt;br /&gt;
# The &#039;&#039;&#039;row set&#039;&#039;&#039; returned by the query is then used as the data source for the Sequence&#039;s child variables.&lt;br /&gt;
# Any CE clauses that were not converted into SQL query clauses should be applied to the data as it is read from the &#039;&#039;&#039;row set&#039;&#039;&#039;.&lt;br /&gt;
# Any array sub-setting operations must be applied to the data returned in the &#039;&#039;&#039;row set&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
[[Image:ParsingConstraintExpression.png|thumb| 640px|center|Processing a DAP Constraint Expression.]]&lt;br /&gt;
&lt;br /&gt;
=== Sending DAP2 Data ===&lt;br /&gt;
In the DDS each Sequence containing projected variables will be serialized:&lt;br /&gt;
&lt;br /&gt;
;Sequence.read() &lt;br /&gt;
: - Make database query using SQL query string generated by constraint parsing activity..&lt;br /&gt;
: - retrieve row set response&lt;br /&gt;
: - set row set cursor to first row, first column.&lt;br /&gt;
: - for each row in the row set:&lt;br /&gt;
:: - serialize() each projected child variable&lt;br /&gt;
:: - pass row set to each variable&lt;br /&gt;
: - Move row set cursor to next row.&lt;br /&gt;
&lt;br /&gt;
;BaseTypeVariable.read()&lt;br /&gt;
: - read value from row set&lt;br /&gt;
: - Apply remaining constraints and array sub-setting&lt;br /&gt;
: - transmit data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Details&#039;&#039;&#039;&lt;br /&gt;
* Each implementation of a simple DAP type will need to be able to read from the &#039;&#039;&#039;row set&#039;&#039;&#039; returned by an SQL query via ODBC.&lt;br /&gt;
* The implementation of Sequence type will have to manage moving the &#039;&#039;&#039;row set&#039;&#039;&#039; &amp;quot;cursor&amp;quot; from one row to the next.&lt;br /&gt;
* The DAP constraint expressions will have to be converted into SQL queries. (By a child class of [http://scm.opendap.org/svn/trunk/libdap/ConstraintEvaluator.cc  ConstraintEvaluator] perhaps? )&lt;br /&gt;
* Each Sequence requested will be associated with a separate SQL query. As the DDS is serialized, each Sequence will use the ODBC API to send the query to the Data Source and then use the returned row set as the data content for the serialization of it&#039;s (the Sequence&#039;s) variables.&lt;br /&gt;
&lt;br /&gt;
== [[RDH: Mapping the ODBC data model to the DAP2 data model | Mapping the ODBC data model to the DAP2 data model]] ==&lt;br /&gt;
&lt;br /&gt;
== [[RDH: Creating an SQL query from a DAP2 Constraint Expression | Creating an SQL query from a DAP2 Constraint Expression]] ==&lt;br /&gt;
&lt;br /&gt;
== [[RDH Catalog Organization]] ==&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Period of use ==&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=Relational_Database_Handler&amp;diff=4190</id>
		<title>Relational Database Handler</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=Relational_Database_Handler&amp;diff=4190"/>
		<updated>2009-05-06T19:26:52Z</updated>

		<summary type="html">&lt;p&gt;Dan: /* Sending DAP2 Data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In order to provide support for a [http://www.opengeospatial.org/standards/sos Sensor Observation Service (SOS)] implementation Hyrax will need a handler that allows it to access data in a Relational Database Management System (RDBMS). (This requirement stems from the observation that many of our stake holders store their in situ measurement data in RDBMSs)&lt;br /&gt;
&lt;br /&gt;
It is anticipated RDBMS handler will have a much broader application than just SOS related data sets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
# [[Adding the RDH to the BES]]&lt;br /&gt;
# [[RDH handles bes:showCatalog request ]]&lt;br /&gt;
# [[RDH handles a DDX request ]]&lt;br /&gt;
# [[RDH handles a DDS request ]]&lt;br /&gt;
# [[RDH handles a DAS request ]]&lt;br /&gt;
# [[RDH handles a DAP2 data request ]]&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; row set&lt;br /&gt;
: A &#039;&#039;row set&#039;&#039; is an object which encapsulates a set of [http://en.wikipedia.org/wiki/Row_(database) rows]. [http://en.wikipedia.org/wiki/Database_table Database tables] are &#039;&#039;row sets&#039;&#039;.  A database &#039;&#039;[http://en.wikipedia.org/wiki/View_(database) view]&#039;&#039; is a &#039;&#039;row set&#039;&#039;. [http://en.wikipedia.org/wiki/SQL_query SQL queries] return &#039;&#039;row sets&#039;&#039;. [http://en.wikipedia.org/wiki/Join_(SQL) SQL JOIN] operations take &#039;&#039;row sets&#039;&#039; as input and produce &#039;&#039;row sets&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
; Constraint Expression (CE)&lt;br /&gt;
: The DAP constraint expression string as described in the [http://www.opendap.org/pdf/ESE-RFC-004v1.1.pdf DAP2 Specification].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
In the past a Java servlet called the DODS Relational Database Server (DRDS)  was used to provide DAP access to RDBMS holdings. However this older implementation has a number of shortcomings that preclude it&#039;s direct use in our current server architecture:&lt;br /&gt;
* No longer supported.&lt;br /&gt;
* Uses the Java DAP implementation &lt;br /&gt;
* Not a BES module&lt;br /&gt;
* Significant memory limitations&lt;br /&gt;
* Difficult to configure/localize&lt;br /&gt;
&lt;br /&gt;
Although there has been continuing interest in a DRDS replacement within the OPeNDAP community, no funding has been available to develop a soution until recently. The IOOS project has a need to provide a [http://www.opengeospatial.org/standards/sos Sensor Observation Service (SOS)] interface for Hyrax. Since much of the sensor data is already held in RDBMSs it is a natural and necessary time to develop a DRDS replacement.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
There are a number of client/server interactions that can take place in the DAP protocol. However, from a programatic viewpoint, pretty much all of the activities involved in these interactions take place when a client requests DAP2 data from the server. In order for the server to respond to a DAP2 data request it must:&lt;br /&gt;
* Build a DDS instance in memory.&lt;br /&gt;
* Populate it with instances of DAP variables (typically from a custom class factory)&lt;br /&gt;
* Parse the DAP2 Constraint Expression.&lt;br /&gt;
* Read data from the underlying data source and apply the CE to the data.&lt;br /&gt;
* Send the constrained data back to the client.&lt;br /&gt;
In order to illuminate the design of the RDH we will examine each component of this interaction in some detail.&lt;br /&gt;
&lt;br /&gt;
The RDH will be a BES module/plug-in. It will use an implementation of the ODBC (most likely [http://www.unixodbc.org/ unixODBC]) to access the RDMS(s). ODBC Data Sources will be defined at the system level as usual.&lt;br /&gt;
[http://www.unixodbc.org/odbcinst.html][http://msdn.microsoft.com/en-us/library/ms188681.aspx]&lt;br /&gt;
[http://support.adobe.com/devsup/devsup.nsf/docs/53765.htm]&lt;br /&gt;
[http://www.internet-webhosting.com/pleskfaq/ch03s77.html]&lt;br /&gt;
&lt;br /&gt;
As with other DAP service implementations, the abstract data type classes in the [[http://www.opendap.org/api/pref/html/index.html libdap library]] get sub-classed and data source specific read methods are implemented. Because of the nature of the RDBMS data sources some data types (such as Sequence) will need to have other methods (such as serialize()) overridden.&lt;br /&gt;
&lt;br /&gt;
[[Image:RDH StaticClasses.png|thumb|640px|center|Data type classes for RDH]]&lt;br /&gt;
&lt;br /&gt;
==== New Class Methods ====&lt;br /&gt;
&lt;br /&gt;
; SqlDDS&lt;br /&gt;
: method01 - explain...&lt;br /&gt;
: method02 - explain...&lt;br /&gt;
&lt;br /&gt;
; SqlSequence&lt;br /&gt;
: method01 - explain...&lt;br /&gt;
&lt;br /&gt;
There may be more...&lt;br /&gt;
&lt;br /&gt;
===Building the DDS object in memory.===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The RDH will load (and cache) from it&#039;s specific configuration section of the BES configuration file a list of ODBC Data Sources that it will serve as DAP data sets (See Use Case  [[Adding the RDH to the BES]]).&lt;br /&gt;
When the RDH receives a request for content (such as a DDS, DDX, DAP2 data etc.) it will identify the DAP dataset from the request, and determine which ODBC Data Source it must interact with to fulfill the request. &lt;br /&gt;
Then, using ODBC (or SQL) introspection methods in the [http://msdn.microsoft.com/en-us/library/ms714177.aspx ODBC API], the RDH will identify the collection of tables and views available in the ODBC Data Source and use them to construct a specialized DDS instance in memory.&lt;br /&gt;
&lt;br /&gt;
[[Image:RDH ActivityDiagram.png|thumb|400px|center| Activity diagram for the RDH]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The RDH will traverse the available tables and views in the ODBC Data Source and it will build a representation of each one as a DAP Sequence object.  The columns in each  table and view will represented by a DAP variable in the corresponding Sequence instance. &lt;br /&gt;
Each of these Sequence instances  will be added to the DDS instance. &lt;br /&gt;
When building  the Sequences and their variables the RDH will use a custom class factory to build instances of DAP objects that can utilize the ODBC API to extract data from the Result Set of an ODBC brokered database query.  Each of the data types generated by the custom factory will have implemented read methods able to read data from the row set returned through the ODBC API. The Sequence instances will each hold the information about their associated ODBC Data Source for use during the data serialization activity.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:BuildingDDS.png|thumb|640px|center|Building a DDS instance from an ODBC Data Source]]&lt;br /&gt;
&lt;br /&gt;
==== Special Metadata for Sequences ====&lt;br /&gt;
&lt;br /&gt;
;Table Relationships&lt;br /&gt;
: Explain...&lt;br /&gt;
&lt;br /&gt;
;ODBC Datasource&lt;br /&gt;
: Explain...&lt;br /&gt;
&lt;br /&gt;
;SQL Query String&lt;br /&gt;
:Explain...&lt;br /&gt;
&lt;br /&gt;
=== Handling the DAP Constraint Expression===&lt;br /&gt;
&lt;br /&gt;
Once an instance of SqlDDS has been created the Constraint Expression can be parsed and applied to it. This process is normally handled in 2 steps: First the CE is parsed and all of the projected variables in the DDS are marked as such. Second, during the reading of the data (which takes place during the serialization process), each data value is checked against the collection of Clauses in the CE. If it meets the CE criteria it is serialized back to the client. In the RDH the process is somewhat more complex because the RDBMS system can (and should) be used to apply most f the relational constraints. Thus in the RDH applying the CE works more like this:&lt;br /&gt;
# Create the DDX in memory&lt;br /&gt;
# Parse the CE&lt;br /&gt;
# Mark all of the projected variables in the DDS.&lt;br /&gt;
# Use the CE to create an SQL query for each Sequence (which represents a table in the RDBMS) in the DDS.&lt;br /&gt;
## Projected variables should be &amp;quot;SELECT&amp;quot;ed in the SQL query.&lt;br /&gt;
## Where possible convert all the clauses in the CE to SQL WHERE clauses.&lt;br /&gt;
## [[RDH: Creating an SQL query from a DAP2 Constraint Expression | More details here.]]&lt;br /&gt;
# When each Sequence variable in the DDS is serialized, the Sequence.serialize() method should first connect to the ODBC Data Source and issue the (previoulsy constructed) SQL query.&lt;br /&gt;
# The &#039;&#039;&#039;row set&#039;&#039;&#039; returned by the query is then used as the data source for the Sequence&#039;s child variables.&lt;br /&gt;
# Any CE clauses that were not converted into SQL query clauses should be applied to the data as it is read from the &#039;&#039;&#039;row set&#039;&#039;&#039;.&lt;br /&gt;
# Any array sub-setting operations must be applied to the data returned in the &#039;&#039;&#039;row set&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
[[Image:ParsingConstraintExpression.png|thumb| 640px|center|Processing a DAP Constraint Expression.]]&lt;br /&gt;
&lt;br /&gt;
=== Sending DAP2 Data ===&lt;br /&gt;
In the DDS each Sequence containing projected variables will be serialized:&lt;br /&gt;
&lt;br /&gt;
;Sequence.read() &lt;br /&gt;
: - Make database query using SQL query string generated by constraint parsing activity..&lt;br /&gt;
: - retrieve row set response&lt;br /&gt;
: - set row set cursor to first row, first column.&lt;br /&gt;
: - for each row in the row set:&lt;br /&gt;
:: - serialize() each projected child variable&lt;br /&gt;
:: - pass row set to each variable&lt;br /&gt;
: - Move row set cursor to next row.&lt;br /&gt;
&lt;br /&gt;
;BaseTypeVariable.read()&lt;br /&gt;
: - read value from row set&lt;br /&gt;
: - Apply remaining constraints and array sub-setting&lt;br /&gt;
: - transmit data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Details&#039;&#039;&#039;&lt;br /&gt;
* Each implementation of a simple DAP type will need to be able to: &lt;br /&gt;
** Read from the &#039;&#039;&#039;row set&#039;&#039;&#039; returned by an SQL query via ODBC.&lt;br /&gt;
** Move the &#039;&#039;&#039;row set&#039;&#039;&#039; &amp;quot;cursor&amp;quot; to the next column in the current row.&lt;br /&gt;
:(The order of these two operations will depend on how the implementation of the Sequence type positions the &#039;&#039;&#039;row set&#039;&#039;&#039; cursor.)&lt;br /&gt;
* The implementation of Sequence type will have to manage moving the &#039;&#039;&#039;row set&#039;&#039;&#039; &amp;quot;cursor&amp;quot; from one row to the next.&lt;br /&gt;
* The DAP constraint expressions will have to be converted into SQL queries. (By a child class of [http://scm.opendap.org/svn/trunk/libdap/ConstraintEvaluator.cc  ConstraintEvaluator] perhaps? )&lt;br /&gt;
* Each Sequence requested will be associated with a separate SQL query. As the DDS is serialized, each Sequence will use the ODBC API to send the query to the Data Source and then use the returned row set as the data content for the serialization of it&#039;s (the Sequence&#039;s) variables.&lt;br /&gt;
&lt;br /&gt;
== [[RDH: Mapping the ODBC data model to the DAP2 data model | Mapping the ODBC data model to the DAP2 data model]] ==&lt;br /&gt;
&lt;br /&gt;
== [[RDH: Creating an SQL query from a DAP2 Constraint Expression | Creating an SQL query from a DAP2 Constraint Expression]] ==&lt;br /&gt;
&lt;br /&gt;
== [[RDH Catalog Organization]] ==&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Period of use ==&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
	<entry>
		<id>https://docs.opendap.org/index.php?title=IOOS_Gateway&amp;diff=3983</id>
		<title>IOOS Gateway</title>
		<link rel="alternate" type="text/html" href="https://docs.opendap.org/index.php?title=IOOS_Gateway&amp;diff=3983"/>
		<updated>2009-04-29T17:30:15Z</updated>

		<summary type="html">&lt;p&gt;Dan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Changes to the DAP, Hyrax, or other proposals stemming from the WCS Gateway Project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Much of the WCS gateway work is focused on:&lt;br /&gt;
&lt;br /&gt;
# Providing DAP2 protocol access to WCS served data.&lt;br /&gt;
&lt;br /&gt;
=== DAP2 access to data served by WCS ===&lt;br /&gt;
&lt;br /&gt;
* [[WCS_Data Access|Data access via DAP2 requests]]&lt;br /&gt;
* [[WCS Site Analysis |WCS Server Analysis]]&lt;br /&gt;
==== DAP2.1 Namespace ====&lt;br /&gt;
There have been some proposed changes to the DAP2 namespace (for the DDX) to hep accommodate this work.&lt;br /&gt;
* [[WCS DAP Attributes|DAP Attributes]]&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Dan</name></author>
	</entry>
</feed>