bes  Updated for version 3.20.8
NCRequestHandler.cc
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of nc_handler, a data handler for the OPeNDAP data
4 // server.
5 
6 // Copyright (c) 2002,2003 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This is free software; you can redistribute it and/or modify it under the
10 // terms of the GNU Lesser General Public License as published by the Free
11 // Software Foundation; either version 2.1 of the License, or (at your
12 // option) any later version.
13 //
14 // This software is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 // 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 // NCRequestHandler.cc
26 
27 #include "config_nc.h"
28 
29 #include <string>
30 #include <sstream>
31 #include <exception>
32 
33 #include <DMR.h>
34 #include <DataDDS.h>
35 #include <mime_util.h>
36 #include <D4BaseTypeFactory.h>
37 
38 #include <BESResponseHandler.h>
39 #include <BESResponseNames.h>
40 #include <BESDapNames.h>
41 #include <BESDASResponse.h>
42 #include <BESDDSResponse.h>
43 #include <BESDataDDSResponse.h>
44 #include <BESVersionInfo.h>
45 
46 #include <BESDapError.h>
47 #include <BESInternalFatalError.h>
48 #include <BESDataNames.h>
49 #include <TheBESKeys.h>
50 #include <BESServiceRegistry.h>
51 #include <BESUtil.h>
52 #include <BESDebug.h>
53 #include <BESStopWatch.h>
54 #include <BESContextManager.h>
55 #include <BESDMRResponse.h>
56 
57 #include <ObjMemCache.h>
58 
59 #include <InternalErr.h>
60 #include <Ancillary.h>
61 
62 #include "NCRequestHandler.h"
63 #include "GlobalMetadataStore.h"
64 
65 #define NC_NAME "nc"
66 
67 using namespace libdap;
68 
69 #define prolog std::string("NCRequestHandler::").append(__func__).append("() - ")
70 
71 
72 bool NCRequestHandler::_show_shared_dims = true;
73 bool NCRequestHandler::_show_shared_dims_set = false;
74 
75 bool NCRequestHandler::_ignore_unknown_types = false;
76 bool NCRequestHandler::_ignore_unknown_types_set = false;
77 
78 bool NCRequestHandler::_promote_byte_to_short = false;
79 bool NCRequestHandler::_promote_byte_to_short_set = false;
80 bool NCRequestHandler::_use_mds = false;
81 
82 unsigned int NCRequestHandler::_cache_entries = 100;
83 float NCRequestHandler::_cache_purge_level = 0.2;
84 
85 ObjMemCache *NCRequestHandler::das_cache = 0;
86 ObjMemCache *NCRequestHandler::dds_cache = 0;
87 ObjMemCache *NCRequestHandler::datadds_cache = 0;
88 ObjMemCache *NCRequestHandler::dmr_cache = 0;
89 
90 extern void nc_read_dataset_attributes(DAS & das, const string & filename);
91 extern void nc_read_dataset_variables(DDS & dds, const string & filename);
92 
99 static bool version_ge(const string &version, float value)
100 {
101  try {
102  float v;
103  istringstream iss(version);
104  iss >> v;
105  //cerr << "version: " << v << ", value: " << value << endl;
106  return (v >= value);
107  }
108  catch (...) {
109  return false;
110  }
111 
112  return false; // quiet warnings...
113 }
114 
118 static bool get_bool_key(const string &key, bool def_val)
119 {
120  bool found = false;
121  string doset = "";
122  const string dosettrue = "true";
123  const string dosetyes = "yes";
124 
125  TheBESKeys::TheKeys()->get_value(key, doset, found);
126  if (true == found) {
127  doset = BESUtil::lowercase(doset);
128  return (dosettrue == doset || dosetyes == doset);
129  }
130  return def_val;
131 }
132 
133 static unsigned int get_uint_key(const string &key, unsigned int def_val)
134 {
135  bool found = false;
136  string doset = "";
137 
138  TheBESKeys::TheKeys()->get_value(key, doset, found);
139  if (true == found) {
140  return atoi(doset.c_str()); // use better code TODO
141  }
142  else {
143  return def_val;
144  }
145 }
146 
147 static float get_float_key(const string &key, float def_val)
148 {
149  bool found = false;
150  string doset = "";
151 
152  TheBESKeys::TheKeys()->get_value(key, doset, found);
153  if (true == found) {
154  return atof(doset.c_str()); // use better code TODO
155  }
156  else {
157  return def_val;
158  }
159 }
160 
161 NCRequestHandler::NCRequestHandler(const string &name) :
162  BESRequestHandler(name)
163 {
164  BESDEBUG(NC_NAME, prolog << "BEGIN" << endl);
165 
166  add_method(DAS_RESPONSE, NCRequestHandler::nc_build_das);
167  add_method(DDS_RESPONSE, NCRequestHandler::nc_build_dds);
168  add_method(DATA_RESPONSE, NCRequestHandler::nc_build_data);
169 
170  add_method(DMR_RESPONSE, NCRequestHandler::nc_build_dmr);
171  add_method(DAP4DATA_RESPONSE, NCRequestHandler::nc_build_dmr);
172 
173  add_method(HELP_RESPONSE, NCRequestHandler::nc_build_help);
174  add_method(VERS_RESPONSE, NCRequestHandler::nc_build_version);
175 
176  // TODO replace with get_bool_key above 5/21/16 jhrg
177 
178  if (NCRequestHandler::_show_shared_dims_set == false) {
179  bool key_found = false;
180  string doset;
181  TheBESKeys::TheKeys()->get_value("NC.ShowSharedDimensions", doset, key_found);
182  if (key_found) {
183  // It was set in the conf file
184  NCRequestHandler::_show_shared_dims_set = true;
185 
186  doset = BESUtil::lowercase(doset);
187  if (doset == "true" || doset == "yes") {
188  NCRequestHandler::_show_shared_dims = true;
189  }
190  else
191  NCRequestHandler::_show_shared_dims = false;
192  }
193  }
194 
195  if (NCRequestHandler::_ignore_unknown_types_set == false) {
196  bool key_found = false;
197  string doset;
198  TheBESKeys::TheKeys()->get_value("NC.IgnoreUnknownTypes", doset, key_found);
199  if (key_found) {
200  doset = BESUtil::lowercase(doset);
201  if (doset == "true" || doset == "yes")
202  NCRequestHandler::_ignore_unknown_types = true;
203  else
204  NCRequestHandler::_ignore_unknown_types = false;
205 
206  NCRequestHandler::_ignore_unknown_types_set = true;
207  }
208  }
209 
210  if (NCRequestHandler::_promote_byte_to_short_set == false) {
211  bool key_found = false;
212  string doset;
213  TheBESKeys::TheKeys()->get_value("NC.PromoteByteToShort", doset, key_found);
214  if (key_found) {
215  doset = BESUtil::lowercase(doset);
216  if (doset == "true" || doset == "yes")
217  NCRequestHandler::_promote_byte_to_short = true;
218  else
219  NCRequestHandler::_promote_byte_to_short = false;
220 
221  NCRequestHandler::_promote_byte_to_short_set = true;
222  }
223  }
224 
225  NCRequestHandler::_use_mds = get_bool_key("NC.UseMDS",false);
226  NCRequestHandler::_cache_entries = get_uint_key("NC.CacheEntries", 0);
227  NCRequestHandler::_cache_purge_level = get_float_key("NC.CachePurgeLevel", 0.2);
228 
229  if (get_cache_entries()) { // else it stays at its default of null
230  das_cache = new ObjMemCache(get_cache_entries(), get_cache_purge_level());
231  dds_cache = new ObjMemCache(get_cache_entries(), get_cache_purge_level());
232  datadds_cache = new ObjMemCache(get_cache_entries(), get_cache_purge_level());
233  dmr_cache = new ObjMemCache(get_cache_entries(), get_cache_purge_level());
234  }
235 
236  BESDEBUG(NC_NAME, prolog << "END" << endl);
237 }
238 
239 NCRequestHandler::~NCRequestHandler()
240 {
241  delete das_cache;
242  delete dds_cache;
243  delete datadds_cache;
244  delete dmr_cache;
245 }
246 
247 bool NCRequestHandler::nc_build_das(BESDataHandlerInterface & dhi)
248 {
249  BESStopWatch sw;
250  if (BESDebug::IsSet(TIMING_LOG_KEY))
251  sw.start("NCRequestHandler::nc_build_das", dhi.data[REQUEST_ID]);
252 
253  BESDEBUG(NC_NAME, prolog << "BEGIN" << endl);
254 
255  BESResponseObject *response = dhi.response_handler->get_response_object();
256  BESDASResponse *bdas = dynamic_cast<BESDASResponse *> (response);
257  if (!bdas)
258  throw BESInternalError("cast error", __FILE__, __LINE__);
259 
260  try {
261  string container_name = bdas->get_explicit_containers() ? dhi.container->get_symbolic_name(): "";
262 
263  DAS *das = bdas->get_das();
264  if (!container_name.empty()) das->container_name(container_name);
265  string accessed = dhi.container->access();
266 
267  // Look in memory cache if it's initialized
268  DAS *cached_das_ptr = 0;
269  if (das_cache && (cached_das_ptr = static_cast<DAS*>(das_cache->get(accessed)))) {
270  // copy the cached DAS into the BES response object
271  BESDEBUG(NC_NAME, prolog << "DAS Cached hit for : " << accessed << endl);
272  *das = *cached_das_ptr;
273  }
274  else {
275  nc_read_dataset_attributes(*das, accessed);
276  Ancillary::read_ancillary_das(*das, accessed);
277  if (das_cache) {
278  // add a copy
279  BESDEBUG(NC_NAME, prolog << "DAS added to the cache for : " << accessed << endl);
280  das_cache->add(new DAS(*das), accessed);
281  }
282  }
283 
284  bdas->clear_container();
285  }
286  catch (BESError &e) {
287  throw;
288  }
289  catch (InternalErr & e) {
290  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
291  throw ex;
292  }
293  catch (Error & e) {
294  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
295  throw ex;
296  }
297  catch (std::exception &e) {
298  string s = string("C++ Exception: ") + e.what();
299  BESInternalFatalError ex(s, __FILE__, __LINE__);
300  throw ex;
301  }
302  catch (...) {
303  string s = "Unknown exception caught building DAS";
304  BESInternalFatalError ex(s, __FILE__, __LINE__);
305  throw ex;
306  }
307 
308  BESDEBUG(NC_NAME, prolog << "END" << endl);
309  return true;
310 }
311 
318 void NCRequestHandler::get_dds_with_attributes(const string& dataset_name, const string& container_name, DDS* dds)
319 {
320  // Look in memory cache if it's initialized
321  DDS* cached_dds_ptr = 0;
322  if (dds_cache && (cached_dds_ptr = static_cast<DDS*>(dds_cache->get(dataset_name)))) {
323  // copy the cached DDS into the BES response object. Assume that any cached DDS
324  // includes the DAS information.
325  BESDEBUG(NC_NAME, prolog << "DDS Cached hit for : " << dataset_name << endl);
326  *dds = *cached_dds_ptr; // Copy the referenced object
327  }
328  else {
329  if (!container_name.empty()) dds->container_name(container_name);
330  dds->filename(dataset_name);
331 
332  nc_read_dataset_variables(*dds, dataset_name);
333 
334  DAS* das = 0;
335  if (das_cache && (das = static_cast<DAS*>(das_cache->get(dataset_name)))) {
336  BESDEBUG(NC_NAME, prolog << "DAS Cached hit for : " << dataset_name << endl);
337  dds->transfer_attributes(das); // no need to cop the cached DAS
338  }
339  else {
340  das = new DAS;
341  // This looks at the 'use explicit containers' prop, and if true
342  // sets the current container for the DAS.
343  if (!container_name.empty()) das->container_name(container_name);
344 
345  nc_read_dataset_attributes(*das, dataset_name);
346  Ancillary::read_ancillary_das(*das, dataset_name);
347 
348  dds->transfer_attributes(das);
349 
350  // Only free the DAS if it's not added to the cache
351  if (das_cache) {
352  // add a copy
353  BESDEBUG(NC_NAME, prolog << "DAS added to the cache for : " << dataset_name << endl);
354  das_cache->add(das, dataset_name);
355  }
356  else {
357  delete das;
358  }
359  }
360 
361  if (dds_cache) {
362  // add a copy
363  BESDEBUG(NC_NAME, prolog << "DDS added to the cache for : " << dataset_name << endl);
364  dds_cache->add(new DDS(*dds), dataset_name);
365  }
366  }
367 }
368 
369 void NCRequestHandler::get_dds_without_attributes(const string& dataset_name, const string& container_name, DDS* dds)
370 {
371  // Look in memory cache if it's initialized
372  DDS* cached_datadds_ptr = 0;
373  if (datadds_cache && (cached_datadds_ptr = static_cast<DDS*>(datadds_cache->get(dataset_name)))) {
374  // copy the cached DDS into the BES response object.
375  BESDEBUG(NC_NAME, prolog << "DataDDS Cached hit for : " << dataset_name << endl);
376  *dds = *cached_datadds_ptr; // Copy the referenced object
377  }
378  else {
379  if (!container_name.empty()) dds->container_name(container_name);
380  dds->filename(dataset_name);
381 
382  nc_read_dataset_variables(*dds, dataset_name);
383 
384  if (datadds_cache) {
385  // add a copy
386  BESDEBUG(NC_NAME, prolog << "DataDDS added to the cache for : " << dataset_name << endl);
387  datadds_cache->add(new DDS(*dds), dataset_name);
388  }
389  }
390 }
391 
392 
393 bool NCRequestHandler::nc_build_dds(BESDataHandlerInterface & dhi)
394 {
395 
396  BESStopWatch sw;
397  if (BESDebug::IsSet(TIMING_LOG_KEY))
398  sw.start("NCRequestHandler::nc_build_dds", dhi.data[REQUEST_ID]);
399 
400  BESResponseObject *response = dhi.response_handler->get_response_object();
401  BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *> (response);
402  if (!bdds)
403  throw BESInternalError("cast error", __FILE__, __LINE__);
404 
405  try {
406  // If there's no value for this set in the conf file, look at the context
407  // and set the default behavior based on the protocol version clients say
408  // they will accept.
409  if (NCRequestHandler::_show_shared_dims_set == false) {
410  bool context_found = false;
411  string context_value = BESContextManager::TheManager()->get_context("xdap_accept", context_found);
412  if (context_found) {
413  BESDEBUG(NC_NAME, prolog << "xdap_accept: " << context_value << endl);
414  if (version_ge(context_value, 3.2))
415  NCRequestHandler::_show_shared_dims = false;
416  else
417  NCRequestHandler::_show_shared_dims = true;
418  }
419  }
420 
421  string container_name = bdds->get_explicit_containers() ? dhi.container->get_symbolic_name(): "";
422  DDS *dds = bdds->get_dds();
423 
424  // Build a DDS in the empty DDS object
425  string filename = dhi.container->access();
426  get_dds_with_attributes(filename, container_name, dds);
427 
428  bdds->set_constraint(dhi);
429  bdds->clear_container();
430  }
431  catch (BESError &e) {
432  throw e;
433  }
434  catch (InternalErr & e) {
435  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
436  throw ex;
437  }
438  catch (Error & e) {
439  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
440  throw ex;
441  }
442  catch (std::exception &e) {
443  string s = string("C++ Exception: ") + e.what();
444  BESInternalFatalError ex(s, __FILE__, __LINE__);
445  throw ex;
446  }
447  catch (...) {
448  string s = "Unknown exception caught building DDS";
449  BESInternalFatalError ex(s, __FILE__, __LINE__);
450  throw ex;
451  }
452 
453  return true;
454 }
455 
456 bool NCRequestHandler::nc_build_data(BESDataHandlerInterface & dhi)
457 {
458  BESStopWatch sw;
459  if (BESDebug::IsSet(TIMING_LOG_KEY))
460  sw.start("NCRequestHandler::nc_build_data", dhi.data[REQUEST_ID]);
461 
462  BESResponseObject *response = dhi.response_handler->get_response_object();
463  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *> (response);
464  if (!bdds)
465  throw BESInternalError("cast error", __FILE__, __LINE__);
466 
467  try {
468  if (NCRequestHandler::_show_shared_dims_set == false) {
469  bool context_found = false;
470  string context_value = BESContextManager::TheManager()->get_context("xdap_accept", context_found);
471  if (context_found) {
472  BESDEBUG(NC_NAME, prolog << "xdap_accept: " << context_value << endl);
473  if (version_ge(context_value, 3.2))
474  NCRequestHandler::_show_shared_dims = false;
475  else
476  NCRequestHandler::_show_shared_dims = true;
477  }
478  }
479 
480  string container_name = bdds->get_explicit_containers() ? dhi.container->get_symbolic_name(): "";
481  DDS *dds = bdds->get_dds();
482 
483  // Build a DDS in the empty DDS object,don't include attributes here. KY 10/30/19
484  get_dds_without_attributes(dhi.container->access(), container_name, dds);
485 
486  bdds->set_constraint(dhi);
487  BESDEBUG(NC_NAME, prolog << "Data ACCESS build_data(): set the including attribute flag to false: "<<dhi.container->access() << endl);
488  bdds->set_ia_flag(false);
489  bdds->clear_container();
490  }
491  catch (BESError &e) {
492  throw;
493  }
494  catch (InternalErr & e) {
495  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
496  throw ex;
497  }
498  catch (Error & e) {
499  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
500  throw ex;
501  }
502  catch (std::exception &e) {
503  string s = string("C++ Exception: ") + e.what();
504  BESInternalFatalError ex(s, __FILE__, __LINE__);
505  throw ex;
506  }
507  catch (...) {
508  string s = "Unknown exception caught building DAS";
509  BESInternalFatalError ex(s, __FILE__, __LINE__);
510  throw ex;
511  }
512 
513  return true;
514 }
515 
516 bool NCRequestHandler::nc_build_dmr(BESDataHandlerInterface &dhi)
517 {
518  BESStopWatch sw;
519  if (BESDebug::IsSet(TIMING_LOG_KEY))
520  sw.start("NCRequestHandler::nc_build_dmr", dhi.data[REQUEST_ID]);
521 
522  // Extract the DMR Response object - this holds the DMR used by the
523  // other parts of the framework.
524  BESResponseObject *response = dhi.response_handler->get_response_object();
525  BESDMRResponse &bdmr = dynamic_cast<BESDMRResponse &>(*response);
526 
527  // Because this code does not yet know how to build a DMR directly, use
528  // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
529  // First step, build the 'full DDS'
530  string dataset_name = dhi.container->access();
531 
532  // Get the DMR made by the BES in the BES/dap/BESDMRResponseHandler, make sure there's a
533  // factory we can use and then dump the DAP2 variables and attributes in using the
534  // BaseType::transform_to_dap4() method that transforms individual variables
535  DMR *dmr = bdmr.get_dmr();
536 
537  try {
538  DMR* cached_dmr_ptr = 0;
539  if (dmr_cache && (cached_dmr_ptr = static_cast<DMR*>(dmr_cache->get(dataset_name)))) {
540  // copy the cached DMR into the BES response object
541  BESDEBUG(NC_NAME, prolog << "DMR Cached hit for : " << dataset_name << endl);
542  *dmr = *cached_dmr_ptr; // Copy the referenced object
543  dmr->set_request_xml_base(bdmr.get_request_xml_base());
544  }
545  else {
546 #if 0
547  // this version builds and caches the DDS/DAS info.
548  BaseTypeFactory factory;
549  DDS dds(&factory, name_path(dataset_name), "3.2");
550 
551  // This will get the DDS, either by building it or from the cache
552  get_dds_with_attributes(dataset_name, "", &dds);
553 
554  dmr->set_factory(new D4BaseTypeFactory);
555  dmr->build_using_dds(dds);
556 #else
557  // This version builds a DDS only to build the resulting DMR. The DDS is
558  // not cached. It does look in the DDS cache, just in case...
559  dmr->set_factory(new D4BaseTypeFactory);
560 
561  DDS *dds_ptr = 0;
562  if (dds_cache && (dds_ptr = static_cast<DDS*>(dds_cache->get(dataset_name)))) {
563  // Use the cached DDS; Assume that all cached DDS objects hold DAS info too
564  BESDEBUG(NC_NAME, prolog << "DDS Cached hit (while building DMR) for : " << dataset_name << endl);
565 
566  dmr->build_using_dds(*dds_ptr);
567  }
568  else {
569  // Build a throw-away DDS; don't bother to cache it. DMR's don't support
570  // containers.
571  BaseTypeFactory factory;
572  DDS dds(&factory, name_path(dataset_name), "3.2");
573 
574  dds.filename(dataset_name);
575  nc_read_dataset_variables(dds, dataset_name);
576 
577  DAS das;
578 
579  nc_read_dataset_attributes(das, dataset_name);
580  Ancillary::read_ancillary_das(das, dataset_name);
581 
582  dds.transfer_attributes(&das);
583  dmr->build_using_dds(dds);
584  }
585 #endif
586 
587  if (dmr_cache) {
588  // add a copy
589  BESDEBUG(NC_NAME, prolog << "DMR added to the cache for : " << dataset_name << endl);
590  dmr_cache->add(new DMR(*dmr), dataset_name);
591  }
592  }
593 
594  // Instead of fiddling with the internal storage of the DHI object,
595  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
596  // methods to set the constraints. But, why? Ans: from Patrick is that
597  // in the 'container' mode of BES each container can have a different
598  // CE.
599  bdmr.set_dap4_constraint(dhi);
600  bdmr.set_dap4_function(dhi);
601  }
602  catch (InternalErr &e) {
603  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
604  }
605  catch (Error &e) {
606  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
607  }
608  catch (...) {
609  throw BESDapError("Caught unknown error build NC DMR response", true, unknown_error, __FILE__, __LINE__);
610  }
611 
612  return true;
613 }
614 
615 bool NCRequestHandler::nc_build_help(BESDataHandlerInterface & dhi)
616 {
617  BESStopWatch sw;
618  if (BESDebug::IsSet(TIMING_LOG_KEY))
619  sw.start("NCRequestHandler::nc_build_help", dhi.data[REQUEST_ID]);
620 
621  BESResponseObject *response = dhi.response_handler->get_response_object();
622  BESInfo *info = dynamic_cast<BESInfo *> (response);
623  if (!info)
624  throw BESInternalError("cast error", __FILE__, __LINE__);
625 
626  map < string, string > attrs;
627  attrs["name"] = MODULE_NAME ;
628  attrs["version"] = MODULE_VERSION ;
629 #if 0
630  attrs["name"] = PACKAGE_NAME;
631  attrs["version"] = PACKAGE_VERSION;
632 #endif
633  list < string > services;
634  BESServiceRegistry::TheRegistry()->services_handled(NC_NAME, services);
635  if (services.size() > 0) {
636  string handles = BESUtil::implode(services, ',');
637  attrs["handles"] = handles;
638  }
639  info->begin_tag("module", &attrs);
640  info->end_tag("module");
641 
642  return true;
643 }
644 
645 bool NCRequestHandler::nc_build_version(BESDataHandlerInterface & dhi)
646 {
647  BESStopWatch sw;
648  if (BESDebug::IsSet(TIMING_LOG_KEY))
649  sw.start("NCRequestHandler::nc_build_version", dhi.data[REQUEST_ID]);
650 
651  BESResponseObject *response = dhi.response_handler->get_response_object();
652  BESVersionInfo *info = dynamic_cast<BESVersionInfo *> (response);
653  if (!info)
654  throw BESInternalError("cast error", __FILE__, __LINE__);
655 
656 #if 0
657  info->add_module(PACKAGE_NAME, PACKAGE_VERSION);
658 #endif
659  info->add_module(MODULE_NAME, MODULE_VERSION);
660 
661  return true;
662 }
663 
664 void NCRequestHandler::add_attributes(BESDataHandlerInterface &dhi) {
665 
666  BESResponseObject *response = dhi.response_handler->get_response_object();
667  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(response);
668  if (!bdds)
669  throw BESInternalError("cast error", __FILE__, __LINE__);
670  DDS *dds = bdds->get_dds();
671  string container_name = bdds->get_explicit_containers() ? dhi.container->get_symbolic_name(): "";
672  string dataset_name = dhi.container->access();
673  DAS* das = 0;
674  if (das_cache && (das = static_cast<DAS*>(das_cache->get(dataset_name)))) {
675  BESDEBUG(NC_NAME, prolog << "DAS Cached hit for : " << dataset_name << endl);
676  dds->transfer_attributes(das); // no need to cop the cached DAS
677  }
678  else {
679  das = new DAS;
680  // This looks at the 'use explicit containers' prop, and if true
681  // sets the current container for the DAS.
682  if (!container_name.empty()) das->container_name(container_name);
683 
684  // Here we will check if we can generate DAS by parsing from MDS
685  if(true == get_use_mds()) {
686 
688  bool valid_mds = true;
689  if(NULL == mds)
690  valid_mds = false;
691  else if(false == mds->cache_enabled())
692  valid_mds = false;
693  if(true ==valid_mds) {
694  string rel_file_path = dhi.container->get_relative_name();
695  // Obtain the DAS lock in MDS
696  bes::GlobalMetadataStore::MDSReadLock mds_das_lock = mds->is_das_available(rel_file_path);
697  if(mds_das_lock()) {
698  BESDEBUG(NC_NAME, prolog << "Using MDS to generate DAS in the data response for file " << dataset_name << endl);
699  mds->parse_das_from_mds(das,rel_file_path);
700  }
701  else {//Don't fail, still build das from the NC APIs
702  nc_read_dataset_attributes(*das, dataset_name);
703  }
704  mds_das_lock.clearLock();
705  }
706  else {
707  nc_read_dataset_attributes(*das, dataset_name);
708  }
709  }
710  else {//Cannot parse from MDS, still build the attributes from NC APIs.
711  nc_read_dataset_attributes(*das, dataset_name);
712  }
713  Ancillary::read_ancillary_das(*das, dataset_name);
714 
715  dds->transfer_attributes(das);
716 
717  // Only free the DAS if it's not added to the cache
718  if (das_cache) {
719  // add a copy
720  BESDEBUG(NC_NAME, prolog << "DAS added to the cache for : " << dataset_name << endl);
721  das_cache->add(das, dataset_name);
722  }
723  else {
724  delete das;
725  }
726  }
727  BESDEBUG(NC_NAME, prolog << "Data ACCESS in add_attributes(): set the including attribute flag to true: "<<dataset_name << endl);
728  bdds->set_ia_flag(true);
729  return;
730 }
std::string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:221
std::string get_relative_name() const
Get the relative name of the object in this container.
Definition: BESContainer.h:186
virtual std::string access()=0
returns the true name of this container
virtual std::string get_context(const std::string &name, bool &found)
retrieve the value of the specified context from the BES
Represents an OPeNDAP DAS DAP2 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
Holds a DDS object within the BES.
virtual void clear_container()
clear the container in the DAP response object
libdap::DDS * get_dds()
Represents an OPeNDAP DMR DAP4 data object within the BES.
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:59
virtual void set_dap4_function(BESDataHandlerInterface &dhi)
set the constraint depending on the context
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
virtual void set_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
bool get_explicit_containers() const
Should containers be explicitly represented in the DD* responses?
std::string get_request_xml_base() const
Return the xml:base URL for this request.
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
Structure storing information used by the BES to handle the request.
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
BESContainer * container
pointer to current container in this interface
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Definition: BESDebug.h:160
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
informational response object
Definition: BESInfo.h:63
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
Represents a specific data type request handler.
virtual BESResponseObject * get_response_object()
return the current response object
Abstract base class representing a specific set of information in response to a request to the BES.
virtual void services_handled(const std::string &handler, std::list< std::string > &services)
returns the list of servies provided by the handler in question
virtual bool start(std::string name)
Definition: BESStopWatch.cc:67
static std::string lowercase(const std::string &s)
Definition: BESUtil.cc:200
static std::string implode(const std::list< std::string > &values, char delim)
Definition: BESUtil.cc:638
An in-memory cache for DapObj (DAS, DDS, ...) objects.
Definition: ObjMemCache.h:84
virtual void add(libdap::DapObj *obj, const std::string &key)
Add an object to the cache and associate it with a key.
Definition: ObjMemCache.cc:63
virtual libdap::DapObj * get(const std::string &key)
Get the cached pointer.
Definition: ObjMemCache.cc:105
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:339
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71
Store the DAP metadata responses.
static GlobalMetadataStore * get_instance()
virtual MDSReadLock is_das_available(const std::string &name)
Is the DAS response for.
Unlock and close the MDS item when the ReadLock goes out of scope.