bes Updated for version 3.20.13
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 <libdap/DMR.h>
34#include <libdap/DataDDS.h>
35#include <libdap/mime_util.h>
36#include <libdap/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 <libdap/InternalErr.h>
60#include <libdap/Ancillary.h>
61
62#include "NCRequestHandler.h"
63#include "GlobalMetadataStore.h"
64
65#define NC_NAME "nc"
66
67using namespace libdap;
68
69#define prolog std::string("NCRequestHandler::").append(__func__).append("() - ")
70
71
72bool NCRequestHandler::_show_shared_dims = true;
73bool NCRequestHandler::_show_shared_dims_set = false;
74
75bool NCRequestHandler::_ignore_unknown_types = false;
76bool NCRequestHandler::_ignore_unknown_types_set = false;
77
78bool NCRequestHandler::_promote_byte_to_short = false;
79bool NCRequestHandler::_promote_byte_to_short_set = false;
80bool NCRequestHandler::_use_mds = false;
81
82unsigned int NCRequestHandler::_cache_entries = 100;
83float NCRequestHandler::_cache_purge_level = 0.2;
84
85ObjMemCache *NCRequestHandler::das_cache = 0;
86ObjMemCache *NCRequestHandler::dds_cache = 0;
87ObjMemCache *NCRequestHandler::datadds_cache = 0;
88ObjMemCache *NCRequestHandler::dmr_cache = 0;
89
90extern void nc_read_dataset_attributes(DAS & das, const string & filename);
91extern void nc_read_dataset_variables(DDS & dds, const string & filename);
92
99static 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
118static 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
133static 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
147static 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
161NCRequestHandler::NCRequestHandler(const string &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
239NCRequestHandler::~NCRequestHandler()
240{
241 delete das_cache;
242 delete dds_cache;
243 delete datadds_cache;
244 delete dmr_cache;
245}
246
247bool 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
318void 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
369void 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
393bool 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
456bool 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
516bool 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
615bool 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
645bool 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
664void 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:168
Base exception class for the BES with basic string message.
Definition: BESError.h:59
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:254
static std::string implode(const std::list< std::string > &values, char delim)
Definition: BESUtil.cc:617
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:340
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.