Qt IOC Container 3.5


XmlObjectDefinitionReader.cpp

Go to the documentation of this file.
00001 #include "XmlObjectDefinitionReader.h"
00002 #include "exception/FileIOException.h"
00003 #include "exception/XmlParseException.h"
00004 #include "Util.h"
00005 #include "DefaultObjectDefinition.h"
00006 #include "PropertyParser.h"
00007 #include "DefaultWireDefinition.h"
00008 #include "ReferenceDefinition.h"
00009 
00010 #include <QFile>
00011 #include <QDir>
00012 
00013 #include <log4cxx/logger.h>
00014 
00015 using namespace log4cxx;
00016 
00017 using namespace qic;
00018 
00019 LoggerPtr XmlObjectDefinitionReader::logger(Logger::getLogger("org.qic.XmlObjectDefinitionReader"));
00020 
00021 const char * XmlObjectDefinitionReader::QIC_BASE_DIR = "QIC_DIR";
00022 const char * XmlObjectDefinitionReader::OBJECTS_TAG = "objects";
00023 const char * XmlObjectDefinitionReader::OBJECT_TAG = "object";
00024 const char * XmlObjectDefinitionReader::PARSER_TAG = "parser";
00025 const char * XmlObjectDefinitionReader::INJECTOR_TAG = "injector";
00026 
00027 const char * XmlObjectDefinitionReader::WIRE_TAG = "wire";
00028 const char * XmlObjectDefinitionReader::WIRE_TYPE_ATTR = "type";
00029 const char * XmlObjectDefinitionReader::SENDER_TAG = "sender";
00030 const char * XmlObjectDefinitionReader::RECEIVER_TAG = "receiver";
00031 const char * XmlObjectDefinitionReader::SENDER_ID_ATTR = "id";
00032 const char * XmlObjectDefinitionReader::RECEIVER_ID_ATTR = "id";
00033 const char * XmlObjectDefinitionReader::SENDER_SIGNAL_ATTR = "signal";
00034 const char * XmlObjectDefinitionReader::RECEIVER_METHOD_ATTR = "method";
00035 
00036 const char * XmlObjectDefinitionReader::TAG_ATTR = "tag";
00037 const char * XmlObjectDefinitionReader::PLUGIN_ATTR = "plugin";
00038 const char * XmlObjectDefinitionReader::ID_ATTR = "id";
00039 const char * XmlObjectDefinitionReader::FACTORY_ATTR = "factory-object";
00040 const char * XmlObjectDefinitionReader::FACTORY_METHOD_ATTR = "factory-method";
00041 const char * XmlObjectDefinitionReader::INIT_METHOD_ATTR = "init-method";
00042 const char * XmlObjectDefinitionReader::DESTROY_METHOD_ATTR = "destroy-method";
00043 const char * XmlObjectDefinitionReader::PROPERTY_TAG = "property";
00044 const char * XmlObjectDefinitionReader::NAME_ATTR = "name";
00045 const char * XmlObjectDefinitionReader::REF_ATTR = "ref";
00046 
00047 const char * XmlObjectDefinitionReader::INJECTOR_TYPE_ATTR = "type";
00048 
00049 
00050 XmlObjectDefinitionReader::XmlObjectDefinitionReader(ObjectDefinitionRegistry * objectRegistry)
00051 {
00052   _objectRegistry = objectRegistry;
00053 
00054   loadParserPlugins();
00055   loadInjectorPlugins();
00056 }
00057 
00058 XmlObjectDefinitionReader::~ XmlObjectDefinitionReader()
00059 {
00060   unloadParserPlugins();
00061 }
00062 
00063 int
00064 XmlObjectDefinitionReader::loadObjectDefinitions (QString path)
00065 {
00066   LOG4CXX_INFO(logger, QString("Loading object definitions: ").append(path).toStdString());
00067 
00068   _currentFile = path;
00069 
00070   QFile file(path);
00071   try
00072   {
00073     if (!file.open(QIODevice::ReadOnly))
00074     {
00075       throw FileIOException (path + " - " + file.errorString());
00076     }
00077     int count = loadObjectDefinitions(file);
00078 
00079     file.close();
00080     return count;
00081   }
00082   catch (std::exception & )
00083   {
00084     if (file.isOpen())
00085     {
00086       file.close();
00087     }
00088     throw;
00089   }
00090 }
00091 
00092 int
00093 XmlObjectDefinitionReader::loadObjectDefinitions (QIODevice & source)
00094 {
00095   QDomDocument doc;
00096   QString errorMsg;
00097   int errorLine;
00098   int errorCol;
00099   if (!doc.setContent(&source, &errorMsg, &errorLine, &errorCol))
00100   {
00101     throw XmlParseException (QString("File %1 (Line %2, Column %3): %4")
00102                              .arg(_currentFile).arg(errorLine).arg(errorCol).arg(errorMsg));
00103   }
00104   return loadObjectDefinitions (doc);
00105 }
00106 
00107 void
00108 XmlObjectDefinitionReader::loadInjectorPlugins ()
00109 {
00110   QString path = Util::getEnvVariable(QIC_BASE_DIR);
00111   QDir parser_dir;
00112 
00113   QString file = parser_dir.absoluteFilePath(path + "/injector_plugins.xml");
00114   LOG4CXX_INFO(logger, "Loading injector plugins: " + file.toStdString());
00115 
00116   loadObjectDefinitions(file);
00117 }
00118 
00119 void
00120 XmlObjectDefinitionReader::loadParserPlugins ()
00121 {
00122   QString path = Util::getEnvVariable(QIC_BASE_DIR);
00123   QDir parser_dir;
00124 
00125   QString file = parser_dir.absoluteFilePath(path + "/parser_plugins.xml");
00126   LOG4CXX_INFO(logger, "Loading parser plugins: " + file.toStdString());
00127 
00128   loadObjectDefinitions(file);
00129 }
00130 
00131 void
00132 XmlObjectDefinitionReader::unloadParserPlugins ()
00133 {
00134   LOG4CXX_INFO(logger, "Unloading parser plugins. ");
00135 
00136   foreach (QString id, _parser_loader_map.keys())
00137   {
00138     QPluginLoader * loader = _parser_loader_map[id];
00139     if (loader)
00140     {
00141       loader->unload();
00142       delete loader;
00143     }
00144     else
00145     {
00146       LOG4CXX_WARN(logger, "Inconsistent application context. NULL plugin loader. id: " + id.toStdString());
00147     }
00148   }
00149 }
00150 
00151 int
00152 XmlObjectDefinitionReader::loadObjectDefinitions (QDomDocument & doc)
00153 {
00154   int count = 0;
00155   QDomElement docElem = doc.documentElement();
00156   if (docElem.isNull())
00157   {
00158     throw XmlParseException (QString("File: %1 Root element NULL.").arg(_currentFile));
00159   }
00160   QString rootTag = docElem.tagName();
00161 
00162   LOG4CXX_DEBUG(logger, "File: " + _currentFile.toStdString() + " Root tag: " + rootTag.toStdString());
00163 
00164   if ( rootTag != OBJECTS_TAG)
00165   {
00166     throw XmlParseException (QString("File: %1 Root element tag name should be '%2'").arg(_currentFile).arg(OBJECTS_TAG));
00167   }
00168   QDomNode n = docElem.firstChild();
00169   while(!n.isNull())
00170   {
00171     QDomElement e = n.toElement();
00172     if (e.isNull())
00173     {
00174       throw XmlParseException (QString ("File: %1 %2 is not Element.").arg(_currentFile).arg(n.nodeName()));
00175     }
00176     QString tag = e.tagName ();
00177     if(tag == OBJECT_TAG)
00178     {
00179       parseObjectTag (e);
00180       count ++;
00181     }
00182     else if(tag == PARSER_TAG)
00183     {
00184       parseParserTag (e);
00185     }
00186     else if(tag == WIRE_TAG)
00187     {
00188       parseWireTag (e);
00189     }
00190     else if(tag == INJECTOR_TAG)
00191     {
00192       parseInjectorTag (e);
00193     }
00194     else
00195     {
00196       throw XmlParseException (QString("File %1: Expecting %2 or %3, %4 encountered.")
00197                                .arg(_currentFile).arg(OBJECT_TAG).arg(PARSER_TAG).arg(tag));
00198     }
00199     n = n.nextSibling();
00200   } // for every child node
00201 
00202   return count;
00203 }
00204 
00205 void
00206 XmlObjectDefinitionReader::parseWireTag( QDomElement & e)
00207 {
00208   DefaultWireDefinition * def = new DefaultWireDefinition();
00209   try
00210   {
00211     QString type = e.attribute(WIRE_TYPE_ATTR);
00212     if (type.isEmpty())
00213     {
00214       type = "auto";
00215     }
00216     def->setWireType( type);
00217 
00218     for(QDomNode objNode = e.firstChild(); !objNode.isNull(); objNode = objNode.nextSibling())
00219     {
00220       QDomElement objEl = objNode.toElement();
00221       if (objEl.isNull())
00222       {
00223         throw XmlParseException (QString ("File: %1 %2 is not Element.").arg(_currentFile).arg(objNode.nodeName()));
00224       }
00225       if (objEl.tagName() == SENDER_TAG)
00226       {
00227         QString id = objEl.attribute(SENDER_ID_ATTR);
00228         if(id.isEmpty())
00229         {
00230           throw XmlParseException (QString("File: %1 sender element must have an '%2' attribute")
00231                                    .arg(_currentFile).arg(SENDER_ID_ATTR));
00232         }
00233         def->setSenderObjectId( id);
00234 
00235         QString signal = objEl.attribute(SENDER_SIGNAL_ATTR);
00236         if(signal.isEmpty())
00237         {
00238           throw XmlParseException (QString("File: %1 sender element must have an '%2' attribute")
00239                                    .arg(_currentFile).arg(SENDER_SIGNAL_ATTR));
00240         }
00241         def->setSenderSignal( signal);
00242       }
00243       else if (objEl.tagName() == RECEIVER_TAG)
00244       {
00245         QString id = objEl.attribute(RECEIVER_ID_ATTR);
00246         if(id.isEmpty())
00247         {
00248           throw XmlParseException (QString("File: %1 receiver element must have an '%2' attribute")
00249                                    .arg(_currentFile).arg(RECEIVER_ID_ATTR));
00250         }
00251         def->setReceiverObjectId( id);
00252 
00253         QString method = objEl.attribute(RECEIVER_METHOD_ATTR);
00254         if(method.isEmpty())
00255         {
00256           throw XmlParseException (QString("File: %1 receiver element must have an '%2' attribute")
00257                                    .arg(_currentFile).arg(RECEIVER_METHOD_ATTR));
00258         }
00259         def->setReceiverMethod( method);
00260       }
00261       else
00262       {
00263         throw XmlParseException (QString("File %1: Expecting %2 and %3, %4 encountered.")
00264                                  .arg(_currentFile).arg(SENDER_TAG).arg(RECEIVER_TAG).arg(objEl.tagName()));
00265       }
00266     }
00267     _objectRegistry->registerWireDefinition( def);
00268   }
00269   catch (std::exception &)
00270   {
00271     delete def;
00272     throw;
00273   }
00274 }
00275 
00276 void
00277 XmlObjectDefinitionReader::parseObjectPropertySubTag (QString id, QString name, QDomNode & objNode, ObjectDefinition * def)
00278 {
00279   QDomNode valueNode = objNode.firstChild();
00280   QString xml = Util::translateVariable(Util::asXml(valueNode));
00281 
00282   QDomDocument tmpDoc;
00283   tmpDoc.setContent(xml);
00284   QDomElement docElem = tmpDoc.documentElement();
00285   QString tag = docElem.tagName();
00286 
00287   if (_parser_map.contains(tag))
00288   {
00289     QObject * parser_obj = _parser_map[tag];
00290     PropertyParser * parser = qobject_cast<PropertyParser *>(parser_obj);
00291     QVariant propVal = parser->parseProperty(docElem, _parser_map);
00292 
00293     def->setPropertyValue(name, propVal);
00294 
00295     if(logger->isDebugEnabled())
00296     {
00297       logger->forcedLog(Level::DEBUG, "Object " + id.toStdString() +  "Property: name: " + name.toStdString() + " value: " + xml.replace("\n", "").toStdString(), __FILE__, __LINE__);
00298     }
00299   }
00300   else
00301   {
00302     throw XmlParseException (QString("File %1: Object: %2, Property: %3: Unexpected tag name %4.")
00303                              .arg(_currentFile).arg(id).arg(name).arg(tag));
00304   }
00305 }
00306 
00307 void
00308 XmlObjectDefinitionReader::parseObjectPropertyTag (QString id, QDomElement & e, ObjectDefinition * def)
00309 {
00310   for(QDomNode objNode = e.firstChild(); !objNode.isNull(); objNode = objNode.nextSibling())
00311   {
00312     QDomElement objEl = objNode.toElement();
00313     if (objEl.isNull())
00314     {
00315       throw XmlParseException (QString ("File: %1 %2 is not Element.").arg(_currentFile).arg(objNode.nodeName()));
00316     }
00317     if (objEl.tagName() == PROPERTY_TAG)
00318     {
00319       QString name = objEl.attribute(NAME_ATTR);
00320       if(name.isEmpty())
00321       {
00322         throw XmlParseException (QString("File: %1 Property element must have an '%2' attribute")
00323                                  .arg(_currentFile).arg(NAME_ATTR));
00324       }
00325 
00326       QString refId = objEl.attribute(REF_ATTR);
00327 
00328       if (refId.isEmpty())
00329       {
00330         parseObjectPropertySubTag(id, name, objNode, def);
00331       }
00332       else
00333       {
00334         // Inline ref property
00335         ReferenceDefinition refDef;
00336         refDef.refId = refId;
00337         refDef.isWeak = false;
00338 
00339         def->setPropertyValue( name, QVariant::fromValue(refDef));
00340 
00341         LOG4CXX_DEBUG(logger, "Object " + id.toStdString() + " property name: " + name.toStdString() + " ref: " + refId.toStdString());
00342       }
00343 
00344     }
00345     else
00346     {
00347       throw XmlParseException (QString("File %1: Expecting %2, %3 encountered.")
00348                                .arg(_currentFile).arg(PROPERTY_TAG).arg(objEl.tagName()));
00349     }
00350   }
00351 }
00352 
00353 void
00354 XmlObjectDefinitionReader::parseFactoryObject (QString id, QDomElement & e, ObjectDefinition * def)
00355 {
00356   // if factory-created object, use the factory to create
00357   // Factory-created object does not have path attribute
00358   QString factory = e.attribute(FACTORY_ATTR);
00359   if (factory.isEmpty())
00360   {
00361     throw XmlParseException (QString("File: %1 Object element must have an '%2' attribute or '%3' attribute")                              .arg(_currentFile).arg(PLUGIN_ATTR).arg(FACTORY_ATTR));
00362   }
00363   else
00364   {
00365     def->setFactoryObjectId(factory);
00366   }
00367 
00368   QString factory_method = e.attribute(FACTORY_METHOD_ATTR);
00369   if (factory_method.isEmpty())
00370   {
00371     throw XmlParseException (QString("File: %1 Factory object element must have an '%2' attribute")                                 .arg(_currentFile).arg(FACTORY_METHOD_ATTR));
00372   }
00373   else
00374   {
00375     def->setFactoryMethodName(factory_method);
00376   }
00377   LOG4CXX_DEBUG(logger, "Object: " + std::string(ID_ATTR) + ": " + id.toStdString() + " " + std::string(FACTORY_ATTR) + ": " + factory.toStdString() + " " + std::string(FACTORY_METHOD_ATTR) + ": " + factory_method.toStdString() );
00378 }
00379 
00380 void
00381 XmlObjectDefinitionReader::parseObjectTag (QDomElement & e)
00382 {
00383   DefaultObjectDefinition * def = new DefaultObjectDefinition();
00384   try
00385   {
00386     QString id = e.attribute(ID_ATTR);
00387     if (id.isEmpty())
00388     {
00389       throw XmlParseException (QString("File: %1 Object element must have an '%2' attribute").arg(_currentFile).arg(ID_ATTR));
00390     }
00391     def->setId(id);
00392 
00393     QString init_method = e.attribute(INIT_METHOD_ATTR);
00394     if (!init_method.isEmpty())
00395     {
00396       def->setInitMethodName(init_method);
00397     }
00398 
00399     QString destroy_method = e.attribute(DESTROY_METHOD_ATTR);
00400     if (!destroy_method.isEmpty())
00401     {
00402       def->setDestroyMethodName(destroy_method);
00403     }
00404 
00405     LOG4CXX_DEBUG(logger, "Object: " + std::string(ID_ATTR) + ": " + id.toStdString() + " " + std::string(INIT_METHOD_ATTR) + ": " + init_method.toStdString() + " " + std::string(DESTROY_METHOD_ATTR) + ": " + destroy_method.toStdString());
00406 
00407     QString plugin_path = Util::translateVariable(e.attribute(PLUGIN_ATTR));
00408     if (plugin_path.isEmpty())
00409     {
00410       parseFactoryObject (id, e, def);
00411     }
00412     else
00413     {
00414       LOG4CXX_DEBUG(logger, "Object: " + std::string(ID_ATTR) + ": " + id.toStdString() + " " + std::string(PLUGIN_ATTR) + ": " + plugin_path.toStdString());
00415       def->setPluginPath(plugin_path);
00416     }
00417 
00418     parseObjectPropertyTag (id, e, def);
00419 
00420     _objectRegistry->registerObjectDefinition(id, def);
00421   }
00422   catch (std::exception &)
00423   {
00424     delete def;
00425     throw;
00426   }
00427 
00428 }
00429 
00430 void
00431 XmlObjectDefinitionReader::parseParserTag(QDomElement & e)
00432 {
00433   QString tag = e.attribute(TAG_ATTR);
00434   if (tag.isEmpty())
00435   {
00436     throw XmlParseException (QString("File: %1 parser element must have an '%2' attribute").arg(_currentFile).arg(TAG_ATTR));
00437   }
00438   QString plugin_path = Util::translateVariable(e.attribute(PLUGIN_ATTR));
00439   if (plugin_path.isEmpty())
00440   {
00441     throw XmlParseException (QString("File: %1 parser element must have an '%2' attribute").arg(_currentFile).arg(PLUGIN_ATTR));
00442   }
00443   else
00444   {
00445     LOG4CXX_DEBUG(logger, "Load parser plugin: tag: " + tag.toStdString() + " path: " + plugin_path.toStdString());
00446 
00447     Util::loadPlugin (tag, plugin_path, _parser_loader_map, _parser_map);
00448   }
00449 
00450 }
00451 
00452 void
00453 XmlObjectDefinitionReader::parseInjectorTag(QDomElement & e)
00454 {
00455   QString type = e.attribute(INJECTOR_TYPE_ATTR);
00456   if (type.isEmpty())
00457   {
00458     throw XmlParseException (QString("File: %1 injector element must have an '%2' attribute").arg(_currentFile).arg(INJECTOR_TYPE_ATTR));
00459   }
00460   QString plugin_path = Util::translateVariable(e.attribute(PLUGIN_ATTR));
00461   if (plugin_path.isEmpty())
00462   {
00463     throw XmlParseException (QString("File: %1 injector element must have an '%2' attribute").arg(_currentFile).arg(PLUGIN_ATTR));
00464   }
00465   else
00466   {
00467     _objectRegistry->registerReferenceInjector( type, plugin_path);
00468   }
00469 }