bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
BESDMRResponseHandler.cc
1// BESDMRResponseHandler.cc
2
3// This file is part of bes, A C++ back-end server implementation framework
4// for the OPeNDAP Data Access Protocol.
5
6// Copyright (c) 2013 OPeNDAP, Inc.
7// Author: Patrick West <pwest@rpi.edu>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#include "config.h"
26
27#include <sstream>
28#include <memory>
29
30#include <libdap/DMR.h>
31#include <libdap/D4Group.h>
32#include <libdap/D4Attributes.h>
33#include <libdap/D4BaseTypeFactory.h>
34
35#include "BESDMRResponseHandler.h"
36#include "BESDMRResponse.h"
37#include "BESRequestHandlerList.h"
38#include "BESDapNames.h"
39#include "BESDapTransmit.h"
40#include "BESContextManager.h"
41#include "GlobalMetadataStore.h"
42
43#include "BESLog.h"
44#include "BESDebug.h"
45
46using namespace bes;
47using namespace std;
48
49#define MODULE "dap"
50#define prolog std::string("BESDMRResponseHandler::").append(__func__).append("() - ")
51
52BESDMRResponseHandler::BESDMRResponseHandler(const string &name) :
54{
55}
56
57BESDMRResponseHandler::~BESDMRResponseHandler()
58{
59}
60
79{
80 dhi.action_name = DMR_RESPONSE_STR;
81
82 // Look in the MDS for dhi.container.get_real_name().
83 // if found, use that response, else build it.
84 // If the MDS is disabled, don't use it.
86
88
89 dhi.first_container();
90 if (mds) lock = mds->is_dmr_available(*(dhi.container));
91
92 if (mds && lock() && dhi.container->get_dap4_constraint().empty() && dhi.container->get_dap4_function().empty()) { // no CE
93 // send the response
94 mds->write_dmr_response(dhi.container->get_relative_name(), dhi.get_output_stream());
95 // suppress transmitting a ResponseObject in transmit()
96 d_response_object = 0;
97 }
98 else {
99 DMR *dmr = 0;
100 if (mds && lock() && dhi.container->get_dap4_function().empty()) {
101 // If mds and lock(), the DDS is in the cache, get the _object_
102 dmr = mds->get_dmr_object(dhi.container->get_relative_name());
103
104 BESDMRResponse *bdmr = new BESDMRResponse(dmr);
105 BESDEBUG(MODULE, prolog << "dmr->request_xml_base(): '"<< dmr->request_xml_base() <<
106 "' (dmr: "<< (void *) dmr << ")" << endl);
107
108 // This method sets the constraint for the current container. It does nothing
109 // if there is no 'current container.'
110 bdmr->set_dap4_constraint(dhi);
111 bdmr->clear_container();
112
113 d_response_object = bdmr;
114 BESDEBUG(MODULE, prolog << "d_response_object: "<< (void *) d_response_object << endl);
115 }
116 else {
117 dmr = new DMR();
118
119 // if (xml_base_found && !xml_base.empty()) dmr->set_request_xml_base(xml_base);
120 BESDMRResponse *bdmr = new BESDMRResponse(dmr);
121 BESDEBUG(MODULE, prolog << "dmr->request_xml_base(): '"<< dmr->request_xml_base()
122 << "' (dmr: "<< (void *)dmr << ")" << endl);
123
124 d_response_object = bdmr;
125
126 BESDEBUG(MODULE, prolog << "d_response_object: "<< (void *) d_response_object << endl);
127
128 // The RequestHandlers set the constraint and reset the container(s)
129 BESRequestHandlerList::TheList()->execute_each(dhi);
130
131 dhi.first_container(); // must reset container; execute_each() iterates over all of them
132
133#if ANNOTATION_SYSTEM
134 // Support for the experimental Dataset Annotation system. jhrg 12/19/18
135 if (!d_annotation_service_url.empty()) {
136 unique_ptr<D4Attribute> annotation_url(new D4Attribute(DODS_EXTRA_ANNOTATION_ATTR, attr_str_c));
137 annotation_url->add_value(d_annotation_service_url);
138
139 // If there is already a DODS_EXTRA container, use it
140 if (dmr->root() && dmr->root()->attributes()->get(DODS_EXTRA_ATTR_TABLE)) {
141 dmr->root()->attributes()->get(DODS_EXTRA_ATTR_TABLE)->attributes()->add_attribute_nocopy(annotation_url.release());
142 }
143 else {
144 // Make DODS_EXTRA and load the attribute into it.
145 unique_ptr<D4Attribute> dods_extra(new D4Attribute(DODS_EXTRA_ATTR_TABLE, attr_container_c));
146 dods_extra->attributes()->add_attribute_nocopy(annotation_url.release());
147
148 // If the root group is null, set the factory (this is an edge case!)
149 if (!dmr->root()) {
150 unique_ptr<D4BaseTypeFactory> factory(new D4BaseTypeFactory);
151 dmr->set_factory(factory.get());
152 dmr->root()->attributes()->add_attribute_nocopy(dods_extra.release());
153 dmr->set_factory(0);
154 }
155 else {
156 dmr->root()->attributes()->add_attribute_nocopy(dods_extra.release());
157 }
158 }
159 }
160#endif
161 // Cache the DMR if the MDS is not null but the response was not present, and..
162 // This request does not contain a server function call.
163 if (mds && !lock() && dhi.container->get_dap4_function().empty()) {
164 mds->add_responses(static_cast<BESDMRResponse*>(d_response_object)->get_dmr(), dhi.container->get_relative_name());
165 }
166 }
167 }
168}
169
183{
184 if (d_response_object) {
185 transmitter->send_response(DMR_SERVICE, d_response_object, dhi);
186 }
187}
188
195void BESDMRResponseHandler::dump(ostream &strm) const
196{
197 strm << BESIndent::LMarg << "BESDMRResponseHandler::dump - (" << (void *) this << ")" << endl;
198 BESIndent::Indent();
200 BESIndent::UnIndent();
201}
202
204BESDMRResponseHandler::DMRResponseBuilder(const string &name)
205{
206 return new BESDMRResponseHandler(name);
207}
208
std::string get_relative_name() const
Get the relative name of the object in this container.
std::string get_dap4_constraint() const
retrieve the constraint expression for this container
std::string get_dap4_function() const
retrieve the constraint expression for this container
response handler that builds an OPeNDAP DMR response object
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)
transmit the response object built by the execute command using the specified transmitter object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual void execute(BESDataHandlerInterface &dhi)
executes the command <get type-"dmr" definition="..">
Represents an OPeNDAP DMR DAP4 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Structure storing information used by the BES to handle the request.
void first_container()
set the container pointer to the first container in the containers list
BESContainer * container
pointer to current container in this interface
handler object that knows how to create a specific response object
void dump(std::ostream &strm) const override
dumps information about this object
Store the DAP metadata responses.
virtual void write_dmr_response(const std::string &name, std::ostream &os)
Write the stored DMR response to a stream.
static GlobalMetadataStore * get_instance()
virtual libdap::DMR * get_dmr_object(const std::string &name)
Build a DMR object from the cached Response.
virtual MDSReadLock is_dmr_available(const std::string &name)
Is the DMR response for.
virtual bool add_responses(libdap::DDS *dds, const std::string &name)
Add the DAP2 metadata responses using a DDS.
Unlock and close the MDS item when the ReadLock goes out of scope.