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