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