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