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