Line data Source code
1 :
2 : /*
3 : * ALMA - Atacama Large Millimeter Array
4 : * (c) European Southern Observatory, 2002
5 : * (c) Associated Universities Inc., 2002
6 : * Copyright by ESO (in the framework of the ALMA collaboration),
7 : * Copyright by AUI (in the framework of the ALMA collaboration),
8 : * All rights reserved.
9 : *
10 : * This library is free software; you can redistribute it and/or
11 : * modify it under the terms of the GNU Lesser General Public
12 : * License as published by the Free software Foundation; either
13 : * version 2.1 of the License, or (at your option) any later version.
14 : *
15 : * This library is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY, without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : * Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; if not, write to the Free Software
22 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 : * MA 02111-1307 USA
24 : *
25 : * Warning!
26 : * --------------------------------------------------------------------
27 : * | This is generated code! Do not modify this file. |
28 : * | If you do, all changes will be lost when the file is re-generated. |
29 : * --------------------------------------------------------------------
30 : *
31 : * File WeatherTable.cpp
32 : */
33 : #include <alma/ASDM/ConversionException.h>
34 : #include <alma/ASDM/DuplicateKey.h>
35 : #include <alma/ASDM/OutOfBoundsException.h>
36 :
37 : using asdm::ConversionException;
38 : using asdm::DuplicateKey;
39 : using asdm::OutOfBoundsException;
40 :
41 : #include <alma/ASDM/ASDM.h>
42 : #include <alma/ASDM/WeatherTable.h>
43 : #include <alma/ASDM/WeatherRow.h>
44 : #include <alma/ASDM/Parser.h>
45 :
46 : using asdm::ASDM;
47 : using asdm::WeatherTable;
48 : using asdm::WeatherRow;
49 : using asdm::Parser;
50 :
51 : #include <iostream>
52 : #include <fstream>
53 : #include <iterator>
54 : #include <sstream>
55 : #include <set>
56 : #include <algorithm>
57 : using namespace std;
58 :
59 : #include <alma/ASDM/Misc.h>
60 : using namespace asdm;
61 :
62 : #include <libxml/parser.h>
63 : #include <libxml/tree.h>
64 :
65 : #ifndef WITHOUT_BOOST
66 : #include "boost/filesystem/operations.hpp"
67 : #include <boost/algorithm/string.hpp>
68 : #else
69 : #include <sys/stat.h>
70 : #endif
71 :
72 : namespace asdm {
73 : // The name of the entity we will store in this table.
74 : static string entityNameOfWeather = "Weather";
75 :
76 : // An array of string containing the names of the columns of this table.
77 : // The array is filled in the order : key, required value, optional value.
78 : //
79 : static string attributesNamesOfWeather_a[] = {
80 :
81 : "stationId"
82 : ,
83 : "timeInterval"
84 :
85 :
86 :
87 : , "pressure"
88 :
89 : , "relHumidity"
90 :
91 : , "temperature"
92 :
93 : , "windDirection"
94 :
95 : , "windSpeed"
96 :
97 : , "windMax"
98 :
99 : , "dewPoint"
100 :
101 : , "numLayer"
102 :
103 : , "layerHeight"
104 :
105 : , "temperatureProfile"
106 :
107 : , "cloudMonitor"
108 :
109 : , "numWVR"
110 :
111 : , "wvrTemp"
112 :
113 : , "water"
114 :
115 : };
116 :
117 : // A vector of string whose content is a copy of the strings in the array above.
118 : //
119 : static vector<string> attributesNamesOfWeather_v (attributesNamesOfWeather_a, attributesNamesOfWeather_a + sizeof(attributesNamesOfWeather_a) / sizeof(attributesNamesOfWeather_a[0]));
120 :
121 : // An array of string containing the names of the columns of this table.
122 : // The array is filled in the order where the names would be read by default in the XML header of a file containing
123 : // the table exported in binary mode.
124 : //
125 : static string attributesNamesInBinOfWeather_a[] = {
126 :
127 : "stationId" , "timeInterval"
128 : ,
129 : "pressure" , "relHumidity" , "temperature" , "windDirection" , "windSpeed" , "windMax" , "dewPoint" , "numLayer" , "layerHeight" , "temperatureProfile" , "cloudMonitor" , "numWVR" , "wvrTemp" , "water"
130 :
131 : };
132 :
133 : // A vector of string whose content is a copy of the strings in the array above.
134 : //
135 : static vector<string> attributesNamesInBinOfWeather_v(attributesNamesInBinOfWeather_a, attributesNamesInBinOfWeather_a + sizeof(attributesNamesInBinOfWeather_a) / sizeof(attributesNamesInBinOfWeather_a[0]));
136 :
137 :
138 : // The array of attributes (or column) names that make up key key.
139 : //
140 : string keyOfWeather_a[] = {
141 :
142 : "stationId"
143 : ,
144 : "timeInterval"
145 :
146 : };
147 :
148 : // A vector of strings which are copies of those stored in the array above.
149 : vector<string> keyOfWeather_v(keyOfWeather_a, keyOfWeather_a + sizeof(keyOfWeather_a) / sizeof(keyOfWeather_a[0]));
150 :
151 : /**
152 : * Return the list of field names that make up key key
153 : * as a const reference to a vector of strings.
154 : */
155 0 : const vector<string>& WeatherTable::getKeyName() {
156 0 : return keyOfWeather_v;
157 : }
158 :
159 :
160 110 : WeatherTable::WeatherTable(ASDM &c) : container(c) {
161 :
162 : // Define a default entity.
163 110 : entity.setEntityId(EntityId("uid://X0/X0/X0"));
164 110 : entity.setEntityIdEncrypted("na");
165 110 : entity.setEntityTypeName("WeatherTable");
166 110 : entity.setEntityVersion("1");
167 110 : entity.setInstanceVersion("1");
168 :
169 : // Archive XML
170 110 : archiveAsBin = false;
171 :
172 : // File XML
173 110 : fileAsBin = false;
174 :
175 : // By default the table is considered as present in memory
176 110 : presentInMemory = true;
177 :
178 : // By default there is no load in progress
179 110 : loadInProgress = false;
180 110 : }
181 :
182 : /**
183 : * A destructor for WeatherTable.
184 : */
185 220 : WeatherTable::~WeatherTable() {
186 14875 : for (unsigned int i = 0; i < privateRows.size(); i++)
187 14765 : delete(privateRows.at(i));
188 220 : }
189 :
190 : /**
191 : * Container to which this table belongs.
192 : */
193 4143 : ASDM &WeatherTable::getContainer() const {
194 4143 : return container;
195 : }
196 :
197 : /**
198 : * Return the number of rows in the table.
199 : */
200 111 : unsigned int WeatherTable::size() const {
201 111 : if (presentInMemory)
202 46 : return privateRows.size();
203 : else
204 65 : return declaredSize;
205 : }
206 :
207 : /**
208 : * Return the name of this table.
209 : */
210 101 : string WeatherTable::getName() const {
211 101 : return entityNameOfWeather;
212 : }
213 :
214 : /**
215 : * Return the name of this table.
216 : */
217 0 : string WeatherTable::name() {
218 0 : return entityNameOfWeather;
219 : }
220 :
221 : /**
222 : * Return the the names of the attributes (or columns) of this table.
223 : */
224 0 : const vector<string>& WeatherTable::getAttributesNames() { return attributesNamesOfWeather_v; }
225 :
226 : /**
227 : * Return the the names of the attributes (or columns) of this table as they appear by default
228 : * in an binary export of this table.
229 : */
230 0 : const vector<string>& WeatherTable::defaultAttributesNamesInBin() { return attributesNamesInBinOfWeather_v; }
231 :
232 : /**
233 : * Return this table's Entity.
234 : */
235 0 : Entity WeatherTable::getEntity() const {
236 0 : return entity;
237 : }
238 :
239 : /**
240 : * Set this table's Entity.
241 : */
242 65 : void WeatherTable::setEntity(Entity e) {
243 65 : this->entity = e;
244 65 : }
245 :
246 : //
247 : // ====> Row creation.
248 : //
249 :
250 : /**
251 : * Create a new row.
252 : */
253 14765 : WeatherRow *WeatherTable::newRow() {
254 14765 : return new WeatherRow (*this);
255 : }
256 :
257 :
258 : /**
259 : * Create a new row initialized to the specified values.
260 : * @return a pointer on the created and initialized row.
261 :
262 : * @param stationId
263 :
264 : * @param timeInterval
265 :
266 : */
267 0 : WeatherRow* WeatherTable::newRow(Tag stationId, ArrayTimeInterval timeInterval){
268 0 : WeatherRow *row = new WeatherRow(*this);
269 :
270 0 : row->setStationId(stationId);
271 :
272 0 : row->setTimeInterval(timeInterval);
273 :
274 0 : return row;
275 : }
276 :
277 :
278 :
279 0 : WeatherRow* WeatherTable::newRow(WeatherRow* row) {
280 0 : return new WeatherRow(*this, row);
281 : }
282 :
283 : //
284 : // Append a row to its table.
285 : //
286 :
287 :
288 :
289 :
290 :
291 : /**
292 : * Returns a string built by concatenating the ascii representation of the
293 : * parameters values suffixed with a "_" character.
294 : */
295 14765 : string WeatherTable::Key(Tag stationId) {
296 29530 : ostringstream ostrstr;
297 : ostrstr
298 :
299 14765 : << stationId.toString() << "_"
300 :
301 : ;
302 29530 : return ostrstr.str();
303 : }
304 :
305 :
306 :
307 0 : WeatherRow* WeatherTable::add(WeatherRow* x) {
308 0 : ArrayTime startTime = x->getTimeInterval().getStart();
309 :
310 : /*
311 : * Is there already a context for this combination of not temporal
312 : * attributes ?
313 : */
314 : string k = Key(
315 0 : x->getStationId()
316 0 : );
317 :
318 0 : if (context.find(k) == context.end()) {
319 : // There is not yet a context ...
320 : // Create and initialize an entry in the context map for this combination....
321 0 : TIME_ROWS v;
322 0 : context[k] = v;
323 : }
324 :
325 0 : return insertByStartTime(x, context[k]);
326 : }
327 :
328 :
329 :
330 :
331 14765 : void WeatherTable::addWithoutCheckingUnique(WeatherRow * x) {
332 14765 : WeatherRow * dummy = checkAndAdd(x, true); // We require the check for uniqueness to be skipped.
333 : // by passing true in the second parameter
334 : // whose value by default is false.
335 : // this statement is never executed, but it hides the unused return value from the compiler to silence that warning.
336 : if (false) cout << (unsigned long long) dummy;
337 14765 : }
338 :
339 :
340 :
341 :
342 : //
343 : // A private method to append a row to its table, used by input conversion
344 : // methods, with row uniqueness.
345 : //
346 :
347 :
348 :
349 :
350 :
351 :
352 :
353 :
354 :
355 14765 : WeatherRow* WeatherTable::checkAndAdd(WeatherRow* x, bool /* skipCheckUniqueness */ ) {
356 : string keystr = Key(
357 14765 : x->getStationId()
358 29530 : );
359 14765 : if (context.find(keystr) == context.end()) {
360 274 : vector<WeatherRow *> v;
361 137 : context[keystr] = v;
362 : }
363 :
364 14765 : vector<WeatherRow*>& found = context.find(keystr)->second;
365 29530 : return insertByStartTime(x, found);
366 : }
367 :
368 :
369 :
370 :
371 :
372 :
373 : //
374 : // A private method to brutally append a row to its table, without checking for row uniqueness.
375 : //
376 :
377 0 : void WeatherTable::append(WeatherRow *x) {
378 0 : privateRows.push_back(x);
379 0 : x->isAdded(true);
380 0 : }
381 :
382 :
383 :
384 :
385 :
386 0 : vector<WeatherRow *> WeatherTable::get() {
387 0 : checkPresenceInMemory();
388 0 : return privateRows;
389 : }
390 :
391 72 : const vector<WeatherRow *>& WeatherTable::get() const {
392 72 : const_cast<WeatherTable&>(*this).checkPresenceInMemory();
393 72 : return privateRows;
394 : }
395 :
396 :
397 :
398 :
399 :
400 :
401 :
402 :
403 :
404 :
405 0 : vector<WeatherRow *> *WeatherTable::getByContext(Tag stationId) {
406 : //if (getContainer().checkRowUniqueness() == false)
407 : //throw IllegalAccessException ("The method 'getByContext' can't be called because the dataset has been built without checking the row uniqueness.", "WeatherTable");
408 :
409 0 : checkPresenceInMemory();
410 0 : string k = Key(stationId);
411 :
412 0 : if (context.find(k) == context.end()) return 0;
413 0 : else return &(context[k]);
414 : }
415 :
416 :
417 :
418 :
419 :
420 :
421 :
422 :
423 :
424 :
425 : /*
426 : ** Returns a WeatherRow* given a key.
427 : ** @return a pointer to the row having the key whose values are passed as parameters, or 0 if
428 : ** no row exists for that key.
429 : **
430 : */
431 :
432 :
433 0 : WeatherRow* WeatherTable::getRowByKey(Tag stationId, ArrayTimeInterval timeInterval) {
434 0 : checkPresenceInMemory();
435 0 : string keystr = Key(stationId);
436 0 : vector<WeatherRow *> row;
437 :
438 0 : if ( context.find(keystr) == context.end()) return 0;
439 :
440 0 : row = context[keystr];
441 :
442 : // Is the vector empty...impossible in principle !
443 0 : if (row.size() == 0) return 0;
444 :
445 : // Only one element in the vector
446 0 : if (row.size() == 1) {
447 0 : WeatherRow* r = row.at(0);
448 0 : if ( r->getTimeInterval().contains(timeInterval.getStart()))
449 0 : return r;
450 : else
451 0 : return 0;
452 : }
453 :
454 : // Optimizations
455 0 : WeatherRow* last = row.at(row.size()-1);
456 0 : if (timeInterval.getStart().get() >= (last->getTimeInterval().getStart().get()+last->getTimeInterval().getDuration().get())) return 0;
457 :
458 0 : WeatherRow* first = row.at(0);
459 0 : if (timeInterval.getStart().get() < first->getTimeInterval().getStart().get()) return 0;
460 :
461 :
462 : // More than one row
463 : // Let's use a dichotomy method for the general case..
464 0 : int k0 = 0;
465 0 : int k1 = row.size() - 1;
466 0 : WeatherRow* r = 0;
467 0 : while (k0!=k1) {
468 :
469 : // Is the start time contained in the time interval of row #k0
470 0 : r = row.at(k0);
471 0 : if (r->getTimeInterval().contains(timeInterval.getStart())) return r;
472 :
473 : // Is the start contained in the time interval of row #k1
474 0 : r = row.at(k1);
475 0 : if (r->getTimeInterval().contains(timeInterval.getStart())) return r;
476 :
477 : // Are the rows #k0 and #k1 consecutive
478 : // Then we know for sure that there is no row containing the start of timeInterval
479 0 : if (k1==(k0+1)) return 0;
480 :
481 : // Proceed to the next step of dichotomy.
482 0 : r = row.at((k0+k1)/2);
483 0 : if ( timeInterval.getStart().get() <= r->getTimeInterval().getStart().get())
484 0 : k1 = (k0 + k1) / 2;
485 : else
486 0 : k0 = (k0 + k1) / 2;
487 : }
488 0 : return 0;
489 : }
490 :
491 :
492 :
493 :
494 :
495 :
496 :
497 :
498 :
499 : #ifndef WITHOUT_ACS
500 : using asdmIDL::WeatherTableIDL;
501 : #endif
502 :
503 : #ifndef WITHOUT_ACS
504 : // Conversion Methods
505 :
506 : WeatherTableIDL *WeatherTable::toIDL() {
507 : WeatherTableIDL *x = new WeatherTableIDL ();
508 : unsigned int nrow = size();
509 : x->row.length(nrow);
510 : vector<WeatherRow*> v = get();
511 : for (unsigned int i = 0; i < nrow; ++i) {
512 : //x->row[i] = *(v[i]->toIDL());
513 : v[i]->toIDL(x->row[i]);
514 : }
515 : return x;
516 : }
517 :
518 : void WeatherTable::toIDL(asdmIDL::WeatherTableIDL& x) const {
519 : unsigned int nrow = size();
520 : x.row.length(nrow);
521 : vector<WeatherRow*> v = get();
522 : for (unsigned int i = 0; i < nrow; ++i) {
523 : v[i]->toIDL(x.row[i]);
524 : }
525 : }
526 : #endif
527 :
528 : #ifndef WITHOUT_ACS
529 : void WeatherTable::fromIDL(WeatherTableIDL x) {
530 : unsigned int nrow = x.row.length();
531 : for (unsigned int i = 0; i < nrow; ++i) {
532 : WeatherRow *tmp = newRow();
533 : tmp->setFromIDL(x.row[i]);
534 : // checkAndAdd(tmp);
535 : add(tmp);
536 : }
537 : }
538 : #endif
539 :
540 :
541 0 : string WeatherTable::toXML() {
542 0 : string buf;
543 :
544 0 : buf.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> ");
545 0 : buf.append("<WeatherTable xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:weathr=\"http://Alma/XASDM/WeatherTable\" xsi:schemaLocation=\"http://Alma/XASDM/WeatherTable http://almaobservatory.org/XML/XASDM/4/WeatherTable.xsd\" schemaVersion=\"4\" schemaRevision=\"-1\">\n");
546 :
547 0 : buf.append(entity.toXML());
548 0 : string s = container.getEntity().toXML();
549 : // Change the "Entity" tag to "ContainerEntity".
550 0 : buf.append("<Container" + s.substr(1,s.length() - 1)+" ");
551 0 : vector<WeatherRow*> v = get();
552 0 : for (unsigned int i = 0; i < v.size(); ++i) {
553 : try {
554 0 : buf.append(v[i]->toXML());
555 0 : } catch (const NoSuchRow &e) {
556 : }
557 0 : buf.append(" ");
558 : }
559 0 : buf.append("</WeatherTable> ");
560 0 : return buf;
561 : }
562 :
563 :
564 0 : string WeatherTable::getVersion() const {
565 0 : return version;
566 : }
567 :
568 :
569 65 : void WeatherTable::fromXML(string& tableInXML) {
570 : //
571 : // Look for a version information in the schemaVersion of the XML
572 : //
573 : xmlDoc *doc;
574 : #if LIBXML_VERSION >= 20703
575 65 : doc = xmlReadMemory(tableInXML.data(), tableInXML.size(), "XMLTableHeader.xml", NULL, XML_PARSE_NOBLANKS|XML_PARSE_HUGE);
576 : #else
577 : doc = xmlReadMemory(tableInXML.data(), tableInXML.size(), "XMLTableHeader.xml", NULL, XML_PARSE_NOBLANKS);
578 : #endif
579 65 : if ( doc == NULL )
580 0 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "Weather");
581 :
582 65 : xmlNode* root_element = xmlDocGetRootElement(doc);
583 65 : if ( root_element == NULL || root_element->type != XML_ELEMENT_NODE )
584 0 : throw ConversionException("Failed to retrieve the root element in the DOM structure.", "Weather");
585 :
586 65 : xmlChar * propValue = xmlGetProp(root_element, (const xmlChar *) "schemaVersion");
587 65 : if ( propValue != 0 ) {
588 56 : version = string( (const char*) propValue);
589 56 : xmlFree(propValue);
590 : }
591 :
592 130 : Parser xml(tableInXML);
593 65 : if (!xml.isStr("<WeatherTable"))
594 0 : error();
595 : // cout << "Parsing a WeatherTable" << endl;
596 195 : string s = xml.getElement("<Entity","/>");
597 65 : if (s.length() == 0)
598 0 : error();
599 130 : Entity e;
600 65 : e.setFromXML(s);
601 65 : if (e.getEntityTypeName() != "WeatherTable")
602 0 : error();
603 65 : setEntity(e);
604 : // Skip the container's entity; but, it has to be there.
605 65 : s = xml.getElement("<ContainerEntity","/>");
606 65 : if (s.length() == 0)
607 0 : error();
608 :
609 : // Get each row in the table.
610 65 : s = xml.getElementContent("<row>","</row>");
611 : WeatherRow *row;
612 65 : if (getContainer().checkRowUniqueness()) {
613 : try {
614 0 : while (s.length() != 0) {
615 0 : row = newRow();
616 0 : row->setFromXML(s);
617 0 : checkAndAdd(row);
618 0 : s = xml.getElementContent("<row>","</row>");
619 : }
620 :
621 : }
622 0 : catch (const DuplicateKey &e1) {
623 0 : throw ConversionException(e1.getMessage(),"WeatherTable");
624 : }
625 0 : catch (const UniquenessViolationException &e1) {
626 0 : throw ConversionException(e1.getMessage(),"WeatherTable");
627 : }
628 0 : catch (...) {
629 : // cout << "Unexpected error in WeatherTable::checkAndAdd called from WeatherTable::fromXML " << endl;
630 : }
631 : }
632 : else {
633 : try {
634 14830 : while (s.length() != 0) {
635 14765 : row = newRow();
636 14765 : row->setFromXML(s);
637 14765 : addWithoutCheckingUnique(row);
638 14765 : s = xml.getElementContent("<row>","</row>");
639 : }
640 : }
641 0 : catch (const DuplicateKey &e1) {
642 0 : throw ConversionException(e1.getMessage(),"WeatherTable");
643 : }
644 0 : catch (...) {
645 : // cout << "Unexpected error in WeatherTable::addWithoutCheckingUnique called from WeatherTable::fromXML " << endl;
646 : }
647 : }
648 :
649 :
650 65 : if (!xml.isStr("</WeatherTable>"))
651 0 : error();
652 :
653 : //Does not change the convention defined in the model.
654 : //archiveAsBin = false;
655 : //fileAsBin = false;
656 :
657 : // clean up the xmlDoc pointer
658 65 : if ( doc != NULL ) xmlFreeDoc(doc);
659 :
660 65 : }
661 :
662 :
663 0 : void WeatherTable::error() {
664 0 : throw ConversionException("Invalid xml document","Weather");
665 : }
666 :
667 :
668 0 : string WeatherTable::MIMEXMLPart(const asdm::ByteOrder* byteOrder) {
669 0 : string UID = getEntity().getEntityId().toString();
670 0 : string withoutUID = UID.substr(6);
671 0 : string containerUID = getContainer().getEntity().getEntityId().toString();
672 0 : ostringstream oss;
673 0 : oss << "<?xml version='1.0' encoding='ISO-8859-1'?>";
674 0 : oss << "\n";
675 0 : oss << "<WeatherTable xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:weathr=\"http://Alma/XASDM/WeatherTable\" xsi:schemaLocation=\"http://Alma/XASDM/WeatherTable http://almaobservatory.org/XML/XASDM/4/WeatherTable.xsd\" schemaVersion=\"4\" schemaRevision=\"-1\">\n";
676 0 : oss<< "<Entity entityId='"<<UID<<"' entityIdEncrypted='na' entityTypeName='WeatherTable' schemaVersion='1' documentVersion='1'/>\n";
677 0 : oss<< "<ContainerEntity entityId='"<<containerUID<<"' entityIdEncrypted='na' entityTypeName='ASDM' schemaVersion='1' documentVersion='1'/>\n";
678 0 : oss << "<BulkStoreRef file_id='"<<withoutUID<<"' byteOrder='"<<byteOrder->toString()<<"' />\n";
679 0 : oss << "<Attributes>\n";
680 :
681 0 : oss << "<stationId/>\n";
682 0 : oss << "<timeInterval/>\n";
683 :
684 0 : oss << "<pressure/>\n";
685 0 : oss << "<relHumidity/>\n";
686 0 : oss << "<temperature/>\n";
687 0 : oss << "<windDirection/>\n";
688 0 : oss << "<windSpeed/>\n";
689 0 : oss << "<windMax/>\n";
690 0 : oss << "<dewPoint/>\n";
691 0 : oss << "<numLayer/>\n";
692 0 : oss << "<layerHeight/>\n";
693 0 : oss << "<temperatureProfile/>\n";
694 0 : oss << "<cloudMonitor/>\n";
695 0 : oss << "<numWVR/>\n";
696 0 : oss << "<wvrTemp/>\n";
697 0 : oss << "<water/>\n";
698 0 : oss << "</Attributes>\n";
699 0 : oss << "</WeatherTable>\n";
700 :
701 0 : return oss.str();
702 : }
703 :
704 0 : string WeatherTable::toMIME(const asdm::ByteOrder* byteOrder) {
705 0 : EndianOSStream eoss(byteOrder);
706 :
707 0 : string UID = getEntity().getEntityId().toString();
708 :
709 : // The MIME Header
710 0 : eoss <<"MIME-Version: 1.0";
711 0 : eoss << "\n";
712 0 : eoss << "Content-Type: Multipart/Related; boundary='MIME_boundary'; type='text/xml'; start= '<header.xml>'";
713 0 : eoss <<"\n";
714 0 : eoss <<"Content-Description: Correlator";
715 0 : eoss <<"\n";
716 0 : eoss <<"alma-uid:" << UID;
717 0 : eoss <<"\n";
718 0 : eoss <<"\n";
719 :
720 : // The MIME XML part header.
721 0 : eoss <<"--MIME_boundary";
722 0 : eoss <<"\n";
723 0 : eoss <<"Content-Type: text/xml; charset='ISO-8859-1'";
724 0 : eoss <<"\n";
725 0 : eoss <<"Content-Transfer-Encoding: 8bit";
726 0 : eoss <<"\n";
727 0 : eoss <<"Content-ID: <header.xml>";
728 0 : eoss <<"\n";
729 0 : eoss <<"\n";
730 :
731 : // The MIME XML part content.
732 0 : eoss << MIMEXMLPart(byteOrder);
733 :
734 : // The MIME binary part header
735 0 : eoss <<"--MIME_boundary";
736 0 : eoss <<"\n";
737 0 : eoss <<"Content-Type: binary/octet-stream";
738 0 : eoss <<"\n";
739 0 : eoss <<"Content-ID: <content.bin>";
740 0 : eoss <<"\n";
741 0 : eoss <<"\n";
742 :
743 : // The MIME binary content
744 0 : entity.toBin(eoss);
745 0 : container.getEntity().toBin(eoss);
746 0 : eoss.writeInt((int) privateRows.size());
747 0 : for (unsigned int i = 0; i < privateRows.size(); i++) {
748 0 : privateRows.at(i)->toBin(eoss);
749 : }
750 :
751 : // The closing MIME boundary
752 0 : eoss << "\n--MIME_boundary--";
753 0 : eoss << "\n";
754 :
755 0 : return eoss.str();
756 : }
757 :
758 :
759 0 : void WeatherTable::setFromMIME(const string & mimeMsg) {
760 0 : string xmlPartMIMEHeader = "Content-ID: <header.xml>\n\n";
761 :
762 0 : string binPartMIMEHeader = "--MIME_boundary\nContent-Type: binary/octet-stream\nContent-ID: <content.bin>\n\n";
763 :
764 : // Detect the XML header.
765 0 : string::size_type loc0 = mimeMsg.find(xmlPartMIMEHeader, 0);
766 0 : if ( loc0 == string::npos) {
767 : // let's try with CRLFs
768 0 : xmlPartMIMEHeader = "Content-ID: <header.xml>\r\n\r\n";
769 0 : loc0 = mimeMsg.find(xmlPartMIMEHeader, 0);
770 0 : if ( loc0 == string::npos )
771 0 : throw ConversionException("Failed to detect the beginning of the XML header", "Weather");
772 : }
773 :
774 0 : loc0 += xmlPartMIMEHeader.size();
775 :
776 : // Look for the string announcing the binary part.
777 0 : string::size_type loc1 = mimeMsg.find( binPartMIMEHeader, loc0 );
778 :
779 0 : if ( loc1 == string::npos ) {
780 0 : throw ConversionException("Failed to detect the beginning of the binary part", "Weather");
781 : }
782 :
783 : //
784 : // Extract the xmlHeader and analyze it to find out what is the byte order and the sequence
785 : // of attribute names.
786 : //
787 0 : string xmlHeader = mimeMsg.substr(loc0, loc1-loc0);
788 : xmlDoc *doc;
789 0 : doc = xmlReadMemory(xmlHeader.data(), xmlHeader.size(), "BinaryTableHeader.xml", NULL, XML_PARSE_NOBLANKS);
790 0 : if ( doc == NULL )
791 0 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "Weather");
792 :
793 : // This vector will be filled by the names of all the attributes of the table
794 : // in the order in which they are expected to be found in the binary representation.
795 : //
796 0 : vector<string> attributesSeq;
797 :
798 0 : xmlNode* root_element = xmlDocGetRootElement(doc);
799 0 : if ( root_element == NULL || root_element->type != XML_ELEMENT_NODE )
800 0 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "Weather");
801 :
802 0 : const ByteOrder* byteOrder=0;
803 0 : if ( string("ASDMBinaryTable").compare((const char*) root_element->name) == 0) {
804 : // Then it's an "old fashioned" MIME file for tables.
805 : // Just try to deserialize it with Big_Endian for the bytes ordering.
806 0 : byteOrder = asdm::ByteOrder::Big_Endian;
807 :
808 : //
809 : // Let's consider a default order for the sequence of attributes.
810 : //
811 :
812 :
813 0 : attributesSeq.push_back("stationId") ;
814 :
815 0 : attributesSeq.push_back("timeInterval") ;
816 :
817 :
818 0 : attributesSeq.push_back("pressure") ;
819 :
820 0 : attributesSeq.push_back("relHumidity") ;
821 :
822 0 : attributesSeq.push_back("temperature") ;
823 :
824 0 : attributesSeq.push_back("windDirection") ;
825 :
826 0 : attributesSeq.push_back("windSpeed") ;
827 :
828 0 : attributesSeq.push_back("windMax") ;
829 :
830 0 : attributesSeq.push_back("dewPoint") ;
831 :
832 0 : attributesSeq.push_back("numLayer") ;
833 :
834 0 : attributesSeq.push_back("layerHeight") ;
835 :
836 0 : attributesSeq.push_back("temperatureProfile") ;
837 :
838 0 : attributesSeq.push_back("cloudMonitor") ;
839 :
840 0 : attributesSeq.push_back("numWVR") ;
841 :
842 0 : attributesSeq.push_back("wvrTemp") ;
843 :
844 0 : attributesSeq.push_back("water") ;
845 :
846 :
847 :
848 :
849 : // And decide that it has version == "2"
850 0 : version = "2";
851 : }
852 0 : else if (string("WeatherTable").compare((const char*) root_element->name) == 0) {
853 : // It's a new (and correct) MIME file for tables.
854 : //
855 : // 1st ) Look for a BulkStoreRef element with an attribute byteOrder.
856 : //
857 0 : xmlNode* bulkStoreRef = 0;
858 0 : xmlNode* child = root_element->children;
859 :
860 0 : if (xmlHasProp(root_element, (const xmlChar*) "schemaVersion")) {
861 0 : xmlChar * value = xmlGetProp(root_element, (const xmlChar *) "schemaVersion");
862 0 : version = string ((const char *) value);
863 0 : xmlFree(value);
864 : }
865 :
866 : // Skip the two first children (Entity and ContainerEntity).
867 0 : bulkStoreRef = (child == 0) ? 0 : ( (child->next) == 0 ? 0 : child->next->next );
868 :
869 0 : if ( bulkStoreRef == 0 || (bulkStoreRef->type != XML_ELEMENT_NODE) || (string("BulkStoreRef").compare((const char*) bulkStoreRef->name) != 0))
870 0 : throw ConversionException ("Could not find the element '/WeatherTable/BulkStoreRef'. Invalid XML header '"+ xmlHeader + "'.", "Weather");
871 :
872 : // We found BulkStoreRef, now look for its attribute byteOrder.
873 0 : _xmlAttr* byteOrderAttr = 0;
874 0 : for (struct _xmlAttr* attr = bulkStoreRef->properties; attr; attr = attr->next)
875 0 : if (string("byteOrder").compare((const char*) attr->name) == 0) {
876 0 : byteOrderAttr = attr;
877 0 : break;
878 : }
879 :
880 0 : if (byteOrderAttr == 0)
881 0 : throw ConversionException("Could not find the element '/WeatherTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader +"'.", "Weather");
882 :
883 0 : string byteOrderValue = string((const char*) byteOrderAttr->children->content);
884 0 : if (!(byteOrder = asdm::ByteOrder::fromString(byteOrderValue)))
885 0 : throw ConversionException("No valid value retrieved for the element '/WeatherTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader + "'.", "Weather");
886 :
887 : //
888 : // 2nd) Look for the Attributes element and grab the names of the elements it contains.
889 : //
890 0 : xmlNode* attributes = bulkStoreRef->next;
891 0 : if ( attributes == 0 || (attributes->type != XML_ELEMENT_NODE) || (string("Attributes").compare((const char*) attributes->name) != 0))
892 0 : throw ConversionException ("Could not find the element '/WeatherTable/Attributes'. Invalid XML header '"+ xmlHeader + "'.", "Weather");
893 :
894 0 : xmlNode* childOfAttributes = attributes->children;
895 :
896 0 : while ( childOfAttributes != 0 && (childOfAttributes->type == XML_ELEMENT_NODE) ) {
897 0 : attributesSeq.push_back(string((const char*) childOfAttributes->name));
898 0 : childOfAttributes = childOfAttributes->next;
899 : }
900 : }
901 : // Create an EndianISStream from the substring containing the binary part.
902 0 : EndianISStream eiss(mimeMsg.substr(loc1+binPartMIMEHeader.size()), byteOrder);
903 :
904 0 : entity = Entity::fromBin((EndianIStream&) eiss);
905 :
906 : // We do nothing with that but we have to read it.
907 0 : Entity containerEntity = Entity::fromBin((EndianIStream&) eiss);
908 :
909 : // Let's read numRows but ignore it and rely on the value specified in the ASDM.xml file.
910 0 : int numRows = ((EndianIStream&) eiss).readInt();
911 0 : if ((numRows != -1) // Then these are *not* data produced at the EVLA.
912 0 : && ((unsigned int) numRows != this->declaredSize )) { // Then the declared size (in ASDM.xml) is not equal to the one
913 : // written into the binary representation of the table.
914 0 : cout << "The a number of rows ('"
915 : << numRows
916 0 : << "') declared in the binary representation of the table is different from the one declared in ASDM.xml ('"
917 0 : << this->declaredSize
918 0 : << "'). I'll proceed with the value declared in ASDM.xml"
919 0 : << endl;
920 : }
921 :
922 0 : if (getContainer().checkRowUniqueness()) {
923 : try {
924 0 : for (uint32_t i = 0; i < this->declaredSize; i++) {
925 0 : WeatherRow* aRow = WeatherRow::fromBin((EndianIStream&) eiss, *this, attributesSeq);
926 0 : checkAndAdd(aRow);
927 : }
928 : }
929 0 : catch (const DuplicateKey &e) {
930 : throw ConversionException("Error while writing binary data , the message was "
931 0 : + e.getMessage(), "Weather");
932 : }
933 0 : catch (const TagFormatException &e) {
934 : throw ConversionException("Error while reading binary data , the message was "
935 0 : + e.getMessage(), "Weather");
936 : }
937 : }
938 : else {
939 0 : for (uint32_t i = 0; i < this->declaredSize; i++) {
940 0 : WeatherRow* aRow = WeatherRow::fromBin((EndianIStream&) eiss, *this, attributesSeq);
941 0 : append(aRow);
942 : }
943 : }
944 : //Does not change the convention defined in the model.
945 : //archiveAsBin = true;
946 : //fileAsBin = true;
947 0 : if ( doc != NULL ) xmlFreeDoc(doc);
948 :
949 0 : }
950 :
951 0 : void WeatherTable::setUnknownAttributeBinaryReader(const string& attributeName, BinaryAttributeReaderFunctor* barFctr) {
952 : //
953 : // Is this attribute really unknown ?
954 : //
955 0 : for (vector<string>::const_iterator iter = attributesNamesOfWeather_v.begin(); iter != attributesNamesOfWeather_v.end(); iter++) {
956 0 : if ((*iter).compare(attributeName) == 0)
957 0 : throw ConversionException("the attribute '"+attributeName+"' is known you can't override the way it's read in the MIME binary file containing the table.", "Weather");
958 : }
959 :
960 : // Ok then register the functor to activate when an unknown attribute is met during the reading of a binary table?
961 0 : unknownAttributes2Functors[attributeName] = barFctr;
962 0 : }
963 :
964 0 : BinaryAttributeReaderFunctor* WeatherTable::getUnknownAttributeBinaryReader(const string& attributeName) const {
965 0 : map<string, BinaryAttributeReaderFunctor*>::const_iterator iter = unknownAttributes2Functors.find(attributeName);
966 0 : return (iter == unknownAttributes2Functors.end()) ? 0 : iter->second;
967 : }
968 :
969 :
970 0 : void WeatherTable::toFile(string directory) {
971 0 : if (!directoryExists(directory.c_str()) &&
972 0 : !createPath(directory.c_str())) {
973 0 : throw ConversionException("Could not create directory " , directory);
974 : }
975 :
976 0 : string fileName = directory + "/Weather.xml";
977 0 : ofstream tableout(fileName.c_str(),ios::out|ios::trunc);
978 0 : if (tableout.rdstate() == ostream::failbit)
979 0 : throw ConversionException("Could not open file " + fileName + " to write ", "Weather");
980 0 : if (fileAsBin)
981 0 : tableout << MIMEXMLPart();
982 : else
983 0 : tableout << toXML() << endl;
984 0 : tableout.close();
985 0 : if (tableout.rdstate() == ostream::failbit)
986 0 : throw ConversionException("Could not close file " + fileName, "Weather");
987 :
988 0 : if (fileAsBin) {
989 : // write the bin serialized
990 0 : string fileName = directory + "/Weather.bin";
991 0 : ofstream tableout(fileName.c_str(),ios::out|ios::trunc);
992 0 : if (tableout.rdstate() == ostream::failbit)
993 0 : throw ConversionException("Could not open file " + fileName + " to write ", "Weather");
994 0 : tableout << toMIME() << endl;
995 0 : tableout.close();
996 0 : if (tableout.rdstate() == ostream::failbit)
997 0 : throw ConversionException("Could not close file " + fileName, "Weather");
998 : }
999 0 : }
1000 :
1001 :
1002 65 : void WeatherTable::setFromFile(const string& directory) {
1003 : #ifndef WITHOUT_BOOST
1004 : if (boost::filesystem::exists(boost::filesystem::path(uniqSlashes(directory + "/Weather.xml"))))
1005 : setFromXMLFile(directory);
1006 : else if (boost::filesystem::exists(boost::filesystem::path(uniqSlashes(directory + "/Weather.bin"))))
1007 : setFromMIMEFile(directory);
1008 : #else
1009 : // alternative in Misc.h
1010 65 : if (file_exists(uniqSlashes(directory + "/Weather.xml")))
1011 65 : setFromXMLFile(directory);
1012 0 : else if (file_exists(uniqSlashes(directory + "/Weather.bin")))
1013 0 : setFromMIMEFile(directory);
1014 : #endif
1015 : else
1016 0 : throw ConversionException("No file found for the Weather table", "Weather");
1017 65 : }
1018 :
1019 :
1020 0 : void WeatherTable::setFromMIMEFile(const string& directory) {
1021 0 : string tablePath ;
1022 :
1023 0 : tablePath = directory + "/Weather.bin";
1024 0 : ifstream tablefile(tablePath.c_str(), ios::in|ios::binary);
1025 0 : if (!tablefile.is_open()) {
1026 0 : throw ConversionException("Could not open file " + tablePath, "Weather");
1027 : }
1028 : // Read in a stringstream.
1029 0 : stringstream ss; ss << tablefile.rdbuf();
1030 :
1031 0 : if (tablefile.rdstate() == istream::failbit || tablefile.rdstate() == istream::badbit) {
1032 0 : throw ConversionException("Error reading file " + tablePath,"Weather");
1033 : }
1034 :
1035 : // And close.
1036 0 : tablefile.close();
1037 0 : if (tablefile.rdstate() == istream::failbit)
1038 0 : throw ConversionException("Could not close file " + tablePath,"Weather");
1039 :
1040 0 : setFromMIME(ss.str());
1041 0 : }
1042 : /*
1043 : void WeatherTable::openMIMEFile (const string& directory) {
1044 :
1045 : // Open the file.
1046 : string tablePath ;
1047 : tablePath = directory + "/Weather.bin";
1048 : ifstream tablefile(tablePath.c_str(), ios::in|ios::binary);
1049 : if (!tablefile.is_open())
1050 : throw ConversionException("Could not open file " + tablePath, "Weather");
1051 :
1052 : // Locate the xmlPartMIMEHeader.
1053 : string xmlPartMIMEHeader = "CONTENT-ID: <HEADER.XML>\n\n";
1054 : CharComparator comparator;
1055 : istreambuf_iterator<char> BEGIN(tablefile.rdbuf());
1056 : istreambuf_iterator<char> END;
1057 : istreambuf_iterator<char> it = search(BEGIN, END, xmlPartMIMEHeader.begin(), xmlPartMIMEHeader.end(), comparator);
1058 : if (it == END)
1059 : throw ConversionException("failed to detect the beginning of the XML header", "Weather");
1060 :
1061 : // Locate the binaryPartMIMEHeader while accumulating the characters of the xml header.
1062 : string binPartMIMEHeader = "--MIME_BOUNDARY\nCONTENT-TYPE: BINARY/OCTET-STREAM\nCONTENT-ID: <CONTENT.BIN>\n\n";
1063 : string xmlHeader;
1064 : CharCompAccumulator compaccumulator(&xmlHeader, 100000);
1065 : ++it;
1066 : it = search(it, END, binPartMIMEHeader.begin(), binPartMIMEHeader.end(), compaccumulator);
1067 : if (it == END)
1068 : throw ConversionException("failed to detect the beginning of the binary part", "Weather");
1069 :
1070 : cout << xmlHeader << endl;
1071 : //
1072 : // We have the xmlHeader , let's parse it.
1073 : //
1074 : xmlDoc *doc;
1075 : doc = xmlReadMemory(xmlHeader.data(), xmlHeader.size(), "BinaryTableHeader.xml", NULL, XML_PARSE_NOBLANKS);
1076 : if ( doc == NULL )
1077 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "Weather");
1078 :
1079 : // This vector will be filled by the names of all the attributes of the table
1080 : // in the order in which they are expected to be found in the binary representation.
1081 : //
1082 : vector<string> attributesSeq(attributesNamesInBinOfWeather_v);
1083 :
1084 : xmlNode* root_element = xmlDocGetRootElement(doc);
1085 : if ( root_element == NULL || root_element->type != XML_ELEMENT_NODE )
1086 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "Weather");
1087 :
1088 : const ByteOrder* byteOrder=0;
1089 : if ( string("ASDMBinaryTable").compare((const char*) root_element->name) == 0) {
1090 : // Then it's an "old fashioned" MIME file for tables.
1091 : // Just try to deserialize it with Big_Endian for the bytes ordering.
1092 : byteOrder = asdm::ByteOrder::Big_Endian;
1093 :
1094 : // And decide that it has version == "2"
1095 : version = "2";
1096 : }
1097 : else if (string("WeatherTable").compare((const char*) root_element->name) == 0) {
1098 : // It's a new (and correct) MIME file for tables.
1099 : //
1100 : // 1st ) Look for a BulkStoreRef element with an attribute byteOrder.
1101 : //
1102 : xmlNode* bulkStoreRef = 0;
1103 : xmlNode* child = root_element->children;
1104 :
1105 : if (xmlHasProp(root_element, (const xmlChar*) "schemaVersion")) {
1106 : xmlChar * value = xmlGetProp(root_element, (const xmlChar *) "schemaVersion");
1107 : version = string ((const char *) value);
1108 : xmlFree(value);
1109 : }
1110 :
1111 : // Skip the two first children (Entity and ContainerEntity).
1112 : bulkStoreRef = (child == 0) ? 0 : ( (child->next) == 0 ? 0 : child->next->next );
1113 :
1114 : if ( bulkStoreRef == 0 || (bulkStoreRef->type != XML_ELEMENT_NODE) || (string("BulkStoreRef").compare((const char*) bulkStoreRef->name) != 0))
1115 : throw ConversionException ("Could not find the element '/WeatherTable/BulkStoreRef'. Invalid XML header '"+ xmlHeader + "'.", "Weather");
1116 :
1117 : // We found BulkStoreRef, now look for its attribute byteOrder.
1118 : _xmlAttr* byteOrderAttr = 0;
1119 : for (struct _xmlAttr* attr = bulkStoreRef->properties; attr; attr = attr->next)
1120 : if (string("byteOrder").compare((const char*) attr->name) == 0) {
1121 : byteOrderAttr = attr;
1122 : break;
1123 : }
1124 :
1125 : if (byteOrderAttr == 0)
1126 : throw ConversionException("Could not find the element '/WeatherTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader +"'.", "Weather");
1127 :
1128 : string byteOrderValue = string((const char*) byteOrderAttr->children->content);
1129 : if (!(byteOrder = asdm::ByteOrder::fromString(byteOrderValue)))
1130 : throw ConversionException("No valid value retrieved for the element '/WeatherTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader + "'.", "Weather");
1131 :
1132 : //
1133 : // 2nd) Look for the Attributes element and grab the names of the elements it contains.
1134 : //
1135 : xmlNode* attributes = bulkStoreRef->next;
1136 : if ( attributes == 0 || (attributes->type != XML_ELEMENT_NODE) || (string("Attributes").compare((const char*) attributes->name) != 0))
1137 : throw ConversionException ("Could not find the element '/WeatherTable/Attributes'. Invalid XML header '"+ xmlHeader + "'.", "Weather");
1138 :
1139 : xmlNode* childOfAttributes = attributes->children;
1140 :
1141 : while ( childOfAttributes != 0 && (childOfAttributes->type == XML_ELEMENT_NODE) ) {
1142 : attributesSeq.push_back(string((const char*) childOfAttributes->name));
1143 : childOfAttributes = childOfAttributes->next;
1144 : }
1145 : }
1146 : // Create an EndianISStream from the substring containing the binary part.
1147 : EndianIFStream eifs(&tablefile, byteOrder);
1148 :
1149 : entity = Entity::fromBin((EndianIStream &) eifs);
1150 :
1151 : // We do nothing with that but we have to read it.
1152 : Entity containerEntity = Entity::fromBin((EndianIStream &) eifs);
1153 :
1154 : // Let's read numRows but ignore it and rely on the value specified in the ASDM.xml file.
1155 : int numRows = eifs.readInt();
1156 : if ((numRows != -1) // Then these are *not* data produced at the EVLA.
1157 : && ((unsigned int) numRows != this->declaredSize )) { // Then the declared size (in ASDM.xml) is not equal to the one
1158 : // written into the binary representation of the table.
1159 : cout << "The a number of rows ('"
1160 : << numRows
1161 : << "') declared in the binary representation of the table is different from the one declared in ASDM.xml ('"
1162 : << this->declaredSize
1163 : << "'). I'll proceed with the value declared in ASDM.xml"
1164 : << endl;
1165 : }
1166 : // clean up xmlDoc pointer
1167 : if ( doc != NULL ) xmlFreeDoc(doc);
1168 : }
1169 : */
1170 :
1171 :
1172 65 : void WeatherTable::setFromXMLFile(const string& directory) {
1173 130 : string tablePath ;
1174 :
1175 65 : tablePath = directory + "/Weather.xml";
1176 :
1177 : /*
1178 : ifstream tablefile(tablePath.c_str(), ios::in|ios::binary);
1179 : if (!tablefile.is_open()) {
1180 : throw ConversionException("Could not open file " + tablePath, "Weather");
1181 : }
1182 : // Read in a stringstream.
1183 : stringstream ss;
1184 : ss << tablefile.rdbuf();
1185 :
1186 : if (tablefile.rdstate() == istream::failbit || tablefile.rdstate() == istream::badbit) {
1187 : throw ConversionException("Error reading file '" + tablePath + "'", "Weather");
1188 : }
1189 :
1190 : // And close
1191 : tablefile.close();
1192 : if (tablefile.rdstate() == istream::failbit)
1193 : throw ConversionException("Could not close file '" + tablePath + "'", "Weather");
1194 :
1195 : // Let's make a string out of the stringstream content and empty the stringstream.
1196 : string xmlDocument = ss.str(); ss.str("");
1197 :
1198 : // Let's make a very primitive check to decide
1199 : // whether the XML content represents the table
1200 : // or refers to it via a <BulkStoreRef element.
1201 : */
1202 :
1203 130 : string xmlDocument;
1204 : try {
1205 65 : xmlDocument = getContainer().getXSLTransformer()(tablePath);
1206 65 : if (getenv("ASDM_DEBUG")) cout << "About to read " << tablePath << endl;
1207 : }
1208 0 : catch (const XSLTransformerException &e) {
1209 0 : throw ConversionException("Caugth an exception whose message is '" + e.getMessage() + "'.", "Weather");
1210 : }
1211 :
1212 65 : if (xmlDocument.find("<BulkStoreRef") != string::npos)
1213 0 : setFromMIMEFile(directory);
1214 : else
1215 65 : fromXML(xmlDocument);
1216 65 : }
1217 :
1218 :
1219 :
1220 :
1221 :
1222 :
1223 :
1224 :
1225 :
1226 : /**
1227 : * Insert a WeatherRow* in a vector of WeatherRow* so that it's ordered by ascending start time.
1228 : *
1229 : * @param WeatherRow* x . The pointer to be inserted.
1230 : * @param vector <WeatherRow*>& row. A reference to the vector where to insert x.
1231 : *
1232 : */
1233 14765 : WeatherRow* WeatherTable::insertByStartTime(WeatherRow* x, vector<WeatherRow*>& row) {
1234 :
1235 14765 : vector <WeatherRow*>::iterator theIterator;
1236 :
1237 29530 : ArrayTime start = x->timeInterval.getStart();
1238 :
1239 : // Is the row vector empty ?
1240 14765 : if (row.size() == 0) {
1241 137 : row.push_back(x);
1242 137 : privateRows.push_back(x);
1243 137 : x->isAdded(true);
1244 137 : return x;
1245 : }
1246 :
1247 : // Optimization for the case of insertion by ascending time.
1248 14628 : WeatherRow* last = *(row.end()-1);
1249 :
1250 14628 : if ( start > last->timeInterval.getStart() ) {
1251 : //
1252 : // Modify the duration of last if and only if the start time of x
1253 : // is located strictly before the end time of last.
1254 : //
1255 14628 : if ( start < (last->timeInterval.getStart() + last->timeInterval.getDuration()))
1256 0 : last->timeInterval.setDuration(start - last->timeInterval.getStart());
1257 14628 : row.push_back(x);
1258 14628 : privateRows.push_back(x);
1259 14628 : x->isAdded(true);
1260 14628 : return x;
1261 : }
1262 :
1263 : // Optimization for the case of insertion by descending time.
1264 0 : WeatherRow* first = *(row.begin());
1265 :
1266 0 : if ( start < first->timeInterval.getStart() ) {
1267 : //
1268 : // Modify the duration of x if and only if the start time of first
1269 : // is located strictly before the end time of x.
1270 : //
1271 0 : if ( first->timeInterval.getStart() < (start + x->timeInterval.getDuration()) )
1272 0 : x->timeInterval.setDuration(first->timeInterval.getStart() - start);
1273 0 : row.insert(row.begin(), x);
1274 0 : privateRows.push_back(x);
1275 0 : x->isAdded(true);
1276 0 : return x;
1277 : }
1278 :
1279 : // Case where x has to be inserted inside row; let's use a dichotomy
1280 : // method to find the insertion index.
1281 0 : unsigned int k0 = 0;
1282 0 : unsigned int k1 = row.size() - 1;
1283 :
1284 0 : while (k0 != (k1 - 1)) {
1285 0 : if (start == row[k0]->timeInterval.getStart()) {
1286 0 : if (row[k0]->equalByRequiredValue(x))
1287 0 : return row[k0];
1288 : else
1289 0 : throw DuplicateKey("DuplicateKey exception in ", "WeatherTable");
1290 : }
1291 0 : else if (start == row[k1]->timeInterval.getStart()) {
1292 0 : if (row[k1]->equalByRequiredValue(x))
1293 0 : return row[k1];
1294 : else
1295 0 : throw DuplicateKey("DuplicateKey exception in ", "WeatherTable");
1296 : }
1297 : else {
1298 0 : if (start <= row[(k0+k1)/2]->timeInterval.getStart())
1299 0 : k1 = (k0 + k1) / 2;
1300 : else
1301 0 : k0 = (k0 + k1) / 2;
1302 : }
1303 : }
1304 :
1305 0 : if (start == row[k0]->timeInterval.getStart()) {
1306 0 : if (row[k0]->equalByRequiredValue(x))
1307 0 : return row[k0];
1308 : else
1309 0 : throw DuplicateKey("DuplicateKey exception in ", "WeatherTable");
1310 : }
1311 0 : else if (start == row[k1]->timeInterval.getStart()) {
1312 0 : if (row[k1]->equalByRequiredValue(x))
1313 0 : return row[k1];
1314 : else
1315 0 : throw DuplicateKey("DuplicateKey exception in ", "WeatherTable");
1316 : }
1317 :
1318 0 : row[k0]->timeInterval.setDuration(start-row[k0]->timeInterval.getStart());
1319 0 : x->timeInterval.setDuration(row[k0+1]->timeInterval.getStart() - start);
1320 0 : row.insert(row.begin()+(k0+1), x);
1321 0 : privateRows.push_back(x);
1322 0 : x->isAdded(true);
1323 0 : return x;
1324 : }
1325 :
1326 :
1327 :
1328 :
1329 :
1330 : } // End namespace asdm
1331 :
|