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