15 wx-consumer-wcs - RAL - University Corporation for Atmospheric

advertisement
WCSRI 4.4
Internal Design and Implementation
Version 1.0
January, 2013
Prepared by:
Aviation Applications Program
Research Applications Laboratory
National Center for Atmospheric Research
This research is in response to requirements and funding by the Federal Aviation Administration
(FAA). The views expressed are those of the authors and do not necessarily represent the official
policy or position of the FAA.
Document Revision History:
Version
Date
Changes
Contributors
1.0
Jan 15, 2013
Initial revision
Rob Weingruber, Andy Gaydos
Please direct comments or questions to:
Rob Weingruber or Andy Gaydos
National Center for Atmospheric Research
Research Applications Laboratory
3450 Mitchell Lane
Boulder, CO 80301
weingrub@ucar.edu or gaydos@ucar.edu
Terms of Use – CSS-Wx Documentation
The following Terms of Use applies to the CSS-Wx Documentation.
1
2
3
4
5
Use. The User may use CSS-Wx Documentation for any lawful purpose without any fee or
cost. Any modification, reproduction and redistribution may take place without further
permission so long as proper copyright notices and acknowledgements are retained.
Acknowledgement. The CSS-Wx Documentation was developed through the sponsorship
of the Federal Aviation Administration.
Copyright. Any copyright notice contained in this Terms of Use, the CSS-Wx
Documentation, any software code, or any part of the website shall remain intact and
unaltered and shall be affixed to any use, distribution or copy. Except as specifically
permitted herein, the user is not granted any express or implied right under any patents,
copyrights, trademarks, or other intellectual property rights with respect to the CSS-Wx
Documentation.
No Endorsements. The names, UCAR and/or NCAR may not be used in any advertising or
publicity to endorse or promote any program, project, product or commercial entity.
Limitation of Liability. The CSS-Wx Documentation, including all content and materials, is
provided "as is." There are no warranties of use, fitness for any purpose, service or goods,
implied or direct, associated with the CSS-Wx Documentation and UCAR expressly
disclaims any warranties. In no event shall UCAR be liable for any damages of any nature
suffered by any user, or any third party resulting in whole or in part from use of the CSSWx Documentation.
Copyright © 2007-2013 University Corporation for Atmospheric Research
2
Table of Contents
1 Background ................................................................................................................................ 8
1.1 Introduction.......................................................................................................................... 8
1.2 Scope .................................................................................................................................. 9
1.3 Prerequisites ..................................................................................................................... 10
2 Terminology ............................................................................................................................. 10
3 Technologies Used .................................................................................................................. 12
3.1 Web Coverage Service Specification (WCS) ..................................................................... 12
3.2 WS-Notification Specification (WS-N) ................................................................................ 12
3.3 OSGI ................................................................................................................................. 12
3.4 Karaf.................................................................................................................................. 13
3.5 Servicemix ......................................................................................................................... 13
3.6 ActiveMQ (JMS) ................................................................................................................ 13
3.7 Database (JDBC) .............................................................................................................. 14
3.8 Camel ................................................................................................................................ 14
3.9 SOAP and WSDL .............................................................................................................. 14
3.10 CXF ................................................................................................................................. 15
3.11 JPA.................................................................................................................................. 16
3.12 Maven ............................................................................................................................. 16
3.13 MINA ............................................................................................................................... 16
3.14 Jetty................................................................................................................................. 17
3.15 Blueprint .......................................................................................................................... 17
3.16 Security ........................................................................................................................... 17
3.16.1 HTTPS/SSL .............................................................................................................. 17
3.16.2 JAAS ......................................................................................................................... 18
3.16.3 WS-Security (wss4j) .................................................................................................. 18
3.17 JAXB ............................................................................................................................... 18
3.18 Monitoring........................................................................................................................ 19
3.18.1 JMX and MBeans ...................................................................................................... 19
3.18.2 Google Guice ............................................................................................................ 19
3.19 NetCDF and NetCDF Climate and Forecast (CF) Metadata Convention .......................... 19
3
3.20 ncWMS ............................................................................................................................ 20
4 SOAP Operations .................................................................................................................... 20
4.1 WSDL ................................................................................................................................ 20
4.1.1 WCS ........................................................................................................................... 21
4.1.2 WS-Notification (WS-N)............................................................................................... 22
4.1.3 Master WSDL.............................................................................................................. 23
4.2 Examples........................................................................................................................... 24
4.2.1 GetCapabilities SOAP Request and Response ........................................................... 24
4.2.2 DescribeCoverage SOAP Request and Response ...................................................... 29
4.2.3 GetCoverage SOAP Request and Response .............................................................. 33
4.2.4 GetMetadata SOAP Request and Response ............................................................... 37
4.2.5 Subscribe SOAP Request and Response ................................................................... 45
4.2.6 KVP Request and Response ....................................................................................... 46
5 Architecture .............................................................................................................................. 47
5.1 Overview ........................................................................................................................... 48
5.1.1 Data Ingest.................................................................................................................. 49
5.1.2 Data Retriever ............................................................................................................. 50
5.1.3 Subscription Management........................................................................................... 50
5.1.4 Pub/Sub Notification Producer .................................................................................... 50
5.2 Single Node vs Cluster ...................................................................................................... 50
5.2.1 Idempotency Database ............................................................................................... 51
5.2.2 ActiveMQ .................................................................................................................... 51
6 Request/Reply Services ........................................................................................................... 53
6.1 Overview ........................................................................................................................... 53
6.2 Web Services and The Frontend ....................................................................................... 54
6.2.1 WCSRI Endpoints ....................................................................................................... 54
6.2.2 The wcsri-frontend Module .......................................................................................... 56
6.2.3 The wcsri-web-service Module .................................................................................... 60
6.3 Synchronous vs Asynchronous Processing for WCS Requests ......................................... 69
6.3.1 Asynchronous Processing ........................................................................................... 70
6.3.2 Synchronous Processing............................................................................................. 75
6.4 The gds-pojo-service Bundle ............................................................................................. 78
6.4.1 Blueprint and Dependency Injected Objects ................................................................ 78
4
6.4.2 DataSourceConfigurator, DataSource and DataSourceManager ................................. 79
6.4.3 GetCapabilities (ServicesMetaGDSRequestHandler) .................................................. 85
6.4.4 GetMetadata (IsoMetadataGDSRequestHandler) ....................................................... 86
6.4.5 DescribeCoverage (DatasetMetadataGDSRequestHandler) ....................................... 86
6.4.6 GetCoverage............................................................................................................... 87
7 Publish/Subscribe MEP ............................................................................................................ 93
7.1 Overview ........................................................................................................................... 93
7.2 Pub/Sub Persistence – DAOs ............................................................................................ 95
7.2.1 JPA ............................................................................................................................. 96
7.2.2 DAO Design ................................................................................................................ 98
7.2.3 DDL and Database Schema ...................................................................................... 100
7.2.4 IdempotentDAO ........................................................................................................ 105
7.3 Subscribe Request and Response................................................................................... 106
7.4 File Polling and Notification Messages ............................................................................ 109
7.4.1 DatasourcePollers ..................................................................................................... 112
7.4.2 TransformationMultiplexers ....................................................................................... 114
7.4.3 Event Processors ...................................................................................................... 114
7.4.4 Notification Messages and Payloads ......................................................................... 115
7.5 Receiving Notifications .................................................................................................... 116
7.5.1 Connecting to the AMQ Temporary Queue - Overview.............................................. 116
7.5.2 Handshake Queue (pubsub.handshake) ................................................................... 116
7.5.3 Listening for Notifications .......................................................................................... 118
7.5.4 AckProcessor ............................................................................................................ 118
7.5.5 ConnectionProcessor ................................................................................................ 119
7.5.6 CleanupProcessor..................................................................................................... 119
7.5.7 TempQueueCleanupProcessor ................................................................................. 120
7.6 Subscription Management ............................................................................................... 120
7.6.1 Unsubscribe .............................................................................................................. 121
7.6.2 Renew....................................................................................................................... 122
7.6.3 Pause / Resume........................................................................................................ 123
8 Repeaters .............................................................................................................................. 123
8.1 Overview ......................................................................................................................... 123
8.2 Repeater Implementation ................................................................................................ 125
5
8.2.1 DataSourceConfigurator............................................................................................ 125
8.2.2 CoverageRepeaterActivator ...................................................................................... 125
8.2.3 IdempotentGetCoverageNotificationListener ............................................................. 127
9 Delegators ............................................................................................................................. 129
9.1 Overview ......................................................................................................................... 129
9.2 Delegator Implementation ................................................................................................ 130
9.2.1 DataSourceConfigurator............................................................................................ 130
9.2.2 DelegatorDatasetDatasource .................................................................................... 131
9.2.3 DatasourceDelegatorActivator................................................................................... 131
9.2.4 IdempotentDelegatorNotificationListener ................................................................... 134
10 Logging ................................................................................................................................ 135
11 Monitoring ............................................................................................................................ 135
11.1 JConsole ....................................................................................................................... 136
11.2 MBeans ......................................................................................................................... 136
11.2.1 BaseWcsriMbean .................................................................................................... 137
11.2.2 SubsetTimesMBean ................................................................................................ 137
11.2.3 SystemPerformanceMBean..................................................................................... 139
11.2.4 ManagedSubscriber, ManagedRepeater and ManagedDelegator MBeans ............. 141
12 Security ................................................................................................................................ 143
13 ncWMS ................................................................................................................................ 144
13.1 Installing the ncWMS ..................................................................................................... 145
13.2 Viewing the ncWMS....................................................................................................... 146
14 Performance Statistics ......................................................................................................... 148
15 wx-consumer-wcs ................................................................................................................ 148
15.1 API ................................................................................................................................ 149
15.1.1 edu.ucar.ral.wxcube.consumer.wcs.domain ............................................................ 150
15.1.2 edu.ucar.ral.wxcube.consumer.wcs.exception ........................................................ 150
15.1.3 edu.ucar.ral.wxcube.consumer.wcs.mbean ............................................................. 150
15.1.4 edu.ucar.ral.wxcube.consumer.wcs.proxy ............................................................... 150
15.1.5 edu.ucar.ral.wxcube.consumer.wcs.repeater .......................................................... 151
15.1.6 edu.ucar.ral.wxcube.consumer.wcs.utils ................................................................. 151
15.2 SimpleClient .................................................................................................................. 151
15.2.1 GetCapabilities ........................................................................................................ 152
6
15.2.2 DescribeCoverage .................................................................................................. 154
15.2.3 GetCoverage........................................................................................................... 155
15.2.4 Subscribe ................................................................................................................ 156
16 Source Code, Building and Installing .................................................................................... 158
7
1 Background
1.1 Introduction
This document describes the intricacies of the Web Coverage Service Reference Implementation
(WCSRI) for the NextGen Common Support Services - Weather (CSS-Wx) program from the
FAA. The WCSRI is an implementation of the Web Coverage Service (WCS) 1.1.2 specification
published by the Open Geospatial Consortium (OGC). The server provides access to gridded
weather data products that have binary data encodings, such as GRIB and NetCDF, as well as
accompanying metadata. The specification implementation includes support for geospatial and
temporal filtering as well as caching functions to allow for flexible and efficient distribution of
weather data. The WCS supports both the publish/subscribe and request/reply message
exchange patterns (MEP) in a consistent manner to meet use cases related to both real-time data
dissemination and ad-hoc requests for information.
The WCSRI is an implementation of the services specified by the WCS 1.1.2 and WS-Notification
(WS-N) specifications. The WCS specification provides the operations to advertise the server’s
capabilities and retrieve weather data subsets and related metadata. The WS-N specification
provides the operations for supporting real-time data distribution including subscriptions and
notifications. The server is implemented as a service-oriented architecture (SOA) built upon core
messaging services and SOA-defined infrastructure. It’s implemented using a variety of opensource and well-known technologies and runs within the Apache enterprise-service bus (ESB),
called servicemix. In order to provide a robust implementation appropriate for an operational
environment, the WCSRI provides enterprise-level capabilities for improved Quality of Service
(QOS) such as high-availability/failover and scalability/load-balancing.
Given that common weather data will be distributed to a potentially large number of FAA
consumers at many sites, the WCSRI provides for intelligent low-latency distribution of data while
minimizing the overall bandwidth required. A diagram depicting a sample architecture is provided
below. Weather data has a tendency to be prohibitively large to distribute in its entirety to each
interested party. Hence, theWCSRI utilizes portions of the WCS specification providing geospatial
and temporal subsetting by product. However, the WCSRI is also based on a hub-and-spoke
topology, allowing for data to be 'fanned out' in a hierarchical fashion. Distribution, or edge,
servers can be employed within a physical architecture or topology, allowing origin servers to
distribute weather data in a flexible fashion according to changing dissemination requirements
and network capabilities.
8
1.2 Scope
The purpose of this document is to describe, at a developer’s level, how the WCSRI codebase is
designed and implemented. In essence, this document describes how much of the WCSRI
actually works. The document introduces complexity slowly by starting with a high level
description of many of the technologies used in the server, moving into the basic request/reply
services and the more complex publish/subscribe services. In order to leverage many enterpriselevel solutions that already exist in the industry, the WCSRI integrates several open-source
technologies. It is beyond the scope of this document to describe the basics, let alone the details,
of these technologies, and hence developers who need to be entrenched in the WCSRI code are
advised to become familiar with many of these technologies first. This document describes much
of what the code written by the WCSRI team does, and when appropriate, why it was designed as
such. Hence, the document should be used as a guide to the code, and is a good starting point for
understanding the WCSRI. That being said, for a true understanding, there’s nothing better than
reading the code.
9
1.3 Prerequisites
A few WCSRI documents have been written in the past, and are very significant for understanding
the high-level usage and architecture of the server. The first and foremost of these is the
Installation Instructions document (i.e., INSTALLATION.doc) available either in the /doc directory
of the WCSRI binary release, or on the NNEW Wiki at the URL below. The Installation Instructions
document describes not only how the server should be installed, but also contains descriptions of
key concepts that are required for an understanding of the server. For example, it describes how
coverages are specified and configured and therefore, exposed to consumers.
http://www.ral.ucar.edu/projects/nnew/wcsri4.3/wcsri-4.3-RELEASE-release/doc/INSTALLATION.htm
In addition, the document “High-availability and Scalability Architectural Alternatives and
Configurations for NCAR NNEW WCSRI” gives a high-level overview of the architecture of the
server. It contains information regarding the different components of the system, their intent and
how they interact. The document also describes how the WCSRI components should be arranged
and configured for a clustered configuration in order to achieve high-availability and scalability.
The focus is on high-level concepts and is required reading.
The “Web Service Description Document (WSDD) for the NextGen Network Enabled Weather
Web Coverage Service” is also pertinent. It describes, in detail, usage of the WCSRI from a
consumer perspective. Information provided therein focuses on the protocol used in
communicating with a WCSRI, specifically the details of the Web Coverage Service (WCS) and
WS-Notification specifications and extensions. To understand the specifics of the XML content in
requests to and responses from the WCSRI, the WSDD is useful.
The documents mentioned above are essentially prerequisites for this WCSRI Internal Design and
Implementation document. Though expertise in the details of those documents is not necessary, it
is advised to have a substantial familiarity with their content.
2 Terminology
Web Coverage Service (WCS) - The WCS 1.1.2 specification is produced by the Open
Geospatial Consortium, and consists of a document and a set of XML schemas representing a set
of operations for describing and retrieving “coverages” from a WCS-compliant server. The WCSRI
implements WCS 1.1.2. The specification designates three operations: getCapabilities,
describeCoverage and getCoverage.
WS-Notification (WS-N) - This is the WS-Notification specification produced by OASIS. The
WCSRI supports some of the publish/subscribe operations as described by this specification. The
primary WS-N operations supported are subscribe, unsubscribe and renew.
wcs.rootDataDir - The WCSRI reads raw weather data from an input disk and outputs subsets
on-demand via getCoverage requests. The wcs.rootDataDir is the root directory for all of the raw
10
weather data. Subdirectories will exist for each DatasetDataSource and will contain a
coveragesConfig.xml file specifying the type of DataSource.
DatasetDataSource - A DataSource is effectively a root data directory (subdirectory under the
wcs.rootDataDir) for a single stream or set of data files, which has its own coveragesConfig.xml
file. A DataSource will provide one or more coverages. In addition, there are two types of
DatasetDataSource classes: DirectoryBasedDataSource and DelegatorDatasetDataSource. The
DirectoryBasedDataSource provides a set of coverages based on locally stored raw weather data
files, whereas a DelegatorDatasetDataSource provides a proxy for a set of coverages located on
an upstream WCSRI. A Repeater configuration in a coveragesConfig.xml file maps to a
DirectoryBasedDataSource plus other supporting classes, but a class such as
RepeaterDataSource does not exist.
Coverage - A coverage is a set of grids or fields representing weather phenomena, based on a
single set of raw weather data files (i.e., existing as part of a single DataSource). A coverage, or
really the fields available, may be 2-dimensional (XY) or 3-dimensional (XYZ) geospatially and 1dimensional (valid time) or 2-dimensional (valid and generation time) temporally but must be
homogenous within a coverage. In other words, the fields within a coverage must have the same
dimensionality (XYZ, valid and generation time).
Field - A field is a single variable representing a weather phenomena within a coverage. All fields
within a coverage must be homogenous in XYZ, Time and generation time (i.e., model runtime or
analysis time).
Coverage Metadata or Coverage Descriptions - High level descriptive information regarding a
coverage. This information will include bounding-box extents (XYZ) in various coordinate
reference systems, a listing of the fields, and a listing of valid times, generation times (i.e.
gentimes or model-run times) and/or time ranges available for the coverage. Coverage
descriptions are essentially responses to describeCoverage requests.
Services Metadata - High level information describing the services available from a WCSRI. This
information will include service provider information (e.g., contact info), and a list of the coverage
identifiers for the coverages available from the server. Services metadata is essentially a
response to a getCapabilities request.
ISO 19139 and getMetadata - An early requirement for the WCSRI required the server to provide
ISO19139-compliant metadata on demand. However, the WCS specification does not abide by
the ISO specification, and hence, an additional SOAP operation was added to the WCSRI’s
implementation and WSDL called getMetadata. This operation is similar to a getCapabilities
request/response, but instead, the response is returned in an ISO19139-compliant fashion.
Message Exchange Pattern (MEP) - A message exchange pattern (MEP) describes the pattern
of messages required by a communications protocol to establish or use a communication
11
channel.1 The WCSRI uses two kinds of MEPs - request/reply and publish/subscribe where
notifications of data availability are pushed to clients.
3 Technologies Used
The WCSRI makes use of several Java-based technologies many of which are briefly described
below. It is beyond the scope of this document to describe these technologies in detail, many of
which have entire books dedicated to them. The WCSRI makes use of these technologies in
varying levels of detail, and hence, varying levels of expertise in those technologies may be
required for a full understanding of the code-base.
3.1 Web Coverage Service Specification (WCS)
The WCS 1.1.2 specification is produced by the Open Geospatial Consortium2 and is the
specification implemented by the WCSRI. The WCS consists of a specification document with
descriptions and a set of XML schemas representing a set of operations for describing and
retrieving “coverages” from a WCS-compliant server. The specification designates three
operations: getCapabilities, describeCoverage, and getCoverage.
3.2 WS-Notification Specification (WS-N)
This is the WS-Notification specification produced by OASIS3. The WCSRI supports some of the
publish/subscribe operations as described by this specification. The primary WS-N operations
supported are subscribe, unsubscribe, and renew.
3.3 OSGI
The OSGi framework (OSGi being an acronym for "Open Services Gateway initiative") is a
module system and service platform for the Java programming language that implements a
complete and dynamic component model. Applications or components (coming in the form of
bundles for deployment) can be remotely installed, started, stopped, updated, and uninstalled
without requiring a reboot; management of Java packages/classes is specified in great detail.
Application life cycle management (start, stop, install, etc.) is done via APIs that allow for remote
downloading of management policies. The service registry allows bundles to detect the addition of
new services, or the removal of services, and adapt accordingly.4
OSGi provides a modular architecture for packaging Java classes into bundles, which is simply a
standard Java jar file with additional manifest information. With bundles, classes and services can
be imported and exported, with versioning, thereby providing a robust means of deploying
1
http://en.wikipedia.org/wiki/Messaging_pattern
http://www.opengeospatial.org/standards/wcs
3
https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wsn
4
http://en.wikipedia.org/wiki/OSGi
2
12
functionality within an integration container. The framework also provides lifecycle management
allowing applications and dependencies to be dynamically updated without stopping and starting
the integration container, hence providing capabilities desirable for an enterprise-level operational
server with a stringent Service-Level Agreement (SLA).
The Java classes and other resources for the WCSRI are packaged into bundles for modularity
and flexibility, and are meant to be deployed and run in an OSGi-compliant container, such as
Servicemix discussed below. In addition, the WCSRI is installed as an OSGi “feature”.
3.4 Karaf
Apache Karaf is a small OSGi based runtime which provides a lightweight container onto which
various components and applications can be deployed.5
Karaf is the OSGi compliant runtime contained in Servicemix.
3.5 Servicemix
Apache ServiceMix is an open-source integration container that unifies features and functionality
of Apache ActiveMQ, Camel, CXF and Karaf into a powerful runtime platform you can use to build
your own integration solutions. Servicemix provides a complete, enterprise ready ESB built on
OSGi.6
The use of the Fuse stack including Servicemix was an early requirement for the WCSRI
mandated by the FAA SWIM program. The WCSRI was required to run within the Servicemix ESB
and hence was implemented as such. Currently, the WCSRI implementation is coupled with
OSGi, but future work may warrant loosening the coupling by refactoring to make the WCSRI
deployable to a more simplistic application container.
Servicemix is the integration container for deploying and running the WCSRI. It provides a
command line administrative console to OSGi, thereby allowing life-cycle management of the
WCSRI and its dependencies. The WCSRI (i.e., feature) and its dependencies (i.e., bundles) can
be hot-deployed, started, stopped and updated as needed without restarting the container.
3.6 ActiveMQ (JMS)
Apache ActiveMQ is an open source (Apache 2.0 licensed) message broker which fully
implements the Java Message Service 1.1 (JMS). It provides "Enterprise Features" like clustering,
multiple message stores, and ability to use any database as a JMS persistence provider besides
VM, cache, and journal persistency.7
5
http://karaf.apache.org
http://servicemix.apache.org/
7
http://en.wikipedia.org/wiki/Apache_ActiveMQ
6
13
The Java Message Service (JMS) API is a Java Message Oriented Middleware (MOM) API for
sending messages between two or more clients. JMS is a part of the Java Platform, Enterprise
Edition, and is […] a messaging standard that allows application components based on the Java
Enterprise Edition (JEE) to create, send, receive, and read messages. It allows the
communication between different components of a distributed application to be loosely coupled,
reliable, and asynchronous.8
ActiveMQ provides a fully JMS-compliant message broker for the WCSRI. JMS is a specification
that defines an API for messaging and publish/subscribe constructs, such as topics and queues.
The WCSRI’s asynchronous processing of weather subset requests and real-time notifications
leverage ActiveMQ queues and the notion of competing consumers for scalability. ActiveMQ can
be run within Servicemix as an embedded feature. However, in an operational environment or one
that requires better performance characteristics, it is advised to run ActiveMQ independently and
externally from the WCSRI. In this way, ActiveMQ can be better tuned for optimum performance
and can be made scalable (if necessary) with a network-of-brokers.
3.7 Database (JDBC)
The WCSRI requires a relational database for persisting information (e.g., messages,
subscriptions) for the real-time notification or publish/subscribe mechanism. The WCSRI uses
JDBC to access the database, and hence theoretically supports any RDBMS. However, the
WCSRI has been tested specifically with Oracle, PostgreSQL, MySQL, HSQLDB and Derby. Note
that the WCSRI is packaged with an HSQLDB, but this is primarily for completeness and testing,
and using the HSQLDB in production is absolutely not recommended.
3.8 Camel
Apache Camel ™ is a versatile open-source integration framework based on known Enterprise
Integration Patterns. Camel empowers you to define routing and mediation rules in a variety of
domain-specific languages, including a Java-based Fluent API, Spring or Blueprint XML
Configuration files [...] Apache Camel uses URIs to work directly with any kind of Transport or
messaging model such as HTTP, ActiveMQ, JMS, [...] MINA or CXF, as well as pluggable
Components and Data Format options.9
Camel provides a framework for accomplishing typical enterprise-level integration tasks. The
WCSRI uses Camel for asynchronous processing of weather metadata and subset requests, as
well as for file polling as part of the real-time notification mechanism.
3.9 SOAP and WSDL
SOAP, originally defined as Simple Object Access Protocol, is a protocol specification for
exchanging structured information in the implementation of Web Services in computer networks. It
8
9
http://en.wikipedia.org/wiki/Java_Message_Service
http://camel.apache.org/
14
relies on Extensible Markup Language (XML) for its message format, and usually relies on other
Application Layer protocols, most notably Hypertext Transfer Protocol (HTTP) and Simple Mail
Transfer Protocol (SMTP), for message negotiation and transmission.10
The Web Services Description Language is an XML-based language that is used for describing
the functionality offered by a Web service. A WSDL description of a web service (also referred to
as a WSDL file) provides a machine-readable description of how the service can be called, what
parameters it expects, and what data structures it returns. It thus serves a roughly similar purpose
as a method signature in a programming language.11
SOAP and WSDL provide the low-level client-server protocol specification for the request/reply
web services implemented by the WCSRI. SOAP defines the low-level envelope, headers and
body of messages. The WSDL for the WCSRI is a concrete document that defines the allowable
operations, or web services including in/out parameters, that can be invoked by a client against
the server. Since the WSDL produced by the WCSRI makes use of the WCS and WS-N
specifications, the WCS and WS-N XML schemas (i.e., XSD files) are a significant part of defining
the web services in the WSDL.
The SOAP with Attachments API for Java or SAAJ provides a standard way to send XML
documents over the Internet from the Java platform. SAAJ enables developers to produce and
consume messages conforming to the SOAP 1.1 specification and SOAP with Attachments
note.12
One of the main purposes of the WCSRI is to produce weather data subset files on demand. The
WCS-compliant method for this request/reply operation is called getCoverage. In order to return
the subsetted weather data NetCDF file as a result of WCS getCoverage requests, the WCSRI
employs SOAP With Attachments for Java.
3.10 CXF
Apache CXF is an open source services framework [that] helps you build and develop services
using frontend programming APIs [...] CXF includes a broad feature set, but it is primarily focused
on the following areas:
●
●
10
Web Services Standards Support: CXF supports a variety of web service standards
including SOAP, the WS-I Basic Profile, WSDL, WS-Addressing, WS-Policy, WSReliableMessaging, WS-Security, WS-SecurityPolicy, WS-SecureConverstation, and WSTrust (partial).
Frontends: CXF supports a variety of "frontend" programming models.
http://en.wikipedia.org/wiki/SOAP
http://en.wikipedia.org/wiki/Web_Services_Description_Language
12
http://en.wikipedia.org/wiki/SOAP_with_Attachments_API_for_Java
11
15
CXF [...] will automatically generate code for request and response bean classes, and [...] also
includes a "simple frontend" which allows creation of clients and endpoints without annotations.
CXF supports both contract first development with WSDL and code first development starting
from Java.13
CXF is the web-services stack employed by the WCSRI. It provides the endpoints for the server’s
request/reply web services, and graciously takes care of the JAXB XML un/marshalling for
request parameter and response types.
3.11 JPA
The Java Persistence API, sometimes referred to as JPA, is a Java programming language
framework managing relational data in applications using Java Platform, Standard Edition and
Java Platform, Enterprise Edition.14
JPA is used for the Object-Relational mapping (ORM) within the WCSRI. The WCSRI leverages
an RDBMS for saving persistent data related to real-time notifications and publish/subscribe (e.g.,
messages, subscriptions). JPA is used to map the Java classes or objects to the tables within the
relational database.
3.12 Maven
Maven is a build automation tool typically used for Java projects. Maven serves a similar purpose
to the Apache Ant tool, but it is based on different concepts [...]. Maven uses an XML file to
describe the software project being built, its dependencies on other external modules and
components, the build order, directories, and required plug-ins. It comes with pre-defined targets
for performing certain well-defined tasks such as compilation of code and its packaging.15
Maven is used in building the WCSRI source code and packaging the WCSRI releases.
3.13 MINA
Apache MINA is a network application framework which helps users develop high performance
and high scalability network applications easily. It provides an abstract event-driven asynchronous
API over various transports such as TCP/IP and UDP/IP via Java NIO.16
MINA provides a low-level NIO framework for optimizing the WCSRI’s performance
characteristics. In addition, the MINA frontend endpoint provided by the WCSRI exposes a unified
WSDL, combining web services or operations from both the WCS and WS-N specifications into a
single master WSDL.
13
http://cxf.apache.org/index.html
http://en.wikipedia.org/wiki/Java_Persistence_API
15
http://en.wikipedia.org/wiki/Apache_Maven
16
http://mina.apache.org/
14
16
3.14 Jetty
The Jetty Web Server provides an HTTP server and Servlet container capable of serving static
and dynamic content either from a standalone or embedded instantiations.17
Jetty is provided as part of Servicemix within the WCSRI deployment, and is simply the HTTP
server for the web container.
3.15 Blueprint
Aries Blueprint provides a dependency injection framework for OSGi and was standardized by the
OSGi Alliance in OSGi Compendium R4.2. It is designed to deal with the dynamic nature of OSGi,
where services can become available and unavailable at any time. The specification is also
designed to work with plain old Java objects (POJOs) enabling simple components [...]. The
Blueprint XML files that define and describe the assembly of various components are key to the
Blueprint programming model. The specification describes how the components get instantiated
and wired together to form a running module.18
Aries Blueprint is an Inversion Of Control - Dependency Injection framework similar to Spring in its
intentions. The WCSRI makes extensive use of Blueprint to instantiate objects and glue them
together in a loosely-coupled, dependency-injected sort of way. Blueprint requires one or more
XML files to define the objects that are to be created, as well as the properties to set on objects
given references to other objects. In other words, Blueprint creates objects and sets them as
properties on other objects, per an XML configuration file. In an OSGi environment, Blueprint XML
files that are part of a bundle are loaded automatically when the bundle is loaded. Hence, after a
bundle is loaded and started, its objects and services are automatically available for use.
3.16 Security
3.16.1 HTTPS/SSL
Hypertext Transfer Protocol Secure (HTTPS) is a widely used communications protocol for secure
communication over a computer network, with especially wide deployment on the Internet.
Technically, it is not a protocol in itself; rather, it is the result of simply layering the Hypertext
Transfer Protocol (HTTP) on top of the SSL/TLS protocol, thus adding the security capabilities of
SSL/TLS to standard HTTP communications. In its popular deployment on the internet. HTTPS
provides authentication of the web site and associated web server that one is communicating
with, which protects against Man-in-the-middle attacks. Additionally, it provides bidirectional
encryption of communications between a client and server, which protects against eavesdropping
and tampering with and/or forging the contents of the communication. In practice, this provides a
reasonable guarantee that one is communicating with precisely the web site that one intended to
17
18
http://www.eclipse.org/jetty/about.php
http://aries.apache.org/modules/blueprint.html
17
communicate with (as opposed to an impostor), as well as ensuring that the contents of
communications between the user and site cannot be read or forged by any third party.19
HTTPS/SSL is used for providing secure communications with upstream WCSRI servers if
required and/or downstream WCSRI clients if security is enabled.
3.16.2 JAAS
Java Authentication and Authorization Service, or JAAS, pronounced "Jazz", is the Java
implementation of the standard Pluggable Authentication Module (PAM) information security
framework. JAAS was introduced as an extension library to the Java Platform, Standard Edition
1.3 and was integrated in version 1.4. The main goal of JAAS is to separate the concerns of user
authentication so that they may be managed independently. While the former authentication
mechanism contained information about where the code originated from and who signed that
code, JAAS adds a marker about who runs the code. By extending the verification vectors JAAS
extends the security architecture for Java applications that require authentication and
authorization modules.20
JAAS is the authentication service used by the WCSRI when security is enabled.
3.16.3 WS-Security (wss4j)
WS-Security (Web Services Security, short WSS) is a flexible and feature-rich extension to SOAP
to apply security to web services. It is a member of the WS-* family of web service specifications
and was published by OASIS.21
The Apache WSS4J™ project provides a Java implementation of the primary security standards
for Web Services, namely the OASIS Web Services Security (WS-Security) specifications from
the OASIS Web Services Security TC. WSS4J provides an implementation of the [...] WS-Security
standards.22
3.17 JAXB
Java Architecture for XML Binding (JAXB) allows Java developers to map Java classes to XML
representations. JAXB provides two main features: the ability to marshal Java objects into XML
and the inverse, i.e. to unmarshal XML back into Java objects. In other words, JAXB allows
storing and retrieving data in memory in any XML format, without the need to implement a specific
set of XML loading and saving routines for the program's class structure. [...] JAXB is a part of the
Java SE platform and one of the APIs in the Java EE platform.23
19
http://en.wikipedia.org/wiki/HTTP_Secure
http://en.wikipedia.org/wiki/Java_Authentication_and_Authorization_Service
21
http://en.wikipedia.org/wiki/WS-Security
22
http://ws.apache.org/wss4j/
23
http://en.wikipedia.org/wiki/Java_Architecture_for_XML_Binding
20
18
The WCSRI uses JAXB bindings for mapping the WCS and WS-N XML schemas to Java objects.
Since CXF provides the endpoints for the server and is the web-stack used, the framework takes
care of the un/marshalling of the XML to and from Java.
3.18 Monitoring
3.18.1 JMX and MBeans
Java Management Extensions (JMX) is a Java technology that supplies tools for managing and
monitoring applications, system objects, devices and service oriented networks. Those resources
are represented by objects called MBeans (for Managed Bean). In the API, classes can be
dynamically loaded and instantiated.24
JMX is a standard for exposing managed and/or monitored Java objects (“MBeans”) from an
application, which can then be invoked for functionality and/or queried for information. End
applications, such as JConsole, can then attach to a running Java application and display
exposed properties (e.g., statistics) and invoke methods (e.g., resubscribe) of MBeans. The
WCSRI exposes several “MBeans” for the intent of gathering and displaying performance
statistics, as well as providing simple management operations.
3.18.2 Google Guice
Google Guice is an open source software framework for the Java platform released by Google
under the Apache License. It provides support for dependency injection using annotations to
configure Java objects. Dependency injection is a design pattern whose core principle is to
separate behavior from dependency resolution. Guice allows implementation classes to be
programmatically bound to an interface, then injected into constructors, methods or fields using an
@Inject annotation.25
The WCSRI uses Guice to inject statistic-gathering MBeans into their target objects in a loosely
coupled fashion.
3.19 NetCDF and NetCDF Climate and Forecast (CF) Metadata
Convention
NetCDF (network Common Data Form) is a set of interfaces for array-oriented data access and a
freely-distributed collection of data access libraries for C, Fortran, C++, Java, and other
languages. The NetCDF libraries support a machine-independent format for representing
scientific data. Together, the interfaces, libraries, and format support the creation, access, and
sharing of scientific data.26
24
http://en.wikipedia.org/wiki/Java_Management_Extensions
http://en.wikipedia.org/wiki/Google_Guice
26
http://www.unidata.ucar.edu/software/netcdf/docs/faq.html#whatisit
25
19
NetCDF-4 is the file format produced by the WCSRI for getCoverage weather data subset
responses. NetCDF-4 is based on HDF5 and allows compression.
The conventions for climate and forecast (CF) metadata are designed to promote the processing
and sharing of files created with the NetCDF API. The CF conventions are increasingly gaining
acceptance and have been adopted by a number of projects and groups as a primary standard.
The conventions define metadata that provide a definitive description of what the data in each
variable represents, and the spatial and temporal properties of the data. This enables users of
data from different sources to decide which quantities are comparable, and facilitates building
applications with powerful extraction, regridding, and display capabilities.27
Since NetCDF is a very general file format and can be used to represent any kind of data, a
convention should be adopted in order to inject well-understood symantics (e.g., variable names)
and structure (e.g., axes) for coverages into each file. The convention required by the WCSRI for
raw weather data is the Climate and Forecast Metadata Convention (CF). This convention is
required since the WCSRI uses the NetCDF Java API and high-level constructs such as
GridDataset which are only accessible when the CF convention is used.
3.20 ncWMS
ncWMS is a Web Map Service for geospatial data that are stored in CF-compliant NetCDF files.
The intention is to create a WMS that requires minimal configuration: the source data files should
already contain most of the necessary metadata. ncWMS is developed and maintained by the
Reading e-Science Centre at the University of Reading, UK. [...] ncWMS is implemented in Java
as a web application.28
The ncWMS is a 3rd party optional feature to the WCSRI that consists of a web-application,
viewable in a web browser, that allows WCSRI administrators (or other) to visually verify NetCDF
files. If and when installed, the ncWMS is dynamically configured to expose the offered coverages
of the server. The coverages are available for viewing as both raw weather data files and the
weather data subset files retrieved using a SOAP getCoverage operation.
4 SOAP Operations
4.1 WSDL
The WCSRI implements the WCS 1.1.2 specification for the request/reply operations and the WSN specification for the publish/subscribe operations. Each specification defines a set of XML
schemas, and from those, a WSDL is defined designating the operations to be made available
from the server. Hence, there are two WSDL files - one for the WCS and one for the WS-N types
27
28
http://cf-pcmdi.llnl.gov/
http://www.resc.rdg.ac.uk/trac/ncWMS/
20
and operations. Two WSDL files is inconvenient considering that the WCSRI ought to advertise
and implement a single set of operations, whether they are targeted to the WCS 1.1.2 or WS-N
specifications. The WCSRI, instead, provides a single master WSDL, described below, that
combines the two subsets of operations.
4.1.1 WCS
The WCS 1.1 specification provides three request/reply MEP operations – GetCapabilities,
DescribeCoverage and GetCoverage. The first of these operations returns metadata describing
the capabilities of the server, including service provider information and high level informational
summaries of the coverages offered by the server. The DescribeCoverage operation provides
more detailed information about specifically requested coverages. The GetCoverage operation
provides a subsetting operation for a coverage constraining the result by field and/or spatiotemporal constraints. In addition, the WCS WSDL was customized to include a GetMetadata
operation in order to return service and coverage level metadata compliant with the ISO19139
specification. Each of these operations is shown below in a snippet from the WCS WSDL (i.e.,
taken from wcsri-web-service/src/main/resources/wsdl/wcs1_1_2_swa.wsdl).
<portType name="wcsPortType">
<operation name="getCapabilitiesOperation">
<documentation>Service definition of function getCapabilities</documentation>
<input message="tns:getCapabilitiesRequestMsg"></input>
<output message="tns:getCapabilitiesResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
<operation name="describeCoverageOperation">
<documentation>Service definition of function describeCoverage</documentation>
<input message="tns:describeCoverageRequestMsg"></input>
<output message="tns:describeCoverageResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
<operation name="getCoverageSwaOperation">
<documentation>Service definition of function getCoverage</documentation>
<input message="tns:getCoverageRequestMsg"></input>
<output message="tns:getCoverageResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
<operation name="getMetadataOperation">
<documentation>Service definition of function getMetadata</documentation>
<input message="tns:getMetadaRequestMsg"></input>
<output message="tns:getMetadataResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
</portType>
The machine-readable WCS WSDL is attainable via an HTTP-GET query against a running
WCSRI instance’s WCS SWA endpoint using the following syntax entered into a browser:
http://hostname:port/path?wsdl
21
Note that the “hostname:port/path” should be substituted with the values used for the server
instance’s WCS SWA (Soap With Attachments) endpoint. The value for this can be found in the
wcs.swa.httpEndpoint property in the server’s wcsri.cfg file.
4.1.2 WS-Notification (WS-N)
The WS-N specification is leveraged by the WCSRI for the symantics of the publish/subscribe
MEP. The WS-N specification provides Subscribe, Unsubscribe, Renew operations which are
supported by the WCSRI, and PauseSubscription and ResumeSubscription which are not
supported by the server at this time. The WS-N operations are described in an OASIS-generated
SOAP WSDL document. Since the WCSRI only supports a subset of the WS-N operations (e.g.,
PullPoint operations are not supported), the WS-N WSDL supported by the WCSRI has been
modified to omit unsupported operations. In addition, some operations (e.g., Subscribe()) have
been moved from the SubscriptionManager to PausableSubscriptionManager for ease of use. The
snippet below indicates the WS-N operations found in the WS-N WSDL (i.e., taken from wcsriweb-service/src/main/resources/NNEW-SubscriptionManagement.wsdl).
<portType name="PausableSubscriptionManager">
<operation name="Renew">
<input message="tns:RenewRequest" name="RenewRequest"></input>
<output message="tns:RenewResponse" name="RenewResponse"></output>
<fault>...</fault>
</operation>
<operation name="PauseSubscription">
<input message="tns:PauseSubscriptionRequest"></input>
<output message="tns:PauseSubscriptionResponse"></output>
<fault>...</fault>
</operation>
<operation name="ResumeSubscription">
<input message="tns:ResumeSubscriptionRequest"></input>
<output message="tns:ResumeSubscriptionResponse"></output>
<fault>...</fault>
</operation>
</portType>
<portType name="NotificationProducer">
<operation name="Subscribe">
<input message="tns:SubscribeRequest"></input>
<output message="tns:SubscribeResponse"></output>
<fault>...</fault>
</operation>
</portType>
The machine-readable WS-N WSDL is attainable via an HTTP-GET query against a running
WCSRI instance’s WCS SWA endpoint using the following syntax entered into a browser:
http://hostname:port/path?wsdl
Note that the “hostname:port/path” should be substituted with the values used for the server
instance’s Subscribe endpoint. The value for this can be found in the wcs.subscribe.httpEndpoint
property in the server’s wcsri.cfg file.
22
4.1.3 Master WSDL
The WCSRI’s master WSDL specifies the operations available from the server and includes the
operations defined by both the WCS (plus the ISO-related operation getMetadata) and WS-N
specifications. This is a convenient WSDL document available from a single endpoint that
advertises all of the operations available from the server, and simply combines the WSDLs from
the WCS and WS-N specifications into one document. The machine-readable master WSDL is
attainable via an HTTP-GET query against a running WCSRI instance’s published front-endpoint
using the following syntax entered into a browser:
http://hostname:port/path?wsdl
Note that the “hostname:port/path” should be substituted with the values used for the server
instance’s front-endpoint. The value for this can be found in the wcs.frontend.external.url property
in the server’s wcsri.cfg file.
The master WSDL snippet below (some parts omitted) shows an example of the complete set of
operations provided by the WCSRI server, which is simply a combination of the operations listed
in the preceding sections.
<portType name="wcsPortType">
<operation name="getCapabilitiesOperation">
<documentation>Service definition of function getCapabilities</documentation>
<input message="tns:getCapabilitiesRequestMsg"></input>
<output message="tns:getCapabilitiesResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
<operation name="describeCoverageOperation">
<documentation>Service definition of function describeCoverage</documentation>
<input message="tns:describeCoverageRequestMsg"></input>
<output message="tns:describeCoverageResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
<operation name="getCoverageSwaOperation">
<documentation>Service definition of function getCoverage</documentation>
<input message="tns:getCoverageRequestMsg"></input>
<output message="tns:getCoverageResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
<operation name="getMetadataOperation">
<documentation>Service definition of function getMetadata</documentation>
<input message="tns:getMetadaRequestMsg"></input>
<output message="tns:getMetadataResponseMsg"></output>
<fault message="tns:exceptionReportMsg" name="ExceptionReport"></fault>
</operation>
</portType>
<portType name="PausableSubscriptionManager">
<operation name="Renew">
<input message="tns:RenewRequest" name="RenewRequest"></input>
<output message="tns:RenewResponse" name="RenewResponse"></output>
<fault>...</fault>
</operation>
<operation name="PauseSubscription">
<input message="tns:PauseSubscriptionRequest"></input>
23
<output message="tns:PauseSubscriptionResponse"></output>
<fault>...</fault>
</operation>
<operation name="ResumeSubscription">
<input message="tns:ResumeSubscriptionRequest"></input>
<output message="tns:ResumeSubscriptionResponse"></output>
<fault>...</fault>
</operation>
</portType>
<portType name="NotificationProducer">
<operation name="Subscribe">
<input message="tns:SubscribeRequest"></input>
<output message="tns:SubscribeResponse"></output>
<fault>...</fault>
</operation>
</portType>
4.2 Examples
The following sections contain examples of KVP and SOAP requests and responses for the
WCSRI. Most of this information can be found in the WSDD document mentioned in the
Prerequisites section of this document, but are included here for completeness.
4.2.1 GetCapabilities SOAP Request and Response
Example 1 of GetCapabilities Request
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1"
xmlns:ns1="http://www.opengis.net/ows/1.1">
<soap:Header/>
<soap:Body>
<ns:GetCapabilities updateSequence="?" service="WCS">
</ns:GetCapabilities>
</soap:Body>
</soap:Envelope>
Example 1 of GetCapabilities Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns11:Capabilities version="1.1.1" xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns9:ServiceIdentification>
<ns9:Title>NNEW Web Coverage Service Version 2.0 (WCS)</ns9:Title>
<ns9:Abstract>This is a trimmed down implementation of the WCS 1.1.2 specification</ns9:Abstract>
<ns9:ServiceType>WCS</ns9:ServiceType>
24
<ns9:ServiceTypeVersion>1.1.0</ns9:ServiceTypeVersion>
<ns9:Fees>None</ns9:Fees>
<ns9:AccessConstraints>none</ns9:AccessConstraints>
</ns9:ServiceIdentification>
<ns9:ServiceProvider>
<ns9:ProviderName>NextGen Network Enabled Weather (NNEW)</ns9:ProviderName>
<ns9:ServiceContact>
<ns9:IndividualName>Jerry</ns9:IndividualName>
<ns9:PositionName>Software Engineer</ns9:PositionName>
<ns9:ContactInfo>
<ns9:Phone>
<ns9:Voice>303-487-2806</ns9:Voice>
</ns9:Phone>
<ns9:Address>
<ns9:DeliveryPoint>FL2</ns9:DeliveryPoint>
<ns9:DeliveryPoint>3300 Mitchell Lane</ns9:DeliveryPoint>
<ns9:City>Boulder</ns9:City>
<ns9:AdministrativeArea>Colorado</ns9:AdministrativeArea>
<ns9:PostalCode>80305</ns9:PostalCode>
<ns9:Country>U.S.</ns9:Country>
<ns9:ElectronicMailAddress>blah[at]ucar[dot]edu</ns9:ElectronicMailAddress>
</ns9:Address>
<ns9:OnlineResource ns12:type="simple" ns12:href="http://ral.ucar.edu/projects/nnew/"/>
<ns9:HoursOfService>8x5x365</ns9:HoursOfService>
<ns9:ContactInstructions>email</ns9:ContactInstructions>
</ns9:ContactInfo>
<ns9:Role>Lead Engineer</ns9:Role>
</ns9:ServiceContact>
</ns9:ServiceProvider>
<ns9:OperationsMetadata>
<ns9:Operation name="GetCapabilities">
<ns9:DCP>
<ns9:HTTP>
<ns9:Post ns12:type="simple" ns12:href="http://mymachine:9090/wcs">
<ns9:Constraint name="PostEncoding">
<ns9:AllowedValues>
<ns9:Value>SOAP</ns9:Value>
</ns9:AllowedValues>
</ns9:Constraint>
</ns9:Post>
<ns9:Get ns12:type="simple" ns12:href="http://mymachine:9090/wcs">
<ns9:Constraint name="PostEncoding">
<ns9:AllowedValues>
<ns9:Value>KVP</ns9:Value>
</ns9:AllowedValues>
</ns9:Constraint>
</ns9:Get>
</ns9:HTTP>
</ns9:DCP>
<ns9:Parameter name="service">
<ns9:AllowedValues>
<ns9:Value>WCS</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="request">
<ns9:AllowedValues>
<ns9:Value>GetCapabilities</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="version">
<ns9:AllowedValues>
25
<ns9:Value>1.1.0</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="AcceptVersions">
<ns9:AllowedValues>
<ns9:Value>1.1.0</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
</ns9:Operation>
<ns9:Operation name="DescribeCoverage">
<ns9:DCP>
<ns9:HTTP>
<ns9:Post ns12:type="simple" ns12:href="http://mymachine:9090/wcs">
<ns9:Constraint name="PostEncoding">
<ns9:AllowedValues>
<ns9:Value>SOAP</ns9:Value>
</ns9:AllowedValues>
</ns9:Constraint>
</ns9:Post>
<ns9:Get ns12:type="simple" ns12:href="http://mymachine:9090/wcs">
<ns9:Constraint name="PostEncoding">
<ns9:AllowedValues>
<ns9:Value>KVP</ns9:Value>
</ns9:AllowedValues>
</ns9:Constraint>
</ns9:Get>
</ns9:HTTP>
</ns9:DCP>
<ns9:Parameter name="service">
<ns9:AllowedValues>
<ns9:Value>WCS</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="request">
<ns9:AllowedValues>
<ns9:Value>DescribeCoverage</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="version">
<ns9:AllowedValues>
<ns9:Value>1.1.0</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="Identifier">
<ns9:AllowedValues>
<ns9:Value>urn:fdc:ncar.ucar.edu:Dataset:RoboRuc</ns9:Value>
<ns9:Value>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Wind</ns9:Value>
<ns9:Value>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
</ns9:Operation>
<ns9:Operation name="GetCoverage">
<ns9:DCP>
<ns9:HTTP>
<ns9:Post ns12:type="simple" ns12:href="http://mymachine:9090/wcs">
<ns9:Constraint name="PostEncoding">
<ns9:AllowedValues>
<ns9:Value>SOAP</ns9:Value>
</ns9:AllowedValues>
</ns9:Constraint>
</ns9:Post>
26
</ns9:HTTP>
</ns9:DCP>
<ns9:Parameter name="service">
<ns9:AllowedValues>
<ns9:Value>WCS</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="request">
<ns9:AllowedValues>
<ns9:Value>GetCoverage</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="version">
<ns9:AllowedValues>
<ns9:Value>1.1.0</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="Identifier">
<ns9:AllowedValues>
<ns9:Value>urn:fdc:ncar.ucar.edu:Dataset:RoboRuc</ns9:Value>
<ns9:Value>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Wind</ns9:Value>
<ns9:Value>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="format">
<ns9:AllowedValues>
<ns9:Value>application/x-NetCDF4</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
<ns9:Parameter name="store">
<ns9:AllowedValues>
<ns9:Value>false</ns9:Value>
</ns9:AllowedValues>
</ns9:Parameter>
</ns9:Operation>
</ns9:OperationsMetadata>
<ns11:Contents>
<ns11:CoverageSummary>
<ns9:Title>RUC Air Temperature (Pox Dixon Netcdf 4)</ns9:Title>
<ns9:Abstract>This dataset consists of RUC data for the Air Temperature 3D field. </ns9:Abstract>
<ns9:Keywords>
<ns9:Keyword>RUC</ns9:Keyword>
</ns9:Keywords>
<ns9:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="2">
<ns9:LowerCorner>233.06837749013812 22.050739639122614</ns9:LowerCorner>
<ns9:UpperCorner>299.6151324722109 48.843403043864825</ns9:UpperCorner>
</ns9:WGS84BoundingBox>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84_plus_Z_in_km</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:NCAR_Corridor_CRS</ns11:SupportedCRS>
<ns11:SupportedFormat>application/x-NetCDF4</ns11:SupportedFormat>
<ns11:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RoboRuc</ns11:Identifier>
</ns11:CoverageSummary>
<ns11:CoverageSummary>
<ns9:Title>Repeater RUC20P Wind</ns9:Title>
<ns9:Abstract>Repeater RUC20P Wind</ns9:Abstract>
<ns9:Keywords>
<ns9:Keyword>RUC</ns9:Keyword>
</ns9:Keywords>
27
<ns9:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="2">
<ns9:LowerCorner>219.97267712178922 16.172479139850356</ns9:LowerCorner>
<ns9:UpperCorner>302.7901259725264 55.534960736265205</ns9:UpperCorner>
</ns9:WGS84BoundingBox>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84_plus_Z_in_km</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:NCAR_Corridor_CRS</ns11:SupportedCRS>
<ns11:SupportedFormat>application/x-NetCDF4</ns11:SupportedFormat>
<ns11:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Wind</ns11:Identifier>
</ns11:CoverageSummary>
<ns11:CoverageSummary>
<ns9:Title>Repeater RUC20P Temperature</ns9:Title>
<ns9:Abstract>Repeater RUC20P Temperature</ns9:Abstract>
<ns9:Keywords>
<ns9:Keyword>RUC</ns9:Keyword>
<ns9:Keyword>Repeater</ns9:Keyword>
</ns9:Keywords>
<ns9:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="2">
<ns9:LowerCorner>219.97267712178922 16.172479139850356</ns9:LowerCorner>
<ns9:UpperCorner>302.7901259725264 55.534960736265205</ns9:UpperCorner>
</ns9:WGS84BoundingBox>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84_plus_Z_in_km</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:NCAR_Corridor_CRS</ns11:SupportedCRS>
<ns11:SupportedFormat>application/x-NetCDF4</ns11:SupportedFormat>
<ns11:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</ns11:Identifier>
</ns11:CoverageSummary>
<ns11:SupportedCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:NCAR_Corridor_CRS</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84_plus_Z_in_km</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedFormat>application/x-NetCDF4</ns11:SupportedFormat>
</ns11:Contents>
</ns11:Capabilities>
</soap:Body>
</soap:Envelope>
Example 2 of GetCapabilities Request
In this example, a specific Section is requested.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1"
xmlns:ns1="http://www.opengis.net/ows/1.1">
<soap:Header/>
<soap:Body>
<ns:GetCapabilities updateSequence="?" service="WCS">
<ns1:Sections>
<ns1:Section>ServiceProvider</ns1:Section>
</ns1:Sections>
</ns:GetCapabilities>
</soap:Body>
</soap:Envelope>
Example 2 of GetCapabilities Response
28
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns11:Capabilities version="1.1.1" xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns9:ServiceProvider>
<ns9:ProviderName>NextGen Network Enabled Weather (NNEW)</ns9:ProviderName>
<ns9:ServiceContact>
<ns9:IndividualName>Jerry</ns9:IndividualName>
<ns9:PositionName>Software Engineer</ns9:PositionName>
<ns9:ContactInfo>
<ns9:Phone>
<ns9:Voice>303-495-2855</ns9:Voice>
</ns9:Phone>
<ns9:Address>
<ns9:DeliveryPoint>FL2</ns9:DeliveryPoint>
<ns9:DeliveryPoint>3300 Mitchell Lane</ns9:DeliveryPoint>
<ns9:City>Boulder</ns9:City>
<ns9:AdministrativeArea>Colorado</ns9:AdministrativeArea>
<ns9:PostalCode>80305</ns9:PostalCode>
<ns9:Country>U.S.</ns9:Country>
<ns9:ElectronicMailAddress>blah[at]ucar[dot]edu</ns9:ElectronicMailAddress>
</ns9:Address>
<ns9:OnlineResource ns12:type="simple" ns12:href="http://ral.ucar.edu/projects/nnew/"/>
<ns9:HoursOfService>8x5x365</ns9:HoursOfService>
<ns9:ContactInstructions>email</ns9:ContactInstructions>
</ns9:ContactInfo>
<ns9:Role>Lead Engineer</ns9:Role>
</ns9:ServiceContact>
</ns9:ServiceProvider>
</ns11:Capabilities>
</soap:Body>
</soap:Envelope>
4.2.2 DescribeCoverage SOAP Request and Response
Example 1 of DescribeCoverage Request
Note that in this example, the server-side coverage is configured to return a ValidTimesList for the
TemporalDomain:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1">
<soap:Header/>
<soap:Body>
<ns:DescribeCoverage service="WCS" version="1.1.2">
<!--1 or more repetitions:-->
<ns:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</ns:Identifier>
</ns:DescribeCoverage>
29
</soap:Body>
</soap:Envelope>
Example 1 of DescribeCoverage Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns11:CoverageDescriptions xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns11:CoverageDescription>
<ns9:Title>Repeater RUC20P Temperature</ns9:Title>
<ns9:Abstract>Repeater RUC20P Temperature</ns9:Abstract>
<ns9:Keywords>
<ns9:Keyword>RUC</ns9:Keyword>
<ns9:Keyword>Repeater</ns9:Keyword>
</ns9:Keywords>
<ns11:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</ns11:Identifier>
<ns11:Domain>
<ns11:SpatialDomain>
<ns9:BoundingBox crs="urn:ncar:def:crs:Lambert_Conformal" dimensions="3">
<ns9:LowerCorner>-3342.314336717163 -599.0517377703311 100000.0</ns9:LowerCorner>
<ns9:UpperCorner>2773.403663282838 3972.4982622296684 10000.0</ns9:UpperCorner>
</ns9:BoundingBox>
<ns9:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="2">
<ns9:LowerCorner>219.97267712178922 16.172479139850356</ns9:LowerCorner>
<ns9:UpperCorner>302.7901259725264 55.534960736265205</ns9:UpperCorner>
</ns9:BoundingBox>
<ns9:BoundingBox crs="urn:ogc:def:crs:OGC:2:84_plus_Z_in_km" dimensions="3">
<ns9:LowerCorner>219.97267712178922 16.172479139850356 0.11088560777723334</ns9:LowerCorner>
<ns9:UpperCorner>302.7901259725264 55.534960736265205 16.179870757649386</ns9:UpperCorner>
</ns9:BoundingBox>
<ns11:GridCRS>
<ns11:GridBaseCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:GridBaseCRS>
<ns11:GridOrigin/>
<ns11:GridOffsets/>
</ns11:GridCRS>
</ns11:SpatialDomain>
<ns11:TemporalDomain>
<ns10:timePosition>2010-05-19T22:00:00.000Z</ns10:timePosition>
</ns11:TemporalDomain>
</ns11:Domain>
<ns11:Range>
<ns11:Field>
<ns11:Identifier>Temperature</ns11:Identifier>
<ns11:Definition>
<ns9:NoValues/>
<ns9:UOM>K</ns9:UOM>
<ns9:Metadata about="Native Vertical Axis Levels" ns12:type="simple">
<ns14:VerticalLevels positive="down" nativeUnits="true" isPressure="true" isRegular="true" units="Pa"
numLevels="37" increment="-2500.0" maxValue="100000.0" minValue="10000.0">
30
<Levels>100000.0 97500.0 95000.0 92500.0 90000.0 87500.0 85000.0 82500.0 80000.0 77500.0 75000.0
72500.0 70000.0 67500.0 65000.0 62500.0 60000.0 57500.0 55000.0 52500.0 50000.0 47500.0
45000.0 42500.0 40000.0 37500.0 35000.0 32500.0 30000.0 27500.0 25000.0 22500.0 20000.0
17500.0 15000.0 12500.0 10000.0</Levels>
</ns14:VerticalLevels>
</ns9:Metadata>
<ns9:Metadata about="Vertical Axis Levels in Km" ns12:type="simple">
<ns14:VerticalLevels positive="up" nativeUnits="false" isPressure="false" isRegular="true" units="Km"
numLevels="37" increment="NaN" maxValue="16.179870757649386" minValue="0.11088560777723334">
<Levels>0.11088560777723334 0.32338480687058807 0.5403428204997017 0.7619743261051326
0.9885104883139163 1.2202007241891037 1.4573147140115628 1.7001447000778767
1.9490081248805802 2.2042506711152416 2.4662497798680345 2.735418740920365
3.0122114714962263 3.2971281285102547 3.5907217365532307 3.8936060623875095
4.206465030692479 4.530064060967885 4.86526382015265 5.213037041694131
5.5744892773071015 5.9508847492221735 6.343678899201953 6.754559849713033
7.185501903866339 7.638835579621711 8.117340777532409 8.624372998142848
9.164037907498692 9.74143857492254 10.363035424926645 11.037208306412305
11.784150993649915 12.630964770198526 13.608539532030846 14.76476506836631
16.179870757649386</Levels>
</ns14:VerticalLevels>
</ns9:Metadata>
</ns11:Definition>
<ns11:InterpolationMethods>
<ns11:InterpolationMethod>nearest</ns11:InterpolationMethod>
<ns11:Default>nearest</ns11:Default>
</ns11:InterpolationMethods>
</ns11:Field>
</ns11:Range>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84_plus_Z_in_km</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:NCAR_Corridor_CRS</ns11:SupportedCRS>
<ns11:SupportedFormat>application/x-NetCDF4</ns11:SupportedFormat>
</ns11:CoverageDescription>
</ns11:CoverageDescriptions>
</soap:Body>
</soap:Envelope>
Example 2 of DescribeCoverage Request
Note that in this example, the server-side coverage is configured to return a ValidTimeRange or
TimePeriod for the TemporalDomain:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1">
<soap:Header/>
<soap:Body>
<ns:DescribeCoverage service="WCS" version="1.1.2">
<!--1 or more repetitions:-->
<ns:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns:Identifier>
</ns:DescribeCoverage>
</soap:Body>
</soap:Envelope>
Example 2 of DescribeCoverage Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
31
<ns11:CoverageDescriptions xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns11:CoverageDescription>
<ns9:Title>RUC Air Temperature (Pox Dixon Netcdf 4)</ns9:Title>
<ns9:Abstract>This dataset consists of RUC data for the Air Temperature 3D field</ns9:Abstract>
<ns9:Keywords>
<ns9:Keyword>RUC</ns9:Keyword>
<ns9:Keyword>Dixon</ns9:Keyword>
<ns9:Keyword>Pox</ns9:Keyword>
<ns9:Keyword>Netcdf4</ns9:Keyword>
</ns9:Keywords>
<ns11:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns11:Identifier>
<ns11:Domain>
<ns11:SpatialDomain>
<ns9:BoundingBox crs="urn:ncar:def:crs:Lambert_Conformal" dimensions="3">
<ns9:LowerCorner>-2549.8992919921875 -50.46342086791992 1.220200777053833</ns9:LowerCorner>
<ns9:UpperCorner>2773.4171142578125 3037.87255859375 16.17987060546875</ns9:UpperCorner>
</ns9:BoundingBox>
<ns9:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="2">
<ns9:LowerCorner>233.06837749013812 22.050739639122614</ns9:LowerCorner>
<ns9:UpperCorner>299.6151324722109 48.843403043864825</ns9:UpperCorner>
</ns9:BoundingBox>
<ns9:BoundingBox crs="urn:ogc:def:crs:OGC:2:84_plus_Z_in_km" dimensions="3">
<ns9:LowerCorner>233.06837749013812 22.050739639122614 1.220200777053833</ns9:LowerCorner>
<ns9:UpperCorner>299.6151324722109 48.843403043864825 16.17987060546875</ns9:UpperCorner>
</ns9:BoundingBox>
<ns11:GridCRS>
<ns11:GridBaseCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:GridBaseCRS>
<ns11:GridOrigin/>
<ns11:GridOffsets/>
</ns11:GridCRS>
</ns11:SpatialDomain>
<ns11:TemporalDomain>
<ns11:TimePeriod>
<ns11:BeginPosition>2009-06-18T18:00:00.000Z</ns11:BeginPosition>
<ns11:EndPosition>2009-06-19T06:00:00.000Z</ns11:EndPosition>
<ns11:TimeResolution>PT10800S</ns11:TimeResolution>
</ns11:TimePeriod>
</ns11:TemporalDomain>
</ns11:Domain>
<ns11:Range>
<ns11:Field>
<ns9:Title>Title Text</ns9:Title>
<ns9:Abstract>Abstract Text</ns9:Abstract>
<ns11:Identifier>TMP</ns11:Identifier>
<ns11:Definition>
<ns9:NoValues/>
<ns9:Meaning>Meaning Text</ns9:Meaning>
<ns9:UOM>C</ns9:UOM>
<ns9:Metadata ns12:type="simple">
<ns14:GenericMetaData>Metadata Text1</ns14:GenericMetaData>
32
</ns9:Metadata>
<ns9:Metadata ns12:type="simple">
<ns14:GenericMetaData>Metadata Text2</ns14:GenericMetaData>
</ns9:Metadata>
<ns9:Metadata about="Native Vertical Axis Levels" ns12:type="simple">
<ns14:VerticalLevels standardname="altitude" positive="up" nativeUnits="true" isPressure="false" isRegular="false"
units="km" numLevels="32" increment="0.4825699944649973" maxValue="16.17987060546875"
minValue="1.220200777053833">
<Levels>1.220200777053833 1.4573147296905518 1.700144648551941 1.9490081071853638
2.2042505741119385 2.466249704360962 2.7354187965393066 3.012211561203003 3.297128200531006
3.590721845626831 3.893605947494507 4.206465244293213 4.530064105987549 4.865263938903809
5.213037014007568 5.574489116668701 5.950884819030762 6.343678951263428 6.7545599937438965
7.185502052307129 7.638835430145264 8.117341041564941 8.624373435974121 9.164037704467773
9.741438865661621 10.363035202026367 11.037208557128906 11.784151077270508
12.630965232849121 13.608539581298828 14.764764785766602 16.17987060546875</Levels>
</ns14:VerticalLevels>
</ns9:Metadata>
</ns11:Definition>
<ns11:InterpolationMethods>
<ns11:InterpolationMethod>nearest</ns11:InterpolationMethod>
<ns11:Default>nearest</ns11:Default>
</ns11:InterpolationMethods>
</ns11:Field>
</ns11:Range>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:Lambert_Conformal</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ogc:def:crs:OGC:2:84_plus_Z_in_km</ns11:SupportedCRS>
<ns11:SupportedCRS>urn:ncar:def:crs:NCAR_Corridor_CRS</ns11:SupportedCRS>
<ns11:SupportedFormat>application/x-NetCDF4</ns11:SupportedFormat>
</ns11:CoverageDescription>
</ns11:CoverageDescriptions>
</soap:Body>
</soap:Envelope>
4.2.3 GetCoverage SOAP Request and Response
Common Example of GetCoverage Response
Note that all getCoverage responses will look similar to the following. Also note that the Reference
refers to the NetCDF file that is attached to the response using SOAP With Attachments.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns11:Coverages xmlns:ns24="http://www.w3.org/2001/SMIL20/Language" xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2"
xmlns:ns22="http://www.wcs.opengis.net/wsdl" xmlns:ns21="http://www.java/lang"
xmlns:ns20="http://www.isotc211.org/2005/gts" xmlns:ns19="http://www.isotc211.org/2005/srv"
xmlns:ns18="http://www.isotc211.org/2005/gmx" xmlns:ns17="http://www.isotc211.org/2005/gco"
xmlns:ns16="http://www.isotc211.org/2005/gmd" xmlns:ns15="http://www.opengis.net/gml/3.2"
xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension" xmlns:ns13="http://www.w3.org/2001/SMIL20/"
xmlns:ns12="http://www.w3.org/1999/xlink" xmlns:ns11="http://www.opengis.net/wcs/1.1"
xmlns:ns10="http://www.opengis.net/gml" xmlns:ns9="http://www.opengis.net/ows/1.1"
xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139" xmlns:ns7="http://docs.oasis-open.org/wsn/b-2"
xmlns:ns6="http://www.w3.org/2005/08/addressing" xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns11:Coverage>
<ns9:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns9:Identifier>
<ns9:Reference ns9:type="simple" ns12:href="cid:wcsri_f09ca6e6-9a65-4eb6-9a65-fcd1d998b273.nc"
33
ns12:role="urn:ogc:def:role:WCS:1.1:coverage"/>
</ns11:Coverage>
</ns11:Coverages>
</soap:Body>
</soap:Envelope>
Example 1 of GetCoverage Request
In this example, we are requesting a 3-D rectilinear section of 3-D rectilinear data, for a single
valid time - note that the TimeRange could extend wider and if the server had more than one raw
data file valid for the time range, then the resulting NetCDF file would contain a time series of
data.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1"
xmlns:ns1="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml">
<soap:Header/>
<soap:Body>
<ns:GetCoverage service="WCS" version="1.1.2">
<ns1:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns1:Identifier>
<ns:DomainSubset>
<ns1:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="3">
<ns1:LowerCorner>-120.0 38.6 3.893606</ns1:LowerCorner>
<ns1:UpperCorner>-106.6 42.5 3.893606</ns1:UpperCorner>
</ns1:BoundingBox>
<ns:TemporalSubset>
<!--You have a CHOICE of the next 2 items at this level-->
<ns:TimePeriod>
<ns:BeginPosition>2009-06-19T03:00:00.000Z</ns:BeginPosition>
<ns:EndPosition>2009-06-19T03:00:00.000Z</ns:EndPosition>
<!--Optional:-->
<!--ns:TimeResolution>?</ns:TimeResolution-->
</ns:TimePeriod>
</ns:TemporalSubset>
</ns:DomainSubset>
<ns:RangeSubset>
<!--1 or more repetitions:-->
<ns:FieldSubset>
<ns1:Identifier>TMP</ns1:Identifier>
<!--Optional:-->
</ns:FieldSubset>
</ns:RangeSubset>
<ns:Output format="application/netcdf4" store="false"></ns:Output>
</ns:GetCoverage>
</soap:Body>
</soap:Envelope>
Example 2 of GetCoverage Request
In this example, we are requesting a 3-D rectilinear section of 3-D rectilinear data, for two specific
valid times resulting in a NetCDF file containing a time series of data.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns=”http://www.opengis.net/wcs/1.1”
xmlns:ns1="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml">
<soap:Header/>
<soap:Body>
34
<ns:GetCoverage service="WCS" version="1.1.2">
<ns1:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns1:Identifier>
<ns:DomainSubset>
<ns1:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="3">
<ns1:LowerCorner>-120.0 38.6 3.893606</ns1:LowerCorner>
<ns1:UpperCorner>-106.6 42.5 3.893606</ns1:UpperCorner>
</ns1:BoundingBox>
<!--Optional:-->
<ns:TemporalSubset>
<!--You have a CHOICE of the next 2 items at this level-->
<gml:timePosition>2009-06-19T03:00:00.000Z</gml:timePosition>
<gml:timePosition>2009-06-19T06:00:00.000Z</gml:timePosition>
</ns:TemporalSubset>
</ns:DomainSubset>
<!--Optional:-->
<ns:RangeSubset>
<!--1 or more repetitions:-->
<ns:FieldSubset>
<ns1:Identifier>TMP</ns1:Identifier>
<!--Optional:-->
</ns:FieldSubset>
</ns:RangeSubset>
<ns:Output format="application/netcdf4" store="false">
</ns:Output>
</ns:GetCoverage>
</soap:Body>
</soap:Envelope>
Example 3 of GetCoverage Request
In this example, we are requesting a 3-D rectilinear section of 3-D rectilinear data, for a single
valid time generated at a specific generation time. The generation and valid times are indicated by
issuing a single TimePeriod, where BeginPosition == EndPosition == the valid time of the data,
and TimeResolution is an XML duration representing the lead seconds for the forecast data (i.e.,
the difference between the valid time and the model generation or analysis time).
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1"
xmlns:ns1="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml">
<soap:Header/>
<soap:Body>
<ns:GetCoverage service="WCS" version="1.1.2">
<ns1:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns1:Identifier>
<ns:DomainSubset>
<ns1:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="3">
<ns1:LowerCorner>-143.0 38.0 3.893606</ns1:LowerCorner>
<ns1:UpperCorner>-111.0 60.0 3.893606</ns1:UpperCorner>
</ns1:BoundingBox>
<!--Optional:-->
<ns:TemporalSubset>
<!--You have a CHOICE of the next 2 items at this level-->
<ns:TimePeriod>
<ns:BeginPosition>2009-06-19T03:00:00.000Z</ns:BeginPosition>
<ns:EndPosition>2009-06-19T03:00:00.000Z</ns:EndPosition>
<ns:TimeResolution>PT21600S</ns:TimeResolution>
</ns:TimePeriod>
</ns:TemporalSubset>
</ns:DomainSubset>
<!--Optional:-->
35
<ns:RangeSubset>
<!--1 or more repetitions:-->
<ns:FieldSubset>
<ns1:Identifier>TMP</ns1:Identifier>
<!--Optional:-->
</ns:FieldSubset>
</ns:RangeSubset>
<ns:Output format="application/netcdf4" store="false">
</ns:Output>
</ns:GetCoverage>
</soap:Body>
</soap:Envelope>
Example 4 of GetCoverage Request
In this example, we are requesting a temporal corridor through 3-D rectilinear data.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.opengis.net/wcs/1.1"
xmlns:ns1="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml">
<soap:Header/>
<soap:Body>
<ns:GetCoverage service="WCS" version="1.1.2">
<ns1:Identifier>urn:fdc:ncar.ucar.edu:Dataset:PoxDixonNetcdf4RUC20_Air_Temperature</ns1:Identifier>
<ns:DomainSubset>
<ns1:BoundingBox crs="temporaryCorridorCRS" dimensions="4">
<ns1:LowerCorner>0 -5.0 -0.5 0</ns1:LowerCorner>
<ns1:UpperCorner>499 5.0 0.5 499</ns1:UpperCorner>
</ns1:BoundingBox>
<!--Optional:-->
<ns:TemporalSubset>
<!--You have a CHOICE of the next 2 items at this level-->
<gml:timePosition>2009-06-19T03:00:00.000Z</gml:timePosition>
<gml:timePosition>2009-06-19T06:00:00.000Z</gml:timePosition>
</ns:TemporalSubset>
</ns:DomainSubset>
<!--Optional:-->
<ns:RangeSubset>
<!--1 or more repetitions:-->
<ns:FieldSubset>
<ns1:Identifier >TMP</ns1:Identifier>
</ns:FieldSubset>
</ns:RangeSubset>
<ns:Output format="application/netcdf4" store="false">
<!--Optional:-->
<ns:GridCRS gml:id="iDontKnow">
<!--Optional:-->
<gml:srsName>temporaryCorridorCRS</gml:srsName>
<ns:GridBaseCRS>urn:ncar:def:crs:NCAR_Corridor_CRS:500:39.863:-104.684:1.609:1245380400000:40.795:111.98:1.288:1245385800000:47.451:-122.316:0.132:1245391200000</ns:GridBaseCRS>
<!--Optional:-->
<ns:GridType>urn:ogc:def:method:WCS:1.1:2dSimpleGrid</ns:GridType>
<!--Optional:-->
<ns:GridOrigin>0 0 0 0</ns:GridOrigin>
<ns:GridOffsets>1 0 0 0 0 0.1 0 0 0 0 0.05 0 0 0 0 1</ns:GridOffsets>
<!--Optional:-->
<ns:GridCS>urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS</ns:GridCS>
</ns:GridCRS>
</ns:Output>
</ns:GetCoverage>
36
</soap:Body>
</soap:Envelope>
4.2.4 GetMetadata SOAP Request and Response
Example 1 of GetMetadata Request
Note that in this example, the ISO 19139 metadata for the WCSRI services, rather than a dataset,
is being requested. This is similar to a getCapabilities request, except for ISO 19139.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:iso1="http://wcsri.ral.ucar.edu/iso19139">
<soap:Header/>
<soap:Body>
<iso1:GetMetadata>
<iso1:ServicesMetadataFilter>
<!--Zero or more repetitions:-->
<!--Xpath>?</Xpath-->
</iso1:ServicesMetadataFilter>
</iso1:GetMetadata>
</soap:Body>
</soap:Envelope>
Example 1 of GetMetadata Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns8:MetadataResponse xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns16:MD_Metadata uuid="urn:fdc:ncar.ucar.edu:Service:WCS-01">
<ns16:fileIdentifier ns17:nilReason="">
<ns17:CharacterString>urn:fdc:ncar.ucar.edu:Service:WCS-01:Service:metadata</ns17:CharacterString>
</ns16:fileIdentifier>
<ns16:hierarchyLevel ns17:nilReason="">
<ns16:MD_ScopeCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ScopeCode"
codeListValue="service"/>
</ns16:hierarchyLevel>
<ns16:contact ns17:nilReason="" ns12:type="simple">
<ns16:CI_ResponsibleParty>
<ns16:organisationName ns17:nilReason="">
<ns17:CharacterString>National Center for Atmospheric Research (NCAR)</ns17:CharacterString>
</ns16:organisationName>
<ns16:contactInfo ns17:nilReason="" ns12:type="simple">
<ns16:CI_Contact>
<ns16:phone ns17:nilReason="" ns12:type="simple">
<ns16:CI_Telephone>
<ns16:voice ns17:nilReason="">
<ns17:CharacterString>303-497-8700</ns17:CharacterString>
37
</ns16:voice>
<ns16:facsimile ns17:nilReason="">
<ns17:CharacterString>303-497-8701</ns17:CharacterString>
</ns16:facsimile>
</ns16:CI_Telephone>
</ns16:phone>
<ns16:address ns17:nilReason="" ns12:type="simple">
<ns16:CI_Address>
<ns16:deliveryPoint ns17:nilReason="">
<ns17:CharacterString>3450 Mitchell Lane</ns17:CharacterString>
</ns16:deliveryPoint>
<ns16:city ns17:nilReason="">
<ns17:CharacterString>Boulder</ns17:CharacterString>
</ns16:city>
<ns16:administrativeArea ns17:nilReason="">
<ns17:CharacterString>CO</ns17:CharacterString>
</ns16:administrativeArea>
<ns16:postalCode ns17:nilReason="">
<ns17:CharacterString>80301</ns17:CharacterString>
</ns16:postalCode>
<ns16:country ns17:nilReason="">
<ns17:CharacterString>USA</ns17:CharacterString>
</ns16:country>
<ns16:electronicMailAddress ns17:nilReason="">
<ns17:CharacterString>break@ucar.edu</ns17:CharacterString>
</ns16:electronicMailAddress>
</ns16:CI_Address>
</ns16:address>
</ns16:CI_Contact>
</ns16:contactInfo>
<ns16:role ns17:nilReason="">
<ns16:CI_RoleCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#"
codeListValue="pointOfContact"/>
</ns16:role>
</ns16:CI_ResponsibleParty>
</ns16:contact>
<ns16:dateStamp ns17:nilReason="">
<ns17:Date xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<ns17:DateTime>2010-07-22T00:00:00Z</ns17:DateTime>
</ns16:dateStamp>
<ns16:identificationInfo ns17:nilReason="" ns12:type="simple">
<ns19:SV_ServiceIdentification uuid="urn:fdc:ncar.ucar.edu:Service:WCS-01:Service:NCAR_WebCoverageService-01"
xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns16:citation ns17:nilReason="" ns12:type="simple">
<ns16:CI_Citation>
<ns16:title ns17:nilReason="">
<ns17:CharacterString>NCAR Web Coverage Service</ns17:CharacterString>
</ns16:title>
<ns16:date ns17:nilReason="" ns12:type="simple">
<ns16:CI_Date>
<ns16:date ns17:nilReason="">
<ns17:Date xsi:nil="true"/>
<ns17:DateTime>2009-07-22T00:00:00Z</ns17:DateTime>
</ns16:date>
<ns16:dateType ns17:nilReason="">
<ns16:CI_DateTypeCode codeList=”…#CI_DateTypeCode" codeListValue="publication"/>
</ns16:dateType>
</ns16:CI_Date>
</ns16:date>
</ns16:CI_Citation>
</ns16:citation>
38
<ns16:abstract ns17:nilReason="">
<ns17:CharacterString>NCAR Web Coverage Server (WCS) providing access to variety of model data
sets</ns17:CharacterString>
</ns16:abstract>
<ns19:serviceType ns17:nilReason="">
<ns17:LocalName codeSpace="http://www.tc211.org/ISO19119/ServiceTypes">WCS</ns17:LocalName>
</ns19:serviceType>
<ns19:serviceTypeVersion ns17:nilReason="">
<ns17:CharacterString>1.1</ns17:CharacterString>
</ns19:serviceTypeVersion>
<ns19:couplingType ns17:nilReason="">
<ns19:SV_CouplingType
codeList="http://www.tc211.org/ISO19119/resources/codeList.xml#SV_CouplingTypeListCode"
codeListValue="tight"/>
</ns19:couplingType>
<ns19:containsOperations ns17:nilReason="inapplicable" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:CEIL" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:CIP-20" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:CIPSEV-20" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:CIPSLD-20" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:FLTCAT" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:GFS" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:GTG2" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:NCWF2" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:RUC-20" ns12:type="simple"/>
<ns19:operatesOn ns17:nilReason="" uuidref="urn:fdc:ncar.ucar.edu:Dataset:VIS" ns12:type="simple"/>
</ns19:SV_ServiceIdentification>
</ns16:identificationInfo>
<ns16:distributionInfo ns17:nilReason="" ns12:type="simple">
<ns16:MD_Distribution>
<ns16:distributionFormat ns17:nilReason="" ns12:type="simple">
<ns16:MD_Format>
<ns16:name ns17:nilReason="">
<ns17:CharacterString>application/x-netcdf</ns17:CharacterString>
</ns16:name>
<ns16:version ns17:nilReason="">
<ns17:CharacterString>4</ns17:CharacterString>
</ns16:version>
</ns16:MD_Format>
</ns16:distributionFormat>
</ns16:MD_Distribution>
</ns16:distributionInfo>
<ns16:metadataConstraints ns17:nilReason="" ns12:type="simple">
<ns16:MD_LegalConstraints>
<ns16:accessConstraints ns17:nilReason="">
<ns16:MD_RestrictionCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_RestrictionCode"
codeListValue="restricted"/>
</ns16:accessConstraints>
</ns16:MD_LegalConstraints>
</ns16:metadataConstraints>
<ns16:metadataConstraints ns17:nilReason="" ns12:type="simple">
<ns16:MD_SecurityConstraints>
<ns16:classification ns17:nilReason="">
<ns16:MD_ClassificationCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ClassificationCode"
codeListValue="unclassified"/>
</ns16:classification>
</ns16:MD_SecurityConstraints>
</ns16:metadataConstraints>
<ns16:metadataMaintenance ns17:nilReason="" ns12:type="simple">
39
<ns16:MD_MaintenanceInformation>
<ns16:maintenanceAndUpdateFrequency ns17:nilReason="">
<ns16:MD_MaintenanceFrequencyCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode"
codeListValue="asNeeded"/>
</ns16:maintenanceAndUpdateFrequency>
</ns16:MD_MaintenanceInformation>
</ns16:metadataMaintenance>
</ns16:MD_Metadata>
</ns8:MetadataResponse>
</soap:Body>
</soap:Envelope>
Example 2 of GetMetadata Request
Note that in this example, the ISO 19139 metadata for a dataset, rather than the WCSRI services,
is being requested. This is similar to a describeCoverage request, though for ISO 19139.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:iso1="http://wcsri.ral.ucar.edu/iso19139">
<soap:Header/>
<soap:Body>
<iso1:GetMetadata>
<!--You have a CHOICE of the next 2 items at this level-->
<!--1 or more repetitions:-->
<iso1:DatasetMetadataFilter>
<!--Zero or more repetitions:-->
<!--Xpath>?</Xpath-->
<Id>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</Id>
</iso1:DatasetMetadataFilter>
</iso1:GetMetadata>
</soap:Body>
</soap:Envelope>
Example 2 of GetMetadata Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns8:MetadataResponse xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns16:MD_Metadata>
<ns16:fileIdentifier ns17:nilReason="">
<ns17:CharacterString>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp:metadata</ns17:CharacterString>
</ns16:fileIdentifier>
<ns16:language ns17:nilReason="">
<ns17:CharacterString>eng</ns17:CharacterString>
</ns16:language>
<ns16:characterSet ns17:nilReason="">
<ns16:MD_CharacterSetCode
40
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode"
codeListValue="utf8"/>
</ns16:characterSet>
<ns16:hierarchyLevel ns17:nilReason="">
<ns16:MD_ScopeCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ScopeCode"
codeListValue="series"/>
</ns16:hierarchyLevel>
<ns16:contact ns17:nilReason="" ns12:type="simple">
<ns16:CI_ResponsibleParty>
<ns16:organisationName ns17:nilReason="">
<ns17:CharacterString>National Center for Atmospheric Research (NCAR)</ns17:CharacterString>
</ns16:organisationName>
<ns16:contactInfo ns17:nilReason="" ns12:type="simple">
<ns16:CI_Contact>
<ns16:phone ns17:nilReason="" ns12:type="simple">
<ns16:CI_Telephone>
<ns16:voice ns17:nilReason="">
<ns17:CharacterString>303-497-8700</ns17:CharacterString>
</ns16:voice>
<ns16:facsimile ns17:nilReason="">
<ns17:CharacterString>303-497-8701</ns17:CharacterString>
</ns16:facsimile>
</ns16:CI_Telephone>
</ns16:phone>
<ns16:address ns17:nilReason="" ns12:type="simple">
<ns16:CI_Address>
<ns16:deliveryPoint ns17:nilReason="">
<ns17:CharacterString>3450 Mitchell Lane</ns17:CharacterString>
</ns16:deliveryPoint>
<ns16:city ns17:nilReason="">
<ns17:CharacterString>Boulder</ns17:CharacterString>
</ns16:city>
<ns16:administrativeArea ns17:nilReason="">
<ns17:CharacterString>CO</ns17:CharacterString>
</ns16:administrativeArea>
<ns16:postalCode ns17:nilReason="">
<ns17:CharacterString>80301</ns17:CharacterString>
</ns16:postalCode>
<ns16:country ns17:nilReason="">
<ns17:CharacterString>USA</ns17:CharacterString>
</ns16:country>
<ns16:electronicMailAddress ns17:nilReason="">
<ns17:CharacterString>bkkk@ucar.edu</ns17:CharacterString>
</ns16:electronicMailAddress>
</ns16:CI_Address>
</ns16:address>
</ns16:CI_Contact>
</ns16:contactInfo>
<ns16:role ns17:nilReason="">
<ns16:CI_RoleCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#"
codeListValue="pointOfContact"/>
</ns16:role>
</ns16:CI_ResponsibleParty>
</ns16:contact>
<ns16:dateStamp ns17:nilReason="">
<ns17:Date xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<ns17:DateTime>2009-07-21T09:00:00Z</ns17:DateTime>
</ns16:dateStamp>
<ns16:referenceSystemInfo ns17:nilReason="" ns12:type="simple">
<ns16:MD_ReferenceSystem>
<ns16:referenceSystemIdentifier ns17:nilReason="" ns12:type="simple">
41
<ns16:RS_Identifier>
<ns16:code ns17:nilReason="">
<ns17:CharacterString>urn:EPSG:1436</ns17:CharacterString>
</ns16:code>
</ns16:RS_Identifier>
</ns16:referenceSystemIdentifier>
</ns16:MD_ReferenceSystem>
</ns16:referenceSystemInfo>
<ns16:identificationInfo ns17:nilReason="" ns12:type="simple">
<ns16:MD_DataIdentification uuid="urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp" xsi:nil="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns16:citation ns17:nilReason="" ns12:type="simple">
<ns16:CI_Citation>
<ns16:title ns17:nilReason="">
<ns17:CharacterString>Rapid Update Cycle - Temperature</ns17:CharacterString>
</ns16:title>
<ns16:date ns17:nilReason="" ns12:type="simple">
<ns16:CI_Date>
<ns16:date ns17:nilReason="">
<ns17:Date xsi:nil="true"/>
<ns17:DateTime>2009-07-20T06:00:00Z</ns17:DateTime>
</ns16:date>
<ns16:dateType ns17:nilReason="">
<ns16:CI_DateTypeCode
codeList="http://standards.iso.org.../Codelist/ML_gmxCodelists.xml#CI_DateTypeCode"
codeListValue="creation"/>
</ns16:dateType>
</ns16:CI_Date>
</ns16:date>
<ns16:date ns17:nilReason="" ns12:type="simple">
<ns16:CI_Date>
<ns16:date ns17:nilReason="">
<ns17:Date xsi:nil="true"/>
<ns17:DateTime>2009-07-20T06:00:00Z</ns17:DateTime>
</ns16:date>
<ns16:dateType ns17:nilReason="">
<ns16:CI_DateTypeCode
codeList="http://standards.iso.org.../Codelist/ML_gmxCodelists.xml#CI_DateTypeCode"
codeListValue="publication"/>
</ns16:dateType>
</ns16:CI_Date>
</ns16:date>
</ns16:CI_Citation>
</ns16:citation>
<ns16:abstract ns17:nilReason="">
<ns17:CharacterString>Rapid Update Cycle - Temperature</ns17:CharacterString>
</ns16:abstract>
<ns16:purpose ns17:nilReason="">
<ns17:CharacterString>Aviation safety</ns17:CharacterString>
</ns16:purpose>
<ns16:status ns17:nilReason="">
<ns16:MD_ProgressCode codeList="./resources/codeList.xml#MD_ProgressCode"
codeListValue="underDevelopment"/>
</ns16:status>
<ns16:descriptiveKeywords ns17:nilReason="" ns12:type="simple">
<ns16:MD_Keywords>
<ns16:keyword ns17:nilReason="">
<ns17:CharacterString>Aviation</ns17:CharacterString>
</ns16:keyword>
<ns16:keyword ns17:nilReason="">
<ns17:CharacterString>Weather</ns17:CharacterString>
42
</ns16:keyword>
</ns16:MD_Keywords>
</ns16:descriptiveKeywords>
<ns16:descriptiveKeywords ns17:nilReason="" ns12:type="simple">
<ns16:MD_Keywords>
<ns16:keyword ns17:nilReason="">
<ns17:CharacterString>urn:ogc:def:ebRIM-ClassificationNode:FAA:DataCube:Unrestricted:SAS:Primary
</ns17:CharacterString>
</ns16:keyword>
<ns16:type ns17:nilReason="">
<ns16:MD_KeywordTypeCode
codeList=http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode
codeListValue="classificationNodeId"/>
</ns16:type>
</ns16:MD_Keywords>
</ns16:descriptiveKeywords>
<ns16:aggregationInfo ns17:nilReason="" ns12:type="simple">
<ns16:MD_AggregateInformation>
<ns16:aggregateDataSetIdentifier ns17:nilReason="" ns12:type="simple">
<ns16:MD_Identifier>
<ns16:code ns17:nilReason="">
<ns17:CharacterString>urn:fdc:ncar.ucar.edu:Dataset:RUC20P_grb2_Temp</ns17:CharacterString>
</ns16:code>
</ns16:MD_Identifier>
</ns16:aggregateDataSetIdentifier>
<ns16:associationType ns17:nilReason="">
<ns16:DS_AssociationTypeCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode"
codeListValue="partOfSeamlessDatabase"/>
</ns16:associationType>
<ns16:initiativeType ns17:nilReason="">
<ns16:DS_InitiativeTypeCode
codeList=http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#DS_InitiativeTypeCode
codeListValue="experiment"/>
</ns16:initiativeType>
</ns16:MD_AggregateInformation>
</ns16:aggregationInfo>
<ns16:spatialRepresentationType ns17:nilReason="">
<ns16:MD_SpatialRepresentationTypeCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode"
codeListValue="grid"/>
</ns16:spatialRepresentationType>
<ns16:spatialResolution ns17:nilReason="">
<ns16:MD_Resolution>
<ns16:distance ns17:nilReason="">
<ns17:Distance uom="m">20000.0</ns17:Distance>
</ns16:distance>
</ns16:MD_Resolution>
</ns16:spatialResolution>
<ns16:language ns17:nilReason="">
<ns17:CharacterString>English</ns17:CharacterString>
</ns16:language>
<ns16:topicCategory ns17:nilReason="">
<ns16:MD_TopicCategoryCode>climatologyMeteorologyAtmosphere</ns16:MD_TopicCategoryCode>
</ns16:topicCategory>
<ns16:extent ns17:nilReason="" ns12:type="simple">
<ns16:EX_Extent>
<ns16:geographicElement ns17:nilReason="" ns12:type="simple">
<ns16:EX_GeographicBoundingBox>
<ns16:westBoundLongitude ns17:nilReason="">
<ns17:Decimal>-121.6</ns17:Decimal>
43
</ns16:westBoundLongitude>
<ns16:eastBoundLongitude ns17:nilReason="">
<ns17:Decimal>-60.9</ns17:Decimal>
</ns16:eastBoundLongitude>
<ns16:southBoundLatitude ns17:nilReason="">
<ns17:Decimal>20.2</ns17:Decimal>
</ns16:southBoundLatitude>
<ns16:northBoundLatitude ns17:nilReason="">
<ns17:Decimal>50.1</ns17:Decimal>
</ns16:northBoundLatitude>
</ns16:EX_GeographicBoundingBox>
</ns16:geographicElement>
<ns16:temporalElement ns17:nilReason="" ns12:type="simple">
<ns16:EX_TemporalExtent>
<ns16:extent ns17:nilReason="" ns12:type="simple">
<ns15:TimePeriod ns15:id="timePeriod-001">
<ns15:beginPosition indeterminatePosition="now"/>
<ns15:endPosition>-P12H</ns15:endPosition>
</ns15:TimePeriod>
</ns16:extent>
</ns16:EX_TemporalExtent>
</ns16:temporalElement>
</ns16:EX_Extent>
</ns16:extent>
</ns16:MD_DataIdentification>
</ns16:identificationInfo>
<ns16:contentInfo ns17:nilReason="" ns12:type="simple">
<ns16:MD_CoverageDescription>
<ns16:attributeDescription ns17:nilReason="inapplicable"/>
<ns16:contentType ns17:nilReason="">
<ns16:MD_CoverageContentTypeCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode"
codeListValue="physicalMeasurement"/>
</ns16:contentType>
<ns16:dimension ns17:nilReason="" ns12:type="simple">
<ns16:MD_Band>
<ns16:sequenceIdentifier ns17:nilReason="" ns12:type="simple">
<ns17:MemberName>
<ns17:aName ns17:nilReason="">
<ns17:CharacterString>Temperature</ns17:CharacterString>
</ns17:aName>
<ns17:attributeType ns17:nilReason="" ns12:type="simple">
<ns17:TypeName>
<ns17:aName ns17:nilReason="">
<ns17:CharacterString>double</ns17:CharacterString>
</ns17:aName>
</ns17:TypeName>
</ns17:attributeType>
</ns17:MemberName>
</ns16:sequenceIdentifier>
</ns16:MD_Band>
</ns16:dimension>
</ns16:MD_CoverageDescription>
</ns16:contentInfo>
<ns16:dataQualityInfo ns17:nilReason="" ns12:type="simple">
<ns16:DQ_DataQuality>
<ns16:scope ns17:nilReason="" ns12:type="simple">
<ns16:DQ_Scope>
<ns16:level ns17:nilReason="">
<ns16:MD_ScopeCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ScopeCode"
44
codeListValue="series"/>
</ns16:level>
</ns16:DQ_Scope>
</ns16:scope>
<ns16:lineage ns17:nilReason="" ns12:type="simple">
<ns16:LI_Lineage>
<ns16:statement ns17:nilReason="">
<ns17:CharacterString>Data is produced by computer model</ns17:CharacterString>
</ns16:statement>
</ns16:LI_Lineage>
</ns16:lineage>
</ns16:DQ_DataQuality>
</ns16:dataQualityInfo>
<ns16:metadataConstraints ns17:nilReason="" ns12:type="simple">
<ns16:MD_LegalConstraints>
<ns16:accessConstraints ns17:nilReason="">
<ns16:MD_RestrictionCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_RestrictionCode"
codeListValue="restricted"/>
</ns16:accessConstraints>
</ns16:MD_LegalConstraints>
</ns16:metadataConstraints>
<ns16:metadataConstraints ns17:nilReason="" ns12:type="simple">
<ns16:MD_SecurityConstraints>
<ns16:classification ns17:nilReason="">
<ns16:MD_ClassificationCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ClassificationCode"
codeListValue="unclassified"/>
</ns16:classification>
</ns16:MD_SecurityConstraints>
</ns16:metadataConstraints>
<ns16:metadataMaintenance ns17:nilReason="" ns12:type="simple">
<ns16:MD_MaintenanceInformation>
<ns16:maintenanceAndUpdateFrequency ns17:nilReason="">
<ns16:MD_MaintenanceFrequencyCode
codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode"
codeListValue="daily"/>
</ns16:maintenanceAndUpdateFrequency>
</ns16:MD_MaintenanceInformation>
</ns16:metadataMaintenance>
</ns16:MD_Metadata>
</ns8:MetadataResponse>
</soap:Body>
</soap:Envelope>
4.2.5 Subscribe SOAP Request and Response
Example 1 of Subscribe Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:b="http://docs.oasis-open.org/wsn/b-2"
xmlns:add="http://www.w3.org/2005/08/addressing" xmlns:ns="http://www.opengis.net/wcs/1.1"
xmlns:ns1="http://www.opengis.net/ows/1.1">
<soapenv:Header/>
<soapenv:Body>
<b:Subscribe>
<b:ConsumerReference>
</b:ConsumerReference>
<b:Filter>
<b:MessageContent Dialect="urn:def:ogc:wcs:1.1">
<ns:GetCoverage service="WCS" version="1.1.2">
45
<ns1:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RoboRuc</ns1:Identifier>
<ns:DomainSubset>
<ns1:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="3">
<ns1:LowerCorner>-120.0 38.6 3.893606</ns1:LowerCorner>
<ns1:UpperCorner>-106.6 42.5 3.893606</ns1:UpperCorner>
</ns1:BoundingBox>
<ns:TemporalSubset>
<ns:TimePeriod>
<ns:BeginPosition>2009-06-19T03:00:00.000Z</ns:BeginPosition>
<ns:EndPosition>2022-01-01T00:00:00.000Z</ns:EndPosition>
</ns:TimePeriod>
</ns:TemporalSubset>
</ns:DomainSubset>
<!--Optional:-->
<ns:RangeSubset/>
<ns:Output format="application/netcdf4" store="false">
</ns:Output>
</ns:GetCoverage>
</b:MessageContent>
</b:Filter>
</b:Subscribe>
</soapenv:Body>
</soapenv:Envelope>
Example 1 of Subscribe Response
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns7:SubscribeResponse xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns7:CurrentTime>2013-01-09T22:07:18.443Z</ns7:CurrentTime>
<ns7:TerminationTime xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<ns3:SubscriptionReference>
<ns3:subscriptionGUID>2a8b2edc-09dd-4411-835e-290297803b0a</ns3:subscriptionGUID>
<ns3:subscriptionURI>jms:http://granite.rap.ucar.edu:16200/tempQueue/pubsub.handshake</ns3:subscriptionURI>
<ns3:userID>ANONYMOUS</ns3:userID>
</ns3:SubscriptionReference>
</ns7:SubscribeResponse>
</soap:Body>
</soap:Envelope>
4.2.6 KVP Request and Response
Example 1 of KVP GetCapabilities Request
Note that this example is requesting a single Section from the getCapabilities document.
http://localhost:8280/?service=WCS&Request=getCapabilities&sections=ServiceProvider
46
Example 1 of KVP GetCapabilities Response
<ns11:Capabilities version="1.1.1" xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2" xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv" xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco" xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2" xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/" xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1" xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1" xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2" xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns9:ServiceProvider>
<ns9:ProviderName>NextGen Network Enabled Weather (NNEW)</ns9:ProviderName>
<ns9:ServiceContact>
<ns9:IndividualName>Jerry</ns9:IndividualName>
<ns9:PositionName>Software Engineer</ns9:PositionName>
<ns9:ContactInfo>
<ns9:Phone>
<ns9:Voice>303-495-2855</ns9:Voice>
</ns9:Phone>
<ns9:Address>
<ns9:DeliveryPoint>FL2</ns9:DeliveryPoint>
<ns9:DeliveryPoint>3300 Mitchell Lane</ns9:DeliveryPoint>
<ns9:City>Boulder</ns9:City>
<ns9:AdministrativeArea>Colorado</ns9:AdministrativeArea>
<ns9:PostalCode>80305</ns9:PostalCode>
<ns9:Country>U.S.</ns9:Country>
<ns9:ElectronicMailAddress>blah[at]ucar[dot]edu</ns9:ElectronicMailAddress>
</ns9:Address>
<ns9:OnlineResource ns12:type="simple" ns12:href="http://ral.ucar.edu/projects/nnew/"/>
<ns9:HoursOfService>8x5x365</ns9:HoursOfService>
<ns9:ContactInstructions>email</ns9:ContactInstructions>
</ns9:ContactInfo>
<ns9:Role>Lead Engineer</ns9:Role>
</ns9:ServiceContact>
</ns9:ServiceProvider>
</ns11:Capabilities>
Example 2 of KVP DescribeCoverage Request
http://localhost:8280/wcs?Service=WCS&request=Describecoverage&version=1.1.2&identifiers=urn:fdc:ncar.ucar.edu:Dataset:RUC20
P_grb2_Temp
Example 2 of KVP DescribeCoverage Response
Note that the response will be identical to the SOAP body of Example 1 response in Section 4.2.2
of this document.
5 Architecture
47
5.1 Overview
Over the five or six years since the inception of the WCSRI, many requirements have been
introduced. In order to maintain a flexible and effective development paradigm, the WCSRI was
implemented in an agile and iterative fashion and has grown in complexity. Early versions of the
WCSRI implemented the WCS specification in a simple fashion, primarily leveraging a set of
plain-old Java objects (POJOs) and a few Spring-based SOAP web services based on a WSDL
defining only three operations. Providing the real-time notification mechanism for WS-N
introduced additional complexity into the server since it required support for more robust features,
such as persistence, file polling and reliable real-time message delivery. Also, to achieve a level
of maturity required for an “enterprise-ready operational” server, additional requirements were
added to the list, including security, monitoring, scalability and reliability. Hence, the WCSRI
requires a certain level of maturity and capability and achieves this by leveraging several proven
technologies without reinvention.
The document “High-availability and Scalability Architectural Alternatives and Configurations for
NCAR NNEW WCSRI” gives a high-level overview of the architecture of the server. It contains
information regarding the different components of the system, their intent and how they interact.
The document also describes how the WCSRI components should be arranged and configured
for a clustered configuration in order to achieve high-availability and scalability. The focus is on
high-level concepts and is required reading, though much of the content is repeated here.
This section of this document briefly gives an overview of the WCSRI architecture as shown in
Figure 1. In a general sense, the WCSRI is an application that runs in an enterprise service bus
(ESB) called Servicemix (an early requirement from the FAA SWIM program). From a high level,
the internals of the WCSRI are broken down into separate components - data ingest, data
retrieval, subscription management and a notification producer. In addition, the WCSRI relies on
external storage disks for raw weather data as input and weather subset data as output, each of
which may be read/written from separate devices. For real-time notifications, the WSCRI requires
a relational database for persistence and relies on a JMS broker, specifically ActiveMQ, for
messaging.
48
Figure 1. WCSRI High Level Components
5.1.1 Data Ingest
Using the WCS protocol, the WCSRI provides on-demand geographical and temporal subsets of
weather data. The raw weather data produced by weather forecasting systems is used as the
input to the server (shown as “Wx Data Files Storage” in the diagram above), and is subsetted
dynamically on-demand in a request/reply fashion. The component of the WCSRI that watches for
raw weather data files and ingests them into the system is called the Data Ingest component. The
Data Ingest uses the wcs.rootDataDir property (as found in the wcsri.cfg file) as the root directory
for the server, and frequently polls the /staging directories of each of the coverage or data source
directories found below the wcs.rootDataDir. Note that the Data Ingest does not care how the raw
data actually arrives in the /staging directories and is completely independent of the mechanism
used for acquiring the raw weather data files. In addition, the Data Ingest uses a relational
database to store information about the weather data files it has found, and uses the ActiveMQ
message broker to post messages regarding new data availability to a queue.
Note that the raw weather data must be ingested atomically, or arrive in an atomic fashion into the
various /staging directories. Once the data is placed in /staging, it is moved to the 2013/...
directory structure defined in the Installation Instructions (e.g.,
49
datasourceRoot/2013/20130102/v_120000). Since the data is moved, it must be placed into
/staging atomically so that the data file is not corrupted when moved. One solution may be to
ingest data into a temporary directory on the same partition, and then moving it into the /staging
directory.
5.1.2 Data Retriever
The Data Retriever functionality of the server is responsible for receiving external client requests
and processing them. This includes requests for server metadata, coverage descriptions, and
data subsetting operations. The Data Retriever component accesses the raw weather data files
found in wcs.rootDataDir, and has the option to either process the requests in a synchronous or
asynchronous mode. When asynchronous, the Data Retriever will leverage ActiveMQ queues to
process the weather data requests. In either case, subsetting operations will result in a temporary
NetCDF file being return to an output directory, identified by the wcs.tempDir property as found in
the wcsri.cfg file. Note that the output directory may be different than the input directory, which
allows different WCSRI nodes in a clustered configuration to share the input data while using a
local disk for output without competing for I/O resources.
5.1.3 Subscription Management
The Subscription Management component does exactly that – it manages subscriptions. It
receives requests for subscriptions, and creates subscription entries in the relational database. It
also takes care of subscription expirations, renewals, etc.
5.1.4 Pub/Sub Notification Producer
The Pub/Sub Notification Producer is the core of the real-time notification system. It uses
ActiveMQ to receive messages of new weather data availability from a queue (from the Data
Ingester), creates notifications for interested subscribers and persists the notifications to the
relational database. Then, the Producer again uses ActiveMQ to deliver the notification messages
to the subscribers, if they are indeed connected at the time (otherwise, the messages will be
delivered when they connect).
5.2 Single Node vs Cluster
The WCSRI can process requests (ie: GetCapabilities, DescribeCoverage, GetCoverage,
GetMetadata requests/replies) in a synchronous or asynchronous mode. The synchronous mode
is appropriate when running a single WCSRI node, whereas the asynchronous mode is required
for a WCSRI clustered configuration. In asynchronous mode, requests are processed as follows:
1. Requests are posted to an AMQ queue by the initiating WCSRI node (the one that
received the initial client request on an exposed endpoint)
2. Requests are asynchronously processed by any WCSRI node participating in the cluster
3. Results may be either written to the processing node’s disk shared by the cluster, or are
streamed back to the initiating node
4. From the initiating node, results are returned back to the client.
50
Adding WCSRI nodes to the cluster improves scalability by adding nodes for additional
processing power. In order to leverage the asynchronous nature of the WCSRI, several properties
must be modified accordingly per the “High-availability and Scalability Architectural Alternatives
and Configurations for NCAR NNEW WCSRI” document.
Figure 2 shows a clustered configuration with four nodes, where two of them have WCSRI
instances running on them. The two WCSRI nodes share the input weather disk and use a local
disk for outputting subsets. Two nodes provide better performance than a single node, and when
using a reverse proxy, provide a failover solution. Other components shown in the diagram
include the idempotency database and ActiveMQ message broker, briefly discussed in the next
section. Figure 3 shows a more complex clustered solution, with additional high-availability and
scalability.
5.2.1 Idempotency Database
The WCSRI uses a relational database to store information about idempotent entities.
“Idempotent” is a term adopted from ActiveMQ and Camel, that simply means processing things
once only. For example, in a WCSRI cluster using a shared input disk, only one of the WCSRI
instances should process the retrieval of a specific weather data file from an upstream origin
server. To keep it simple, the WCSRI stores information about ingested files, subscriptions,
connected subscribers, and notification messages in the relational database.
5.2.2 ActiveMQ
The ActiveMQ message broker provides the infrastructure for the asynchronous nature and
notification mechanism of a clustered WCSRI. ActiveMQ can be run internally to the WCSRI
(within servicemix) for a single node configuration, but in a clustered WCSRI, ActiveMQ must be
run externally as a standalone application since each node in the cluster will need to access it.
Since ActiveMQ uses significant resources (both CPU and disk I/O), it ideally should be run on its
own machine accessible from each node of the WCSRI cluster.
51
Figure 2. 4-Node Cluster
52
Figure 3. Complex Cluster
6 Request/Reply Services
6.1 Overview
Clients communicate with the WCSRI primarily using two MEPs - request/reply and
publish/subscribe. This section describes some of the components used in support of the
request/reply message exchange pattern.
Several aspects to the WCSRI exist in support of the request/reply services. Configurable
properties for these services are accessed in the server’s wcsri.cfg file, providing fine-grained
customization for significant properties. When the server starts up, the OSGi container
automatically uses the Blueprint specification to instantiate the primary components, services and
their dependencies. The objects instantiated in support of the request/reply services consist of
those for the frontend services and web services, including endpoints and security, and those for
the weather subset processing. The responsibilities are generally broken down as such for a
separation of concerns, constraining the technologies to the frontend and web services and the
domain-specific logic to plain-old-Java-objects (POJOs).
53
The frontend and web services of the WCSRI center on the web-service stack of technology used
by the server. Two modules, named the wcsri-frontend and the wcsri-web-service, provide the
implementation and contain the source code. The frontend and web-service modules provide
access points, or endpoints, to be called by external clients as well as internal services. The
communication details and protocols used at various levels, whether its low-level TCP
communications or high-level SOAP communications, are contained in these modules.
The weather metadata retrieval and weather data subsetting logic for the server is contained in
POJOs. These objects are generally known as the gridded-data-server objects, or GDS objects.
They exist in several modules (and bundles) of the source code, generally named with the ‘gds’
prefix. These objects are independent of web service technologies, and contain the complex
algorithms for data retrieval of gridded data products, supporting features such as aggregation,
corridor subsetting, chunking and decimation.
6.2 Web Services and The Frontend
6.2.1 WCSRI Endpoints
The WCSRI provides a number of endpoints that are available from the server. The most
significant endpoint is the WCSRI’s frontend endpoint, called the wcs.frontend.publish.url, which
provides an entry point for all of the services offered by the WCSRI. The frontend endpoint
provides a convenient access point for external clients since it provides a combination of services
coming from different specifications, and hence clients are not required to maintain a map of
different endpoints for different services. The services provided by the frontend endpoint include
the WCS SOAP services, the WCS KVP services, the WS-N subscribe service, WS-N
subscription management services and a master WSDL document advertising all of the services.
In addition, there is an equivalent endpoint, called the wcs.frontend.ssl.publish.url, that optionally
provides the same functionality as the frontend endpoint but with the addition of SSL and
authentication.
The frontend endpoints (secure and non-secure) are exposed to the outside world and are
intended to be used externally. However, other endpoints exist within the WCSRI, but are
intended for internal use only. Each internal endpoint provides services specific to a single
specification and is intended to be called from the frontend endpoint rather than from external
clients.
A list of the internal and external endpoints is shown below. The URLs for the endpoints are
configurable according to the appropriate properties found in the server’s wcsri.cfg file. The list
below shows the endpoints listed by the configurable property name accompanied by a brief
description of the endpoint’s intent:
●
54
wcs.frontend.publish.url - This is the SOAP 1.2 exposed single endpoint providing a
single frontend service for all WCSRI functionality. The operations supported by this
●
●
●
●
●
●
●
●
●
55
endpoint include the retrieval of the master WSDL, WCS 1.1.2 Key-Value-Pair (KVP)
operations, WCS 1.1.2 SOAP operations, WS-N subscription requests and WS-N
subscription management requests. The wcs.frontend.publish.url endpoint is a low-level,
high-performance TCP MINA endpoint that provides a unified interface for all other
endpoints in the server. Since all of this functionality is broken down into separate
components and endpoints, this frontend endpoint will delegate much of its functionality to
other internal endpoints listed below.
wcs.frontend.ssl.publish.url - This is the same as the wcs.frontend.publish.url but if
security is enabled (with the wcs.frontend.enableSSL property), then this endpoint will
provide SSL (i.e., authentication) on top of the wcs.frontend.publish.url endpoint. Note that
the port used for this endpoint must be different than the port used for
wcs.frontend.publish.url.
wcs.frontend.external.url - This is the same as the wcs.frontend.publish.url but is the
advertised version of the endpoint, advertised in the master WSDL. If the WCSRI is
running behind a firewall or proxy, the wcs.frontend.publish.url will likely be the internallyknown version of the URL, whereas the wcs.frontend.external.url will be the externallyknown version of the URL.
wcs.frontend.ssl.external.url - This is the same as the wcs.frontend.external.url but if
security is enabled (with the wcs.frontend.enableSSL property), then this endpoint will
provide SSL (i.e., authentication) on top of the wcs.frontend.external.url endpoint. Note
that the port used for this endpoint must be different than the port used for
wcs.frontend.external.url.
wcs.httpEndpoint - This endpoint is deprecated.
wcs.swa.httpEndpoint - This is the main SOAP 1.2 internal endpoint for the
wcsSwaPortType which implements the WCS 1.1.2 SOAP operations, including
getCapabilities, describeCoverage, getCoverage and the additional getMetadata operation
for ISO-compliance.
wcs.soap.httpEndpoint - This should have the value ${wcs.swa.httpEndpoint}. Originally,
the WCSRI codebase was intended to support both MTOM and Soap-With-Attachments
(i.e., SWA or SAAJ) though only one or the other could be used in a WCSRI instance.
Hence, this property was intended to expose either an MTOM or SWA endpoint as the
instance’s main internal endpoint for WCS 1.1.2 operations (and getMetadata). However,
since MTOM is deprecated, the wcs.soap.httpEndpoint should always be set to the value
of wcs.swa.httpEndpoint.
wcs.kvp.httpEndpoint - This is the internal endpoint for WCS 1.1.2 Key-Value-Pair (KVP)
operations. If wcs.kvp.disabled is set to false, then KVP will be enabled. If enabled, the
only KVP operations supported by the WCSRI are getCapabilities and describeCoverage.
wcs.subscribe.httpEndpoint - This is the SOAP 1.1 internal endpoint for the
NotificationProducer PortType which implements the WS-N Subscribe operation.
wcs.mngSubscription.httpEndpoint - This is the SOAP 1.1 internal endpoint for the
PausableSubscriptionManager PortType which implements the WS-N subscription
management operations, including Renew, Unsubscribe, PauseSubscription and
ResumeSubscription.
●
wcs.remote_mng.httpEndpoint - This is the endpoint used for remote management of
the WCSRI, applicable only if the wcs.remote.disabled property is set to false;
Note that the port values for the endpoints listed above should all be different in order to avoid
endpoint clashes.
6.2.2 The wcsri-frontend Module
The wcsri-frontend module in the source code provides the frontend endpoint (secure and nonsecure) and supporting classes. The wcsri-frontend module in the source code is built and
packaged into an OSGi bundle also called wcsri-frontend. When the bundle is loaded into
ServiceMix as part of the WCSRI installation (i.e., as part of the WCSRI feature), Blueprint will
automatically create the objects as specified in the bundle’s OSGI-INF/blueprint/frontend.xml file.
The objects that are significant in that file relate to the master WSDL generation and the low-level
MINA TCP/IP interceptors that provide the frontend endpoint(s).
6.2.2.1 Master WSDL and WSDL Generator
For convenience, the WCSRI provides a single frontend endpoint for all supported operations. As
stated above, this set of services is derived from different specifications and includes the WCS
SOAP services, the WS-N subscribe service and WS-N subscription management services.
These operations can be advertised through several WSDL documents, but for convenience, the
frontend endpoint advertises a single master WSDL, merged from many WSDLs. The master
WSDL can be retrieved from a running WCSRI instance using an HTTP GET request with the
following URL:
http://hostname:port/path?wsdl
Note that the “hostname:port/path” should be substituted with the values used for the server
instance’s wcs.frontend.external.url (or wcs.frontend.ssl.external.url).
Within the wcsri-frontend module, the class that generates the master WSDL is called the
MasterWSDLGenerator. The MasterWSDLGenerator has a getMasterWsdl(...) method that uses
the WsdlMerger class to merge the WCS 1.1.2, getMetadata and WS-N WSDLs into a single
master WSDL. It then cleans up the merged result by removing duplicate “import” and “include”
statements, and returns the master WSDL appropriate for advertising in a machine-readable
format.
The WsdlMerger object is created via Blueprint with the following specification:
<bean id="wsdlMerger" class="edu.ucar.ral.wcsri.wcs.wsdl.WsdlMerger" init-method="init">
<property name="targetNs" value="http://edu.ucar.ral.wcsri/wcs-master-wsdl"/>
<property name="baseUrls">
<list>
<value>${wcs.soap.httpEndpoint}</value>
<value>${wcs.subscribe.httpEndpoint}</value>
<value>${wcs.mngSubscription.httpEndpoint}</value>
56
</list>
</property>
<property name="rewriteUrl" value="${wcs.frontend.external.url}"/>
</bean>
Note that the WsdlMerger object is supplied with a list of SOAP endpoints - the
wcs.soap.httpEndpoint for the WCS 1.1.2 and getMetadata operations, the
wcs.subscribe.httpEndpoint for the WS-N Subscribe operation and the
wcs.mngSubscription.httpEndpoint for the WS-N subscription management operations. In the
WsdlMerger’s init(...) method, the WsdlMerger will wait for each supplied endpoint to become
available since they are started from a different bundle (i.e., the wcsri-web-services bundle). Then
each endpoint will be validated for returning a SOAP WSDL document, which is then cached. Also
as part of initialization, the WsdlMerger will call generateMasterWsdl(...) to combine the bindings,
services, messages, ports and types into a single Master WSDL which is then cached. On
demand, the MasterWSDLGenerator will call WsdlMerger’s getMasterWsdl(...) method to retrieve
the cached master document.
The WsdlMerger also has an important responsibility of maintaining a map of operations defined
by the child endpoint WSDLs to their respective child endpoint addresses. This information is kept
in the WsdlMerger’s operationsRegistry. When requests are made to the frontend, the
ClientToProxyIoHandler (described below) will use the WsdlMerger to determine which operation
is being called, and thus, which child endpoint will be used (via delegation) to satisfy the request.
6.2.2.2 MINA Frontend
The wcsri-frontend module or bundle provides the blueprint for MINA frontend endpoints, secure
and non-secure. MINA provides a scalable and high-performance solution for network
communications, and in the case of the WCSRI, provides the NIO TCP/IP socket connections for
the frontend endpoints. MINA also provides out-of-the-box SSL for the secure frontend endpoint.
In addition to the WsdlMerger, the Blueprint specification for the wcsri-frontend module
instantiates two objects - a TCPProxyFrontEnd and a ClientToProxyIoHandler. The blueprint
specification for the TCPProxyFrontEnd is as follows:
<bean id="frontEndRouting" class="edu.ucar.ral.wcsri.wcs.tcp.TCPProxyFrontEnd" init-method="initProxy" destroymethod="destroy" depends-on="clientProxyHandler">
<property name="clientHandler" ref="clientProxyHandler"/>
<property name="publishUrl" value="${wcs.frontend.publish.url}"/>
<property name="externalUrl" value="${wcs.frontend.external.url}"/>
<property name="readBufferSize" value="${wcs.frontend.requestBuffer}"/>
<property name="readerIdleTime" value="${wcs.frontend.readerIdleTime}"/>
<property name="writerIdleTime" value="${wcs.frontend.writerIdleTime}"/>
<property name="enableSSL" value="${wcs.frontend.enableSSL}"/>
<property name="needClientAuth" value="${wcs.frontend.needClientAuth}"/>
<property name="wantClientAuth" value="${wcs.frontend.wantClientAuth}"/>
<property name="useClientMode" value="${wcs.frontend.useClientMode}"/>
<property name="sslURL" value="${wcs.frontend.ssl.publish.url}"/>
<property name="externalSslUrl" value="${wcs.frontend.ssl.external.url}"/>
<property name="keyStoreLocation" value="${wcs.keystoreFile}"/>
<property name="trustStoreLocation" value="${wcs.truststoreFile}"/>
57
<property name="sslPassword" value="${wcs.keyPassword}"/>
<property name="sslKeyPassword" value="${wcs.keystorePassword}"/>
<property name="keystoreType" value="${wcs.keystoreType}"/>
<property name="sslContextType" value="${wcs.sslContextType}"/>
<property name="keyManagerFactoryAlgorithm" value="${wcs.keyManagerFactoryAlgorithm}"/>
<property name="secureRandomAlgorithm" value="${wcs.secureRandomAlgorithm}"/>
<property name="debug" value="${wcs.keystoreDebug}"/>
</bean>
The TCPProxyFrontEnd’s initProxy(...) method is called by Blueprint, and this method takes care
of initializing, configuring and binding a NioSocketAcceptor to the frontend endpoint’s port. The
NioSocketAcceptor is the MINA class that handles incoming TCP/IP based socket connections for
the WCSRI. If security is enabled (with the wcs.frontend.enableSSL configuration property), the
method will also call the initSSLProxy(...) method to initialize, configure and bind another
NioSocketAcceptor to the secure frontend endpoint’s port. Note that in both cases, an instance of
a ClientToProxyIoHandler is set as the handler for the acceptor, and hence, incoming requests to
the frontend endpoint(s) will be delegated to this object.
The blueprint specification for the ClientToProxyIoHandler is as follows:
<bean id="clientProxyHandler" class="edu.ucar.ral.wcsri.wcs.tcp.ClientToProxyIoHandler">
<property name="kvpHttpEndpoint" ref="kvpHttpEndpointURL"/>
<property name="remoteHttpEndpoint" ref="remoteHttpEndpointURL"/>
<property name="remoteHttpEndpointContext" value="${wcs.remote_mng.context}"/>
<property name="wsdlMerger" ref="wsdlMerger"/>
<property name="routeResolver" ref="wsdlPostTcpResolver"/>
<property name="readerIdleTime" value="${wcs.frontend.readerIdleTime}"/>
<property name="writerIdleTime" value="${wcs.frontend.writerIdleTime}"/>
<property name="connectTimeout" value="${wcs.frontend.connectTimeout}"/>
</bean>
Since the ClientToProxyIoHandler is the handler for all incoming socket connections, all
request/reply MEP requests will be routed through it. Note that the ClientToProxyIoHandler is
configured with a”routeResolver” (an instance of WsdlPostTCPRouteResolver) and the
“wsdlMerger”, as above. The ClientToProxyIoHandler’s messageReceived(...) method handles all
incoming requests, and when a HTTP-POST request is received, the handler will use a
WsdlPostTCPRouteResolver to determine which child SOAP endpoint to invoke, or delegate to,
for the particular request. The WsdlPostTCPRouteResolver will use the WsdlMerger instance’s
operationsRegistry to map the incoming request type or operation invocation to the appropriate
child endpoint that can satisfy the request.
In the case of HTTP-GET, the ClientToProxyIoHandler will check the type of request. If the
request is for the master WSDL, the handler will use the MasterWSDLGenerator to return the
WSDL document. If the request is a KVP WCS request, either getCapabilities or
describeCoverage, the handler will delegate to the KVP endpoint as specified in the wcsri.cfg file.
Figure 4 depicts the sequence of method invocations for a client request to the WCSRI’s frontend.
58
Figure 4. Sequence Diagram for Frontend
59
6.2.3 The wcsri-web-service Module
The wcsri-web-service module provides the SOAP and KVP endpoints for the WCSRI that are
used by the frontend endpoint. The wcsri-web-service module in the source code is built and
packaged into an OSGi bundle called wcs-service. When the bundle is loaded into ServiceMix as
part of the WCSRI installation (i.e., as part of the WCSRI feature), Blueprint will automatically
create the objects as specified in the bundle’s OSGI-INF/blueprint/wcs-web-service.xml file.
The following endpoints are instantiated by the wcsri-web-service module’s Blueprint
specification:
wcs.httpEndpoint
Description: This endpoint is deprecated. It was initially intended for MTOM SOAP requests.
Endpoint Id: http_wcs1.1
Implementing Class: edu.ucar.ral.wcsri.ws.WcsPortTypeImpl
Specification: wcs1_1_2.wsdl
Blueprint snippet: Omitted since deprecated
wcs.swa.httpEndpoint
Description: This is the main internal endpoint which implements the WCS 1.1.2 SOAP
operations, including getCapabilities, describeCoverage, getCoverage and the additional
getMetadata operation for ISO-compliance.
Endpoint Id: http_wcsSwa1.1
Implementing Class: edu.ucar.ral.wcsri.ws.WcsSwaPortTypeImpl
Specification: wcs1_1_2_swa.wsdl
Blueprint Snippet:
<jaxws:endpoint id="http_wcsSwa1.1" implementor="#wcsSwaImpl" address="${wcs.swa.httpEndpoint}"
wsdlLocation="classpath:wsdl/wcs1_1_2_swa.wsdl">
<jaxws:properties>
<jaxws:entry key="schema-validation-enabled" value="${wcs.xmlValidation}"/>
</jaxws:properties>
<jaxws:inInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.NNEWWSS4JInInterceptor">
<...>
</bean>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASInterceptor">
<...>
</bean>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASOutInterceptor"/>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
</jaxws:outInterceptors>
<jaxws:outFaultInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASOutInterceptor"/>
</jaxws:outFaultInterceptors>
<jaxws:dataBinding>
<ref component-id="wcsriJaxb"/>
60
</jaxws:dataBinding>
</jaxws:endpoint>
wcs.kvp.httpEndpoint
Description: This is the internal endpoint for WCS 1.1.2 Key-Value-Pair (KVP) operations.
Note that this endpoint is REST-ful (i.e., jaxrs) rather than SOAP.
Endpoint Id: wcsKvpServiceNoAnnotations
Implementing Class: edu.ucar.ral.wcsri.rs.WcsKvpServiceImpl
Specification: REST-ful WCS 1.1.2 KVP operations
Blueprint Snippet:
<jaxrs:server id="wcsKvpServiceNoAnnotations" address="${wcs.kvp.httpEndpoint}">
<jaxrs:properties>
<jaxrs:entry key="mtom-enabled" value="true"/>
<jaxrs:entry key="org.apache.cxf.propogate.exception" value="false"/>
</jaxrs:properties>
<jaxrs:inInterceptors>
<ref component-id="logInbound"/>
<ref component-id="securityInterceptor"/>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<ref component-id="logOutbound"/>
</jaxrs:outInterceptors>
<jaxrs:model>
<jaxrs:resource name="edu.ucar.ral.wcsri.rs.WcsKvpServiceImpl" path="/" produces="application/xml">
<jaxrs:operation name="handleService" verb="GET" path="/">
<jaxrs:param name="info" type="CONTEXT"/>
</jaxrs:operation>
</jaxrs:resource>
</jaxrs:model>
<jaxrs:serviceBeans>
<ref component-id="wcsKvpServiceFrondEnd"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref component-id="wcsJaxbProvider"/>
<ref component-id="restCustomExceptionMapperProvider"/>
</jaxrs:providers>
</jaxrs:server>
wcs.subscribe.httpEndpoint
Description: This is the internal endpoint which implements the WS-N Subscribe operation.
Endpoint Id: NotificationProducer
Implementing Class: edu.ucar.ral.wcsri.pubsub.subscription.service.SubscribeToNotifications
Specification: NNEW-SubscriptionManagement.wsdl
Blueprint Snippet:
<jaxws:endpoint id="NotificationProducer"
implementor="#notificationProducerImpl"
address="${wcs.subscribe.httpEndpoint}" wsdlLocation="classpath:NNEW-SubscriptionManagement.wsdl">
<jaxws:properties></jaxws:properties>
61
<jaxws:features>
<wsa:addressing xmlns:wsa="http://cxf.apache.org/ws/addressing"/>
</jaxws:features>
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.NNEWWSS4JInInterceptor">
<...>
</bean>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASInterceptor">
<...>
</bean>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASOutInterceptor"/>
<bean class="edu.ucar.ral.wcsri.pubsub.subscription.service.interceptor.CustomPubSubBrokerURLOutInterceptor"
init-method="parseAlternativeSubscriptionURLs">
<property name="alternativeSubscriptionURLsString" value="${amq.alternative.http.connectors.url}"/>
</bean>
</jaxws:outInterceptors>
<jaxws:outFaultInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASOutInterceptor"/>
</jaxws:outFaultInterceptors>
<jaxws:dataBinding>
<ref component-id="wcsriJaxb"/>
</jaxws:dataBinding>
<jaxws:inFaultInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
</jaxws:inFaultInterceptors>
</jaxws:endpoint>
wcs.mngSubscription.httpEndpoint
Description: This is the internal endpoint which implements the WS-N Subscription
Management operations.
Endpoint Id: PausableSubscriptionManager
Implementing Class: edu.ucar.ral.wcsri.pubsub.subscription.service.SubscriptionManagement
Specification: NNEW-SubscriptionManagement.wsdl
Blueprint Snippet:
<jaxws:endpoint id="PausableSubscriptionManager" implementor="#subscriptionManagementImpl"
address="${wcs.mngSubscription.httpEndpoint}" wsdlLocation="classpath:NNEW-SubscriptionManagement.wsdl">
<jaxws:properties></jaxws:properties>
<jaxws:features>
<wsa:addressing xmlns:wsa="http://cxf.apache.org/ws/addressing"/>
</jaxws:features>
<jaxws:inInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.NNEWWSS4JInInterceptor">
<...>
<property name="enableSecurity" value="${wcs.securityEnabled}"/>
</bean>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASInterceptor">
<...>
</bean>
62
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASOutInterceptor"/>
</jaxws:outInterceptors>
<jaxws:outFaultInterceptors>
<bean class="edu.ucar.ral.security.ws.cxf.interceptors.JAASOutInterceptor"/>
</jaxws:outFaultInterceptors>
<jaxws:dataBinding>
<ref component-id="wcsriJaxb"/>
</jaxws:dataBinding>
</jaxws:endpoint>
Note that each of the endpoints have in- and out- Interceptors that are responsible for security,
including authentication. These are described in the Security section of this document.
6.2.3.1 The WcsSwaPortTypeImpl Services Implementation
6.2.3.1.1 Overview
In the wcsri-web-service module, the edu.ucar.ral.wcsri.ws.WcsSwaPortTypeImpl class provides
the implementation for the operations found in the wcs1_1_2_swa.wsdl. The wcs1_1_2_swa.wsdl
is a description of the services specified in the WCS 1.1.2 specification and includes the SOAP
bindings for the getCapabilities, describeCoverage, getCoverage as well as getMetadata
operations. The Blueprint specification for the WcsSwaPortTypeImpl is as follows:
<bean id="wcsSwaImpl"
class="edu.ucar.ral.wcsri.ws.WcsSwaPortTypeImpl">
<property name="getCapabilitiesService" ref="getCapabilitiesService"/>
<property name="describeCoverageService" ref="describeCoverageService"/>
<property name="getCoverageService" ref="getCoverageService"/>
<property name="getIsoMetaService" ref="getIsoMetaService"/>
<property name="streaming" value="${gds.datasource.streaming}"/>
<property name="publishAddress" value="${datastreamer.publishAddress}"/>
<property name="publishPort" value="${datastreamer.port}"/>
</bean>
The WcsSwaPortTypeImpl class has one method for each SOAP operation defined in the WSDL.
The CXF web-service stack for JAXWS provides the wcs.swa.httpEndpoint and takes care of
calling one of these methods, passing the appropriate Java bindings, whenever one of the
endpoint’s SOAP operations are invoked. When one of these methods is called, the
WcsSwaPortTypeImpl will delegate the request to one of the following: getCapabilitiesService,
describeCoverageService, getCoverageService or a getIsoMetaService depending on the method
invoked. Note that these “services” are configured as properties on the WcsSwaPortTypeImpl and
are also defined in the web OSGI-INF/blueprint/wcs-web-service.xml file, as follows:
<bean id="getCapabilitiesService"
class="edu.ucar.ral.wcsri.protocol.wcs112.jaxb.WCS112GetCapabilitiesService">
<property name="getCapabilitiesConstraintsBuilder" ref="getCapsConstraintsBuilder"/>
<property name="servicesMetadataGDSRequestHandler" ref="servicesMetadataGDSRequestHandlerRef"/>
63
<property name="connectionFactory" ref="jmsConnectionPool"/>
<property name="asynchronous" value="${wcs.async.getCaps}"/>
<property name="timeoutInMillis" value="${wcs.async.getCaps.timeout}"/>
<property name="camelContext" ref="wsGDSPojo"/>
<property name="wcsriJaxbEngine" ref="globalContext"/>
<property name="processingQueue" value="${gds.processorQueue}"/>
</bean>
<bean id="describeCoverageService"
class="edu.ucar.ral.wcsri.protocol.wcs112.jaxb.WCS112DescribeCoverageService">
<property name="describeCoverageConstraintsBuilder" ref="descCvgConstraintsBuilder"/>
<property name="datasetMetadataGDSRequestHandler" ref="datasetMetadataGDSRequestHandlerRef"/>
<property name="connectionFactory" ref="jmsConnectionPool"/>
<property name="asynchronous" value="${wcs.async.descvg}"/>
<property name="timeoutInMillis" value="${wcs.async.descvg.timeout}"/>
<property name="camelContext" ref="wsGDSPojo"/>
<property name="wcsriJaxbEngine" ref="globalContext"/>
<property name="processingQueue" value="${gds.processorQueue}"/>
</bean>
<bean id="getCoverageService"
class="edu.ucar.ral.wcsri.protocol.wcs112.jaxb.WCS112GetCoverageService">
<property name="getCoverageConstraintsBuilder" ref="getCvgConstraintsBuilder"/>
<property name="volumeGDSRequestHandler" ref="volumeGDSRequestHandlerRef"/>
<property name="corridorGDSRequestHandler" ref="corridorGDSRequestHandlerRef"/>
<property name="connectionFactory" ref="jmsConnectionPool"/>
<property name="asynchronous" value="${wcs.async.getCvg}"/>
<property name="timeoutInMillis" value="${wcs.async.getCvg.timeout}"/>
<property name="camelContext" ref="wsGDSPojo"/>
<property name="wcsriJaxbEngine" ref="globalContext"/>
<property name="processingQueue" value="${gds.processorQueue}"/>
</bean>
<bean id="getIsoMetaService"
class="edu.ucar.ral.wcsri.protocol.wcs112.jaxb.WCS112GetIsoMetadataService">
<property name="getIsoMetadataConstraintsBuilder" ref="getIsoMetaConstraintsBuilder"/>
<property name="isoMetaGDSRequestHandler" ref="isoMetaGDSRequestHandlerRef"/>
<property name="connectionFactory" ref="jmsConnectionPool"/>
<property name="asynchronous" value="${wcs.async.getMeta}"/>
<property name="timeoutInMillis" value="${wcs.async.getMeta.timeout}"/>
<property name="camelContext" ref="wsGDSPojo"/>
<property name="wcsriJaxbEngine" ref="globalContext"/>
<property name="processingQueue" value="${gds.processorQueue}"/>
</bean>
These service objects are subclasses of the WCS112Service (in the package
edu.ucar.ral.wcsri.protocol.wcs112.jaxb). The intent of the WCS112Service class (and its
superclass GDSService) was to provide a bridge or adapter between specific technologies such
as JAXB and the more general category of functionality for serving and subsetting gridded data
(i.e., the GDS classes). See Figure 5 for a schematic of the classes, their relationships and a
sequence for how the operations are invoked from a client and delegated.
64
Figure 5. WcsSwaPortTypeImpl and GDSServices
65
6.2.3.1.2 Streaming
The WcsSwaPortTypeImpl’s getCoverageSwaOperation(...) method deserves special attention.
This particular method is called by the web service stack as an implementation of the WCS
getCoverage operation. As you might guess, this method ultimately provides the functionality for
subsetting weather data and has the responsibility of returning a binary attachment for the
NetCDF weather data file. The method signature is as follows:
public void getCoverageSwaOperation(
edu.ucar.ral.bindings.net.opengis.wcs.v1_1_2.GetCoverage request,
javax.xml.ws.Holder<edu.ucar.ral.bindings.net.opengis.wcs.v1_1_2.CoveragesType_> response,
javax.xml.ws.Holder<DataHandler> coverageData )
throws ExceptionReportMsg
Note that the NetCDF file is returned to the web services stack as coverageData of a type
javax.xml.ws.Holder<DataHandler>. Looking into the method’s source code, you can see that the
coverage subsetting is delegated as follows:
edu.ucar.ral.bindings.net.opengis.wcs.v1_1_2.Coverages_ coverages = getCvgService.getCoverage( request );
Once the coverages object is received, it is later queried for the “Href” of the NetCDF data file.
The Href is then used to create a DataHandler object to be returned as part of the coverageData
response. To create the DataHandler object, either a FileDataSource or a StreamDataSource is
used. When the WCSRI is run on a single node, not part of a cluster, the processing of the initial
client request (and response) and the weather data subsetting are done within the same JVM.
Hence, the NetCDF file is written to a temporary location accessible to the request/response
processing. In this scenario, a FileDataSource is created since the NetCDF data resides in a local
file. However, in the case of a cluster where there are more than one WCSRI nodes, the
processing of the initial client request (and response) and the weather data subsetting could
potentially be done on different nodes. In this scenario, the initiating node (i.e., the node that
originally received the client request) must stream the NetCDF file from the node that actually did
the weather data subset processing back to the initiating node. To handle this, a
StreamDataSource is used. In addition, see 6.3.1.4 GDSPojoWrapper for more information on
streaming.
6.2.3.2 The WcsKvpServiceImpl Services Implementation
In the wcsri-web-service module, the edu.ucar.ral.wcsri.rs.WcsKvpServiceImpl class provides the
implementation for the REST-ful key-value-pair (KVP) operations specified in the WCS 1.1.2
specification. Note that KVP operations are dis/enabled via the wcs.kvp.disabled property found in
the wcsri.cfg file, and if enabled, will provide an implementation of the getCapabilities,
describeCoverage and getMetadata operations only. The Blueprint specification for the
WcsKvpServiceImpl is as follows:
<bean id="wcsKvpServiceFrondEnd"
class="edu.ucar.ral.wcsri.rs.WcsKvpServiceImpl">
<property name="getCapabilitiesService" ref="getCapabilitiesService"/>
66
<property name="describeCoverageService" ref="describeCoverageService"/>
<property name="getCoverageService" ref="getCoverageService"/>
<property name="getIsoMetaService" ref="getIsoMetaService"/>
<property name="supportedWCSVersions">
<list>
<value>${wcs.version}</value>
</list>
</property>
<property name="disabled" value="${wcs.kvp.disabled}"/>
</bean>
The WcsKvpServiceImpl class has a method called handleService(...). The CXF web-service
stack for JAXRS provides the wcs.kvp.httpEndpoint and takes care of calling the
handleService(...) method passing the URI used for the request. Based on the request
parameters, the WcsKvpServiceImpl handleService(...) method will the call the getCapabilities(...),
describeCoverage(...) or getMetadata(...) method as appropriate. Each of those methods will then
delegate the request to one of the following: getCapabilitiesService, describeCoverageService or
a getIsoMetaService depending on the method invoked. Note that these “services” are configured
as properties on the WcsKvpServiceImpl and are the identical instances used for configuring the
WcsSwaPortTypeImpl.
6.2.3.3 The SubscribeToNotifications Services Implementation
The edu.ucar.ral.wcsri.pubsub.subscription.service.SubscribeToNotifications class (found in the
source code’s pubsub/subscription-service module) provides the implementation for the Subscribe
operation found in the NNEW-SubscriptionManagement.wsdl. The NNEWSubscriptionManagement.wsdl is a description of the services specified in the WS-N specification
and includes the SOAP bindings for the Subscribe operation as well as operations related to
subscription management. The Blueprint specification for the SubscribeToNotifications object is
as follows:
<bean id="notificationProducerImpl"
class="edu.ucar.ral.wcsri.pubsub.subscription.service.SubscribeToNotifications">
<property name="subscribeDescribeCoverageService" ref="subscribeToDescribeCoverageService"/>
<property name="subscribeGetCoverageService" ref="subscribeToGetCoverageService"/>
<property name="supportedDialects">
<list>
<value>urn:def:ogc:wcs:1.1</value>
</list>
</property>
</bean>
The SubscribeToNotifications class has a method called subscribe(...) which is the
implementation of the corresponding SOAP operation defined in the WSDL. The CXF web-service
stack for JAXWS provides the wcs.subscribe.httpEndpoint and takes care of calling this method,
passing the appropriate Java bindings, whenever the endpoint’s subscribe SOAP operation is
invoked. Within the subscribe(...) method, the SubscribeToNotifications object will delegate the
request to either a subscribeGetCoverageService or a subscribeDescribeCoverageService
depending on the type of subscription being requested. The notion for this design was that clients
could subscribe with either GetCoverage or DescribeCoverage symantics. However, in both
67
cases, notifications are effectively the same thing and consist of a message saying that new data
is available on the server. Note that these “services” are configured as properties on the
SubscribeToNotifications and are also defined in the web OSGI-INF/blueprint/wcs-webservice.xml file, as follows:
<bean id="subscribeToDescribeCoverageService"
class="edu.ucar.ral.wcsri.pubsub.subscription.service.wsn.jaxb.SubscribeDescribeCoverageService">
<property name="subscribeDescribeCoverageConstrainsBuilder" ref="subscribeDescribeCvgConstraintsBuilder"/>
<property name="subscribeRequestHandler" ref="subscribeRequestHandlerRef"/>
</bean>
<bean id="subscribeToGetCoverageService"
class="edu.ucar.ral.wcsri.pubsub.subscription.service.wsn.jaxb.SubscribeGetCoverageService">
<property name="subscribeGetCoverageConstrainsBuilder" ref="subscribeGetCvgConstraintsBuilder"/>
<property name="subscribeRequestHandler" ref="subscribeRequestHandlerRef"/>
</bean>
The subscription request is then propagated down the line to a POJO layer, independent of
technologies. For example, the subscribeGetCoverageService will delegate to a
SubscriptionRequestHandler, really an instance of a SubscribeRequestHandler (note spelling), in
order to create the subscription, persist it to the database, and build a response. The response
will include the endpoint URL of the handshake queue that the client will use to connect to in order
to receive notifications. The SubscribeRequestHandler is imported into wcs-web-service.xml using
the following reference:
<reference id="subscribeRequestHandlerRef"
interface="edu.ucar.ral.wcsri.pubsub.sm.handler.SubscriptionRequestHandler" filter="(subscribeRequestHandler=true)"/>
Note that the actual instance of the SubscriptionRequestHandler is a SubscribeRequestHandler,
(note spelling) as defined in a different blueprint file in a different module, pubsub/subscriptionmanagement/OSGI-INF/blueprint/subscription-management.xml, as follows:
<!-- Subscribe service handler -->
<bean id="subscribeRequestHandler" class="edu.ucar.ral.wcsri.pubsub.sm.handler.SubscribeRequestHandler">
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="brokerURL" value="${amq.http.connector.url}"/>
<tx:transaction method="handle*" value="Required"/>
</bean>
6.2.3.4 The SubscriptionManagement Services Implementation
The edu.ucar.ral.wcsri.pubsub.subscription.service.SubscriptionManagement class (found in the
source code’s pubsub/subscription-service module) provides the implementation for the
subscription management operations found in the NNEW-SubscriptionManagement.wsdl. The
NNEW-SubscriptionManagement.wsdl is a description of the services specified in the WS-N
specification and includes the SOAP bindings for the subscription management operations as well
as the subscribe operation. The Blueprint specification for the SubscriptionManagement object is
as follows:
68
<bean id="subscriptionManagementImpl"
class="edu.ucar.ral.wcsri.pubsub.subscription.service.SubscriptionManagement">
<property name="subsMngtHandler" ref="subscriptionManagementRequestHandlerRef"/>
</bean>
The SubscriptionManagement class has methods implementing the subscription management
SOAP operations defined in the WSDL. The CXF web-service stack for JAXWS provides the
wcs.mngSubscription.httpEndpoint and takes care of calling the appropriate method, passing the
appropriate Java bindings, whenever one of the endpoint’s SOAP operations is invoked. Within
the implementing methods, the SubscriptionManagement object will delegate the request to a
SubscriptionRequestHandler (or subsMngtHandler), configured as a property shown above. The
SubscriptionRequestHandler is imported into wcs-web-service.xml using the following reference:
<reference id="subscriptionManagementRequestHandlerRef"
interface="edu.ucar.ral.wcsri.pubsub.sm.handler.SubscriptionRequestHandler"
filter="(subscriptionMgmtRequestHandler=true)"/>
Note that a SubscriptionManagementRequestHandler is the actual instance used for the
SubscriptionRequestHandler property, as a defined in a different blueprint in a different module,
pubsub/subscription-management/OSGI-INF/blueprint/subscription-management.xml, as follows:
<bean id="subscriptionManagementRequestHandler"
class="edu.ucar.ral.wcsri.pubsub.sm.handler.SubscriptionManagementRequestHandler">
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<tx:transaction method="handle*" value="Required"/>
</bean>
Again, the intent was to provide a POJO layer of handlers independent of technology stacks.
6.3 Synchronous vs Asynchronous Processing for WCS Requests
Much of the WCSRI codebase consists of code dedicated to providing weather metadata retrieval
and weather data subsetting. This sort of functionality is encompassed by the operations specified
in the WCS 1.1.2 specification, and include the getCapabilities, describeCoverage, getCoverage
operations as well as getIsoMetadata. These operations are loosely referred to as the “WCS
services” in the following section, and at the highest level, are handled by the previously
described WcsSwaPortTypeImpl.
Requests for WCS services (i.e., getCapabilities, describeCoverage, getCoverage,
getIsoMetadata) can be handled synchronously or asynchronously, based on the configuration
setting in wcsri.cfg. Synchronous request handling is suitable for a single WCSRI node acting in
isolation. Asynchronous request handling takes advantage of the load-sharing capabilities of a
multi-node WCSRI cluster, allowing more heavily-loaded nodes to delegate request processing to
a node with more resources available at the time of the request, via a JMS message queue.
Note that with asynchronous request handling, the maximum number of concurrent consumers is
defined in the wcsri.cfg file. This effectively limits the load of any one node in a WCSRI cluster, as
69
well as the load on a single-node WCSRI. Synchronous request processing offers no such
limitations; thus it is susceptible to overloading when asked to fulfill large numbers of requests
simultaneously.
6.3.1 Asynchronous Processing
Asynchronous processing delivers incoming requests to the JMS (e.g. ActiveMQ), where
competing consumers can handle them based on load and availability. The node receiving the
WCS service request, via the frontend endpoint, simply enqueues the request message and waits
for a response message to be generated (by another thread running on the same node, or by
another WCSRI node in the cluster).
6.3.1.1 GDSService
As described in Section 6.2.3.1.1 and Figure 5, the WcsSwsPortTypeImpl delegates incoming
requests to the GDSService object via its handleServiceRequest() method. For asynchronous
requests, the GDSService then calls the handleAsyncServiceRequest() method. This method
uses JAXB bindings to marshal the request into XML and sends it to ActiveMQ using an In/Out
exchange pattern, i.e. the method blocks until it either times out or receives a response. This frees
the CPU to devote resources to other tasks until a response is created, by any WCSRI node in
the cluster. When an XML response is returned by ActiveMQ, it is unmarshalled (again using
JAXB) and the response object is returned to the WcsSwsPortTypeImpl’s calling method (where it
will then be returned to the CXF stack and hence, the client).
6.3.1.2 ActiveMQ and the gds.processorQueue
The GDSService class will enqueue the XML requests to the ActiveMQ queue identified by the
gds.processorQueue property specified in the wcsri.cfg (however, this property should NOT be
changed!), as shown in Figure 6 - this is a good diagram to follow while reading the next several
sections. ActiveMQ receives, enqueues, and delivers Camel Exchange message objects
containing XML requests and responses wrapped in the body of the Exchange. A Camel route,
initialized by Blueprint on startup, listens for new requests appearing on the gds.processorQueue
and routes them to the process() method of the GDSPojoWrapper object (also instantiated by
Blueprint on startup). The Camel route is created via Blueprint with the following specification,
from the OSGI-INF.blueprint/gds-async-wrapper.xml file in the gds-async-wrapper module:
<camelContext id="asyncGDSPojo" xmlns="http://camel.apache.org/schema/blueprint">
<endpoint id="gdsProcessorQueue" uri="jms:queue:gds.processor"/>
<route>
<from ref="gdsProcessorQueue"/>
<to uri="gdsPojoWrapper"/>
</route>
</camelContext>
6.3.1.3 Competing Consumers
70
All of the WCSRI nodes in a cluster compete to consume the next available message on the
gds.ProcessorQueue. ActiveMQ ensures that request messages are handled by one and only one
consumer. Any node that is already servicing its asynchronous request limit (i.e. the configured
gds.numberConcurrentConsumers per wcsri.cfg) will not be able to compete for new request
messages in the gds.processorQueue. This request limit is handled by Camel, through a Blueprint
configuration of its JMS component (also from the OSGI-INF.blueprint/gds-async-wrapper.xml file
in the gds-async-wrapper module):
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsConnectionPool"/>
<property name="concurrentConsumers" value="${gds.numberConcurrentConsumers}"/>
<property name="jmsOperations" ref="jmsTemplate"/>
</bean>
6.3.1.4 GDSPojoWrapper
The 'winning' consumer delivers the request to a GDSPojoWrapper object's process() method, via
the Camel route described above. The dequeued XML message is unmarshalled into a Java
object using the WCSRI JAXB bindings. The bindings determine the type of
WebServiceResponse object (i.e., response builder) to use for the incoming request. This
WebServiceResponse contains request-specific ConstraintsBuilder and GDSRequestHandler
objects glued up via the gds-async-wrapper module’s Blueprint specification, according to the
following table:
IncomingRequest
WebService
Response
ConstraintsBuilder
GDSRequestHandler
DescribeCoverage
DescribeCoverage
ResponseBuilder
DescribeCoverage
ConstraintsBuilder
DatasetMetadata
GDSRequestHandler
GetCapabilities
GetCapabilities
ResponseBuilder
GetCapabilities
ConstraintsBuilder
ServicesMetadata
GDSRequestHandler
GetCoverage
GetCoverageService
ResponseBuilder
GetCoverage
ConstraintsBuilder
Volume
GDSRequestHandler,
Corridor
GDSRequestHandler
GetMetadata
RequestType
GetIsoMetaData
ResponseBuilder
GetIsoMetadata
ConstraintsBuilder
IsoMeta
GDSRequestHandler
The Blueprint (from OSGI-INF.blueprint/gds-async-wrapper.xm) for the GDSPojoWrapper is as
follows:
<bean class="edu.ucar.ral.gds.responsebuilders.DescribeCoverageResponseBuilder" id="describeCoverageResponseBuilder">
<property name="constraintsBuilder" ref="descCvgConstraintsBuilder"/>
<property name="datasetMetadataGDSRequestHandler" ref="datasetMetadataGDSRequestHandlerRef"/>
71
</bean>
<bean id="getCapabilitiesResponseBuilder" class="edu.ucar.ral.gds.responsebuilders.GetCapabilitiesResponseBuilder">
<property name="getCapabilitiesConstraintsBuilder" ref="getCapsConstraintsBuilder"/>
<property name="servicesMetadataGDSRequestHandler" ref="servicesMetadataGDSRequestHandlerRef"/>
</bean>
<bean id="getCoverageServiceResponseBuilder" class="edu.ucar.ral.gds.responsebuilders.GetCoverageServiceResponseBuilder">
<property name="getCoverageConstraintsBuilder" ref="getCvgConstraintsBuilder"/>
<property name="volumeGDSRequestHandler" ref="volumeGDSRequestHandlerRef"/>
<!-- from gds-pojo-service bundle -->
<property name="corridorGDSRequestHandler" ref="corridorGDSRequestHandlerRef"/>
</bean>
<bean id="getIsoMetaDataResponseBuilder" class="edu.ucar.ral.gds.responsebuilders.GetIsoMetaDataResponseBuilder">
<property name="getIsoMetadataConstraintsBuilder" ref="getIsoMetaConstraintsBuilder"/>
<property name="isoMetaGDSRequestHandler" ref="isoMetaGDSRequestHandlerRef"/>
</bean>
<bean id="gdsPojoWrapper" class="edu.ucar.ral.gds.async.GDSPojoWrapper">
<property name="describeCoverageResponseBuilder" ref="describeCoverageResponseBuilder"/>
<property name="getCapabilitiesResponseBuilder" ref="getCapabilitiesResponseBuilder"/>
<property name="getCoverageServiceResponseBuilder" ref="getCoverageServiceResponseBuilder"/>
<property name="getIsoMetaDataResponseBuilder" ref="getIsoMetaDataResponseBuilder"/>
<property name="wcsriJaxbEngine" ref="globalContext"/>
<property name="dataSourceLocator" ref="dataSourceLocator"/>
<property name="streaming" value="${gds.datasource.streaming}"/>
<property name="publishAddress" value="${datastreamer.publishAddress}"/>
<property name="publishPort" value="${datastreamer.port}"/>
</bean>
Note that the various GDSRequestHandlers are instances or references that come from the gdspojo-service bundle’s Blueprint in its OSGI-INF/blueprint/gds.xml file, as described in Section 6.4.
The ConstraintsBuilder is used to assemble a GDSRequest object, which is passed to the
GDSRequestHandler using its handleGDSRequest() method. This returns a GDSResponse object
- note that the GDSReponse object is a POJO and is not sufficient for returning to ActiveMQ.
Hence, the next steps involve converting the object to a JAXB, and then marshalling it to XML for
return to ActiveMQ.
The GDSResponse object return by the GDSRequestHandler is then passed to the
getWebServiceResponse() method of the request-specific WebServiceResponse instance. The
response builder is then responsible for creating and returning a JAXB object representing the
GDSResponse (and GDSRequest). In the response builder’s getWebServiceResponse() method,
it creates an appropriate JAXB response (e.g., CoverageDescriptions, or Coverages_ object) and
populates it by extracting information from the GDSRequest and GDSResponse objects. This
JAXB object is then returned to the GDSPojoWrapper. In the case of a GriddedDataResponse
resulting from a getCoverage request, the dataset’s location (either a file if local or a stream if
remote) is included as the GridDatasetURL in the response (to be used later by the
WcsSwaPortTypeImpl in creating the binary weather data attachment). The GDSPojoWrapper
then marshals the JAXB object into an XML response for the ActiveMQ gds.processorQueue. The
72
output section of the ActiveMQ message is set to the value of the XML (converted to a string)
using the message’s getOut().setBody() method. After the process() method returns, ActiveMQ
returns the response to the original WCSRI node handling the request, unblocking its
GDSService’s handleServiceRequest() method and allowing the GDSService to complete the
request/response sequence.
73
Figure 6. GDSService and Asynchronous WCS Requests
74
6.3.2 Synchronous Processing
Synchronous requests are handled as they arrive by the WCSRI node receiving the request,
without the aid of ActivemQ or JMS. As described in Section 6.2.3.1.1 and Figure 5, the
WcsSwsPortTypeImpl delegates incoming requests to the GDSService object via its
handleServiceRequest() method. For synchronous requests, the GDSService then calls the
handleSyncServiceRequest() method as shown in Figure 7. The GDSService object is an
instance of a WCS112Service matching the request, according to the following table:
IncomingRequest
GDSService
ConstraintsBuilder
GDSRequestHandler
DescribeCoverage
WCS112
DescribeCoverage
Service
DescribeCoverage
ConstraintsBuilder
DatasetMetadata
GDSRequestHandler
GetCapabilities
WCS112
GetCapabilitiesService
GetCapabilities
ConstraintsBuilder
ServicesMetadata
GDSRequestHandler
GetCoverage
WCS112
GetCoverageService
GetCoverage
ConstraintsBuilder
Volume
GDSRequestHandler,
Corridor
GDSRequestHandler
GetMetadata
RequestType
WCS112
GetIsoMetadataService
GetIsoMetadata
ConstraintsBuilder
IsoMeta
GDSRequestHandler
As a reminder, the GDSService concrete instances are created and configured as properties on
the WcsSwaPortTypeImpl defined in the web OSGI-INF/blueprint/wcs-web-service.xml file (see
Section 6.2.3.1.1). However, the concrete instances of the GDSRequestHandlers are defined in
the gds-pojo-service bundle’s Blueprint described in Section 6.4.
The GDSService object uses its ConstraintsBuilder to build a GDSRequest object, which is
handled by the service's GDSRequestHandler using its handleGDSRequest() method. The
GDSResponse object returned is passed to the service's buildWebServiceResponse() method,
which creates and returns the appropriate web service response object.
75
Figure 7. GDSService and Synchronous WCS Requests
76
Figure 8. WCS Request Processing Classes
77
6.4 The gds-pojo-service Bundle
6.4.1 Blueprint and Dependency Injected Objects
The gds-pojo-service bundle contains a Blueprint file that specifies a number of plain-old-javaobjects (POJOs). These POJOs are independent of web-service technologies, and take care of
much of the “simple” functionality of the server. The following is a list of objects that are
instantiated via Blueprint:
●
●
●
●
●
●
●
●
●
DataSourceConfigurator – creates and configures all data sources on startup
DataSourceManager – maintains a list of datasources and repeated datasources
servicesMetadataGDSRequestHandler – handles getCapabilites requests
datasetMetadataGDSRequestHandler – handles describeCoverage requests
isoMetaGDSRequestHandler – handles getMetadata requests
volumeGDSRequestHandler – handles getCoverage requests for volumes
corridorGDSRequestHandler – handles getCoverage requests for corridors
reqReplyWcsClient – used for communicating with upstream WCSRI nodes
wsPortTypeManager - used for communicating with upstream WCSRI nodes
The Blueprint file for the gds-pojo-service bundle is in its OSGI-INF/blueprint/gds.xml file, as
follows:
<bean id="dataSourceMgr" class="edu.ucar.ral.gds.core.datasource.DataSourceManagerImpl"/>
<bean id="servicesMetadataGDSRequestHandler" class="edu.ucar.ral.gds.handler.ServicesMetadataGDSRequestHandler"
init-method="validateInitializationConfiguration">
<property name="dataSourceManager" ref="dataSourceMgr"/>
</bean>
<bean id="datasetMetadataGDSRequestHandler" class="edu.ucar.ral.gds.handler.DatasetMetadataGDSRequestHandler"
init-method="validateInitializationConfiguration">
<property name="dataSourceManager" ref="dataSourceMgr"/>
</bean>
<bean id="volumeGDSRequestHandler" class="edu.ucar.ral.gds.handler.VolumeGDSRequestHandler"
init-method="validateInitializationConfiguration">
<property name="dataSourceManager" ref="dataSourceMgr"/>
</bean>
<bean id="corridorGDSRequestHandler" class="edu.ucar.ral.gds.handler.CorridorGDSRequestHandler"
init-method="validateInitializationConfiguration">
<property name="dataSourceManager" ref="dataSourceMgr"/>
</bean>
<bean id="isoMetaGDSRequestHandler" class="edu.ucar.ral.gds.handler.IsoMetaGDSRequestHandler"
init-method="validateInitializationConfiguration">
<property name="dataSourceManager" ref="dataSourceMgr"/>
</bean>
<bean id="wsPortTypeManager" class="edu.ucar.ral.wxcube.consumer.wcs.WcsSwaPortTypeManager">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableOutLogging" value="${webServicesRequestLogEnabled}"/>
78
<property name="enableInLogging" value="${webServicesResponseLogEnabled}"/>
</bean>
<bean id="reqReplyWcsClient" class="edu.ucar.ral.wxcube.consumer.wcs.ReqReplyWcsSwaClientImpl">
<property name="portTypeMgr" ref="wsPortTypeManager"/>
<property name="unitManager" ref="unitManager"/>
</bean>
<!-- This is the thing that will configure all of the data sources -->
<bean id="dataSourceConfigurator" class="edu.ucar.ral.gds.core.datasource.DataSourceConfigurator"
init-method="init" destroy-method="destroy">
<property name="gdsRootDataDirPath" value="${wcs.rootDataDir}"/>
<property name="gdsTempDirPath" value="${wcs.tempDir}"/>
<property name="tempDirectoryCleanupFrequency" value="${wcs.tempCleanupFreq}"/>
<property name="tempFilesMaxAge" value="${wcs.tempMaxAge}"/>
<property name="gdsServicesMetaFileName" value="${wcs.servicesMetaFile}"/>
<property name="isoServicesMetaFileName" value="${wcs.isoServicesMetaFile}"/>
<property name="dataSourceManager" ref="dataSourceMgr"/>
<property name="wxConsumer" ref="reqReplyWcsClient"/>
</bean>
<service id="servicesMetadataGDSRequestHandlerOsgi" ref="servicesMetadataGDSRequestHandler"
interface="edu.ucar.ral.gds.handler.ServicesMetadataGDSRequestHandler"/>
<service id="datasetMetadataGDSRequestHandlerOsgi" ref="datasetMetadataGDSRequestHandler"
interface="edu.ucar.ral.gds.handler.DatasetMetadataGDSRequestHandler"/>
<service id="volumeGDSRequestHandlerOsgi" ref="volumeGDSRequestHandler"
interface="edu.ucar.ral.gds.handler.VolumeGDSRequestHandler"/>
<service id="corridorGDSRequestHandlerOsgi" ref="corridorGDSRequestHandler"
interface="edu.ucar.ral.gds.handler.CorridorGDSRequestHandler"/>
<service id="isoMetaGDSRequestHandlerOsgi" ref="isoMetaGDSRequestHandler"
interface="edu.ucar.ral.gds.handler.IsoMetaGDSRequestHandler"/>
<!-- Export this so that FilePollers can access the GDS's directory structure -->
<service id="dataSourceMgrOsgi" ref="dataSourceMgr"
interface="edu.ucar.ral.gds.core.datasource.DataSourceManagerReadOnly"/>
6.4.2 DataSourceConfigurator, DataSource and DataSourceManager
The DataSourceManager maintains a list of all coverages that are accessible via the WCSRI
instance. This can include coverages stored on the local filesystem as well as coverages that are
retrieved from an upstream WCSRI node (via delegation or a repeater). Each coverage, whether
local or delegated, is represented by a DataSource object. These objects are constructed at
startup and are later used to retrieve data and metadata requested by WCSRI clients.
On startup, DataSourceConfigurator and DataSourceManager instances are created (by
blueprint), followed by a call to the DataSourceConfigurator's init() method as shown in the
sequence diagram in Figure 9. This method reads each coveragesConfig.xml file below the
WCSRI’s root data directory and configures a DataSource object for each delegated or repeated
coverage, and/or a single DataSource object wrapping multiple coverages in a single directory on
the local filesystem. The DataSourceConfigurator populates the DataSourceManager's master list
with each new DataSource created, referenced by a list of DatasetIdentifier objects representing
each coverage's identifier string. Note that since this process is performed once on startup, it is
79
necessary to restart the WCSRI if any new coverages are added (or changed) to a running
instance.
A DataSource can be an instance of a DirectoryBasedDataSource (i.e., type=”FileSystem” as in
Figure 10), in which case the raw coverage data and metadata are stored on the local filesystem,
through direct file ingest (atomically) into the coverage's /staging directory or via a subscription to
an upstream WCSRI node (i.e. a repeater).
A DataSource can also be an instance of a DelegatorDatasetDataSource (i.e., type=”Delegator”
as in Figure 11), in which case data is retrieved on demand from the upstream WCSRI node
described in the coveragesConfig.xml file. See Section 9 for a discussion on Delegators.
If the coveragesConfig.xml indicates that the directory is to be automatically populated with any
new data (or a subset of that data) arriving on an upstream node (i.e. type=”Repeater” as in
Figure 12), a RepeaterConfig object is also created for each coverage found in
coveragesConfig.xml, along with a DirectoryBasedDataSource object to handle the data once it
arrives. The RepeaterConfig is populated with information about the upstream node (URL, any
required login information, etc.), the desired bounding box of the data, and coverage-specific
information such as the identifier and available fields. The DataSourceManager maintains a list of
RepeaterConfig objects which are later used to create subscriptions to upstream WCSRI nodes.
See Section 8 for a discussion on Repeaters.
In addition to describing the coverage, the coveragesConfig.xml file allows configuration of an
optional janitor process, which runs on a scheduler (Quartz). The janitor functions to clean up old
data files and temporary files to prevent data (and temporary data such as client-requested
subsets and corridors) from filling the disks. Note that the Janitor will only function if the WCSRI is
running - hence it is advisable to use the WCSRI’s Janitor to clean up “young” files, and use a
custom janitor on a cron job for “older” files.
For DirectoryBasedDataSource objects, a DatasetMetadata object is created for each configured
coverage. This object is marked as INVALID until the metadata can be verified. The verification is
performed on startup (see Figure 13), and if deemed INVALID, again for each data and metadata
request thereafter. Verification involves opening and reading a sample data file to verify data
valid/run times, fields, and coordinate axes. Metadata is then constructed from the sample file,
including data extents, coordinate reference systems, and available vertical levels. Finally, a test
volume request is performed, using a small subset of the data extent. If this request is successful,
the DatasetMetadata object is marked as VALID. Clearly, since only a single raw weather data file
is verified, it assumed that all other raw weather data files for the coverage are similarly valid (or
invalid).
80
Figure 9. DataSourceConfigurator's init() method
81
Figure 10. coveragesConfig.xml with FileSystem DataSource
Figure 11. coveragesConfig.xml with Delegator DataSource
82
Figure 12. coveragesConfig.xml with Repeater DataSource
83
Figure 13. DataSource Validation
84
Figure 14. DataSource and Class Relationships
6.4.3 GetCapabilities (ServicesMetaGDSRequestHandler)
A GetCapabilities request is handled by the ServicesMetadataGDSRequestHandler, which
retrieves the ServicesMetadataDataSource from the DataSourceManager. The
85
getServicesMetadata() method on the ServicesMetadataDataSource is called to construct a
ServicesMetadataResponse to return. The method loops through each of the
DataSourceManager's DataSource objects and gathers metadata by calling its
getDatasetMetadata() method. This may involve reading metadata for local datasets, or
requesting metadata for delegated coverages from an upstream WCSRI. Note that since available
coverage times are not included in a GetCapabilities response, cached metadata created during
WCSRI initialization can be used for this operation.
When dataset metadata has been collected, the ServicesMetadataDataSource object constructs a
ServicesMetadataResponse, and populates it with each dataset's metadata, along with the global
metadata contained in the wcs.servicesMetaFile. This response object is returned to the
ServicesMetadataGDSRequestHandler, and ultimately to the requesting client.
6.4.4 GetMetadata (IsoMetadataGDSRequestHandler)
A GetMetadata request provides service and dataset metadata according to the ISO 19139
metadata schema. This request is passed to the IsoMetaGDSRequestHandler object, which
determines the type of request (services metadata or dataset metadata).
If a request for services metadata is made, the IsoMetaGDSRequestHandler responds with the
contents of the wcs.isoServicesMetaFile, wrapped in an IsoMetaResponse JAXB object.
If the request is for dataset metadata, the IsoMetaGDSRequestHandler creates a list of
DataSource objects, using the DatasetIdentifiers provided in the request, obtained from the
DataSourceManager. For each DataSource, an IsoMetaRequest is constructed, along with any
filtering constraints provided in the original request, and passed to the DataSource object's
getIsoMetadata() method. This allows the DataSource to gather metadata from the local
filesystem or from an upstream WCSRI node (in the case of a delegated coverage). The response
is in the form of a IsoMetaResponse object.
For a local dataset, getIsoMetadata() reads the metadata file for each requested coverage, as
specified in the coverage's <CoverageIsoMetadataFile> element located in the dataset's
coveragesConfig.xml. A JAXB object is marshalled from the ISO metadata file and returned in the
DataSource response.
The individual responses are then aggregated into a single IsoMetaResponse object, which is
returned by the IsoMetaGDSRequestHandler.
6.4.5 DescribeCoverage (DatasetMetadataGDSRequestHandler)
The DatasetMetadataGDSRequestHandler handles WCS DescribeCoverage requests by finding
the DataSource associated with each DatasetIdentifier provided in the request, and calling its
getDatasetMetadata() method in a fashion similar to the GetCapabilities operation.
86
In the case of DescribeCoverage, however, a current list of available data times (or current
available time range) is also requested from the DataSource. For a DirectoryBasedDataSource,
the getDatasetMetadata() method triggers the creation of an AvailableTimesGenerator object
which traverses the local dataset directory tree and assembles a time list based on directory and
file naming conventions (i.e. data times are constructed from the file names themselves rather
than by prohibitively inspecting each file's contents). For a DelegatorDatasetDataSource, the
getDatasetMetadata() method triggers a request upstream using the DataSource’s
ReqReplyWcsClientImpl.
6.4.6 GetCoverage
6.4.6.1 Get Volume (VolumeGDSRequestHandler)
When a request is made for a gridded data volume via GetCoverage, it is handled by the
VolumeGDSRequestHandler using the handleGDSRequest() method call. This method gets a
matching DatasetDataSource object from the DataSourceManager using the coverage identifier
provided in the request, and calls its getVolume() method. The requested dataset may reside
locally on the WCSRI node's filesystem, or it may be located on an upstream node. In the latter
case, the DatasetDataSource object will be an instance of the DelegatorDatasetDataSource
class, and the volume is simply requested from the upstream WCSRI using the wxconsumer
library and passed along to the client.
For requests made for datasets residing on the local filesystem, the DatasetDataSource object will
be an instance of the DirectoryBasedDataSource class. The getVolume() method first validates
the request, making sure a coverage id, bounding box, and a time list (or time range) are
included, as shown in Figure 15. It then generates a list of files containing the requested data, and
uses a TemporalFileAggregator to aggregate them into a single GridDatasetWrapper object. Note
that the TemporalFileAggregator uses NCML to aggregate the files.
Next, a VolumeSubsetter object is created. Note that this is a thread-safe operation since a
VolumeSubsetter instance is created for each individual request. The VolumeSubsetter is
configured according to settings provided in the coverage metadata file (i.e. the
coveragesConfig.xml file). This includes setting a maximum chunk size (see Chunking, below) as
well as decimation limits in the x,y (and possibly z) dimensions.
The VolumeSubsetter's subset() method is then called, passing in the request, aggregated
dataset wrapper, and a temporary output file object for the subsetted data. When the method
returns successfully, the DataSource object returns a GriddedDataResponse, which includes a
path to the populated output file on the local filesystem. (Note that while the input data may be
shared among several nodes in a WCSRI cluster, the output file will be written to the request
handling node's local disk as specified by the wcsri.cfg file’s wcs.tempDir property)
87
6.4.6.1.1 Subsetting Algorithm
The algorithm used by the VolumeSubsetter to subset (and possibly decimate) the requested
coverage is fairly complex due to the wide variety of coverages and data that are supported by the
WCSRI. Early in the requirements gathering phase of development, it was mandated that raw
legacy data that is NOT a coverage (e.g., informational) should be propagated to subset results.
This legacy data may include variables that can't be subsetted (e.g., no dimensionality along the
x, y, z, or time dimensions), or can only be partially subsetted (e.g., a variable that has an x
dimension but no y dimension). Additionally, units of the spatial axes may need to be converted to
match the requested bounding box. All fields in a given coverage must be homogeneous in terms
of axis dimensions. That is, the x, y, z, time and runtime axes must match exactly across all fields
in a coverage.
The VolumeSubsetter first checks to make sure the native dataset and the requested subset of
data are consistent. It then calculates the dimension sizes, ranges and deltas of the input and
output datasets. This includes handling subset requests that do not overlap or only partially
overlap the available data, as well as calculating new axis values for decimation requests.
Next it prepares the output dataset by declaring non-subsettable, partially subsettable (i.e. defined
in one or more, but not all, of the x, y, z, time, and runtime dimensions) and fully subsettable
variables and their attributes. Though they are not coverages, non-subsettable and partially
subsettable variables are carried forward into the resulting coverage subset since they are legacy
data - an early requirement for the WCSRI was to propagate legacy data/variables when
appropriate since presumably there’s a reason for the data existing in the raw data files.
Finally, data is written to the output dataset in the following order: 1) non-gridded variable values,
2) values for each axis dimension, 3) partially subsettable variable values, 4) grid values (using
chunking and decimation where configured and/or requested), and 5) performance statistics for
disk reads, writes, etc.
6.4.6.1.2 Decimation
A volume request can include an option to increase or decrease the grid resolution in the x and y
dimensions (and optionally the z dimension, if one exists). The amount of allowable resolution
change is limited on a per-coverage basis to prevent excessive loading of the WCSRI (e.g. trying
to remap a large 5km grid to a 1 meter grid). Currently grid reprojections are not supported – the
requested output CRS must match the native dataset's CRS. It is important to note that while the
requested bounding box is given in lat/lon/km units, the requested resolution MUST be specified
in the dataset's native units.
Decimated data is remapped to the requested resolution using 'nearest neighbor' interpolation –
that is, no averaging is performed.
88
6.4.6.1.3 Chunking
A volume subset may optionally be written in 'chunks', depending on per-coverage settings in the
coveragesConfig.xml file. This option can improve server performance when dealing with very
large grids. When chunking is enabled, memory usage is limited to a maximum chunk size, and
each chunk of the dataset is read, processed, and written back to disk before moving on to the
next chunk. With undecimated requests, the input and output chunks will be the same, but for
decimated requests, the subsetting algorithm must allocate memory for both the input and output
grid chunks (which will not be the same size), and the sum of both must not exceed the maximum
chunk size.
Note that when decimation along the z axis is requested, vertical levels are processed one at a
time regardless of whether chunking is enabled or not, since it cannot be assumed that vertical
levels will be evenly spaced.
89
Figure 15. Volume Subsetting Sequence
90
6.4.6.2 Get Corridor (CorridorGDSRequestHandler)
Corridor requests are handled in a manner similar to Volume requests, except that a
CorridorGDSRequestHandler is used. This handler calls the getCorridor() method of the
DatasetDataSource object matching the coverage identifier provided in the request, as shown in
Figure 16.
The getCorridor() method is similar to the getVolume() method, except that subsetting is
performed by a CorridorSubsetter object. Request validation, file aggregation, and wrapping tasks
are the same as for a Get Volume request.
6.4.6.2.1 Corridor Subsetting Algorithm
The CorridorSubsetter first assembles the trajectory waypoints provided in the request into a
series of route segments. The total length of the trajectory is then divided by the number of
requested sample points to get the delta of the sample points along the trajectory, or x, axis. This
delta is used to calculate the latitude, longitude, altitude, heading, and time for each sample point
along the corridor.
Next, the entire data volume that encompasses the given corridor spatially and temporally is read
into memory. Note that data chunking is not available for corridor requests.
Temporary arrays are defined for all dimensions and requested variables. The algorithm loops
through each sample point, determines the position of all sub-sample points within the requested
y and z extents for the corridor, and records the time, latitude, longitude, and altitude of each subsample point to the appropriate dimension array. Then, values for each requested field are read
from the data volume using nearest-neighbor interpolation.
Once all of the datapoint locations and field values have been found, these arrays are written to
the output file, along with any non-subsettable fields and dimensions that are present in the
dataset.
91
Figure 16. Corridor Subsetting Sequence
92
7 Publish/Subscribe MEP
The WCSRI supports real-time notifications through the implementation of the publish/subscribe
message exchange pattern (MEP). In the general sense, the WCSRI provides an endpoint for
un/subscribing, an endpoint for subscription management (e.g., renew), a mechanism for sending
notification messages to subscribers and a variety of components in support of this functionality.
The delivery of notifications is implemented via JMS queues, specifically ActiveMQ, exposing a
middleware as a business interface in order to reuse many of the connectivity facilities provided
by JMS. The decision to expose JMS to clients, directly, was mandated by an early FAA
requirement and hence, the WCSRI is implemented as such.
The usage of JMS queues by the WCSRI has the following implications:
●
●
●
●
●
Each subscription is meant for exactly one “subscriber”, though the conceptual
“subscriber” may consist of one to many consumers of messages from the notification
queue. In other words, only a single notification queue will exist per subscriber.
Each notification, or message, has only one consumer (i.e., the subscriber).
Each message is kept to a minimum size so as not to overload the AMQ broker. Hence,
the messages consist of notifications advertising the availability of data on the server, and
do not contain the actual gridded weather data. The notifications include enough
information to identify the new data, and it is the responsibility of the subscriber to request
the weather data, via getCoverage requests, when notified of availability.
The WCSRI and subscribers have no timing dependencies with respect to message
notifications. The subscriber can fetch message(s) intended for it whether or not it was
running when the WCSRI sent the message(s).
The subscriber acknowledges the successful processing of a message, which implies that
the consumer has successfully downloaded the appropriate weather data files (via
getCoverage). Once messages are acknowledged, they are scheduled for deletion.
7.1 Overview
The WCSRI’s publish/subscribe system is comprised of six significant components as follows:
Subscription Endpoint – This is the wcs.subscribe.httpEndpoint, implemented by the
SubscribeToNotifications class, which handles the Subscribe operation. This endpoint is
responsible for accepting subscription requests, providing responses containing subscription IDs
and notification connection endpoints for clients, and persisting this information to the database.
Subscription Management – Part of Subscription Management consists of the
wcs.mngSubscription.httpEndpoint. This endpoint is implemented by the
SubscriptionManagement class, which handles operations such as Renew and Unsubscribe.
Subscription Management also includes the handling of the initial handshake of client
connections, expired subscriptions, expired messages, and physical deletion of expired messages
93
after a holding period. It also manages abandoned subscriptions based on non-connectivity over a
period of time.
File Poller – A Camel component that periodically queries or polls coverage directories for the
arrival of new weather data files. When new files are found, the FilePoller sends query events to
the Transformation Multiplexer via a Camel route. The TransformationMultiplexer is responsible
for multiplexing a file event into one or more coverage JMS messages, since a weather data file
may map to one or more coverages. The TransformationMultiplexer also enqueues the JMS
messages to another JMS queue, whose messages are consumed by the Event Processors as
below.
Event Processor – A specific data transformer that receives events that reflect the arrival of some
new information in the system (e.g. new data for a specific coverage) and produces specific
events or messages for each interested subscriber. The Event Processor persists the subscriber’s
messages to the database, and delivers them if the subscriber is connected to the JMS Consumer
Temporary Queue (as below) or the next time that the subscriber connects.
JMS Consumer Temporary Queue - An exposed ActiveMQ temporary queue for the subscriber or
consumer, acting as an endpoint that is used to deliver notification messages. Note that the WS-N
specification has the notion that publishing servers should initiate connections to the subscriber in
order to deliver notifications. However, this approach has negative firewall implications, and
hence, the WCSRI implements this in reverse - the WCSRI will respond to a subscription request
with the AMQ broker’s connection URL so that the subscriber can initiate temporary queue
connections for receiving notifications. The client also uses this queue to acknowledge receipt of
the message.
Relational Database - This is the relational database used for persisting subscription and
message metadata for the publish/subscribe MEP. In many instances, the database is referred to
as the ‘Idempotent’ database.
The Figure 17below depicts the sequence of events that occur for subscribing and for connecting
to receive notifications.
94
Figure 17. Component Interaction
7.2 Pub/Sub Persistence – DAOs
The WCSRI uses a relational database for persisting subscription and message metadata for the
publish/subscribe MEP. The WCSRI implementation currently supports Oracle, PostgreSQL,
95
MySQL or Derby. However the WCSRI also is released with HSQLDB primarily intended for
validation purposes, and HSQLDB is not intended for operational use.
7.2.1 JPA
The WCSRI uses an implementation of the Java Persistence API (JPA) to store and retrieve
subscription-related information in a database that will persist between server restarts (the
WCSRI uses OpenJPA). JPA maps database entities (e.g. tables, columns) to Java objects (e.g.,
classes, properties). The WCSRI codebase can interact with these objects through accessor and
mutator method calls. JPA handles all read/write operations and ensures that the persistent data
store stays synchronized with the objects they are mapped to.
JPA allows portable queries to be written in the Java Persistence Query Language (JPQL), and
translates them into DBMS-specific queries using the configured JDBC driver and other JDBC
settings (see jdbc.* properties in wcsri.cfg). This allows a choice of back-end DBMS solutions
(such as MySQL or Oracle) to meet the needs of a particular WCSRI installation, without having
to modify any code.
JPA uses Java annotations to construct object mappings at compile time. For example, a
Message object corresponds to a table called 'message', with accessor and mutator methods for
several database fields, in the following code snippet:
/**
* The domain object pojo for the Message table.
*/
@Entity
@Table(name = "message")
public class Message {
@Column(name = "message_id")
private String messageId;
@Column(name = "payload")
private String payload;
@Column(name = "creation_time")
private Date creationTime;
…
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public String getPayload() {
return payload;
}
96
public void setPayload(String payload) {
this.payload = payload;
}
public Date getCreationTime() {
return creationTime;
}
public void setCreationTime(Date creationTime) {
this.creationTime = creationTime;
}
…
}
These objects are instantiated at runtime, and can be populated with data from the database,
inserted as a new row in a database table, used to create query filters, etc. The WCSRI classes
that are annotated for JPA are located in the pubsub/persistence module, within the
edu.ucar.ral.wcsri.pubsub.persistence.domain source code package. The WCSRI employs an
additional layer of Data Access Objects (DAOs) to instantiate and manipulate these objects
through various queries written in JPQL.
JPA classes are grouped together into a 'persistence unit' at compile time. This signals JPA to
look in these files to generate database mappings based on the annotations it finds. Each
persistence unit is assigned (by JPA) a factory-generated EntityManager object at runtime to
coordinate database access. The WCSRI DAOs use the EntityManager to provide the context for
performing queries and returning results.
Here is an XML snippet of a persistence unit definition, taken from the pubsub/persistence
bundle’s META-INF/persistence.xml file:
<persistence-unit name="wcsri-jpa" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>blueprint:comp/jta</jta-data-source>
<non-jta-data-source>osgi:service/javax.sql.DataSource/(transactional=false)
</non-jta-data-source>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.Subscription</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.DescCvgSubCoverage</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.DescCvgSubscription</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.GetCapsSubscription</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.GetCvgSubscription</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.Idempotent</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.Message</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.EventProducer</class>
<class>edu.ucar.ral.wcsri.pubsub.persistence.domain.VersionInfo</class>
….
</persistence-unit>
The pubsub/persistence bundle also contains the Blueprint specification (in OSGIINF.blueprint/pubsub-persist.xml) for the creation of the DAOs and makes them available for other
WCSRI bundles. Below is a Blueprint definition snippet linking a DAO to a persistence-unit:
<!-- Message -->
97
<bean id="messageDAO"
class="edu.ucar.ral.wcsri.pubsub.persistence.dao.jpa.MessageJPADAO">
<jpa:context property="entityManager" unitname="wcsri-jpa"/>
<tx:transaction method="*" value="Required"/>
</bean>
<!-- EventProducer -->
<bean id="eventProducerDAO"
class="edu.ucar.ral.wcsri.pubsub.persistence.dao.jpa.EventProducerJPADAO">
<jpa:context property="entityManager" unitname="wcsri-jpa"/>
<tx:transaction method="*" value="Required"/>
</bean>
….
<service ref="messageDAO"
interface="edu.ucar.ral.wcsri.pubsub.persistence.dao.MessageDAO">
<service-properties>
<entry key="tranAttribute" value="Required"/>
<entry key="version" value="1.1.0"/>
</service-properties>
</service>
<service ref="eventProducerDAO"
interface="edu.ucar.ral.wcsri.pubsub.persistence.dao.EventProducerDAO">
<service-properties>
<entry key="tranAttribute" value="Required"/>
<entry key="version" value="1.1.0"/>
</service-properties>
</service>
….
Notice that the above also contains a snippet showing the DAOs being made available as
“services” for being imported into other OSGI WCSRI bundles.
7.2.2 DAO Design
As above, the WCSRI uses Blueprint to instantiate the DAOs at startup. These DAOs contain
convenience methods for performing the various pub/sub operations, such as deleting messages
tied to an abandoned subscription, or getting a list of non-delivered messages to send to a
subscribed client who has recently reconnected. These methods use JPQL queries of varying
complexity to perform these operations using the JPA-instantiated object mappings.
Here is an example MessageDAO method, which returns a JPA message object:
public Message getMessageByMessageId(String messageId)
{
Query q = em.createQuery("select msg from Message msg where” +
“ msg.messageId = :messageId");
q.setParameter("messageId", messageId);
List list = q.getResultList();
if (list.size() == 0)
return null;
return (Message) list.iterator().next();
}
98
Note that the Message object and associated fields are referenced from within the supplied query
string. JPA translates this to a SQL query, using actual field names and syntax particulars related
to the underlying DBMS being used. The method caller is returned a Message object
corresponding to the supplied messageId, and can be examined or modified using any of its
accessor and mutator methods (e.g. getPayload(), setCreationTime(), etc.)
The following is a list of DAOs used by the WCSRI, and some of their useful public methods:
EventProducerDAO
EventProducer getProducerByname(String name);
IdempotentDAO
Idempotent getIdempotentByEventIdentifier(String eventIdentifier);
MessageDAO
List<Message> getNonDeliveredMessages(Subscription sub);
Message getMessageByMessageId(String messageId);
int bulkLogicalDeleteByExpiration(Subscription sub, Date deleteBefore, Date deletionDateTime);
int bulkLogicalDeleteBySubscription(Subscription sub, Date deletionDateTime);
int physicalDeleteBySubscription(Subscription sub);
int physicalDeleteByDeletionDate(Date deletionDate);
SubscriptionDAO
Subscription getSubscriptionByTempQueue(String tempQueue);
Subscription getSubscriptionByGuid(String guid);
deleteSubscriptionById(Long id);
List<DescCvgSubscription> findDescCvgSubscriptionMatches(String coverageId);
List<GetCvgSubscription> findGetCvgSubscriptionMatches( String coverageId,
Date genTime, Date validTime);
int bulkLogicalDeleteAbandonedSubscriptions(Date expireBeforeDate);
int physicalDeleteSubscriptions(Date deletionDateTime);
SubscriptionReaderDAO
Iterator<Message> getNonDeliveredMessages(Subscription sub);
Iterator<Message> getAckDeliveredMessages(Subscription sub, Date deleteTime);
Iterator<DescCvgSubCoverage> findDescCvgSubscriptionMatches(String coverageId);
Iterator<GetCvgSubscription> findGetCvgSubscriptionMatches(
String coverageId, Date genTime, Date validTime);
Iterator<Subscription> findActiveSubscriptions();
void reset();
public void close();
99
VersionInfoDAO
public VersionInfo read();
7.2.3 DDL and Database Schema
The tables below depict the relational database tables and column descriptions for the entities
required by the WCSRI and the WCSRI’s DAOs. Below the tables is an example of the DDL used
to create these entities against the MySQL database. At compile time, the pom.xml (in
pubsub/persistence) uses the maven-antrun-plugin during the generate-sources phase to
generate the DDL files for each supported database. The db.sql file (in
pubsub/persistence/src/db) is used as the template, and vendor-specific database constructs are
substituted as appropriate to generate the vendor-specific DDL file. Note that the DDL scripts that
result, one script for each supported database, are placed into the $WCSRI_HOME/doc/db
directory as part of each WCSRI release.
Subscription Meta Data Table
Description
Type
ID
Primary Key - Number
Subscriber ID (GUID)
String – GUID unique identifier that represents this
subscription
Payload
Character payload (for XML) of the initial request for
the subscription
Start Date/Time
Date – The time the subscription will begin
End Date/Time (Expiration)
Date – The time this subscription is set to expire.
User Name
String – The client user name credential that uniquely
identifies the client.
Subscription Type
String - Type identifier for subscriptions. Valid types
are GETCAPS, GETCVG, and DESCCVG
Temp Queue
String – The name of the currently active temporary
queue name that the client has open for the present
connection that is associated with this subscription
Creation Time
Creation Time
Date - Time the subscription was created
Last Connect Time
Date – Last time the subscription data was accessed
by the client.
Last Disconnect Time
Date – Last time the client disconnected from the
100
subscription queue.
Logical Delete Flag
Boolean - Signifies if record is deleted
Deletion Time
Date – The time the subscription was deleted
Get Caps Subscription Table
(One-to-One Relation to Subscription Table)
Description
Type
ID
Primary Key – Number – Should match the ID from
the Subscription table
Get Coverage Subscription Table
(One-to-One Relation to Subscription Table)
Description
Type
ID
Primary Key – Number – Should match the ID from
the Subscription table
Coverage ID
String – Coverage Identifier
Generation Time Minimum
Date – Minimum Generation Time
Generation Time Maximum
Date – Maximum Generation Time
Valid Time Minimum
Date – Minimum Valid Time
Valid Time Maximum
Date – Maximum Valid Time
Describe Coverage Subscription Table
(One-to-One Relation to Subscription Table)
Description
Type
ID
Primary Key – Number – Should match the ID from
the Subscription table
Describe Sub-Coverage Subscription Table
(Many-to-One Relation to Describe Coverage Subscription Table)
Description
Type
ID
Primary Key – Number
101
Describe Coverage Subscription ID
Number – Represents the foreign key to the parent
record Describe Coverage Subscription table
Coverage ID
String – Coverage Identifier
Message Meta Data Table
(Many To One With Subscription)
Description
Type
ID
Primary Key – Number
Subscription ID (foreign key to ID)
Number – Represents the foreign key to the parent
record of the Subscription table.
Message ID
String – Message Identifier
Payload
String – Contents of the message’s payload (XML)
Creation Time
Date – The time the message was created.
Logical Delete Flag
Signifies if record is deleted
Deletion Time
Date – The time the subscription was deleted
Event Producer Table
Description
Type
ID
Primary Key – Number
Event Producer Code
String – Unique identifier in human readable form for
the Event Producer record
Event Producer Description
String – Event producer description.
Idempotent Table
Description
Type
ID
Primary Key – Number
Event Producer ID (foreign key to
Event Producer)
String – Unique identifier in human readable form for
the Event Producer record
Event Identifier
String – Unique identifier (could be a hash of a file
name, or date/time, etc) that identifies the idempotent
event for a given Event Producer.
102
Creation Time
Date – The time the message was created.
Sequence Table
Description
Type
ID Name
Primary Key – String – Name of the table
ID Value
Number – The sequence number for generating
primary keys for tables.
Version Info Table
Description
Type
ID
Primary Key – Number
Minimum Version
Number – The minimum version that the WCSRI can
use with this schema
Maximum Version
Number – The Maximum version that the WCSRI can
use with this schema
DDL Example for MySQL
create table subscription (
id integer not null primary key,
guid varchar(64) not null,
payload longtext,
start_date timestamp not null,
end_date timestamp null default null,
username varchar(50) not null,
subscription_type varchar(10),
temp_queue varchar(128),
creation_time timestamp null default null,
last_connect_time timestamp null default null,
last_disconnect_time timestamp null default null,
deleted smallint not null,
deletion_time timestamp null default null
);
create unique index guid_subscription_idx on subscription( guid );
create index creation_time_subscription_idx on subscription( creation_time );
create index last_cnct_tm_subscription_idx on subscription( last_connect_time );
create index last_dcnct_tm_subscription_idx on subscription( last_disconnect_time );
create index deletion_time_subscription_idx on subscription( deletion_time );
create table get_caps_subscription (
id integer not null primary key
);
create table get_cvg_subscription (
103
id integer not null primary key,
coverage_id varchar(128) not null,
gen_time_min timestamp null default null,
gen_time_max timestamp null default null,
valid_time_min timestamp null default null,
valid_time_max timestamp null default null
);
create index coverage_id_getcvg_idx on get_cvg_subscription( coverage_id );
create index gen_time_min_getcvg_idx on get_cvg_subscription( gen_time_min );
create index gen_time_max_getcvg_idx on get_cvg_subscription( gen_time_max );
create index valid_time_min_getcvg_idx on get_cvg_subscription( valid_time_min );
create index valid_time_max_getcvg_idx on get_cvg_subscription( valid_time_max );
create table desc_cvg_subscription (
id integer not null primary key
);
create table desc_cvg_sub_coverage (
id integer not null primary key,
desc_cvg_subscription_id integer not null,
coverage_id varchar(128) not null,
foreign key ( desc_cvg_subscription_id ) references desc_cvg_subscription( id )
);
create index coverage_id_desccvgsub_idx on desc_cvg_sub_coverage( coverage_id );
create table message (
id integer not null primary key,
subscription_id integer not null,
message_id varchar(128),
payload longtext,
creation_time timestamp null default null,
deleted smallint not null,
deletion_time timestamp null default null,
foreign key ( subscription_id ) references subscription( id )
);
create unique index message_message_id_idx on message( message_id );
create index deletion_time_message_idx on message( deletion_time );
create table event_producer (
id integer not null primary key,
event_producer_code varchar(150) not null,
description varchar(512) not null
);
create unique index event_producer_epc_idx on event_producer( event_producer_code );
create table idempotent (
id integer not null primary key,
event_producer_id integer not null,
event_identifier varchar(512),
creation_time timestamp null default null,
foreign key ( event_producer_id ) references event_producer( id )
);
create unique index idempotent_evt_identifier_idx on idempotent( event_identifier );
create table seq_table (
id_name varchar(50) not null primary key,
id_value integer
);
-- There should only be one record in this table
create table version_info (
104
id integer not null primary key,
minversion double not null,
maxversion double not null
);
-- The versions below should match the compatible release versions
insert into version_info (id, minversion, maxversion) values (0, 1.00, 1.00);
insert into seq_table(id_name, id_value) values ('subscription', 100);
insert into seq_table(id_name, id_value) values ('message', 100);
insert into seq_table(id_name, id_value) values ('event_producer', 100);
insert into seq_table(id_name, id_value) values ('idempotent', 100);
insert into seq_table(id_name, id_value) values ('version', 100);
insert into seq_table(id_name, id_value) values ('desc_cvg_sub_coverage', 100);
7.2.4 IdempotentDAO
When multiple WCSRI nodes are used in a cluster, it is important to prevent multiple nodes from
performing identical transactions with respect to various operations. The database, sometimes
called the ‘idempotent’ database, is used for sharing information across nodes, and effectively
communicates to all nodes of a cluster that a particular task is/has been handled and requires no
further action. For example, each node in a WCSRI cluster will be polling for files in a particular
/staging directory, since the raw weather data input disk is shared across all the WCSRI nodes.
However, only one of them should perform the operations of moving the file to the 2012/...
directory, creating the messages for pertinent subscribers, persisting those messages and
delivering them. Hence, when an unprocessed file is found by a WCSRI node’s
DatasourcePollerConsumer, a global identifier for the file is added to the “idempotent” database
so that it can signal to the other WCSRI nodes that this particular file is being/has been handled
already. Other nodes who polled the same directory and found the same file after the first node
will then ignore the remaining operations since the file is being/has been processed. The
abstractions in the WCSRI codebase supporting idempotency are the Idempotent JPA class (in
the package edu.ucar.ral.wcsri.pubsub.persistence.domain), the IdempotentDAO, and the
DAOIdempotentRepository.
The DAOIdempotentRepository is a wrapper/helper class to handle concurrent management of
idempotent calls. Classes assigned to handle events, such as Camel processors, create an
Idempotent object and set several of its properties, including the unique identifier of the event:
Idempotent idempotent = new Idempotent();
idempotent.setPoller(eventProducer);
idempotent.setCreationTime(new Date());
idempotent.setEventIdentifier(destInfo.getDestination().getQualifiedName())
When handling an event, the event processor first checks if it can add the Idempotent object via
the DAOIdempotentRepository add() method:
if (idempotentRepository.add(idempotent)) { … }
105
This triggers the Repository to look for an Idempotent object in the persistent database with a
matching Event Identifier. If it finds one, it assumes the event is already being handled by another
node and returns false, bypassing further processing. If no matching Idempotent object is found, it
is added to the database and returns true, allowing event handling to continue. Once processing
has been completed, the Idempotent object is removed through a call to the remove() method of
the DAOIdempotentRepository.
7.3 Subscribe Request and Response
The pub/sub process begins with a consumer initiated SOAP request for a subscription containing
a SubscribeRequest. This request is issued against the WCSRI’s frontend endpoint which
ultimately is delegated to the wcs.subscribe.httpEndpoint. A basic subscription request follows the
schema for WS-Notification, and includes a WCS DescribeCoverage or GetCoverage request as
the Filter. A DescribeCoverage filter must be a valid DescribeCoverage request, and will
necessarily include the coverage ID of interest. A GetCoverage filter must be a valid GetCoverage
element, and necessarily includes the coverage ID and geospatial bounding box. The WSDL
operation that is used for the SubscribeRequest is:
<wsdl:message name="SubscribeRequest" >
<wsdl:part name="SubscribeRequest" element="wsnt:Subscribe"/>
</wsdl:message>
An example of a SubscribeRequest follows.
<ns2:Subscribe xmlns="http://www.w3.org/2005/08/addressing"
xmlns:ns2="http://docs.oasis-open.org/wsn/b-2"
xmlns:ns3="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns5="http://www.opengis.net/ows/1.1"
xmlns:ns6="http://www.opengis.net/wcs/1.1"
xmlns:ns7="http://www.w3.org/1999/xlink"
xmlns:ns8="http://www.opengis.net/gml"
xmlns:ns9="http://www.w3.org/2001/SMIL20/"
xmlns:ns10="http://wcsri.ral.ucar.edu/pubsub/subscription-service"
xmlns:ns11="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns12="http://docs.oasis-open.org/wsrf/r-2">
<ns2:ConsumerReference>
<Address>TO BE DETERMINED</Address>
</ns2:ConsumerReference>
<ns2:Filter>
<ns2:MessageContent Dialect="urn:def:ogc:wcs:1.1">
<ns6:GetCoverage service="WCS" version="1.1.2">
<ns5:Identifier>
urn:fdc:mdl-nextgen.nws.noaa.gov:Dataset:AFWA-CONUS-Prevailing-visibility
</ns5:Identifier>
<ns6:DomainSubset>
<ns5:BoundingBox crs="urn:ogc:def:crs:OGC:2:84" dimensions="2">
<ns5:LowerCorner>245.0 34.0</ns5:LowerCorner>
<ns5:UpperCorner>250.0 40.0</ns5:UpperCorner>
</ns5:BoundingBox>
<ns6:TemporalSubset>
106
<ns6:TimePeriod>
<ns6:BeginPosition>2012-08-29T06:00:00.000Z</ns6:BeginPosition>
<ns6:EndPosition>2022-12-12T21:24:50.282Z</ns6:EndPosition>
</ns6:TimePeriod>
</ns6:TemporalSubset>
</ns6:DomainSubset>
<ns6:RangeSubset/>
<ns6:Output format="application/netcdf4" store="false"/>
</ns6:GetCoverage>
</ns2:MessageContent>
</ns2:Filter>
</ns2:Subscribe>
The response message is a SubscribeResponse populated with a destination SOAP payload
containing a description of where the consumer can connect for the continuation of lifecycle
communications (i.e., notifications). In the case of failure, a SubscribeCreationFailedFault error is
returned.
<wsdl:message name="SubscribeResponse">
<wsdl:part name="SubscribeResponse" element="wsnt:SubscribeResponse"/>
</wsdl:message>
The SubscribeResponse has the following schema:
<xsd:element name="SubscribeResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="SubscriptionReference" type="wsa:EndpointReferenceType"/>
<xsd:element minOccurs="0" ref="wsnt:CurrentTime"/>
<xsd:element minOccurs="0" ref="wsnt:TerminationTime"/>
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other"
processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
The SubscribeResponse will be populated with a SubscriptionReference. This is a globally unique
ID (GUID) and is a correlation key used in further communications, and is also the name of the
subscriber’s temporary queue. This key is also stored in the subscription engine database
providing for a persistent subscription across restarts or possible system problems. A timestamp
for the transaction as well as a confirmation of the expected subscription termination time is
added to the response object as well as a destination JMS queue and connection descriptor. The
consumer then is responsible for connecting to the JMS broker, establishing a connection to the
appropriate queue and awaiting further communications.
An example SubscribeResponse follows:
<ns7:SubscribeResponse
xmlns:ns24="http://www.w3.org/2001/SMIL20/Language"
xmlns:ns23="http://docs.oasis-open.org/wsrf/r-2"
xmlns:ns22="http://www.wcs.opengis.net/wsdl"
xmlns:ns21="http://www.java/lang" xmlns:ns20="http://www.isotc211.org/2005/gts"
xmlns:ns19="http://www.isotc211.org/2005/srv"
107
xmlns:ns18="http://www.isotc211.org/2005/gmx"
xmlns:ns17="http://www.isotc211.org/2005/gco"
xmlns:ns16="http://www.isotc211.org/2005/gmd"
xmlns:ns15="http://www.opengis.net/gml/3.2"
xmlns:ns14="http://wcsri.ral.ucar.edu/owsExtension"
xmlns:ns13="http://www.w3.org/2001/SMIL20/"
xmlns:ns12="http://www.w3.org/1999/xlink"
xmlns:ns11="http://www.opengis.net/wcs/1.1"
xmlns:ns10="http://www.opengis.net/gml"
xmlns:ns9="http://www.opengis.net/ows/1.1"
xmlns:ns8="http://wcsri.ral.ucar.edu/iso19139"
xmlns:ns7="http://docs.oasis-open.org/wsn/b-2"
xmlns:ns6="http://www.w3.org/2005/08/addressing"
xmlns:ns5="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:ns4="http://docs.oasis-open.org/wsn/t-1"
xmlns:ns3="http://wcsri.ral.ucar.edu/pubsub/subscription-service">
<ns7:CurrentTime>2012-12-14T21:50:40.406Z</ns7:CurrentTime>
<ns7:TerminationTime
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
<ns3:SubscriptionReference>
<ns3:subscriptionGUID>
7ea0cede-9df6-401e-85b0-36a367056dae
</ns3:subscriptionGUID>
<ns3:subscriptionURI>
jms:http://wcsri.ral.ucar.edu:16200/tempQueue/pubsub.handshake
</ns3:subscriptionURI>
<ns3:userID>ANONYMOUS</ns3:userID>
</ns3:SubscriptionReference>
</ns7:SubscribeResponse>
108
Figure 18. Subscribe Operation Sequence
7.4 File Polling and Notification Messages
On WCSRI startup, the datasource-poller bundle uses Blueprint to initialize the objects and Camel
routes used to poll for new data. The file OSGI-INF.blueprint/datasource-poller.xml in the
pubsub/datasource-poller module contains this Blueprint specification. This includes the
functionality for polling for new files arriving on the local filesystem in each
DirectoryBasedDataSource's /staging directory.
Blueprint instantiates a DatasourcePollerActivator object as follows:
<bean id="datasourcePoller"
class="edu.ucar.ral.wcsri.pubsub.datasource.poller.internal.DatasourcePollerActivator" init-method="init">
<property name="camelContext" ref="datasourceContext"/>
<property name="idempotentDAO" ref="idempotentDAO"/>
<property name="dataSourceManager" ref="dataSourceMgrOsgi"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
<property name="transformerInformationService" ref="transformerInformationService"/>
<property name="allowReprocessing" value="${datasource-poller.reprocess}"/>
<property name="allowOverwrite" value="${datasource-poller.overwrite}"/>
<property name="idempotentFilesPath" value="${datasource-poller.idempotentDir}"/>
<property name="delayNextPoll" value="${datasource-poller.delayNextPoll}"/>
<property name="useFixedDelay" value="${datasource-poller.useFixedDelay}"/>
<property name="initialDelay" value="${datasource-poller.initDelay}"/>
109
</bean>
In the DatasourcePollerActivator’s init(...) method, as shown in Figure 19, it obtains a list of
DirectoryBasedDataSource objects from the DatasourceManager, and defines a Camel route for
each that polls for new files arriving in the DataSource's /staging directory. When new raw
weather data files arrive, they are moved into the DataSource’s /2013/... directory structure (as
described in the Installation Instructions document), and then notification events are produced and
routed to one or more TransformationMultiplexers (and then Event Processors), which notify
subscribed clients that new data is available.
110
Figure 19. DatasourcePollerActivator's init() method
111
7.4.1 DatasourcePollers
The DatasourcePollerActivator’s init(...) method sets up a Camel route for each DataSource,
wiring a DatasourcePollerEndpoint with a DatasourcePollerConsumer (i.e. an Event Producer) to
a TransformationMultiplexer (i.e. an Event Transformer). Snippets for the code that creates the
Camel route and onCompletion processor is shown below:
RouteDefinition route = new RouteDefinition();
String staging = ds.getConfig().getStagingDirectory();
// The file polling camel route.
route.from("datasource://" + staging + "?exclude=.*tmp&recursive=true&idempotent=true&initialDelay=" + …);
List destinations = Arrays.asList(transformerInformationService.getTransformers().values().toArray());
TransformationMultiplexer mp =
new TransformationMultiplexer(camelContext, ds.getConfig().getOfferedCoverages(), destinations);
route.onCompletion().bean(mp);
The DatasourcePollerConsumer extends the Camel GenericFileConsumer and
ScheduledPollConsumer classes, which poll the DataSource's /staging directory at regular
intervals for new files, using the DatasourcePollerConsumer’s pollDirectory() method - Figure 20.
This method checks the idempotent database for each new file that it finds, to make sure the file
is not already being handled by another WCSRI node, and returns a list of files that are ready to
be processed.
For each file to be processed, the GenericFileConsumer creates a Camel Exchange object using
the DatasourcePollerEndpoint's createExchange() method. This method wraps the incoming file in
a CoverageFile object and binds it to the Exchange. This binding involves setting the Exchange's
incoming message (exchange.setIn()) to a new Message object containing information reflecting
the file's valid and generation times (parsed from the filename), current file path (in /staging), and
destination file path (the dated directory structure where the file will be moved to, e.g.
2012/20121217/v_170000/)
Each Exchange thus created is processed by the DatasourcePollerConsumer's
processExchange() method, which passes the Exchange on to the TransformationMultiplexer in
order to create subscriber notifications. In addition, processExchange() calls the Exchange's
addOnCompletion() method, passing in a PollerOnCompletion object to move the file to its final
destination once notification processing is completed.
112
Figure 20. Polling for Files Sequence Diagram
113
7.4.2 TransformationMultiplexers
The TransformationMultiplexer object, which was instantiated by the DatasourcePollerActivator’s
init(...) method on WCSRI startup (one for each DataSource), processes the incoming Exchange
by creating a cloned Exchange for each coverage contained in the incoming data file since a
single weather file can contain multiple coverages. Each of those Exchanges are then dispatched
to one or more destinations as defined in the wcsri.cfg’s submgt.transformer.list property:
submgt.transformer.list=DESCRIPTION COVERAGE|jms:pubsub.xformer.DescribeCoverage,GET COVERAGE|jms:pubsub.xfo
rmer.GetCoverage
This process is known as multiplexing. These destinations are Event Processors that produce
requested notifications for their active subscribers (if any). The current WCSRI defines two
destinations for this purpose: DescribeCoverage and GetCoverage, which specify two transformer
destination classes DescribeCoverageProcessor and GetCoverageProcessor respectively (both
implementations of the Camel Processor interface). The TransformationMultiplexer creates an
instance of each transformer destination (as above) and passes it the cloned Exchange(s) for
further processing.
7.4.3 Event Processors
The Event Processors transform file discovery events into notification messages that are
delivered to subscribers via JMS. The two processors that match the above destinations are the
DescribeCoverageProcessor and GetCoverageProcessor classes found in the pubsub/eventtransformers/describe-coverage and /get-coverage Maven modules respectively. The Blueprint
specifications for the processors are as follows:
OSGI-INF.blueprint/describe-coverage.xml
<camelContext xmlns="http://camel.apache.org/schema/blueprint" id="describeCoverage">
<route>
<from uri="jms:queue:pubsub.xformer.DescribeCoverage"/>
<transacted/>
<to uri="describeCoverageProcessor"/>
</route>
</camelContext>
<!-- DescribeCoverageProcessor -->
<bean id="describeCoverageProcessor" class="edu.ucar.ral.wcsri.pubsub.descrcvg.DescribeCoverageProcessor">
<property name="messageDAO" ref="messageDAO"/>
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="streamingFactory" ref="streamingFactory"/>
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="describeCoveragePayload" ref="describeCoveragePayload"/>
</bean>
OSGI-INF.blueprint/get-coverage.xml
<camelContext xmlns="http://camel.apache.org/schema/blueprint" id="getCoverage">
<route>
114
<from uri="jms:queue:pubsub.xformer.GetCoverage"/>
<transacted/>
<to uri="getCoverageProcessor"/>
</route>
</camelContext>
<!-- GetCoverageProcessor -->
<bean id="getCoverageProcessor" class="edu.ucar.ral.wcsri.pubsub.getcvg.GetCoverageProcessor">
<property name="messageDAO" ref="messageDAO"/>
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="streamingFactory" ref="streamingFactory"/>
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="getCoveragePayload" ref="getCoveragePayload"/>
</bean>
Note that the Processors handle Exchange(s) routed from the DataSource's
TransformationMultiplexer object, and do so since the TransformationMultiplexer’s destinations
match the Processor’s “from” property of the Camel route they are processing.
Each Processor, after validating the input message, uses the SubscriptionReaderDAO to find
subscriptions matching the coverage identifier and gen/valid times of the incoming Exchange. For
each matching subscription, a notification message is created and enqueued on the subscription's
JMS temporary queue, using the injected JmsTemplate object (defined in the Blueprint XML files
described above).The message is also saved to the persistence database in case the message
cannot be immediately delivered (e.g. the client is not currently connected).
7.4.4 Notification Messages and Payloads
The notification messages are created by the process(...) methods of the GetCoverageProcessor
and DescribeCoverageProcessor. The messages contain the subscription ID and the creation
time of the message. They also contain an XML payload which contains the coverage ID, valid
time, and generation time of the arriving data. The processor constructs the XML payload by
calling the getPayload() method of its Blueprint-injected helper payload object (either a
GetCoveragePayload or DescribeCoveragePayload). Note that the helper is poorly named since it
does not actually represent an XML payload instance, but is simply able to construct one using a
JAXB context (i.e., WcsriJaxbEngine) and un/marshalling. The getPayload(...) methods create a
JAXB CoverageDescriptions object and populates it with the coverage ID, valid time, and
generation time of the arriving data. The CoverageDescriptions object is then marshalled to XML
and returned to the Processor’s process(...) method. The process(...) method then sends the XML
as the payload for messages to all matching subscriptions.
It is important to note that the notification messages DO NOT contain any data – it is the
responsibility of the subscribed client to obtain the data described by the notification message via
the normal GetCoverage request/response mechanism of the WCSRI.
Here is an example notification message payload:
<wcs:CoverageDescriptions xmlns:wcs="http://www.opengis.net/wcs/1.1"
xmlns:ows="http://www.opengis.net/ows/1.1">
115
<wcs:CoverageDescription>
<wcs:Identifier>urn:fdc:ncar.ucar.edu:Dataset:RUC-20P_grb2_Wind</wcs:Identifier>
<wcs:Domain>
<wcs:TemporalDomain>
<wcs:TimePeriod>
<wcs:BeginPosition>2012-01-22T03:00:00.000Z</wcs:BeginPosition>
<wcs:EndPosition>2012-01-22T03:00:00.000Z</wcs:EndPosition>
<wcs:TimeResolution>PT1H</wcs:TimeResolution>
</wcs:TimePeriod>
</wcs:TemporalDomain>
</wcs:Domain>
</wcs:CoverageDescription>
</wcs:CoverageDescriptions>
7.5 Receiving Notifications
7.5.1 Connecting to the AMQ Temporary Queue - Overview
Once a subscription has been requested and a successful subscription response has been
received, it is up to the client to initiate the connection to the AMQ broker to start receiving
notifications. An example of the original subscription response (omitting namespace declarations)
is shown below duplicated from Section 7.3:
<ns7:SubscribeResponse ...>
<ns7:CurrentTime>2012-12-14T21:50:40.406Z</ns7:CurrentTime>
<ns7:TerminationTime
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
<ns3:SubscriptionReference>
<ns3:subscriptionGUID>
7ea0cede-9df6-401e-85b0-36a367056dae
</ns3:subscriptionGUID>
<ns3:subscriptionURI>
jms:http://wcsri.ral.ucar.edu:16200/tempQueue/pubsub.handshake
</ns3:subscriptionURI>
<ns3:userID>ANONYMOUS</ns3:userID>
</ns3:SubscriptionReference>
</ns7:SubscribeResponse>
7.5.2 Handshake Queue (pubsub.handshake)
The process begins with the client establishing a TemporaryQueue on the AMQ broker advertised
in the subscriptionURI of the original SubscribeResponse (e.g., in the example above,
http://wcsri.ral.ucar.edu:16200/tempQueue/). The client must then tell the WCSRI server where and how it is
connected, and does so by delivering a “handshake” message to the advertised
pubsub.handshake queue on the JMS AMQ broker (e.g., in the example above,
http://wcsri.ral.ucar.edu:16200/tempQueue/pubsub.handshake). The handshake message is created using JMS
API calls with the temporary queue name as the location where the JMS should send the
handshake reply - this is done by setting the JMSReplyTo header on the message. In addition,
credential header information is set if security is enabled as well as the subscription GUID
(globally unique ID) header for server-side authentication. This handshake message is then
delivered to the JMS handshake queue. The client then registers itself as a listener for incoming
116
messages on the temporary queue, and waits for messages to arrive from the JMS. If the server
successfully validates the handshake request using the HandshakeProcessor (as below), the
HandshakeProcessor will send a single handshake response message to the client’s temporary
queue. Thereafter, file event notification messages will be sent to the temporary queue as
appropriate. The following shows a client-side example, from the WxConsumer’s
AMQSubscriptionClient’s connect(...) method, illustrating a client establishing a TemporaryQueue
and including it as part of the initial handshake:
// create a JMS producer for the handshake queue and a temporary
// queue destination
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionURL);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE);
Destination handshakeQueue = session.createQueue(handshakeQueueName);
MessageProducer producer = session.createProducer(handshakeQueue);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TemporaryQueue tq = session.createTemporaryQueue();
Message message = session.createMessage();
message.setJMSReplyTo(tq);
message.setStringProperty("subscription.guid", subscriptionGUID);
MessageConsumer subscriptionConsumer = session.createConsumer(tq);
subscriptionConsumer.setMessageListener(this);
// send the handshake message
producer.send(message);
setConnected(true);
7.5.2.1 HandshakeProcessor
The server-side HandshakeProcessor comes from the Blueprint specification, shown below, from
the pubsub/subscription-management bundle’s OSGI-INF.blueprint/subscription-management.xml
file. The HandshakeProcessor is part of a Camel route that handles the initial handshake
connection from a client connecting to receive events. The HandshakeProcessor’s process(...)
method handles authentication (if security is enabled) and registers the client's temporary queue
connection and creation time with the Subscription database. The success or failure of the
handshake is then returned to the client's temporary queue as the first message. If the handshake
is successful, the HandshakeProcessor will also query the SubscriptionReaderDAO for any
outstanding messages intended for the subscriber and deliver them.
<!-- Handles the handshake -->
<route>
<from uri="jms:queue:pubsub.handshake"/>
<transacted/>
<to uri="handshakeProcessor"/>
</route>
117
<bean id="handshakeProcessor"
class="edu.ucar.ral.wcsri.pubsub.sm.hidden.HandshakeProcessor">
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="messageDAO" ref="messageDAO"/>
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="securityEnabled" value="${wcs.securityEnabled}"/>
<property name="securityRealm" value="${wcs.securityRealm}"/>
<property name="authenticationService" ref="jaasAuthenticationService"/>
<property name="streamingFactory" ref="streamingFactory"/>
<tx:transaction method="process*" value="Required"/>
</bean>
7.5.3 Listening for Notifications
Messages or notifications can then be received, asynchronously, on the client by implementing
the javax.jms.MessageListener interface and registering as a MessageListener on the
MessageConsumer as in the example above. The snippet below shows an implementation of the
MessageListener’s onMessage(...) method taken from the WxConsumer’s AMQSubscriptionClient
class. Note that the client listens for incoming messages on the TemporaryQueue created during
the initial handshake process, as well as for any subsequent notifications (provided the
handshake was successful).
/**
* Callback method called when notification or handshake message is received
*
* @param message subscription notification message
*/
public void onMessage(Message message) {
if (message.propertyExists("message.type")) {
String messageType = message.getStringProperty("message.type");
if (message instanceof TextMessage && messageType != null &&
messageType.equals("PAYLOAD_EVENT")) {
TextMessage notification = (TextMessage) message;
String notificationPayload = notification.getText();
// acknowledge the message back to the broker
message.acknowledge();
} else if (messageType != null && messageType.equals("HANDSHAKE")) {
int code = message.getIntProperty("handshake.return.code");
// check the code for handshake failures
if (code != 0) {
setConnected(false); // handshake was unsuccessful
}
}
}
7.5.4 AckProcessor
The server-side AckProcessor is a Camel processor that handles message acknowledgments by
listening on JMS Advisory topics for temporary queue consumption. It then maps the originating
message id with the existing database record and flags it for deletion. The AckProcessor is
defined in the pubsub/subscription-management bundle’s Blueprint specification as defined in the
file OSGI-INF.blueprint/subscription-management.xml, shown below,
<!-- Handles the ack messages -->
118
<route>
<from uri="jms:topic:ActiveMQ.Advisory.MessageConsumed.TempQueue.>"/>
<transacted/>
<to uri="ackProcessor"/>
</route>
<bean id="ackProcessor" class="edu.ucar.ral.wcsri.pubsub.sm.hidden.AckProcessor">
<property name="messageDAO" ref="messageDAO"/>
<property name="eventProducerId" value="AckProcessor"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
<property name="idempotentRepository" ref="idempotentRepository"/>
<property name="streamingFactory" ref="streamingFactory"/>
<tx:transaction method="process*" value="Required"/>
</bean>
7.5.5 ConnectionProcessor
The server-side ConnectionProcessor handles updating the Subscription with a last disconnection
time when the client disconnects from ActiveMQ. It is determined by receiving the Advisory Topic
for disconnects on temporary queues. The processor attempts to match the queue to the
subscription and sets the last disconnect time. The ConnectionProcessor is defined in the
pubsub/subscription-management bundle’s OSGI-INF.blueprint/subscription-management.xml
Blueprint file as below:
<!-- Handles the queue access/disconnect messages -->
<route>
<from uri="jms:topic:ActiveMQ.Advisory.TempQueue"/>
<transacted/>
<to uri="connectionProcessor"/>
</route>
<bean id="connectionProcessor"
class="edu.ucar.ral.wcsri.pubsub.sm.hidden.ConnectionProcessor">
<property name="messageDAO" ref="messageDAO"/>
<property name="streamingFactory" ref="streamingFactory"/>
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="eventProducerId" value="ConnectionProcessor"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
<property name="idempotentRepository" ref="idempotentRepository"/>
<tx:transaction method="process*" value="Required"/>
</bean>
7.5.6 CleanupProcessor
The server-side CleanupProcessor is triggered by a Quartz Scheduler, which awakens every 5
minutes to clean up the database by identifying abandoned subscriptions and flagging them for
logical deletes, and also by deleting Subscriptions and Messages in the database that have been
flagged and are ready for physical deletion after a specified amount of time. CleanupProcessor in
the pubsub/subscription-management bundle’s OSGI-INF.blueprint/subscription-management.xml
Blueprint file is defined as follows:
<!-- Handles the cleanup of the subscription meta data -->
<route>
<!-- Fire quartz every 5 minutes -->
119
<from uri="timer://foo?fixedRate=true&period=600000&delay=30000"/>
<to uri="cleanupProcessor"/>
</route>
<bean id="cleanupProcessor" class="edu.ucar.ral.wcsri.pubsub.sm.hidden.CleanupProcessor"
depends-on="eventProducerDAO">
<property name="abandonedDays" value="${submgt.abandoned.days}"/>
<property name="deletedHoldDays" value="${submgt.deleted.hold.days}"/>
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="messageDAO" ref="messageDAO"/>
<property name="eventProducerId" value="CleanupProcessor"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
<property name="idempotentRepository" ref="idempotentRepository"/>
<tx:transaction method="process*" value="Required"/>
</bean>
7.5.7 TempQueueCleanupProcessor
The TempQueueCleanupProcessor is triggered by a Quartz Scheduler, which awakens every 5
minutes to clean up the database subscriptions by determining non-existing temporary queues
attached to subscriptions. This scenario occurs when clients inadvertently disconnect after
establishing a temporary queue connection. The Blueprint for the TempQueueCleanupProcessor,
as below, is found in the OSGI-INF.blueprint/subscription-management.xml file:
<!-- Handles the cleanup of the subscription/tempQueue meta data -->
<route>
<!-- Fire timer every 3 minutes -->
<from uri="timer://jmxCleanup?fixedRate=true&period=300000&delay=30000"/>
<to uri="tempQueueCleanupProcessor"/>
</route>
<bean id="tempQueueCleanupProcessor"
class="edu.ucar.ral.wcsri.pubsub.sm.hidden.TempQueueCleanupProcessor"
depends-on="eventProducerDAO">
<property name="subscriptionDAO" ref="subscriptionDAO"/>
<property name="streamingFactory" ref="streamingFactory"/>
<property name="eventProducerId" value="TempQueueCleanupProcessor"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
<property name="idempotentRepository" ref="idempotentRepository"/>
<property name="jmxUtil" ref="jmxUtil"/>
<tx:transaction method="process*" value="Required"/>
</bean>
7.6 Subscription Management
Subscriptions are watched via the Subscription Manager service, which cleans up
abandoned/expired messages and subscriptions. The advisory messages sent to the Subscription
manager updates subscription meta-data to save the last connect/disconnect time when the client
initiated the handshake (connection) or when the client disconnected from ActiveMQ. The
Subscription Manager periodically analyzes the last connection time with each active subscription
to determine abandoned subscriptions and to clean up queues.
120
7.6.1 Unsubscribe
This service is a simple soap call service that adheres to the WS-N specification. The calling
sequence shown in the figure below requires a subscription id (GUID) and credentials to
unsubscribe. This is implemented as a SOAP endpoint and call in the Subscription engine, which
updates the database meta-data record and clears any pending messages that are due to be sent
to the consumer. The destruction of the queue is done by notifying the JMS queue manager.
To unsubscribe, the consumer needs to pass in a String containing the subscription id. The
consumer is then removed from the persisting mechanism. A reply is passed back with the
following schema:
<complexType>
<complexContent>
<restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
<sequence>
<any processContents='lax' namespace='##other'
maxOccurs="unbounded" minOccurs="0"/>
</sequence>
</restriction>
</complexContent>
</complexType>
This operation is essentially assumed to be correct and valid unless a server error occurs. In
which case the following UnableToDestroySubscriptionFaultType is returned:
<complexType name="UnableToDestroySubscriptionFaultType">
<complexContent>
<extension base="{http://docs.oasis-open.org/wsrf/bf-2}BaseFaultType">
<anyAttribute processContents='lax' namespace='##other'/>
</extension>
</complexContent>
</complexType>
This fault indicates that the client is still subscribed. This is to be considered a rather severe
critical condition and should be supplemented with logging and potentially notifications to
monitoring and security systems as the implications would be that an subscribed systems
persistence layer is in a state that leads to non-operable conditions. This fault can occur if the
SubscriptionID (GUID) do not match the subscription meta-data found in the database.
121
Figure 21. Unsubscribe Operation Sequence Diagram
7.6.2 Renew
Consumers also need to be able to renew their subscriptions. The request used for this function
has the following schema:
<complexType>
<complexContent>
<restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
<sequence>
<element name="TerminationTime"
type="{http://docs.oasis-open.org/wsn/b-2}AbsoluteOrRelativeTimeType"/>
<any processContents='lax' namespace='##other' maxOccurs="unbounded"
minOccurs="0"/>
</sequence>
</restriction>
</complexContent>
</complexType>
It is a request met with a simple response containing the update notification and if necessary a
newly created queue for the consumer.
122
Figure 22. Renew Operation Sequence Diagram
7.6.3 Pause / Resume
The pause/resume operations, although part of the WS-N specification, are not implemented in
the WCSRI. These operations are not particularly useful for real-time scenarios as envisioned by
CSS-Wx, and support for these features introduces significant implementation complexity that is
not judged to be worth the cost.
8 Repeaters
8.1 Overview
Repeaters are a concept used for the flexible distribution architecture supported by the WCSRI.
Repeaters allow WCSRI nodes to be set up in a layered topology where origin WCSRI nodes
provide data for downstream distribution WCSRI nodes. This allows distribution nodes to act as
data sources, thereby fanning-out weather data providers and client load according to usage
requirements on the topology or concrete architecture.
123
Per the installation documentation, Repeaters are specified by using a <RepeaterConfig> element
within coveragesConfig.xml files, and specifying a DataSource of type “Repeater”. The following is
an example of a coveragesConfig.xml file containing a Repeater specification:
<?xml version="1.0" encoding="UTF-8"?>
<DataSource type="Repeater" fileExtension="nc">
<RepeaterConfig>
<OriginServerWcsEndpoint>http://collision.rap.ucar.edu:8280/wcs</OriginServerWcsEndpoint>
</RepeaterConfig>
<ValidTimesType type="TimeList"/>
<Janitor enabled="true">
<ScrubFrequency cronPattern="0 0 2 ? * *"/>
<KeepTime duration="-P5D"/>
</Janitor>
<!-- You may list multiple Coverage elements if multiple coverages come from the same data files. -->
<Coverage>
<Id>urn:fdc:ncar.ucar.edu:Dataset:FLTCAT</Id>
<CoverageMetadataFile name="coverageMeta1.xml"/>
<Field name="Flight_Category" id="urn:fdc:ncar.ucar.edu:Field:Flight_Category"/>
</Coverage>
<Coverage>
<Id>urn:fdc:ncar.ucar.edu:Dataset:CEIL</Id>
<CoverageMetadataFile name="coverageMetaCeil.xml"/>
<Field name="Geometric_height" id="urn:fdc:ncar.ucar.edu:Field:Geometric_height"/>
</Coverage>
</DataSource>
In the general sense, a Repeater will subscribe upstream for one or more coverages, and retrieve
and store the weather data, via getCoverage requests, when notified of availability. Each
Repeater DataSource can repeat one or more coverages, as specified above by <Coverage>
elements. However, only a single OriginServerWcsEndpoint can be used for a RepeaterConfig,
which implies that the coverages specified as <Coverage> elements must all be available from
the single upstream endpoint. On startup of the downstream WCSRI, a Repeater will issue a
describeCoverage to the upstream endpoint, for each repeated coverage, in order to cache
metadata about the coverage(s). The metadata includes information such as the geospatial
bounding box (X, Y and possibly Z) of the data. The Repeater will then subscribe upstream for
each coverage, and if successful, will connect to the upstream AMQ broker to listen for
notifications. Upon notification of data availability, the Repeater will issue a getCoverage request
upstream with a bounding box and the appropriate fields to retrieve the weather data. The
resulting NetCDF-4 file will then be available as raw weather data to be served from the
downstream distribution WCSRI node as part of the coverage specified. The downstream raw
data files will contain data for the fields specified in the XML above and bounding box, either
specified in the XML coveragesConfig.xml file or retrieved from describeCoverage.
124
8.2 Repeater Implementation
8.2.1 DataSourceConfigurator
When the WCSRI starts up, the DataSourceConfigurator object will be created from the gds-pojoservice bundle’s Blueprint specification. The DataSourceConfigurator is configured with the
wcs.rootDataDir, and within its getCoverageConfigFiles(...) method, it will recurse downwards
looking for coveragesConfig.xml files. For each file found, the configCoverages(...) method is
called, and ultimately createDatasetDataSources(...) to create the DataSources. If a Repeatertype DataSource is specified in a coveragesConfig.xml file, the method
parseAndCreateDataSourcesForRepeater(...) will be called to create a directory and a
DirectoryBasedDataSource for each coverage specified as part of the Repeater’s DataSource.
This is significant because each coverage will then be treated as a local file-system data source,
with its own child directory (e.g., “coverage1”) under the Repeater’s root directory, to serve up its
raw weather data files just like any other local DirectoryBasedDataSource. When the method
parseAndCreateDataSourcesForRepeater(...) returns, a RepeaterConfig object, a child staging
directory (e.g., coverage1/staging) and a child temporary directory (e.g., coverage1/tmp) will be
created for each repeated coverage. The RepeaterConfig object will be used later by the
CoverageRepeaterActivator to subscribe upstream for each coverage. In addition, the staging and
temporary directories become available for the GetCoverageNotificationListener as the target
directories for the independent process of retrieving the weather data files from the origin server.
An example of the directory structure created for the Repeater as defined in the XML example
above is shown here:
wcsRootDataDir/
servicesMeta.xml
repeaterExampleDir/
coveragesConfig.xml
coverageMeta1.xml
coverageMetaCeil.xml
coverage1/
staging/
tmp/
coverage2/
staging/
tmp/
8.2.2 CoverageRepeaterActivator
The CoverageRepeaterActivator is created by the coverageRepeater.xml Blueprint file in the
coverage-repeater bundle, as shown below, with an id of “coverageRepeaterManager”. The
CoverageRepeaterActivator’s init(...) method uses the RepeaterConfig objects from the
DataSourceManager to create and initialize the Repeaters for a downstream WCSRI node.
<bean id="subscribePortTypeMngr" class="edu.ucar.ral.wxcube.consumer.wcs.SubscribePortTypeMngr">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableLogging" value="true"/>
<property name="installCert" value="${coverage-repeater.installCert}"/>
<property name="disableCNCheck" value="${coverage-repeater.disableCNCheck}"/>
125
<property name="trustFilePath" value="${coverage-repeater.truststoreFile}"/>
<property name="keyFilePath" value="${coverage-repeater.keystoreFile}"/>
</bean>
<bean id="subscriptionMngrPortTypeManager"
class="edu.ucar.ral.wxcube.consumer.wcs.SubscriptionMngrPortTypeManager">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableLogging" value="true"/>
<property name="installCert" value="${coverage-repeater.installCert}"/>
<property name="disableCNCheck" value="${coverage-repeater.disableCNCheck}"/>
<property name="trustFilePath" value="${coverage-repeater.truststoreFile}"/>
<property name="keyFilePath" value="${coverage-repeater.keystoreFile}"/>
</bean>
<bean id="wsPortTypeManager" class="edu.ucar.ral.wxcube.consumer.wcs.WcsSwaPortTypeManager">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableOutLogging" value="${webServicesRequestLogEnabled}"/>
<property name="enableInLogging" value="${webServicesResponseLogEnabled}"/>
<property name="installCert" value="${coverage-repeater.installCert}"/>
<property name="disableCNCheck" value="${coverage-repeater.disableCNCheck}"/>
<property name="trustFilePath" value="${coverage-repeater.truststoreFile}"/>
<property name="keyFilePath" value="${coverage-repeater.keystoreFile}"/>
</bean>
<!-- jaxb builder that allows to build getCVg without a bbox constraint -->
<bean id="getCvgJaxbBuilder"
class="edu.ucar.ral.wcsri.util.wcs112.jaxb.GetCoverageJaxbBuilder">
<property name="requireBboxConstraint" value="false"/>
</bean>
<bean id="pubSubWcsClient" class="edu.ucar.ral.wxcube.consumer.wcs.PubSubWcsClientImpl">
<property name="cvgJaxbBuilder" ref="getCvgJaxbBuilder"/>
<property name="subscribeManager" ref="subscribePortTypeMngr"/>
<property name="subscriptionMngrManager" ref="subscriptionMngrPortTypeManager"/>
<property name="passwordCallback" ref="passwordCallback"/>
<property name="messagecontentDialect" value="${coverage-repeater.messageContentDialect}"/>
<property name="numConsumers" value="${coverage-repeater.numConsumers}"/>
</bean>
<bean id="reqReplyWcsClient" class="edu.ucar.ral.wxcube.consumer.wcs.ReqReplyWcsSwaClientImpl">
<property name="portTypeMgr" ref="wsPortTypeManager"/>
</bean>
<!-- configuration for cvg listenrs to use in repeaters -->
<bean id="getCvgNotifListConfig" class="edu.ucar.ral.wxcube.consumer.wcs.GetCvgNotifListConfig">
<property name="reprocessingPeriod" value="${coverage-repeater.listener.reprocessingPeriod}"/>
<property name="maxRetryTimes" value="${coverage-repeater.listener.maxRetryTimes}"/>
<property name="persistPeriod" value="${coverage-repeater.listener.persistPeriod}"/>
</bean>
<bean id="coverageRepeaterManager"
class="edu.ucar.ral.wcsri.pubsub.coverage.repeater.internal.CoverageRepeaterActivator"
init-method="init" destroy-method="destroy" activation="eager">
<property name="dataSourceManager" ref="dataSourceMgrOsgi"/>
<property name="subscriber" ref="pubSubWcsClient"/>
<property name="consumer" ref="reqReplyWcsClient"/>
<property name="idempotentRepository" ref="idempotentRepository"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
126
<!-- Time in milliseconds -->
<property name="retryPeriod" value="${coverage-repeater.retryPeriod}"/>
<property name="retrySubValidityPeriod" value="${coverage-repeater.retrySubValidityPeriod}"/>
<property name="cvgListConfig" ref="getCvgNotifListConfig"></property>
<property name="disableDnsLookup" value="${coverage-repeater.mbean.disableDnsLookup}"/>
</bean>
For each RepeaterConfig, the CoverageRepeaterActivator creates an IdempotentRepeater and
sets some properties on the new object. For example, the IdempotentRepeater’s
reqReplyWcsClient and pubSubWcsClient properties are set with the instances obtained from the
Blueprint above. Then the CoverageRepeaterActivator calls the IdempotentRepeater’s init(...)
method (inherited from SubscriberImpl).
IdempotentRepeater is a subclass of Repeater, which is a subclass of SubscriberImpl both from
the edu.ucar.ral.wxcube.consumer.wcs package. The SubscriberImpl’s init(...) method will first
verify the existence of the reqReplyWcsClient - an instance of ReqReplyWcsSwaClientImpl - and
the pubSubWcsClient - an instance of PubSubWcsClientImpl - initially created from the Blueprint
above and set by the CoverageRepeaterActivator. These two client objects will later be used as
the client-side port types in communicating to the upstream server. After performing some timer
and SSL configurations, the SubscriberImpl will then use its reqReplyWcsClient to issue a
describeCoverage request upstream to obtain metadata, such as the geospatial bounding box,
about the coverage being repeated. Then the SubscriberImpl will create a sample volume request
(i.e., the subscriptions <Filter> element) to be used immediately in a subscription request
upstream, and information regarding the subscription will be saved to disk for later use. If the
subscription is successful and a valid subscription client id is obtained, the SubscriberImpl will
create the notification listeners with a call to the createNotificationListeners(...) method and
connect to the subscription (i.e., the upstream ActiveMQ instance’s temporary queue) with a call
to the connectToSubscription(...) method.
8.2.3 IdempotentGetCoverageNotificationListener
When the createNotificationListeners(...) method is called in the IdempotentRepeater class (from
SubscriberImpl’s init(...) method), it will create an IdempotentGetCoverageNotificationListener. In
the general sense, the IdempotentGetCoverageNotificationListener is responsible for listening for
subscription notifications from ActiveMQ. If the IdempotentGetCoverageNotificationListener is
subscribed and connected to the message broker, ActiveMQ will notify the listener when
appropriate by calling its onNotify(...) method or ultimately the processNotification(...) method.
IdempotentGetCoverageNotificationListener is a subclass of GetCoverageNotificationListener,
and is suited for use in a WCSRI cluster. In a cluster, each WCSRI node will connect to the
upstream AMQ to listen for notifications, and hence, each will be notified when appropriate. Each
listener (or node) will attempt to add its notification to an idempotentRepository (i.e., the
database), and success indicates that the notification has not been processed yet by any other
WCSRI nodes. Hence, each node is effectively a competing consumer of notifications, and the
127
first one to successfully add the notification to the database will be the node that actually requests
the weather data from the upstream WCSRI server.
The IdempotentGetCoverageNotificationListener’s processNotification(...) method will first create
a unique ID for the notification, and add it to the idempotent database. If successful, it will call
GetCoverageNotificationListener’s version of the processNotification(...) method. That will then
create a volume request, or a getCoverage request, using the coverage ID, field names, valid
time, lead seconds and geospatial bounding box information. The ReqReplyWcsClientImpl’s
getVolume(...) (i.e., consumer.getVolume(...)) method will be called to do the actual upstream
SOAP request, and if successful, latencies will be calculated and stored on the
managedSubscriber MBean (see GetCoverageNotificationListener’s calculateLatencyAndNotify
method). Finally, the weather data file is moved to the /staging directory of the coverage so that it
will be available for that coverage’s DataPoller and ultimately that coverage’s
DirectoryBasedDataSource.
There are several properties that can be configured in the wcsri.cfg file in regards to Repeaters.
The following properties are pertinent:
coverage-repeater.retryPeriod=30000 - This is the time in milliseconds before attempting to
reinitialize a repeater that is not subscribed and connected. For example, if a repeater has not
successfully retrieved the geospatial bounding box from the upstream WCSRI server, it will not be
successfully subscribed since it can not issue a valid getCoverage request without it. Also, the
repeater may not be connected to the upstream AMQ. In both cases, the repeater is not
subscribed and/or connected.
coverage-repeater.retrySubValidityPeriod=120000 - If the repeater has a successful
subscription connection, it will periodically check to make sure the subscription and its connection
are still valid. This property configures that period of time in milliseconds.
coverage-repeater.listener.maxRetryTimes=20 - When a repeater is notified of upstream
weather data availability, it will attempt to retrieve that data. If it is not successful, it will retry a
number of times up to the value of this property.
coverage-repeater.listener.reprocessingPeriod=30000 - The time to wait between repeated
getCoverage requests upstream, in milliseconds, due to previous failed attempts.
coverage-repeater.listener.persistPeriod=600000 - Period of time, in milliseconds, between
saving the state of the repeater to a local file.
coverage-repeater.numConsumers=1 - Multiple, “simultaneous” notifications can be processed
by more than one consumer at a time. This property tells AMQ how many consumers to make
available for processing notifications simultaneously.
128
coverage-repeater.mbean.disableDnsLookup=true - This property is used by the
ManagedSubscriber MBean. When providing readable statistics regarding the hop latencies
between WCSRI nodes, the MBean will either use DNS or not in order to resolve upstream node
IP addresses. If a DNS is available, set this to false.
coverage-repeater.security.credentials= - If an upstream WCSRI node requires authentication,
this property will indicate the file in which to find credentials to use in communicating upstream.
coverage-repeater.installCert=true - Flag indicating whether or not an upstream https/ssl
endpoint will download and save the server’s certificate automatically.
coverage-repeater.disableCNCheck=true - Flag indicating that the https URL hostname does
not need to match the Common Name (CN) on the server certificate. It is recommended to set this
to false in an operational environment.
coverage-repeater.keystoreFile=${karaf.base}/etc/client.jks - Location of the Repeater’s client
certificate for mutual SSL.
coverage-repeater.truststoreFile=${karaf.base}/etc/truststore.jks - Location of the Repeater’s
client trust store for SSL.
9 Delegators
9.1 Overview
Delegators are a concept used for the flexible distribution architecture supported by the WCSRI.
Delegators allow WCSRI nodes to be set up as proxy nodes, delegating requests and
subscriptions upstream to other WCSRI nodes. The Delegator is similar to the Repeater pattern,
but does not actually repeat the data on the downstream distribution node. Instead, Delegators
simply forward requests upstream, and responses downstream to clients using the request/reply
MEP. For the publish/subscribe MEP, the Delegator will subscribe upstream, and forward
notifications downstream to interested and subscribed clients. This is a useful architecture for
providing a proxied frontend for a number of coverages without repeating the actual data.
Delegators are specified on a DataSource or coverage basis, a Delegator node may provide a
unified exposed service node for several backend WCSRI nodes existing behind a firewall. Also,
note that the initial intent of the Delegator was to add functionality to dynamically cache frequently
requested data on the Delegator node, however, this has not yet been implemented.
Per the installation documentation, Delegators are specified by using a <DelegatorConfig>
element within coveragesConfig.xml files, and specifying a DataSource of type “Delegator”. The
following is an example of a coveragesConfig.xml file containing a Delegator specification:
<?xml version="1.0" encoding="UTF-8"?>
<DataSource type="Delegator">
129
<DelegatorConfig>
<OriginServerWcsEndpoint>http://collision.rap.ucar.edu:8280/wcs</OriginServerWcsEndpoint>
</DelegatorConfig>
<!-- You may list multiple Coverage elements if multiple coverages come from the same data files. -->
<Coverage>
<Id>urn:fdc:ncar.ucar.edu:Dataset:FLTCAT</Id>
<UpstreamId>urn:fdc:ncar.ucar.edu:Dataset:FLTCAT_UPSTREAM</UpstreamId>
</Coverage>
<Coverage>
<Id>urn:fdc:ncar.ucar.edu:Dataset:CEIL</Id>
</Coverage>
</DataSource>
Each Delegator DataSource can delegate one or more coverages, as specified above by
<Coverage> elements. However, only a single OriginServerWcsEndpoint can be used for a
DelegatorConfig, which implies that the coverages specified as <Coverage> elements must all be
available from the single upstream endpoint. Delegators will make the specified coverages
available from the Delegator node as if the coverages actually existed there. The WCS 1.1.2
operations for the specified coverage(s) - DescribeCoverage, GetCoverage - will be forwarded
upstream to the OriginServerWcsEndpoint. Responses for GetCapabilities, DescribeCoverage
and GetMetadata requests issued against the Delegator node’s WCSRI will include the content
from the DescribeCoverage responses retrieved from the upstream node. For the
publish/subscribe MEP, a Delegator will subscribe upstream for the specified coverages, and
maintain downstream subscriptions locally on the Delegator WCSRI node. When notifications are
received from the upstream node, the Delegator will retrieve or match downstream subscriptions,
and notify as appropriate.
Note that the above XML configuration does not contain content typical for FileSystem and/or
Repeater configurations. <ValidTimesType> and <CoverageMetadataFile> elements are not
specified since those are used in satisfying DescribeCoverage requests locally, and Delegators
simply forward results from upstream DescribeCoverage requests downstream to clients. In
addition, <Janitor> elements are not specified since the raw weather data is kept upstream and
not repeated locally, and hence there is no data to clean up.
On startup of the downstream WCSRI, a Delegator will issue a describeCoverage to the upstream
endpoint, for each delegated coverage, in order to cache metadata about the coverage(s). The
metadata includes information such as the geospatial bounding box (X, Y and possibly Z) of the
data. The metadata is then used as the <Filter> element when subscribing upstream.
9.2 Delegator Implementation
9.2.1 DataSourceConfigurator
130
When the WCSRI starts up, the DataSourceConfigurator object will be created from the gds-pojoservice bundle’s Blueprint specification. The DataSourceConfigurator is configured with the
wcs.rootDataDir, and within its getCoverageConfigFiles(...) method, it will recurse downwards
looking for coveragesConfig.xml files. For each file found, the method configCoverages(...) is
called, and ultimately createDatasetDataSources(...) to create the DataSources. If a Delegatortype DataSource is specified in a coveragesConfig.xml file, the
parseAndCreateDelegatorDataSources(...) method will be called to create a
DelegatorDatasetDataSource for each coverage specified as part of the Delegator’s DataSource.
Also note that the DataSourceConfigurator is configured with a reqReplyWcsClient from Blueprint
(i.e., gds.xml). The DataSourceConfigurator will set the DelegatorDatasetDataSource’s
reqReplyWcsClient that will be used for forwarding request/reply MEPs upstream. When the
parseAndCreateDelegatorDataSources(...) method returns, a DelegatorConfig object and a child
directory (e.g., coverage1/) will be created for each delegated coverage. The DelegatorConfig
object will be used later by the DatasourceDelegatorActivator to subscribe upstream for each
coverage. In addition, the child directories become available for temporarily storing getCoverage
data as it is retrieved from upstream and forwarded downstream. An example of the directory
structure created for the Delegator as defined in the XML example above is shown here:
wcsRootDataDir/
delegatorExampleDir/
coveragesConfig.xml
coverage1/
tmp/
coverage2/
tmp/
9.2.2 DelegatorDatasetDatasource
The DelegatorDatasetDatasource (in the edu.ucar.ral.gds.core.datasource package) is used in
lieu of a DirectoryBasedDatasource for satisfying request/reply MEPs for delegated coverages.
Note that the DelegatorDatasetDatasource has a reqReplyWcsClient property that is set by the
DataSourceConfigurator on startup, as mentioned above. This reqReplyWcsClient is part of the
wx-consumer library, and provides the port type implementations for making SOAP
describeCoverage and getCoverage requests to a WCSRI. Hence, the getVolume(...),
getCorridor(...) and getDatasetMetadata(...) methods of the DelegatorDatasetDatasource simply
use the reqReplyWcsClient to forward requests upstream.
9.2.3 DatasourceDelegatorActivator
The DatasourceDelegatorActivator is created by the datasource-delegator.xml Blueprint file in the
datasource-delegator bundle, as partially shown below, with “datasourceDelegatorManager” as its
identifier. The DatasourceDelegatorActivator init(...) method, depicted in Figure 23, uses the
DelegatorConfig objects from the DataSourceManager to create and initialize the Delegators for a
downstream WCSRI node.
<bean id="passwordCallback"
class="edu.ucar.ral.wxcube.consumer.wcs.KeystorePasswordCallback" init-method="init">
<property name="userCredentialsdFilePath" value="${datasource-delegator.security.credentials}"/>
131
<!--<property name="passwords" ref="passwords"/>-->
</bean>
<bean id="subscribePortTypeMngr"
class="edu.ucar.ral.wxcube.consumer.wcs.SubscribePortTypeMngr">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableLogging" value="true"/>
<property name="installCert" value="${datasource-delegator.installCert}"/>
<property name="disableCNCheck" value="${datasource-delegator.disableCNCheck}"/>
</bean>
<bean id="subscriptionMngrPortTypeManager"
class="edu.ucar.ral.wxcube.consumer.wcs.SubscriptionMngrPortTypeManager">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableLogging" value="true"/>
<property name="installCert" value="${datasource-delegator.installCert}"/>
<property name="disableCNCheck" value="${datasource-delegator.disableCNCheck}"/>
</bean>
<bean id="wsPortTypeManager"
class="edu.ucar.ral.wxcube.consumer.wcs.WcsSwaPortTypeManager">
<property name="passwordCallback" ref="passwordCallback"/>
<property name="enableOutLogging" value="${webServicesRequestLogEnabled}"/>
<property name="enableInLogging" value="${webServicesResponseLogEnabled}"/>
<property name="installCert" value="${datasource-delegator.installCert}"/>
<property name="disableCNCheck" value="${datasource-delegator.disableCNCheck}"/>
</bean>
<!-- jaxb builder that allows to build getCVg without a bbox constraint -->
<bean id="getCvgJaxbBuilder"
class="edu.ucar.ral.wcsri.util.wcs112.jaxb.GetCoverageJaxbBuilder">
<property name="requireBboxConstraint" value="false"/>
</bean>
<bean id="pubSubWcsClient"
class="edu.ucar.ral.wxcube.consumer.wcs.PubSubWcsClientImpl">
<property name="cvgJaxbBuilder" ref="getCvgJaxbBuilder"/>
<property name="subscribeManager" ref="subscribePortTypeMngr"/>
<property name="subscriptionMngrManager" ref="subscriptionMngrPortTypeManager"/>
<property name="passwordCallback" ref="passwordCallback"/>
<property name="messagecontentDialect" value="${datasource-delegator.messageContentDialect}"/>
</bean>
<bean id="reqReplyWcsClient"
class="edu.ucar.ral.wxcube.consumer.wcs.ReqReplyWcsSwaClientImpl">
<property name="portTypeMgr" ref="wsPortTypeManager"/>
</bean>
<bean id="datasourceDelegatorManager"
class="edu.ucar.ral.wcsri.pubsub.datasource.delegator.internal.DatasourceDelegatorActivator" init-method="init"
destroy-method="destroy" activation="eager">
<property name="dataSourceManager" ref="dataSourceMgrOsgi"/>
<property name="subscriber" ref="pubSubWcsClient"/>
<property name="consumer" ref="reqReplyWcsClient"/>
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="transformerInformationService" ref="transformerInformationService"/>
<property name="idempotentRepository" ref="idempotentRepository"/>
<property name="eventProducerDAO" ref="eventProducerDAO"/>
132
<!-- Time in milliseconds -->
<property name="retryPeriod" value="30000"/>
<property name="retrySubValidityPeriod" value="120000"/>
</bean>
For each DelegatorConfig, the DatasourceDelegatorActivator creates an IdempotentDelegator
and sets some properties on the new object. For example, the IdempotentDelegator’s
reqReplyWcsClient and pubSubWcsClient properties are set with the instances obtained from the
Blueprint above. In addition, the transformerDestinations is set on the IdempotentDelegator for
use in processing future notifications. Then the DatasourceDelegatorActivator calls the
IdempotentDelegator’s init(...) method (inherited from SubscriberImpl).
Figure 23. DatasourceDelegatorActivator's init() method
133
IdempotentDelegator is a subclass of Delegator, which is a subclass of SubscriberImpl both from
the edu.ucar.ral.wxcube.consumer.wcs package. The SubscriberImpl’s init(...) method will first
verify the existence of the reqReplyWcsClient - an instance of ReqReplyWcsSwaClientImpl - and
the pubSubWcsClient - an instance of PubSubWcsClientImpl - initially created from the Blueprint
above and set by the DatasourceDelegatorActivator. These two client objects will later be used as
the client-side port types in communicating to the upstream server. After performing some timer
and SSL configurations, the SubscriberImpl will then use its reqReplyWcsClient to issue a
describeCoverage request upstream to obtain metadata, such as the geospatial bounding box,
about the coverage being repeated. Then the SubscriberImpl will create a sample volume request
to be used immediately in subscribing upstream, and information regarding the subscription will
be saved to disk for later use. If the subscription is successful and a valid subscription client id is
obtained, the SubscriberImpl will create the notification listeners with a call to the
createNotificationListeners(...) method and connect to the subscription (i.e., the upstream
ActiveMQ instance’s temporary queue) with a call to the connectToSubscription(...) method.
9.2.4 IdempotentDelegatorNotificationListener
When the createNotificationListeners(...) method is called in the IdempotentDelegator class (from
SubscriberImpl’s init(...) method), it will create an IdempotentDelegatorNotificationListener. In the
general sense, the IdempotentDelegatorNotificationListener is responsible for listening for
subscription notifications from ActiveMQ. If the IdempotentDelegatorNotificationListener is
subscribed and connected to the message broker, ActiveMQ will notify the listener when
appropriate by calling its onNotify(...) method or ultimately the processNotification(...) method.
IdempotentDelegatorNotificationListener is a subclass of DelegatorNotificationListener, and is
suited for use in a WCSRI cluster. In a cluster, each WCSRI node will connect to the upstream
AMQ to listen for notifications, and hence, each will be notified when appropriate. Each listener (or
node) will attempt to add its notification to an idempotentRepository (i.e., the database), and
success indicates that the notification has not been processed yet by any other WCSRI nodes.
Hence, each node is effectively a competing consumer of notifications, and the first one to
successfully add the notification to the database will be the node that creates appropriate
messages for downstream delivery.
The IdempotentDelegatorNotificationListener’s processNotification(...) method will first create a
unique ID for the notification, and add it to the idempotent database. If successful, it will call
DelegatorNotificationListener’s version of the processNotification(...) method. That will then create
a JMS message to be enqueued on the TransformerMultiplexer queues referenced in this
document’s “TransformationMultiplexers” Section 7.4.2. Note that this approach leverages the
existing downstream notification mechanism in order to notify all subscribed (and potentially
connected) clients. Notification downstream is triggered by a notification received from upstream
rather than through the normal process of triggering a downstream notification through the results
of file polling with the DatasourcePollerConsumer.
134
There are several properties that can be configured in the wcsri.cfg file in regards to Delegators.
The following properties are pertinent:
datasource-delegator.security.credentials= - If an upstream WCSRI node requires
authentication, this property will indicate the file in which to find credentials to use in
communicating upstream.
datasource-delegator.installCert=true - Flag indicating whether or not an upstream https/ssl
endpoint will download and save the server’s certificate automatically.
datasource-delegator.disableCNCheck=true - Flag indicating that the https URL hostname
does not need to match the Common Name (CN) on the server certificate. It is recommended to
set this to false in an operational environment.
10 Logging
This section intentionally left blank and will be completed in the next version of the document.
11 Monitoring
JMX is a standard for exposing managed and/or monitored Java objects (“MBeans”) from an
application, which can then be invoked for functionality and/or queried for information. End
applications, such as JConsole, can then attach to a running Java application and display
exposed properties (e.g., statistics) and invoke methods (e.g., resubscribe) of MBeans. The
WCSRI exposes several “MBeans” for the intent of gathering and displaying performance
statistics, as well as providing simple management operations.
Statistics can be easily gathered around method invocation boundaries, before the call of a
method and after a method returns. MBeans that gather statistics in this manner can be wrapped
around target objects (i.e., classes to be monitored) and can then be used in lieu of those target
objects. This mechanism then allows the MBean to intercept the original target method invocation
and method return in order to gather and store the statistics. This approach is typically
implemented with Java aspect-oriented programming (AOP).
Method boundaries are not the only significant point at which statistics should be measured and
gathered. Code within a Java class can be considerably complex, and may require a different
class or method design that is incompatible with a method structure targeted to the monitoring
requirements. For example, a single method may contain many lines of code for ease of
understandability and readability. That method may contain several points that are relevant for
statistics gathering, however, due to the design of the class (i.e., the structure and intent of the
class’s methods), it may not provide monitorable method boundaries.
135
The monitoring design of the WCSRI avoided the use of AOP for the above reason. Instead of
being completely unaware of the statistics gathering MBeans, the WCSRI is more tightly coupled
with the MBeans that monitor its functionality. Several target classes within the WCSRI are aware
of the objects monitoring them, and simply use them to hold the statistics that are gathered at
specific points by the target class’s code. The target class is best suited for deciding what and
when statistics should be gathered, and uses the MBeans as containers for the statistics which
can easily be queried within applications such as JConsole.
The implementation of the MBeans, on the other hand, is loosely coupled from the target classes
being monitored. The WCSRI uses Google Guice to inject statistic-gathering MBeans into their
target objects in a loosely coupled fashion. Hence, a monitored target is aware that it has an
MBean for statistics gathering, but is decoupled from how the MBean is created and how it is
implemented (e.g., saves statistics to a log file, or sends statistics emails). Google Guice provides
the MBean creation and injection to the WCSRI’s target objects dynamically, and is better suited
for this than Blueprint (since Blueprint is more oriented towards statically defined objects).
11.1 JConsole
JConsole is an application packaged with the Java Development Toolkit (JDK), and provides a
simple user-interface for viewing and managing JMX MBeans exposed by a running Java
process. For connecting to a locally running instance of the WCSRI, start jconsole (usually found
in $JAVA_HOME/bin), create a new connection and select the “org.apache.karaf.main.Main” local
process. To connect to a remote WCSRI instance, create a new connection, select “Remote
Process” and enter a URL similar to the following:
service:jmx:rmi:///jndi/rmi://myWcsriMachineName:1099/karaf-root
Note that you will need to replace myWcsriMachineName with the appropriate machine name
where the WCSRI is running, and enter the username and password for the servicemix instance
(by default it’s “smx” and “smx”). Note that you can change the username and password within the
file $SERVICEMIX/etc/users.properties. It is also frequently useful to connect to ActiveMQ (when
running it externally from servicemix) for information and management of WCSRI-related MBeans
running within the message broker. To connect to an external, remote ActiveMQ instance, create
a new connection, select “Remote Process” and enter a URL similar to the following:
service:jmx:rmi:///jndi/rmi://myActiveMQMachineName:1098/jmxrmi
Note that you will need to replace myActiveMQMachineName with the appropriate machine name
where the ActiveMQ instance is running, and potentially enter a username and password for the
ActiveMQ instance (by default, there are none).
11.2 MBeans
The WCSRI uses JMX annotations to indicate MBean classes and their exposed, or managed,
attributes and operations. Also, the WCSRI uses Google Guice to instantiate and inject the
136
MBeans into their appropriate target objects. The following sections give an overview of the
various MBeans provided by the WCSRI, and some descriptions for their usage.
11.2.1 BaseWcsriMbean
The BaseWcsriMbean, within the edu.ucar.ral.wcsri.monitoring.jmx package, is the superclass for
all WCSRI MBeans. It provides the high-level MBean management or infrastructure details
required for using JMX. The functionality it provides includes access to a JMX MBean server, and
un/registering of MBean instances.
11.2.2 SubsetTimesMBean
The SubsetTimesMBean is defined in the edu.ucar.ral.wcsri.monitoring.jmx package of the source
code and is used for gathering statistics regarding getCoverage operations. The
SubsetTimesMBean is used by the VolumeSubsetter (in edu.ucar.ral.gds.core.datasource) and
provides averages, minimums, maximums and operation counts for different aspects of subsetting
the native weather data files. The attributes for the SubsetTimesMBean are as follows (also
shown in Figure 24):
Subset Read Times - the time, in milliseconds, used in reading a subset (X, Y, Z and
Time) of weather data from raw, native data files.
Subset Write Times - the time, in milliseconds, used in writing a subset (X, Y, Z and
Time) of weather data out to a temporary NetCDF-4 file.
Subset Times - the time, in milliseconds, used in performing a complete subset operation.
One SubsetTimesMBean instance is created for each locally served coverage offered by the
server (i.e., Delegator coverages are not included). The DataSourceConfigurator uses an instance
of com.google.inject.Injector, called the mbeanInjector, to create an instance of the
SubsetTimesMBean, and then adds it to the DirectoryBasedDataSource by coverageId (see the
DataSourceConfigurator’s createFileSystemDataSource(...) method). Figure XX shows a
snapshot of JConsole for a running WCSRI (or servicemix) instance, depicting the
SubsetTimesMBeans available from the WCSRI and one of the MBean’s attributes. Note that the
SubsetTimesMBeans are listed by name including their coverageId.
137
Figure 24. Attributes for SubsetTimesMBean
The SubsetTimesMBean also provides a set of exposed management operations as shown in
Figure 25. A brief description for the operations follows:
resetReadTimes - resets the subset read times statistics.
resetWriteTimes - resets the subset write times statistics.
resetSubsetTimes - resets the complete subset times statistics.
getFileSizeBytes - returns the file size, in bytes, of a specified native weather data file for
the coverage. The method requires a String as a parameter in the format of
“yyyymmdd_v_xxxxxx_l_xxxxxxx” (e.g., 20121218_v_150000_l_0000000) to identify a
specific data file.
getFileTimeStamp - returns the timestamp of a specified native weather data file for the
coverage. The method requires a String as a parameter in the format of
“yyyymmdd_v_xxxxxx_l_xxxxxxx” (e.g., 20121218_v_150000_l_0000000) to identify a
specific data file.
138
Figure 25. Operations for SubsetTimesMBean
11.2.3 SystemPerformanceMBean
The SystemPerformanceMBean is found in the edu.ucar.ral.wcsri.system.performance.mbean
package. This package, or bundle, is loaded into servicemix by the wcsri-system-performance
feature which is installed when the “features:install wcsri-system-performance” command is
executed. The Blueprint specification for this bundle is called “systemPerfMonitor.xml” within the
wcsri-system-performance Maven module, and contains a Blueprint for the
SystemPerformanceProcessor as follows:
<bean id="systemPerformanceProcessor" class="edu.ucar.ral.wcsri.system.performance.SystemPerformanceProcessor"
init-method="init" destroy-method="destroy">
<property name="interval" value="${system.performance.interval}" />
<property name="inputDisk" value="${system.performance.idisk}" />
<property name="outputDisk" value="${system.performance.odisk}" />
<property name="nfs" value="${system.performance.nfs}" />
<property name="testsToRun" value="${system.performance.tests}" />
<property name="fieldsOfInterest" value="${system.performance.fos}" />
</bean>
The SystemPerformanceProcessor uses Google Guice to create an instance of the
SystemPerformanceMBean. The SystemPerformanceProcessor runs on a Camel Timer to
periodically gather performance statistics, and stores that information on the
SystemPerformanceMBean. The SystemPerformanceMBean’s attributes are related to CPU
usage, I/O usage and memory usage, and are shown in a JConsole snapshot in Figure 26. In
addition, Figure 27 shows the operations available from the MBean.
139
Figure 26. SystemPerformanceMBean Attributes
Figure 27. SystemPerformanceMBean Operations
140
11.2.4 ManagedSubscriber, ManagedRepeater and ManagedDelegator MBeans
The ManagedSubscriber, ManagedRepeater and ManagedDelegator MBeans are found in the
edu.ucar.ral.wxcube.consumer.wcs.mbean package. Note that these classes are part of the wxconsumer-wcs library, and are not part of the WCSRI trunk source code. However, since
Repeaters and Delegators are used by the server itself in communicating with upstream WCSRI
instances, the wx-consumer-wcs package is also used within the server. ManagedRepeater and
ManagedDelegator MBeans store statistics regarding the repeating and delegating of a coverage.
If Repeater and/or Delegator configurations have been specified (within coveragesConfig.xml files
under wcs.rootDataDir) for a WCSRI instance, ManagedRepeater and ManagedDelegator
MBeans will be exposed via JMX to provide such statistics.
A ManagedRepeater MBean is created for each Repeater configuration (i.e., RepeaterConfig).
The CoverageRepeaterActivator (defined in the pubsub/coverage-repeater module’s Blueprint
coverageRepeater.xml file) will create an instance of an IdempotentRepeater for each Repeater
configuration using Guice, and in the process, Guice will inject a ManagedRepeater into the
IdempotentRepeater (see the managedRepeater instance variable). When the
IdempotentRepeater’s init(...) method is eventually called, it will call its own
createNotificationListeners(...) method and create a IdempotentGetCoverageNotificationListener
that is responsible for listening for notifications and then retrieving appropriate coverage files. The
IdempotentGetCoverageNotificationListener is also configured with the ManagedRepeater MBean
instance, which is then used in the GetCoverageNotificationListener superclass (see its
managedSubscriber instance variable) to gather and store statistics related to repeating
coverages.
The ManagedRepeater MBean contains statistics relevant to repeating coverages (see Figure
28). In general, it tracks information regarding notifications, such as the total number of
notifications, the number of notifications that have failed and the number that have succeeded. In
addition, ManagedRepeaters track statistics relevant to retrieving upstream weather data, such as
mean, maximum and minimum latency and request times. Request time is defined as how long it
takes to successfully do a getCoverage request upstream (after being notified) and save the
resulting weather data file locally. Latency time, on the other hand, is the time difference between
the timestamp on the downstream repeated data file (i.e., the result of the getCoverage) and the
timestamp on the upstream original data file from the originating node. Note that latency refers to
the time spent in retrieving the data file from the originating node, regardless of how many
intermediate WCSRI nodes exist along the path.
141
Figure 28. ManagedRepeater MBean Attributes
The ManagedRepeater MBean also contains several management operations as shown Figure
29. Some of the methods relate to subscription management, such as resume, disconnect,
unsubscribe and pause. Other methods such as getNotificationsInfo and getLatencyInfo
communicate additional information in regards to statistics, beyond the existing MBean’s
attributes. Note that the getLatencyInfo(...) method requires a String in the format
“YYYYMMDD_v_HHmmss_l_(-)sssssss” (e.g., “20120906_v_120000_l_0000000”), and returns
the latencies acquired between WCSRI hops rather than simply the total latency.
The ManagedDelegator MBean is also a subclass of the ManagedSubscriber, and hence has
similar statistics and management operations to the ManagedRepeater. However, the Delegator
pattern does not repeat data from upstream, and therefore latency statistics are not relevant. The
ManagedDelegator’s latency-related operations are not implemented as a result.
142
Figure 29. ManagedRepeater MBean Operations
12 Security
This section intentionally left blank and will be completed in the next version of the document.
143
13 ncWMS
The WCSRI includes in its release a web application, ncWMS with some extensions, to display
WCSRI datasets and subsets in a map using the Web Map Service (WMS) specification. (For
more information about this application visit http://www.resc.rdg.ac.uk/trac/ncWMS/). If the
optional service is installed, it allows a WCSRI administrator (or other) to visually verify coverage
data, both the raw weather data files and the weather data subset files retrieved using a SOAP
getCoverage operation.
The WCSRI generates the configuration required by ncWMS from a Blueprint specification found
in wcsri-ncWMS/src/main/resources/OSGI-INF/blueprint, using the following properties:
<bean id="ncWMSconfigurator" class="edu.ucar.ral.wcsri.ncwms.internal.NcWMSConfigurator" init-method="init">
<property name="configFile" value="${ncwms.workingDirectory}/config.xml"/>
<property name="wcsEndpointUrl" value="${wcs.frontend.publish.url}"/>
<property name="wcsExtEndpointUrl" value="${wcs.frontend.external.url}"/>
<property name="dataSourceManager" ref="dataSourceMgrOsgi"/>
<property name="contactname" value="${ncwms.contactName}"/>
<property name="organization" value="${ncwms.organization}"/>
<property name="telephone" value="${ncwms.telephone}"/>
<property name="email" value="${ncwms.email}"/>
<property name="providerUrl" value="${ncwms.providerUrl}"/>
<property name="maxImageWidth" value="${ncwms.maxImageWidth}"/>
<property name="maxImageHeight" value="${ncwms.maxImageHeight}"/>
<property name="allowFeatureInfo" value="${ncwms.allowFeatureInfo}"/>
<property name="allowglobalcapabilities" value="${ncwms.allowglobalcapabilities}"/>
<property name="adminpassword" value="${ncwms.adminpassword}"/>
<property name="cacheEnabled" value="${ncwms.cache.enabled}"/>
<property name="cacheElementLifetimeMinutes" value="${ncwms.cache.elementLifetimeMinutes}"/>
<property name="cacheMaxNumItemsInMemory" value="${ncwms.cache.maxNumItemsInMemory}"/>
<property name="cacheEnableDiskStore" value="${ncwms.cache.enableDiskStore}"/>
<property name="cacheMaxNumItemsOnDisk" value="${ncwms.cache.maxNumItemsOnDisk}"/>
<property name="title" value="${ncwms.title}"/>
<property name="abstr" value="${ncwms.abstract}"/>
<property name="keywords" value="${ncwms.keywords}"/>
<property name="copyrightStatement" value="${ncwms.copyrightStatement}"/>
<property name="updateInterval" value="${ncwms.updateInterval}"/>
<property name="configureLocal" value="${ncwms.configureLocal}"/>
<property name="configureWCS" value="${ncwms.configureWCS}"/>
<property name="configureRepeater" value="${ncwms.configureRepeater}"/>
</bean>
This Blueprint file is used to instantiate and initialize the NcWMSConfigurator object. This object is
used to auto-generate an ncWMS runtime configuration file, which configures the application
when the feature is installed into the Servicemix container. The Blueprint file also contains a
number of configuration properties for ncWMS, whose names are prepended with ‘ncwms.’, and
the properties are specified with default values. The default property values can be overridden for
a customized ncWMS application by adding the property/value pairs to the wcsri.cfg before
installing the WCSRI, as in the following example:
ncwms.providerUrl=
ncwms.cache.maxNumItemsInMemory=200
144
ncwms.updateInterval=5
ncwms.configureRepeater=false
ncwms.keywords=WCSRI, WMS, NNEW
ncwms.title=WCSRI ncWMS
ncwms.workingDirectory=${karaf.base}/etc/ncWMS
ncwms.configureLocal=true
ncwms.allowFeatureInfo=true
ncwms.maxImageWidth=1024
ncwms.cache.enableDiskStore=true
ncwms.organization=
ncwms.cache.enabled=true
ncwms.cache.maxNumItemsOnDisk=2000
ncwms.configureWCS=true
ncwms.allowglobalcapabilities=true
ncwms.telephone=
ncwms.maxImageHeight=1024
ncwms.cache.elementLifetimeMinutes=1440
ncwms.contactName=
ncwms.email=
ncwms.abstract=This is a WMS server configured to display WCSRI related datasets
ncwms.copyrightStatement=NNEW
ncwms.adminpassword=ncWMS
By default the WCSRI generates an ncWMS configuration that provides access to the datasets in
two different ways. Datasets with a “Local” prefix indicate that the data is read directly from disk
(via the NetCDF API used in the ncWMS libraries) and displayed. Datasets with a “WCS” prefix,
however, indicate that access is via a GetCoverage request to the local WCSRI server. To disable
the addition of either retrieval method use:
ncwms.configureLocal=false
or
ncwms.configureWCS=false
Also note that many of the ncWMS classes have been modified so that the WCSRI can be used
as a data provider. The source code with these modifications is not available in the WCSRI
subversion repository at this time.
13.1 Installing the ncWMS
The ‘ncWMS’ application is not automatically installed with the WCSRI - it must be installed
explicitly by typing:
smx@root> features:install ncWMS
in the servicemix console. Note that must be done AFTER the main WCSRI bundles are installed
and running.
The feature installation can be confirmed in the servicemix console by typing:
145
smx@root> list | grep -i ncwms
[ 204] [Active ] [Created ] [ ] [ 60] WCSRI :: wcsri-ncWMS (4.4.0.SNAPSHOT)
[ 216] [Active ] [ ] [ ] [ 60] uk.ac.rdg.resc.ncwms (1.0.0.SNAPSHOT)
13.2 Viewing the ncWMS
After ncWMS is installed, it can be accessed with a web browser via the URL http://[wcsri
host]:8086/ncWMS/godiva2.html as shown in the images below (Figure 30 and Figure 31).
Additionally ncWMS provides an administrative page at http://[wcsri host]:8086/ncWMS/admin/
that can be used to change some parts of the ncWMS configuration at runtime. The images below
show the “local” coverages, labelled as such, that render the raw weather data files. In addition,
the “WCS” coverages, labelled as such, are also shown and will render the coverage subsets as
retrieved from the WCSRI using SOAP getCoverage requests.
Under each coverage, either local or WCS, the offered fields are listed and may be turned on/off
for rendering. The geospatial X/Y extents to be rendered are supplied by the map within the
ncWMS, and are used when making local or server-provided data subsets. The altitudes, if
appropriate, are listed in a drop-down menu and allow the user to select the vertical level of
interest. In addition, the list of available times appropriate for the data are retrieved either with a
directory listing in the case of “local” data, and via a describeCoverage request/response in the
case of server-provided coverages. The times are available for selection by the user within the
Date/time dropdown and/or calendar.
146
Figure 30. ncWMS with Local (raw) Dataset Indicated
147
Figure 31. ncWMS with WCSRI-served Dataset Indicated
14 Performance Statistics
This section intentionally left blank and will be completed in the next version of this document.
15 wx-consumer-wcs
The wx-consumer-wcs library is a client-side Java API for accessing the various external services
provided by the WCSRI. It is part of the wx-consumer library, which contains functionality for the
Web Feature Service Reference Implementation and the Regrep, and exists in a different code
base in Subversion. The primary purpose of the library is to provide API and command-line
access, via a SimpleClient application, to the top-level WCS 1.1.2 and WS-N operations including
GetCapabilities, DescribeCoverage, GetCoverage, and Subscribe operations. Though the
codebase is separate from the WCSRI, it used extensively by the server to handle delegation and
repeater tasks which require communication with an upstream WCSRI. In addition, it is used by
the Css-Wx Cubeview application to retrieve and display data from a WCSRI.
148
15.1 API
The wx-consumer-wcs library is contained in the wx-consumer-wcs Maven module and the
edu.ucar.ral.wxcube.consumer.wcs Java package. This is the parent package for all WCS client
operations. It includes the SimpleClient application class as well as the WcsClient and
PubSubWcsClient interfaces for top-level client-side operations. The WcsClient interface provides
the WCS 1.1.2 functionality including GetCapabilities, DescribeCoverage and GetCoverage, by
exposing the following methods:
getCorridor(CorridorRequest request, File out, String endpoint, String user)
getVolume(VolumeRequest request, File out, String endpoint, String user)
getDatasetMeta(DatasetMetadataRequest request, String endpoint, String user)
getServicesMeta(ServicesMetadataRequest request, String endpoint, String user)
The library contains three implementations of the WcsClient interface:
ReqReplyWcsClientImpl - This is a deprecated implementation of the WCS operations
using MTOM.
ReqReplyWcsKvpClientImpl - The implementation of the GetCapabilities and
DescribeCoverage operations using Key-Value pairs or REST-style communication
to a WCSRI server.
ReqReplyWcsSwaClientImpl - The implementation of the GetCapabilities,
DescribeCoverage and GetCoverage operations using SOAP and SOAP With
Attachments (SAAJ) when communicating to a WCSRI server. Uses the
WcsSwaPortTypeManager port type for communications.
The PubSubWcsClient interface provides the WS-N functionality including subscribe and
unsubscribe by exposing the following methods:
subscribeToGetCoverage( Subscription subscription, VolumeRequest
getCoverageRequest, String endPt, String user )
unSubscribe( String sui, String endPt, String user )
The library provides a single implementation of the PubSubWcsClient interface:
PubSubWcsClientImpl - The implementation of the WS-N operations, using
SubscribePortTypeMngr and SubscriptionMngrPortTypeManager instances for
communications upstream.
The package also contains several interfaces and implementations for common server-side
subscription, repeater, and delegation tasks. These classes and interfaces are used by the server
for implementing robust communications to upstream WCSRI nodes. Though they can be
leveraged by 3rd party client applications, they were written specifically for the WCSRI’s repeater
and delegator functionality. These classes and interfaces include:
149
Subscriber - a simple interface for WS-N subscription operations
SubscriberImpl – a complex implementation of the Subscriber interface. Includes support
for SOAP subscription communications, JMS communications, proxies, security,
and asynchronous callbacks for notifications. Uses WcsClient for WCS-operations
and PubSubWcsClientImpl for WS-N operations when communicating to an
upstream WCSRI. Superclass for Delegator and Repeater classes.
Delegator - extension of SubscriberImpl. Includes functionality that implements server-side
delegation.
Repeater - extension of SubscriberImpl. Includes functionality that implements server-side
repeating.
SubscriptionClient – interface for connecting and handles subscription notifications for
subscribers, repeaters and delegators
SubscriptionNotificationListener – listener interface for consuming JMS message
notifications from an upstream WCSRI. This interface is implemented by concrete
classes including the DelegatorNotificationListener and the
GetCoverageNotificationListener, each of which perform tasks related to data
retrieval specific to delegation and repeating respectively.
SubscriptionErrorListener – listener interface for handling JMS connection and handshake
errors
The edu.ucar.ral.wxcube.consumer.wcs package also contains several sub-packages for lowerlevel and utility operations, which are outlined in the next sections.
15.1.1 edu.ucar.ral.wxcube.consumer.wcs.domain
This package contains classes which encapsulate subscriptions and notifications. These classes
are used by the WcsClient to handle WCS client pub/sub operations.
15.1.2 edu.ucar.ral.wxcube.consumer.wcs.exception
This package contains Exception classes thrown when errors occur with data retrieval or when
subscribing or listening for data notifications. These include GDSClientException and
SubscriptionClientException classes.
15.1.3 edu.ucar.ral.wxcube.consumer.wcs.mbean
This package is used for binding to and monitoring WCS client operations via Google Guice
injection. It includes ManagedDelegator, ManagedRepeater, and ManagedSubscriber classes as
well as the ConsumerMBeanBinder class, which implements Guice's com.google.inject.Module
interface. Note that these classes are intended for server-side monitoring and the gathering of
statistics for delegation and repeating coverages.
15.1.4 edu.ucar.ral.wxcube.consumer.wcs.proxy
This package contains the ProxyNode and ProxySupportHelper classes. These classes maintain
connection endpoint information for WCSRI proxy nodes, and keep track of connection failures,
150
retry attempts, time of last failure, etc. The ProxySupportHelper contains logic for selecting
alternate proxy nodes to use when failures occur.
15.1.5 edu.ucar.ral.wxcube.consumer.wcs.repeater
This package manages WCSRI repeater operations. It contains a RepeatersManager class for
managing client repeater requests, as well as JAXB bindings for marshalling and unmarshalling
XML data and metadata requests to (and responses from) upstream WCSRIs.
15.1.6 edu.ucar.ral.wxcube.consumer.wcs.utils
This package contains client utility classes for date parsing and formatting, writing files to the local
filesystem, handling client-side unit conversions, and handling security tasks such as handling
SSL certificates for secure WCSRI connections.
15.2 SimpleClient
As mentioned previously, SimpleClient is a Java command-line interface to the major WxConsumer-wcs API operations. A request for the application help gives a list of supported
operations and parameters:
$ java -cp wx-consumer-all-dependencies-4.0-RELEASE-shaded.jar \
edu.ucar.ral.wxcube.consumer.wcs.SimpleClient -h
Option
------?, -h
-b <?[0-9]*>
Description
----------Show help
BoundingBox of requested data(minLon,
minLat,maxLon,maxLat)
-c
Coverage Identifier - URN of the
dataset
--ct
Initial connection timeout(in ms).
(default: 60000)
--debug
debug mode on
-e
Comma-separated endpoint URLs
-f
Field Identifier - name of the field
--from
The email address the email report is
sent from (default: wcsrisupport@rap.ucar.edu)
--leadTime, --lt
Forecast lead time of requested data
in ms. Only available for a single
valid time. Ex: 3600000
--mail
Mailing address(es) to send error
messages
-o
Operation (default: testEndpoint)
<getCapabilities|describeCoverage|getCoverage|subscribeToGetCvg|testEndpoint>
--of
151
Filepath to which data is written.
-p, --password
--ret
--rt <soap|soap_swa|kvp>
-s, --sections
--smtp
-t
--tp
--tr
-u, --user
-v <?[0-9]*>
Password used for authentication
Response read timeout (in ms)
(default: 180000)
Request type (default: soap)
Comma-separated section list for
GetCapabilities.
SMTP host URL to use when sending
email (ex: 'mail.rap.ucar.edu')
Valid time/s (Ordred) of requested
data in UTC separated by commas.
Ex: 2009-07-22T04:00:00.000Z,2009-0722T05:00:00.000Z,2009-07-22T06:00:
00.000Z
Valid time period of requested data in
UTC. Ex: 2009-07-22T04:00:00.000Z,
2009-07-22T06:00:00.000Z
Time resolution for the time period of
the data in ms. Ex: 3600000
User for authenticating requests
Vertical extent of requested data
(minAltKm,maxAltKm)
Usage examples of the most common operations are given in the following sections. Note that
each section shows an example of how the SimpleClient can be used from the command line, as
well as a code snippet for how the SimpleClient implements the request/response. For a more
thorough coverage of example code, look into the SimpleClient.java and read the code.
15.2.1 GetCapabilities
$ java -cp wx-consumer-all-dependencies-4.0-RELEASE-shaded.jar \
edu.ucar.ral.wxcube.consumer.wcs.SimpleClient -e http://nnew.aero/fy12/wcs/soap \
-o getCapabilities -rt soap_swa
This invocation of SimpleClient simply requests and displays the capabilities of the WCSRI
located at http://nnew.aero/fy12/wcs/soap. An example response might be:
…
------------------------------------------------------------------------GetCapabilities for http://nnew.aero/fy12/wcs/soap
------------------------------------------------------------------------Service Identification:
NNEW Web Coverage Service Version 2.0 (WCS)
This is a trimmed down implementation of the WCS 1.1.2 specification (see
www.opengeospatial.org). The intent of the server is to provide gridded
data access services for aviation weather, as part of the NextGen Network
152
Enabled Weather (NNEW) program.
WCS
Fees: None
AccessConstraints: none
Service Provider:
NextGen Network Enabled Weather (NNEW)
ServiceContact:
John Smith
Software Engineer
Lead Engineer
Contact Info:
FL2, 3300 Mitchell Lane
Boulder 80305 Colorado U.S.
smith[at]ucar[dot]edu
Phone: 303-497-2806
Site: http://ral.ucar.edu/projects/nnew/
24x7x365
email
…
Metadata:
Parameter:
Name: Identifier
Allowed Values:
Allowed values:
urn:fdc:ncar.ucar.edu:Dataset:FLTCAT
urn:fdc:ncar.ucar.edu:Dataset:GOES-VIS
urn:fdc:ncar.ucar.edu:Dataset:GFS
urn:fdc:ncar.ucar.edu:Dataset:RUC-20
urn:fdc:ncar.ucar.edu:Dataset:NCWF2
urn:fdc:ncar.ucar.edu:Dataset:CIPSEV-20
urn:fdc:ncar.ucar.edu:Dataset:VIS
urn:fdc:ncar.ucar.edu:Dataset:CEIL
urn:fdc:ncar.ucar.edu:Dataset:CIP-20
urn:fdc:ncar.ucar.edu:Dataset:CIPSLD-20
urn:fdc:ncar.ucar.edu:Dataset:GOES-IR
urn:fdc:ncar.ucar.edu:Dataset:GTG2
…
Coverages Summary
Coverage 'urn:fdc:ncar.ucar.edu:Dataset:GOES-IR':
Supported CRS:
urn:ogc:def:crs:OGC:2:84 {minCorner=236.93388137090488 14.32113992772382 ,
maxCorner=310.5783543252825 59.826594210238625 }
urn:ogc:def:crs:OGC:2:84
urn:ncar:def:crs:Lambert_Conformal
urn:ogc:def:crs:OGC:2:84
SupportedFormats:
application/x-NetCDF4
153
Coverage 'urn:fdc:ncar.ucar.edu:Dataset:RUC-20':
SupportedFormats:
application/x-NetCDF4
Coverage 'urn:fdc:ncar.ucar.edu:Dataset:CIPSEV-20':
Supported CRS:
urn:ogc:def:crs:OGC:2:84 {minCorner=220.0431265201236 16.27837936187072 ,
maxCorner=302.97148768455224 55.58786530540488 }
urn:ogc:def:crs:OGC:2:84
urn:ncar:def:crs:Lambert_Conformal
urn:ogc:def:crs:OGC:2:84
urn:ogc:def:crs:OGC:2:84_plus_Z_in_km
urn:ncar:def:crs:NCAR_Corridor_CRS
SupportedFormats:
application/x-NetCDF4
...
The SimpleClient’s implementation of the GetCapabilities request looks similar to the following,
where wcsConsumer is either a ReqReplyWcsSwaClientImpl or a ReqReplyWcsKvpClientImpl
depending on the request type desired:
public ServicesMetadataResponse getCapabilities(String wcsEndpointURL, String[] sections) throws GDSClientException {
ServicesMetadataRequest smr = new ServicesMetadataRequest();
if (sections != null) {
SectionsConstraint sectionsConstraint = new SectionsConstraint();
for (String section : sections) {
if (section.equals(GetCapabilitiesConstraintsBuilder.SVC_ID)) {
sectionsConstraint.addSection(SectionsConstraint.Section.SVC_IDENTIFICATION);
} else if (section.equals(GetCapabilitiesConstraintsBuilder.SVC_PROVIDER)) {
sectionsConstraint.addSection(SectionsConstraint.Section.SVC_PROVIDER);
} else if (section.equals(GetCapabilitiesConstraintsBuilder.OPS_META)) {
sectionsConstraint.addSection(SectionsConstraint.Section.OPS_METADATA);
} else if (section.equals(GetCapabilitiesConstraintsBuilder.CONTENTS)) {
sectionsConstraint.addSection(SectionsConstraint.Section.CONTENTS);
} else {
throw new GDSClientException("getCapabilities received an invalid section " + section);
}
}
smr.setSectionsConstraint(sectionsConstraint);
}
ServicesMetadataResponse serviceMetaResp = wcsConsumer.getServicesMeta(smr, wcsEndpointURL, user);
return serviceMetaResp;
}
15.2.2 DescribeCoverage
$ java -cp wx-consumer-all-dependencies-4.0-RELEASE-shaded.jar \
edu.ucar.ral.wxcube.consumer.wcs.SimpleClient -e http://nnew.aero/fy12/wcs/soap \
-o describeCoverage -c urn:fdc:ncar.ucar.edu:Dataset:FLTCAT -rt soap_swa
154
In this example, SimpleClient would use SOAP (with Attachments) to request a description of the
urn:fdc:ncar.ucar.edu:Dataset:FLTCAT dataset, which might return something like:
-----------------------------------------------------------------------DescribeCoverage for http://nnew.aero/fy12/wcs/soap response :
-----------------------------------------------------------------------Coverage 'urn:fdc:ncar.ucar.edu:Dataset:FLTCAT':
Title:
Flight Category
Keywords:
Flight Category
FLTCAT
grb
Supported CRS:
urn:ncar:def:crs:Lambert_Conformal {minCorner=-2765.75655219723 266.3301247139125 , maxCorner=2684.0104478027706 3233.100875286087 }
urn:ogc:def:crs:OGC:2:84 {minCorner=229.85849939690758 20.165246665510267 ,
maxCorner=299.1468294651712 50.11891045721693 }
Available Time Ranges:
Sun Dec 30 02:05:00 UTC 2012 to Fri Jan 04 22:00:00 UTC 2013 resolution 300000
ms
Field 'Flight_Category':
SupportedFormats:
application/x-NetCDF4
The SimpleClient’s implementation of the DescribeCoverage request looks similar to the following,
where wcsConsumer is either a ReqReplyWcsSwaClientImpl or a ReqReplyWcsKvpClientImpl
depending on the request type desired:
public DatasetMetadataResponse describeCoverage(final String wcsEndpointURL, final String coverageId)
throws GDSClientException {
if (wcsEndpointURL == null) {
throw new GDSClientException("describeCoverage - EndpointURL is null");
}
if (coverageId == null) {
throw new GDSClientException("describeCoverage - coverageId is null");
}
DatasetMetadataRequest datasetMetaRequest = createDatasetMetadataRequest(coverageId);
DatasetMetadataResponse metaResp = wcsConsumer.getDatasetMeta(datasetMetaRequest, wcsEndpointURL, user);
return metaResp;
}
15.2.3 GetCoverage
$ java -cp wx-consumer-all-dependencies-4.0-RELEASE-shaded.jar \
155
edu.ucar.ral.wxcube.consumer.wcs.SimpleClient -b 220.85,20.16,230.85,32.17 -v
1.0,2.0 \
-e http://nnew.aero/fy12/wcs/soap -c urn:fdc:ncar.ucar.edu:Dataset:FLTCAT -f
Temperature \
-o getCoverage -t 2012-12-31T09:00:00.000Z -of /tmp/example.nc -rt soap_swa
This request would retrieve a volume subset with the specified lat/lon bounding box, vertical limits,
and time for the FLTCAT coverage, and write it to the file /tmp/example.nc. Note that the field
name could have been omitted in this example in order to retrieve all fields contained in the
coverage.
The SimpleClient’s implementation of the GetCoverage request looks similar to the following,
where wcsConsumer is either a ReqReplyWcsSwaClientImpl or a ReqReplyWcsKvpClientImpl
depending on the request type desired:
public void getCoverage(final String endpointURL, final String coverageId, final String fieldId, TimeConstraint timeConstraint,
Double[] bbox, Double[] vert, final File outputFile) throws GDSClientException {
...
GDSLonLatPointIF minCorner = null;
GDSLonLatPointIF maxCorner = null;
if (vert == null) {
minCorner = new GDSLonLatPoint(bbox[0], bbox[1]);
maxCorner = new GDSLonLatPoint(bbox[2], bbox[3]);
} else {
minCorner = new GDSLonLatAltPoint(bbox[0], bbox[1], vert[0]);
maxCorner = new GDSLonLatAltPoint(bbox[2], bbox[3], vert[1]);
}
VolumeRequest volReq = buildVolumeRequest(new DatasetIdentifier(coverageId), minCorner, maxCorner, fieldId,
timeConstraint, true);
long startTime = System.currentTimeMillis();
if (volReq != null) {
wcsConsumer.getVolume(volReq, outputFile, endpointURL, user);
} else {
throw (new GDSClientException("Volume request could not be generated"));
}
System.out.println("Successfully retrieved data in " + (System.currentTimeMillis() - startTime) + " ms");
}
15.2.4 Subscribe
$ java -cp wx-consumer-all-dependencies-4.0-RELEASE-shaded.jar \
edu.ucar.ral.wxcube.consumer.wcs.SimpleClient -e http://nnew.aero/fy11/wcs/soap \
-o subscribeToGetCvg -of /tmp/data -c urn:fdc:ncar.ucar.edu:Dataset:FLTCAT \
-t 2009-05-10T00:00:00.000Z -b -115,34,-110,40 -rt soap_swa
Note that this will stay running until you terminate the process (e.g. with Ctrl-C). SimpleClient will
subscribe, listen for notifications, and then retrieve the coverage files (per the bounding box
specified) and store them in the directory specified by -of (in this case /tmp/data).
156
Note also that -t in this case specifies the start valid time of the data that you are interested in –
i.e. if a new file appears on the server, valid 2011-05-12T00:00:00.000Z, but you specified a start
time of 2011-05-12T02:00:00.000Z, you would NOT be notified.
The SimpleClient’s implementation of the Subscribe request looks similar to the following, where
wcsConsumer is either a ReqReplyWcsSwaClientImpl or a ReqReplyWcsKvpClientImpl and the
subscriber is an instance of PubSubWcsClientImpl:
public void subscribeToGetCvg(final String wcsEndpointURL, final String coverageId, final String fieldId, TimeConstraint
timeConstraint, Double[] bbox, Double[] vert, final String subsDataPath) throws ... {
...
GDSLonLatPointIF minCorner = null;
GDSLonLatPointIF maxCorner = null;
if (vert == null) {
minCorner = new GDSLonLatPoint(bbox[0], bbox[1]);
maxCorner = new GDSLonLatPoint(bbox[2], bbox[3]);
} else if (vert != null) {
minCorner = new GDSLonLatAltPoint(bbox[0], bbox[1], vert[0]);
maxCorner = new GDSLonLatAltPoint(bbox[2], bbox[3], vert[1]);
}
VolumeRequest volReq = buildVolumeRequest(new DatasetIdentifier(coverageId), minCorner, maxCorner, fieldId,
timeConstraint, false);
Subscription subscription = new edu.ucar.ral.wxcube.consumer.wcs.domain.Subscription();
final String subsClientUID = subscriber.subscribeToGetCoverage(subscription, volReq, wcsEndpointURL, user);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
if (subscriber.isClientconnected(subsClientUID)) {
System.out.println("Disconnecting and unsubscribing from subscription ...");
subscriber.disconnectFromSubscription(subsClientUID);
subscriber.unSubscribe(subsClientUID, wcsEndpointURL, user);
}
} catch (GDSClientException e) {
…
}
}
});
System.out.println("Successfully subscribed to " + wcsEndpointURL);
GetCoverageNotificationListener getCvgListener = new GetCoverageNotificationListener();
getCvgListener.setOriginalVolReqt(volReq);
getCvgListener.setListenerId(1);
getCvgListener.setOutputFormatExtension("nc");
getCvgListener.setConsumer(wcsConsumer);
getCvgListener.setWcsEndpointURL(wcsEndpointURL);
getCvgListener.setCoverageId(coverageId);
getCvgListener.setDirectoryDestinationPath(subsDataPath);
getCvgListener.setTempDir(subsDataPath);
157
getCvgListener.setUser(user);
Set<SubscriptionNotificationListener> asyncListeners = new HashSet<SubscriptionNotificationListener>();
asyncListeners.add(getCvgListener);
subscriber.connectToSubscription(subsClientUID, asyncListeners, new HandshakeErrorListener(subsClientUID,
wcsEndpointURL, user), new ClientConnectionErrorListener(subsClientUID,
wcsEndpointURL, user));
System.out.println("Successfully connected to start receiving data for: " + coverageId);
while (subscriber.isClientconnected(subsClientUID)) {
// just loop and wait for 5 seconds
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
…
}
}
subscriber.unSubscribe(subsClientUID, wcsEndpointURL, user);
}
16 Source Code, Building and Installing
This section intentionally left blank and will be completed in the next version of this document.
158
Download