ctkPluginPrivate.cpp

Go to the documentation of this file.
00001 /*=============================================================================
00002 
00003   Library: CTK
00004 
00005   Copyright (c) 2010 German Cancer Research Center,
00006     Division of Medical and Biological Informatics
00007 
00008   Licensed under the Apache License, Version 2.0 (the "License");
00009   you may not use this file except in compliance with the License.
00010   You may obtain a copy of the License at
00011 
00012     http://www.apache.org/licenses/LICENSE-2.0
00013 
00014   Unless required by applicable law or agreed to in writing, software
00015   distributed under the License is distributed on an "AS IS" BASIS,
00016   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00017   See the License for the specific language governing permissions and
00018   limitations under the License.
00019 
00020 =============================================================================*/
00021 
00022 #include "ctkPluginPrivate_p.h"
00023 
00024 #include "ctkPluginConstants.h"
00025 #include "ctkPluginDatabaseException.h"
00026 #include "ctkPluginArchive_p.h"
00027 #include "ctkPluginFrameworkContext_p.h"
00028 #include "ctkPluginFrameworkUtil_p.h"
00029 #include "ctkPluginActivator.h"
00030 
00031 
00032   const ctkPlugin::States ctkPluginPrivate::RESOLVED_FLAGS = ctkPlugin::RESOLVED | ctkPlugin::STARTING | ctkPlugin::ACTIVE | ctkPlugin::STOPPING;
00033 
00034 
00035   ctkPluginPrivate::ctkPluginPrivate(
00036       ctkPlugin& qq,
00037       ctkPluginFrameworkContext* fw,
00038       ctkPluginArchive* pa)
00039     : q_ptr(&qq), fwCtx(fw), id(pa->getPluginId()),
00040     location(pa->getPluginLocation().toString()), state(ctkPlugin::INSTALLED),
00041     archive(pa), pluginContext(0), pluginActivator(0), pluginLoader(pa->getLibLocation()),
00042     lastModified(0), eagerActivation(false), activating(false), deactivating(false)
00043   {
00044     //TODO
00045     //checkCertificates(pa);
00046 
00047     checkManifestHeaders();
00048 
00049     // fill require list
00050     QString requireString = archive->getAttribute(PluginConstants::REQUIRE_PLUGIN);
00051     QList<QMap<QString, QStringList> > requireList = ctkPluginFrameworkUtil::parseEntries(PluginConstants::REQUIRE_PLUGIN,
00052                                                                          requireString, true, true, false);
00053     QListIterator<QMap<QString, QStringList> > i(requireList);
00054     while (i.hasNext())
00055     {
00056       const QMap<QString, QStringList>& e = i.next();
00057       const QStringList& res = e.value(PluginConstants::RESOLUTION_DIRECTIVE);
00058       const QStringList& version = e.value(PluginConstants::PLUGIN_VERSION_ATTRIBUTE);
00059       ctkRequirePlugin* rp = new ctkRequirePlugin(this, e.value("$key").front(),
00060                                             res.empty() ? QString() : res.front(),
00061                                             version.empty() ? QString() : version.front());
00062       require.push_back(rp);
00063     }
00064   }
00065 
00066   ctkPluginPrivate::ctkPluginPrivate(ctkPlugin& qq,
00067     ctkPluginFrameworkContext* fw,
00068     long id, const QString& loc, const QString& sym, const ctkVersion& ver)
00069       : q_ptr(&qq), fwCtx(fw), id(id), location(loc), symbolicName(sym), version(ver),
00070       state(ctkPlugin::INSTALLED), archive(0), pluginContext(0),
00071       pluginActivator(0), lastModified(0),
00072       eagerActivation(false), activating(false), deactivating(false)
00073   {
00074 
00075   }
00076 
00077   ctkPluginPrivate::~ctkPluginPrivate()
00078   {
00079     qDeleteAll(require);
00080   }
00081 
00082   ctkPlugin::State ctkPluginPrivate::getUpdatedState()
00083   {
00084     if (state & ctkPlugin::INSTALLED)
00085     {
00086       try
00087       {
00088         if (state == ctkPlugin::INSTALLED)
00089         {
00090           fwCtx->resolvePlugin(this);
00091           state = ctkPlugin::RESOLVED;
00092           fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::RESOLVED, this->q_func()));
00093         }
00094 
00095       }
00096       catch (const ctkPluginException& pe)
00097       {
00098         Q_Q(ctkPlugin);
00099         this->fwCtx->listeners.frameworkError(q, pe);
00100         throw;
00101       }
00102     }
00103 
00104     return state;
00105   }
00106 
00107   void ctkPluginPrivate::setAutostartSetting(const ctkPlugin::StartOptions& setting) {
00108     try
00109     {
00110       if (archive)
00111       {
00112         archive->setAutostartSetting(setting);
00113       }
00114     }
00115     catch (const ctkPluginDatabaseException& e)
00116     {
00117       Q_Q(ctkPlugin);
00118       this->fwCtx->listeners.frameworkError(q, e);
00119     }
00120   }
00121 
00122   void ctkPluginPrivate::checkManifestHeaders()
00123   {
00124     symbolicName = archive->getAttribute(PluginConstants::PLUGIN_SYMBOLICNAME);
00125 
00126     if (symbolicName.isEmpty())
00127     {
00128       throw std::invalid_argument(std::string("ctkPlugin has no symbolic name, location=") +
00129                                            qPrintable(location));
00130     }
00131 
00132     QString mpv = archive->getAttribute(PluginConstants::PLUGIN_VERSION);
00133     if (!mpv.isEmpty())
00134     {
00135       try
00136       {
00137         version = ctkVersion(mpv);
00138       }
00139       catch (const std::exception& e)
00140       {
00141         throw std::invalid_argument(std::string("ctkPlugin does not specify a valid ") +
00142                                     qPrintable(PluginConstants::PLUGIN_VERSION) + " header. Got exception: " + e.what());
00143       }
00144     }
00145 
00146     QString ap = archive->getAttribute(PluginConstants::PLUGIN_ACTIVATIONPOLICY);
00147     if (PluginConstants::ACTIVATION_EAGER == ap)
00148     {
00149       eagerActivation = true;
00150     }
00151 
00152   }
00153 
00154   void ctkPluginPrivate::finalizeActivation()
00155   {
00156     switch (getUpdatedState())
00157     {
00158       case ctkPlugin::INSTALLED:
00159         // we shouldn't be here, getUpdatedState should have thrown
00160         // an exception during resolving the plugin
00161         throw ctkPluginException("Internal error: expected exception on plugin resolve not thrown!");
00162       case ctkPlugin::STARTING:
00163         if (activating) return; // finalization already in progress.
00164         // Lazy activation; fall through to RESOLVED.
00165       case ctkPlugin::RESOLVED:
00166         //6:
00167         state = ctkPlugin::STARTING;
00168         activating = true;
00169         qDebug() << "activating #" << this->id;
00170         //7:
00171         if (!pluginContext)
00172         {
00173           pluginContext = new ctkPluginContext(this);
00174         }
00175         try
00176         {
00177           //TODO maybe call this in its own thread
00178           start0();
00179         }
00180         catch (...)
00181         {
00182           //8:
00183           state = ctkPlugin::STOPPING;
00184           // NYI, call outside lock
00185           fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::STOPPING, this->q_func()));
00186           removePluginResources();
00187           delete pluginContext;
00188 
00189           state = ctkPlugin::RESOLVED;
00190           // NYI, call outside lock
00191           fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::STOPPED, this->q_func()));
00192           activating = false;
00193           throw;
00194         }
00195         activating = false;
00196         break;
00197       case ctkPlugin::ACTIVE:
00198         break;
00199       case ctkPlugin::STOPPING:
00200         // This happens if start is called from inside the ctkPluginActivator::stop method.
00201         // Don't allow it.
00202         throw ctkPluginException("start called from ctkPluginActivator::stop",
00203                               ctkPluginException::ACTIVATOR_ERROR);
00204       case ctkPlugin::UNINSTALLED:
00205         throw std::logic_error("ctkPlugin is in UNINSTALLED state");
00206       }
00207   }
00208 
00209   void ctkPluginPrivate::start0()
00210   {
00211     fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::STARTING, this->q_func()));
00212 
00213     try {
00214       pluginLoader.load();
00215       if (!pluginLoader.isLoaded())
00216       {
00217         throw ctkPluginException(QString("Loading plugin %1 failed: %2").arg(pluginLoader.fileName()).arg(pluginLoader.errorString()),
00218                               ctkPluginException::ACTIVATOR_ERROR);
00219       }
00220 
00221       pluginActivator = qobject_cast<ctkPluginActivator*>(pluginLoader.instance());
00222       if (!pluginActivator)
00223       {
00224         throw ctkPluginException(QString("Creating ctkPluginActivator instance from %1 failed: %2").arg(pluginLoader.fileName()).arg(pluginLoader.errorString()),
00225                               ctkPluginException::ACTIVATOR_ERROR);
00226       }
00227 
00228       pluginActivator->start(pluginContext);
00229 
00230       if (ctkPlugin::UNINSTALLED == state)
00231       {
00232         throw ctkPluginException("ctkPlugin uninstalled during start()", ctkPluginException::STATECHANGE_ERROR);
00233       }
00234       state = ctkPlugin::ACTIVE;
00235     }
00236     catch (const std::exception& e)
00237     {
00238       throw ctkPluginException("ctkPlugin start failed", ctkPluginException::ACTIVATOR_ERROR, e);
00239     }
00240 
00241     qDebug() << "activating #" << id << "completed.";
00242 
00243     //10:
00244     fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::STARTED, this->q_func()));
00245   }
00246 
00247   void ctkPluginPrivate::removePluginResources()
00248   {
00249     // automatic disconnect due to Qt signal slot
00250     //fwCtx->listeners.removeAllListeners(this);
00251 
00252     // TODO
00253 //    Set srs = fwCtx.services.getRegisteredByBundle(this);
00254 //    for (Iterator i = srs.iterator(); i.hasNext();) {
00255 //      try {
00256 //        ((ctkServiceRegistration)i.next()).unregister();
00257 //      } catch (IllegalStateException ignore) {
00258 //        // Someone has unregistered the service after stop completed.
00259 //        // This should not occur, but we don't want get stuck in
00260 //        // an illegal state so we catch it.
00261 //      }
00262 //    }
00263 //    Set s = fwCtx.services.getUsedByBundle(this);
00264 //    for (Iterator i = s.iterator(); i.hasNext(); ) {
00265 //      ((ServiceRegistrationImpl) i.next()).reference.ungetService(this, false);
00266 //    }
00267 
00268 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines