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 
52 using namespace std;
53 using namespace bes;
54 
55 namespace ngap {
56 
67 NgapContainer::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 
76 void 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 
105 NgapContainer::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 
119 void 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;
127  BESContainer::_duplicate(copy_to);
128 }
129 
130 BESContainer *
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 
138 NgapContainer::~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 
248 void 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 
277 bool 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