Qt IOC Container 3.5


DefaultApplicationContext.cpp

Go to the documentation of this file.
00001 #include "DefaultApplicationContext.h"
00002 #include "exception/ObjectNotFoundException.h"
00003 #include "exception/FactoryCreateInstanceException.h"
00004 #include "exception/DuplicateObjectIdException.h"
00005 #include "exception/ObjectInitFailException.h"
00006 #include "exception/ObjectDestroyFailException.h"
00007 #include "exception/SetPropertyFailException.h"
00008 #include "exception/CyclicDependencyException.h"
00009 #include "exception/PluginLoadingException.h"
00010 #include "exception/WireFailException.h"
00011 #include "ObjectDefinition.h"
00012 #include "WireDefinition.h"
00013 #include "Util.h"
00014 #include "ReferenceDefinition.h"
00015 #include "ReferenceInjector.h"
00016 
00017 #include <QtGlobal>
00018 #include <QFileInfo>
00019 #include <QLibrary>
00020 #include <QVariant>
00021 
00022 #include <log4cxx/logger.h>
00023 
00024 using namespace log4cxx;
00025 
00026 using namespace qic;
00027 
00028 LoggerPtr DefaultApplicationContext::logger(Logger::getLogger("org.qic.DefaultApplicationContext"));
00029 
00030 QVariant
00031 DefaultApplicationContext::resolveReferenceInPropertyValue(QVariant val)
00032 {
00033   QString type(val.typeName());
00034   LOG4CXX_DEBUG(logger, "Resolving property of type: " + type.toStdString());
00035 
00036   if (_injector_map.contains(type))
00037   {
00038 
00039     LOG4CXX_DEBUG(logger, "Injector plugin found for type: " + type.toStdString());
00040     QObject * injector_obj = _injector_map[type];
00041     ReferenceInjector * injector = qobject_cast<ReferenceInjector *>(injector_obj);
00042     QVariant propVal = injector->injectReference( val, this, _injector_map);
00043     return propVal;
00044   }
00045   else
00046   {
00047     LOG4CXX_DEBUG(logger, "No Injector plugin found for type: " + type.toStdString());
00048     return val;
00049   }
00050 }
00051 
00052 void
00053 DefaultApplicationContext::setProperty(QString id, QString name, QVariant prop)
00054 {
00055   QObject * obj = _object_map[id];
00056   Q_ASSERT (obj);
00057   const QMetaObject * metaObj = obj->metaObject();
00058   Q_ASSERT (metaObj);
00059   int propIndex = metaObj->indexOfProperty(name.toStdString().c_str());
00060   if (propIndex != -1)
00061   {
00062     LOG4CXX_DEBUG(logger, "Resolving reference for object: id: " + id.toStdString() + " property name: " + name.toStdString());
00063     QVariant val = resolveReferenceInPropertyValue(prop);
00064 
00065     LOG4CXX_DEBUG(logger, "Set property. id: " + id.toStdString() + " name: " + name.toStdString());
00066     if(!obj->setProperty(name.toStdString().c_str(), val))
00067     {
00068       throw SetPropertyFailException (QString("Object: %1, Property %2").arg(id).arg(name));
00069     }
00070   }
00071   else
00072   {
00073     throw SetPropertyFailException (QString("Object: %1, Property %2 not defined").arg(id).arg(name));
00074   }
00075 }
00076 
00077 void
00078 DefaultApplicationContext::initObject(QString id)
00079 {
00080   ObjectDefinition * def = _object_definition_map[id];
00081   Q_ASSERT(def);
00082   QString initMethod = def->getInitMethodName();
00083 
00084   if (!initMethod.isEmpty())
00085   {
00086     QObject * obj = _object_map[id];
00087     Q_ASSERT(obj);
00088     const QMetaObject * metaObj = obj->metaObject();
00089     Q_ASSERT(metaObj);
00090     int methodIndex = metaObj->indexOfMethod((initMethod+"()").toStdString().c_str());
00091     if (methodIndex != -1)
00092     {
00093       LOG4CXX_DEBUG(logger, "Calling init-method for object: id: " + id.toStdString() + " init-method: " + initMethod.toStdString());
00094 
00095       if (!QMetaObject::invokeMethod(obj, initMethod.toAscii().data()))
00096       {
00097         throw ObjectInitFailException(id);
00098       }
00099       _object_status_map[id].initMethodCalled = true;
00100     }
00101     else
00102     {
00103       throw ObjectInitFailException (QString("Object: %1, slot method %2 not defined.").arg(id).arg(initMethod));
00104     }
00105   }
00106   else
00107   {
00108     LOG4CXX_DEBUG(logger, "No init-method for object. id: " + id.toStdString());
00109   }
00110 }
00111 
00112 void
00113 DefaultApplicationContext::destroyObject (QString id)
00114 {
00115   ObjectDefinition * def = _object_definition_map[id];
00116   Q_ASSERT(def);
00117   QString destroyMethod = def->getDestroyMethodName();
00118   if (!destroyMethod.isEmpty())
00119   {
00120     bool callDestroy = false;
00121     QString initMethod = def->getInitMethodName();
00122     if (initMethod.isEmpty())
00123     {
00124       callDestroy = true;
00125     }
00126     else
00127     {
00128       if (_object_status_map.contains(id))
00129       {
00130         callDestroy = _object_status_map[id].initMethodCalled;
00131       }
00132       else
00133       {
00134         LOG4CXX_DEBUG(logger, "Init-method was not successfully called. id: " + id.toStdString());
00135       }
00136     }
00137 
00138     if (callDestroy)
00139     {
00140       QObject * obj = _object_map[id];
00141       Q_ASSERT(obj);
00142       const QMetaObject * metaObj = obj->metaObject();
00143       Q_ASSERT(metaObj);
00144       int methodIndex = metaObj->indexOfMethod((destroyMethod+"()").toStdString().c_str());
00145       if (methodIndex != -1)
00146       {
00147         LOG4CXX_DEBUG(logger, "Call destroy method on object: id: " + id.toStdString() + " destroy-method: " + destroyMethod.toStdString());
00148 
00149         if (!QMetaObject::invokeMethod(obj, destroyMethod.toAscii().data()))
00150         {
00151           throw ObjectDestroyFailException(id);
00152         }
00153       }
00154       else
00155       {
00156         throw ObjectDestroyFailException(QString("Object: %1, slot method %2 not defined.").arg(id).arg(destroyMethod));
00157       }
00158     }
00159   }
00160   else
00161   {
00162     LOG4CXX_DEBUG(logger, "Object does not have destroy-method. id: " + id.toStdString());
00163   }
00164 }
00165 
00166 void
00167 DefaultApplicationContext::loadObjects()
00168 {
00169   foreach (QString id, _object_id_list)
00170   {
00171     loadObject (id);
00172   }
00173 }
00174 
00175 void
00176 DefaultApplicationContext::wireObjects ()
00177 {
00178   foreach (WireDefinition * def, _wire_definition_list)
00179   {
00180     wireObject(def);
00181   }
00182 }
00183 
00184 void
00185 DefaultApplicationContext::wireObject (WireDefinition * def)
00186 {
00187   QString signalPrefix = SIGNAL();
00188   QString slotPrefix = SLOT();
00189 
00190   QString sObjId = def->getSenderObjectId();
00191   QString rObjId = def->getReceiverObjectId();
00192   QString sSignal = def->getSenderSignal();
00193   QString rMethod = def->getReceiverMethod();
00194 
00195   LOG4CXX_INFO(logger, "Wiring: sender " + sObjId.toStdString() + " signal " + sSignal.toStdString() + " receiver " + rObjId.toStdString() + " method " + rMethod.toStdString());
00196 
00197   QString type = def->getWireType();
00198 
00199   Qt::ConnectionType connectionType = Util::translateConnectionType(type);
00200 
00201   QObject * sObj = getObject(sObjId);
00202   QObject * rObj = getObject(rObjId);
00203 
00204   const QMetaObject * sMeta = sObj->metaObject ();
00205   const QMetaObject * rMeta = rObj->metaObject ();
00206 
00207   if (sMeta->indexOfSignal(QMetaObject::normalizedSignature(sSignal.toStdString().c_str()).constData()) == -1)
00208   {
00209     throw WireFailException (QString("%1 is not a signal for %2").arg(sSignal).arg(sObjId));
00210   }
00211 
00212   QString signal = signalPrefix + sSignal;
00213 
00214   QString method;
00215 
00216   if (rMeta->indexOfSlot(QMetaObject::normalizedSignature(rMethod.toStdString().c_str()).constData()) == -1)
00217   {
00218     if (rMeta->indexOfSignal(QMetaObject::normalizedSignature(rMethod.toStdString().c_str()).constData()) == -1)
00219     {
00220       throw WireFailException (QString("%1 is not a signal or slot for %2").arg(rMethod).arg(rObjId));
00221     }
00222     else
00223     {
00224       method = signalPrefix + rMethod;
00225     }
00226   }
00227   else
00228   {
00229     method = slotPrefix + rMethod;
00230   }
00231 
00232   LOG4CXX_INFO(logger, "Called QObject::connect for: sender " + sObjId.toStdString() + " signal " + signal.toStdString() + " receiver " + rObjId.toStdString() + " method " + method.toStdString());
00233   if (!QObject::connect (sObj, signal.toStdString().c_str(), rObj, method.toStdString().c_str(), connectionType))
00234   {
00235     throw WireFailException (QString("Signal Slot Connection Fail: sender %1, signal %2, receiver %3 method %4").arg(sObjId).arg(sSignal).arg(rObjId).arg(rMethod));
00236   }
00237 }
00238 
00239 void
00240 DefaultApplicationContext::createObject (QString id)
00241 {
00242   ObjectDefinition * def = _object_definition_map[id];
00243   Q_ASSERT(def);
00244   QString factory = def->getFactoryObjectId();
00245   if (factory.isEmpty())
00246   {
00247     // plugin objects
00248     QString plugin_path = def->getPluginPath();
00249     QFileInfo f(plugin_path);
00250     if (!f.exists())
00251     {
00252       throw PluginLoadingException(plugin_path + " does not exist. ");
00253     }
00254     if (!QLibrary::isLibrary(plugin_path))
00255     {
00256       throw PluginLoadingException(plugin_path + " is not a plugin. ");
00257     }
00258     LOG4CXX_DEBUG(logger, "Load plugin object. id: " + id.toStdString() + " plugin-path: " + plugin_path.toStdString());
00259     Util::loadPlugin(id, plugin_path, _object_loader_map, _object_map);
00260   }
00261   else
00262   {
00263     if (!objectLoaded(factory))
00264     {
00265       // if factory is not loaded, load it first
00266       if (_object_definition_map.contains(factory))
00267       {
00268         LOG4CXX_DEBUG(logger, "Load factory. id: " + factory.toStdString());
00269         loadObject (factory);
00270       }
00271       else
00272       {
00273         throw ObjectNotFoundException(factory);
00274       }
00275     }
00276 
00277     QObject * fac_obj = _object_map[factory];
00278     Q_ASSERT(fac_obj);
00279     QString method = def->getFactoryMethodName();
00280     const QMetaObject * metaObj = fac_obj->metaObject();
00281     Q_ASSERT(metaObj);
00282     int methodIndex = metaObj->indexOfMethod((method + "()").toStdString().c_str());
00283     if (methodIndex != -1)
00284     {
00285       LOG4CXX_DEBUG(logger, "Create object using factory. factory id: " + factory.toStdString() + " factory-method: " + method.toStdString());
00286       QVariant ret;
00287       if (!QMetaObject::invokeMethod(fac_obj, method.toAscii().data(), Q_RETURN_ARG(QVariant, ret)))
00288       {
00289         throw FactoryCreateInstanceException(QString("Factory object: %1, method: %2").arg(factory).arg(method));
00290       }
00291       _object_map[id] = ret.value<QObject *>();
00292     }
00293     else
00294     {
00295       throw FactoryCreateInstanceException(QString("Factory method %1 not found for object id %2.").arg(method).arg(factory));
00296     }
00297   }
00298 }
00299 
00300 void
00301 DefaultApplicationContext::registerReferenceInjector (QString type, QString plugin_path)
00302 {
00303   LOG4CXX_DEBUG(logger, "Load injector plugin: type: " + type.toStdString() + " path: " + plugin_path.toStdString());
00304 
00305   Util::loadPlugin (type, plugin_path, _injector_loader_map, _injector_map);
00306 }
00307 
00308 QObject *
00309 DefaultApplicationContext::resolveReferenceObject (ReferenceDefinition ref)
00310 {
00311   if(!_object_definition_map.contains(ref.refId))
00312   {
00313     throw ObjectNotFoundException(ref.refId);
00314   }
00315   if (!objectLoaded(ref.refId))
00316   {
00317     if (ref.isWeak)
00318     {
00319       createObject (ref.refId);
00320     }
00321     else
00322     {
00323       loadObject (ref.refId);
00324     }
00325   }
00326 
00327   QObject * refObj = _object_map[ref.refId];
00328   return refObj;
00329 }
00330 
00331 void
00332 DefaultApplicationContext::injectDependencies (QString id)
00333 {
00334 
00335   ObjectDefinition * def = _object_definition_map[id];
00336   Q_ASSERT(def);
00337 
00338   QHash<QString, QVariant> * props = def->getPropertyValues();
00339   Q_ASSERT(props);
00340   foreach (QString name, props->keys())
00341   {
00342     QVariant val = props->value(name);
00343     setProperty(id, name, val);
00344   }
00345 }
00346 
00347 bool
00348 DefaultApplicationContext::objectStartLoading (QString id)
00349 {
00350   return _object_status_map.contains(id);
00351 }
00352 
00353 bool
00354 DefaultApplicationContext::objectLoaded (QString id)
00355 {
00356   if(!_object_status_map.contains(id))
00357   {
00358     return false;
00359   }
00360   else
00361   {
00362     ObjectStatus status = _object_status_map[id];
00363     return !status.inConstruction;
00364   }
00365 }
00366 
00367 void
00368 DefaultApplicationContext::loadObject (QString id)
00369 {
00370   if (!objectLoaded( id))
00371   {
00372     if(!objectStartLoading(id))
00373     {
00374       ObjectStatus status;
00375       status.inConstruction = true;
00376       status.initMethodCalled = false;
00377       _object_status_map.insert(id, status);
00378 
00379       LOG4CXX_INFO(logger, "Loading object. id: " + id.toStdString());
00380       if (!containsObject(id))
00381       {
00382         createObject (id);
00383       }
00384       injectDependencies (id);
00385       initObject (id);
00386       _object_status_map[id].inConstruction = false;
00387       LOG4CXX_INFO(logger, "Object loaded. id: " + id.toStdString());
00388     }
00389     else
00390     {
00391       ObjectStatus status = _object_status_map[id];
00392       Q_ASSERT(status.inConstruction);
00393       throw CyclicDependencyException (id);
00394     }
00395   }
00396 }
00397 
00398 void
00399 DefaultApplicationContext::deleteFactoryCreatedObjects ()
00400 {
00401   LOG4CXX_INFO(logger, "Delete factory created objects.");
00402 
00403   // delete factory created objects
00404   foreach (QString id, _object_map.keys())
00405   {
00406     ObjectDefinition * def = _object_definition_map[id];
00407     Q_ASSERT(def);
00408     QString factory = def->getFactoryObjectId();
00409     if (!factory.isEmpty())
00410     {
00411       LOG4CXX_DEBUG(logger, "Delete factory created object: id: " + id.toStdString() + " factory: " + factory.toStdString());
00412 
00413       QObject * obj = _object_map[id];
00414       delete obj;
00415     }
00416     else
00417     {
00418       LOG4CXX_DEBUG(logger, "Plugin object, don't need to delete. id: " + id.toStdString());
00419     }
00420   }
00421 }
00422 
00423 void
00424 DefaultApplicationContext::unloadPlugins ()
00425 {
00426   // unload plugin objects, delete plugin loader
00427   foreach (QString id, _object_loader_map.keys())
00428   {
00429     QPluginLoader * loader = _object_loader_map[id];
00430     Q_ASSERT(loader);
00431     LOG4CXX_DEBUG(logger, "Unload plugin object. id: " + id.toStdString());
00432     loader->unload();
00433     delete loader;
00434   }
00435 }
00436 
00437 void
00438 DefaultApplicationContext::deleteObjectDefinitions()
00439 {
00440   // delete object definitions
00441   foreach (QString id, _object_definition_map.keys())
00442   {
00443     ObjectDefinition * def = _object_definition_map[id];
00444     Q_ASSERT(def);
00445     LOG4CXX_DEBUG(logger, "Delete object definition. id: " + id.toStdString());
00446 
00447     delete def;
00448   }
00449 }
00450 
00451 void
00452 DefaultApplicationContext::deleteWireDefinitions ()
00453 {
00454   foreach (WireDefinition * def, _wire_definition_list)
00455   {
00456     if (def)
00457     {
00458       delete def;
00459     }
00460   }
00461 }
00462 
00463 void
00464 DefaultApplicationContext::destroyObjects()
00465 {
00466   foreach (QString id, _object_id_list)
00467   {
00468     destroyObject (id);
00469   }
00470 }
00471 
00472 DefaultApplicationContext::DefaultApplicationContext ()
00473 {}
00474 
00475 DefaultApplicationContext::~ DefaultApplicationContext()
00476 {
00477   //call destroy-method on objects
00478   destroyObjects ();
00479   deleteFactoryCreatedObjects ();
00480   unloadPlugins ();
00481   deleteObjectDefinitions();
00482   deleteWireDefinitions();
00483   unloadInjectorPlugins();
00484 }
00485 
00486 void
00487 DefaultApplicationContext::unloadInjectorPlugins ()
00488 {
00489   LOG4CXX_INFO(logger, "Unloading injector plugins. ");
00490 
00491   foreach (QString id, _injector_loader_map.keys())
00492   {
00493     QPluginLoader * loader = _injector_loader_map[id];
00494     if (loader)
00495     {
00496       loader->unload();
00497       delete loader;
00498     }
00499     else
00500     {
00501       LOG4CXX_WARN(logger, "Inconsistent application context. NULL plugin loader. id: " + id.toStdString());
00502     }
00503   }
00504 }
00505 
00506 bool
00507 DefaultApplicationContext::containsObject(QString id)
00508 {
00509   return _object_map.contains(id);
00510 }
00511 
00512 QObject *
00513 DefaultApplicationContext::getObject(QString id)
00514 {
00515   if (containsObject(id))
00516   {
00517     return _object_map[id];
00518   }
00519   else
00520   {
00521     throw ObjectNotFoundException(id);
00522   }
00523 }
00524 
00525 ObjectDefinition *
00526 DefaultApplicationContext::getObjectDefinition(QString id)
00527 {
00528   if (_object_definition_map.contains(id))
00529   {
00530     return _object_definition_map[id];
00531   }
00532   else
00533   {
00534     throw ObjectNotFoundException(id);
00535   }
00536 }
00537 
00538 QList<WireDefinition *>
00539 DefaultApplicationContext::getWireDefinitions ()
00540 {
00541   return _wire_definition_list;
00542 }
00543 
00544 QStringList
00545 DefaultApplicationContext::getObjectDefinitionIds ()
00546 {
00547   return _object_id_list;
00548 }
00549 
00550 void
00551 DefaultApplicationContext::registerObjectDefinition (QString id, ObjectDefinition * objectDefinition)
00552 {
00553   LOG4CXX_INFO(logger, "Registering object. id: " + id.toStdString());
00554   if (_object_definition_map.contains(id))
00555   {
00556     throw DuplicateObjectIdException (id);
00557   }
00558   _object_id_list.append(id);
00559   _object_definition_map[id] = objectDefinition;
00560 }
00561 
00562 void
00563 DefaultApplicationContext::registerWireDefinition (WireDefinition * wireDefinition)
00564 {
00565   LOG4CXX_INFO(logger, "Registering wire definition. sender: " + wireDefinition->getSenderObjectId().toStdString() + " signal: " + wireDefinition->getSenderSignal().toStdString() + " receiver: " + wireDefinition->getReceiverObjectId().toStdString() + " method: " + wireDefinition->getReceiverMethod().toStdString());
00566 
00567   _wire_definition_list.append(wireDefinition);
00568 }
00569 
00570 
00571 
00572 
00573 
00574