bes Updated for version 3.20.13
NgapContainer.cc
1// NgapContainer.cc
2
3// -*- mode: c++; c-basic-offset:4 -*-
4
5// This file is part of ngap_module, A C++ module that can be loaded in to
6// the OPeNDAP Back-End Server (BES) and is able to handle remote requests.
7
8// Copyright (c) 2020 OPeNDAP, Inc.
9// Author: Nathan Potter <ndp@opendap.org>
10//
11// This library is free software; you can redistribute it and/or
12// modify it under the terms of the GNU Lesser General Public
13// License as published by the Free Software Foundation; either
14// version 2.1 of the License, or (at your option) any later version.
15//
16// This library is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19// Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public
22// License along with this library; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24//
25// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26// Authors:
27// ndp Nathan Potter <ndp@opendap.org>
28
29#include "config.h"
30
31#include <map>
32#include <sstream>
33#include <string>
34
35#include "BESStopWatch.h"
36#include "BESLog.h"
37#include "BESSyntaxUserError.h"
38#include "BESInternalError.h"
39#include "BESDebug.h"
40#include "TheBESKeys.h"
41#include "BESContextManager.h"
42#include "CurlUtils.h"
43#include "RemoteResource.h"
44#include "url_impl.h"
45
46#include "NgapContainer.h"
47#include "NgapApi.h"
48#include "NgapNames.h"
49
50#define prolog std::string("NgapContainer::").append(__func__).append("() - ")
51
52using namespace std;
53using namespace bes;
54
55namespace ngap {
56
67NgapContainer::NgapContainer(const string &sym_name,
68 const string &real_name,
69 const string &type) :
70 BESContainer(sym_name, real_name, type),
71 d_dmrpp_rresource(nullptr) {
72 initialize();
73}
74
75
76void NgapContainer::initialize()
77{
78 BESDEBUG(MODULE, prolog << "BEGIN (obj_addr: "<< (void *) this << ")" << endl);
79 BESDEBUG(MODULE, prolog << "sym_name: "<< get_symbolic_name() << endl);
80 BESDEBUG(MODULE, prolog << "real_name: "<< get_real_name() << endl);
81 BESDEBUG(MODULE, prolog << "type: "<< get_container_type() << endl);
82
83 bool found;
84
85 NgapApi ngap_api;
86 if (get_container_type().empty())
87 set_container_type("ngap");
88
89 string uid = BESContextManager::TheManager()->get_context(EDL_UID_KEY, found);
90 BESDEBUG(MODULE, prolog << "EDL_UID_KEY(" << EDL_UID_KEY << "): " << uid << endl);
91
92 string data_access_url = ngap_api.convert_ngap_resty_path_to_data_access_url(get_real_name(), uid);
93
94 set_real_name(data_access_url);
95// Because we know the name is really a URL, then we know the "relative_name" is meaningless
96// So we set it to be the same as "name"
97 set_relative_name(data_access_url);
98 BESDEBUG(MODULE, prolog << "END (obj_addr: "<< (void *) this << ")" << endl);
99
100}
101
105NgapContainer::NgapContainer(const NgapContainer &copy_from) :
106 BESContainer(copy_from),
107 d_dmrpp_rresource(copy_from.d_dmrpp_rresource) {
108 BESDEBUG(MODULE, prolog << "BEGIN object address: "<< (void *) this << " Copying from: " << (void *) &copy_from << endl);
109 // we can not make a copy of this container once the request has
110 // been made
111 if (d_dmrpp_rresource) {
112 string err = (string) "The Container has already been accessed, "
113 + "can not create a copy of this container.";
114 throw BESInternalError(err, __FILE__, __LINE__);
115 }
116 BESDEBUG(MODULE, prolog << "object address: "<< (void *) this << endl);
117}
118
119void NgapContainer::_duplicate(NgapContainer &copy_to) {
120 if (copy_to.d_dmrpp_rresource) {
121 string err = (string) "The Container has already been accessed, "
122 + "can not duplicate this resource.";
123 throw BESInternalError(err, __FILE__, __LINE__);
124 }
125 BESDEBUG(MODULE, prolog << "BEGIN object address: "<< (void *) this << " Copying to: " << (void *) &copy_to << endl);
126 copy_to.d_dmrpp_rresource = d_dmrpp_rresource;
128}
129
132 NgapContainer *container = new NgapContainer;
133 _duplicate(*container);
134 BESDEBUG(MODULE, prolog << "object address: "<< (void *) this << " to: " << (void *)container << endl);
135 return container;
136}
137
138NgapContainer::~NgapContainer() {
139 BESDEBUG(MODULE, prolog << "BEGIN object address: "<< (void *) this << endl);
140 if (d_dmrpp_rresource) {
141 release();
142 }
143 BESDEBUG(MODULE, prolog << "END object address: "<< (void *) this << endl);
144}
145
146
147
154 BESDEBUG(MODULE, prolog << "BEGIN (obj_addr: "<< (void *) this << ")" << endl);
155
156 // Since this the ngap we know that the real_name is a URL.
157 string data_access_url_str = get_real_name();
158
159 // And we know that the dmr++ file should "right next to it" (side-car)
160 string dmrpp_url_str = data_access_url_str + ".dmrpp";
161
162 // And if there's a missing data file (side-car) it should be "right there" too.
163 string missing_data_url_str = data_access_url_str + ".missing";
164
165 BESDEBUG(MODULE, prolog << " data_access_url: " << data_access_url_str << endl);
166 BESDEBUG(MODULE, prolog << " dmrpp_url: " << dmrpp_url_str << endl);
167 BESDEBUG(MODULE, prolog << "missing_data_url: " << missing_data_url_str << endl);
168
169 string href="href=\"";
170 string trusted_url_hack="\" dmrpp:trust=\"true\"";
171
172 string data_access_url_key = href + DATA_ACCESS_URL_KEY + "\"";
173 BESDEBUG(MODULE, prolog << " data_access_url_key: " << data_access_url_key << endl);
174
175 string data_access_url_with_trusted_attr_str = href + data_access_url_str + trusted_url_hack;
176 BESDEBUG(MODULE, prolog << " data_access_url_with_trusted_attr_str: " << data_access_url_with_trusted_attr_str << endl);
177
178 string missing_data_access_url_key = href + MISSING_DATA_ACCESS_URL_KEY + "\"";
179 BESDEBUG(MODULE, prolog << " missing_data_access_url_key: " << missing_data_access_url_key << endl);
180
181 string missing_data_url_with_trusted_attr_str = href + missing_data_url_str + trusted_url_hack;
182 BESDEBUG(MODULE, prolog << "missing_data_url_with_trusted_attr_str: " << missing_data_url_with_trusted_attr_str << endl);
183
184 string type = get_container_type();
185 if (type == "ngap")
186 type = "";
187
188 if (!d_dmrpp_rresource) {
189 BESDEBUG(MODULE, prolog << "Building new RemoteResource (dmr++)." << endl);
190 map<string,string> content_filters;
191 if (inject_data_url()) {
192 content_filters.insert(pair<string,string>(data_access_url_key, data_access_url_with_trusted_attr_str));
193 content_filters.insert(pair<string,string>(missing_data_access_url_key, missing_data_url_with_trusted_attr_str));
194 }
195 shared_ptr<http::url> dmrpp_url(new http::url(dmrpp_url_str, true));
196 {
197 d_dmrpp_rresource = new http::RemoteResource(dmrpp_url);
198 BESStopWatch besTimer;
199 if (BESISDEBUG(MODULE) || BESDebug::IsSet(TIMING_LOG_KEY) || BESLog::TheLog()->is_verbose()){
200 besTimer.start("DMR++ retrieval: "+ dmrpp_url->str());
201 }
202 d_dmrpp_rresource->retrieveResource(content_filters);
203 }
204 BESDEBUG(MODULE, prolog << "Retrieved remote resource: " << dmrpp_url->str() << endl);
205 }
206
207 // TODO This file should be read locked before leaving this method.
208 // 10/8/21 I think the RemoteResource should do that. jhrg
209 string cachedResource = d_dmrpp_rresource->getCacheFileName();
210 BESDEBUG(MODULE, prolog << "Using local cache file: " << cachedResource << endl);
211
212 type = d_dmrpp_rresource->getType();
213 set_container_type(type);
214 BESDEBUG(MODULE, prolog << "Type: " << type << endl);
215 BESDEBUG(MODULE, prolog << "Done retrieving: " << dmrpp_url_str << " returning cached file " << cachedResource << endl);
216 BESDEBUG(MODULE, prolog << "END (obj_addr: "<< (void *) this << ")" << endl);
217
218 return cachedResource; // this should return the dmr++ file name from the NgapCache
219}
220
221
229 // TODO The cache file (that will be) read locked in the access() method must be unlocked here.
230 // If we make that part of the RemoteResource dtor, the unlock will happen here. jhrg
231 if (d_dmrpp_rresource) {
232 BESDEBUG(MODULE, prolog << "Releasing RemoteResource" << endl);
233 delete d_dmrpp_rresource;
234 d_dmrpp_rresource = 0;
235 }
236
237 BESDEBUG(MODULE, prolog << "Done releasing Ngap response" << endl);
238 return true;
239}
240
248void NgapContainer::dump(ostream &strm) const {
249 strm << BESIndent::LMarg << "NgapContainer::dump - (" << (void *) this
250 << ")" << endl;
251 BESIndent::Indent();
252 BESContainer::dump(strm);
253 if (d_dmrpp_rresource) {
254 strm << BESIndent::LMarg << "RemoteResource.getCacheFileName(): " << d_dmrpp_rresource->getCacheFileName()
255 << endl;
256 strm << BESIndent::LMarg << "response headers: ";
257 vector<string> *hdrs = d_dmrpp_rresource->getResponseHeaders();
258 if (hdrs) {
259 strm << endl;
260 BESIndent::Indent();
261 vector<string>::const_iterator i = hdrs->begin();
262 vector<string>::const_iterator e = hdrs->end();
263 for (; i != e; i++) {
264 string hdr_line = (*i);
265 strm << BESIndent::LMarg << hdr_line << endl;
266 }
267 BESIndent::UnIndent();
268 } else {
269 strm << "none" << endl;
270 }
271 } else {
272 strm << BESIndent::LMarg << "response not yet obtained" << endl;
273 }
274 BESIndent::UnIndent();
275}
276
277bool NgapContainer::inject_data_url(){
278 bool result = false;
279 bool found;
280 string key_value;
281 TheBESKeys::TheKeys()->get_value(NGAP_INJECT_DATA_URL_KEY, key_value, found);
282 if (found && key_value == "true") {
283 result = true;
284 }
285 BESDEBUG(MODULE, prolog << "NGAP_INJECT_DATA_URL_KEY(" << NGAP_INJECT_DATA_URL_KEY << "): " << result << endl);
286 return result;
287}
288}
A container is something that holds data. E.G., a netcdf file or a database entry.
Definition: BESContainer.h:65
void set_container_type(const std::string &type)
set the type of data that this container represents, such as cedar or netcdf.
Definition: BESContainer.h:161
std::string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:221
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: BESContainer.cc:73
void set_real_name(const std::string &real_name)
set the real name for this container, such as a file name if reading a data file.
Definition: BESContainer.h:146
std::string get_container_type() const
retrieve the type of data this container holds, such as cedar or netcdf.
Definition: BESContainer.h:232
void set_relative_name(const std::string &relative)
Set the relative name of the object in this container.
Definition: BESContainer.h:152
void _duplicate(BESContainer &copy_to)
duplicate this instance into the passed container
Definition: BESContainer.cc:54
std::string get_real_name() const
retrieve the real name for this container, such as a file name.
Definition: BESContainer.h:180
virtual std::string get_context(const std::string &name, bool &found)
retrieve the value of the specified context from the BES
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Definition: BESDebug.h:168
exception thrown if internal error encountered
virtual bool start(std::string name)
Definition: BESStopWatch.cc:67
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:340
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71
std::string getCacheFileName()
std::vector< std::string > * getResponseHeaders()
std::string getType()
std::string convert_ngap_resty_path_to_data_access_url(const std::string &restified_path, const std::string &uid="")
Converts an NGAP restified granule path into a CMR metadata query for the granule.
Definition: NgapApi.cc:425
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual std::string access()
access the remote target response by making the remote request
virtual BESContainer * ptr_duplicate()
pure abstract method to duplicate this instances of BESContainer
virtual bool release()
release the resources