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&amp;period=600000&amp;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&amp;period=300000&amp;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