bes Updated for version 3.20.13
build_dmrpp.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of the Hyrax data server.
4
5// Copyright (c) 2018 OPeNDAP, Inc.
6// Author: James Gallagher <jgallagher@opendap.org>
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Lesser General Public
10// License as published by the Free Software Foundation; either
11// version 2.1 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Lesser General Public License for more details.
17//
18// You should have received a copy of the GNU Lesser General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21//
22// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
23
24#include "config.h"
25
26
27#include <iostream>
28#include <sstream>
29#include <memory>
30#include <iterator>
31
32#include <unistd.h>
33#include <cstdlib>
34#include <libgen.h>
35
36#include <libdap/Array.h>
37#include <libdap/util.h>
38#include <libdap/D4Attributes.h>
39#include <libdap/D4ParserSax2.h>
40
41#include <TheBESKeys.h>
42#include <BESUtil.h>
43#include <BESDebug.h>
44#include <BESError.h>
45
46#include "DMRpp.h"
47#include "DmrppTypeFactory.h"
48#include "DmrppD4Group.h"
49#include "DmrppMetadataStore.h"
50
51#include "build_dmrpp_util.h"
52
53using namespace std;
54using namespace libdap;
55using namespace dmrpp;
56using namespace build_dmrpp_util;
57
58#define DEBUG_KEY "metadata_store,dmrpp_store,dmrpp"
59#define ROOT_DIRECTORY "BES.Catalog.catalog.RootDirectory"
60
67static string cmdln(int argc, char *argv[])
68{
69 stringstream ss;
70 for(int i=0; i<argc; i++) {
71 if (i > 0)
72 ss << " ";
73 ss << argv[i];
74 }
75 return ss.str();
76}
77
85void inject_version_and_configuration(int argc, char **argv, DMRpp *dmrpp)
86{
87 dmrpp->set_version(CVER);
88
89 // Build the version attributes for the DMR++
90 auto version = new D4Attribute("build_dmrpp_metadata", StringToD4AttributeType("container"));
91
92 auto build_dmrpp_version = new D4Attribute("build_dmrpp", StringToD4AttributeType("string"));
93 build_dmrpp_version->add_value(CVER);
94 version->attributes()->add_attribute_nocopy(build_dmrpp_version);
95
96 auto bes_version = new D4Attribute("bes", StringToD4AttributeType("string"));
97 bes_version->add_value(CVER);
98 version->attributes()->add_attribute_nocopy(bes_version);
99
100 stringstream ldv;
101 ldv << libdap_name() << "-" << libdap_version();
102 auto libdap4_version = new D4Attribute("libdap", StringToD4AttributeType("string"));
103 libdap4_version->add_value(ldv.str());
104 version->attributes()->add_attribute_nocopy(libdap4_version);
105
106 if(!TheBESKeys::ConfigFile.empty()) {
107 // What is the BES configuration in play?
108 auto config = new D4Attribute("configuration", StringToD4AttributeType("string"));
109 config->add_value(TheBESKeys::TheKeys()->get_as_config());
110 version->attributes()->add_attribute_nocopy(config);
111 }
112
113 // How was build_dmrpp invoked?
114 auto invoke = new D4Attribute("invocation", StringToD4AttributeType("string"));
115 invoke->add_value(cmdln(argc, argv));
116 version->attributes()->add_attribute_nocopy(invoke);
117
118 // Inject version and configuration attributes into DMR here.
119 dmrpp->root()->attributes()->add_attribute_nocopy(version);
120}
121
122void usage() {
123 const char *help = R"(
124 build_dmrpp -h: Show this help
125
126 build_dmrpp -V: Show build versions for components that make up the program
127
128 build_dmrpp -c <bes.conf> -f <data file> [-u <href url>]: Build the DMR++ using the <bes.conf>
129 options to initialize the software for the <data file>. Optionally substitute the <href url>.
130 Builds the DMR using the HDF5 handler as configured using the options in the <bes.conf>.
131
132 build_dmrpp build_dmrpp -f <data file> -r <dmr file> [-u <href url>]: As above, but uses the DMR
133 read from the given file (so it does not run the HDF5 handler code and does not require the
134 Metadata Store - MDS - be configured). Note that the get_dmrpp command appears to use this
135 option and thus, the configuration options listed in the built DMR++ files lack the MDS setup.
136
137 Other options:
138 -v: Verbose
139 -d: Turn on BES software debugging output
140 -M: Add information about the build_dmrpp software, incl versions, to the built DMR++)";
141
142 cerr << help << endl;
143}
144
145int main(int argc, char *argv[]) {
146 string h5_file_name;
147 string h5_dset_path;
148 string dmr_name;
149 string url_name;
150 bool add_production_metadata = false;
151
152 int option_char;
153 while ((option_char = getopt(argc, argv, "c:f:r:u:dhvVM")) != -1) {
154 switch (option_char) {
155 case 'V':
156 cerr << basename(argv[0]) << "-" << CVER << " (bes-"<< CVER << ", " << libdap_name() << "-"
157 << libdap_version() << ")" << endl;
158 return 0;
159
160 case 'v':
161 build_dmrpp_util::verbose = true; // verbose hdf5 errors
162 break;
163
164 case 'd':
165 BESDebug::SetUp(string("cerr,").append(DEBUG_KEY));
166 break;
167
168 case 'f':
169 h5_file_name = optarg;
170 break;
171
172 case 'r':
173 dmr_name = optarg;
174 break;
175
176 case 'u':
177 url_name = optarg;
178 break;
179
180 case 'c':
181 TheBESKeys::ConfigFile = optarg;
182 break;
183
184 case 'M':
185 add_production_metadata = true;
186 break;
187
188 case 'h':
189 usage();
190 exit(EXIT_FAILURE);
191
192 default:
193 break;
194 }
195 }
196
197 if (h5_file_name.empty()) {
198 cerr << "HDF5 file name must be given (-f <input>)." << endl;
199 return EXIT_FAILURE;
200 }
201
202 try {
203 // Turn off automatic hdf5 error printing.
204 // See: https://support.hdfgroup.org/HDF5/doc1.8/RM/RM_H5E.html#Error-SetAuto2
205
206 // For a given HDF5, get info for all the HDF5 datasets in a DMR or for a
207 // given HDF5 dataset
208 if (!dmr_name.empty()) {
209 // Get dmr:
210 DMRpp dmrpp;
212 dmrpp.set_factory(&dtf);
213
214 ifstream in(dmr_name.c_str());
215 D4ParserSax2 parser;
216 parser.intern(in, &dmrpp, false);
217
218 add_chunk_information(h5_file_name, &dmrpp);
219
220 if (add_production_metadata) {
221 inject_version_and_configuration(argc, argv, &dmrpp);
222 }
223
224 XMLWriter writer;
225 dmrpp.print_dmrpp(writer, url_name);
226
227 cout << writer.get_doc();
228 } else {
229 string bes_data_root = TheBESKeys::TheKeys()->read_string_key(ROOT_DIRECTORY, "");
230 if (bes_data_root.empty()) {
231 cerr << "Could not find the data directory." << endl;
232 return EXIT_FAILURE;
233 }
234
235 // Use the values from the bes.conf file... jhrg 5/21/18
237 if (!mds) {
238 cerr << "The Metadata Store (MDS) must be configured for this command to work (but see the -r option)." << endl;
239 return EXIT_FAILURE;
240 }
241
242 // Use the full path to open the file, but use the 'name' (which is the
243 // path relative to the BES Data Root) with the MDS.
244 // Changed this to utilize assemblePath() because simply concatenating the strings
245 // is fragile. - ndp 6/6/18
246 string h5_file_path = BESUtil::assemblePath(bes_data_root, h5_file_name);
247
248 bes::DmrppMetadataStore::MDSReadLock lock = mds->is_dmr_available(h5_file_path, h5_file_name, "h5");
249 if (lock()) {
250 // parse the DMR into a DMRpp (that uses the DmrppTypes)
251 unique_ptr<DMRpp> dmrpp(dynamic_cast<DMRpp *>(mds->get_dmr_object(h5_file_name /*h5_file_path*/)));
252 if (!dmrpp) {
253 cerr << "Expected a DMR++ object from the DmrppMetadataStore." << endl;
254 return EXIT_FAILURE;
255 }
256
257 add_chunk_information(h5_file_path, dmrpp.get());
258
259 dmrpp->set_href(url_name);
260
261 mds->add_dmrpp_response(dmrpp.get(), h5_file_name /*h5_file_path*/);
262
263 XMLWriter writer;
264 dmrpp->set_print_chunks(true);
265 dmrpp->print_dap4(writer);
266
267 cout << writer.get_doc();
268 } else {
269 cerr << "Error: Could not get a lock on the DMR for '" + h5_file_path + "'." << endl;
270 return EXIT_FAILURE;
271 }
272 }
273 }
274 catch (const BESError &e) {
275 cerr << "Error: " << e.get_message() << endl;
276 return EXIT_FAILURE;
277 }
278 catch (const std::exception &e) {
279 cerr << "std::exception: " << e.what() << endl;
280 return EXIT_FAILURE;
281 }
282 catch (...) {
283 cerr << "Unknown error." << endl;
284 return EXIT_FAILURE;
285 }
286
287 return EXIT_SUCCESS;
288}
static void SetUp(const std::string &values)
Sets up debugging for the bes.
Definition: BESDebug.cc:98
Base exception class for the BES with basic string message.
Definition: BESError.h:59
std::string get_message() const
get the error message for this exception
Definition: BESError.h:111
static std::string assemblePath(const std::string &firstPart, const std::string &secondPart, bool leadingSlash=false, bool trailingSlash=false)
Assemble path fragments making sure that they are separated by a single '/' character.
Definition: BESUtil.cc:801
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71
static std::string ConfigFile
Definition: TheBESKeys.h:185
std::string read_string_key(const std::string &key, const std::string &default_value)
Read a string-valued key from the bes.conf file.
Definition: TheBESKeys.cc:423
Store the DAP DMR++ metadata responses.
virtual libdap::DMR * get_dmr_object(const string &name)
Use the DMR response to build a DMR with Dmrpp Types.
static DmrppMetadataStore * get_instance()
virtual MDSReadLock is_dmr_available(const std::string &name)
Is the DMR response for.
Provide a way to print the DMR++ response.
Definition: DMRpp.h:44
virtual void print_dmrpp(libdap::XMLWriter &xml, const std::string &href="", bool constrained=false, bool print_chunks=true)
Print the DMR++ response.
Definition: DMRpp.cc:71
void print_dap4(libdap::XMLWriter &xml, bool constrained=false)
override DMR::print_dap4() so the chunk info will print too.
Definition: DMRpp.cc:140
Unlock and close the MDS item when the ReadLock goes out of scope.