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