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