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