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
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
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
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
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
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
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