//---------------------------------------------------------------------------- void ctkPluginPrivate::finalizeActivation() { Locker sync(&operationLock); // 4: Resolve plugin (if needed) switch (getUpdatedState_unlocked()) { case ctkPlugin::INSTALLED: Q_ASSERT_X(resolveFailException != 0, Q_FUNC_INFO, "no resolveFailException"); throw ctkPluginException(*resolveFailException); case ctkPlugin::STARTING: if (operation.fetchAndAddOrdered(0) == ACTIVATING) return; // finalization already in progress. // Lazy activation; fall through to RESOLVED. case ctkPlugin::RESOLVED: { //6: state = ctkPlugin::STARTING; operation.fetchAndStoreOrdered(ACTIVATING); if (fwCtx->debug.lazy_activation) { qDebug() << "activating #" << this->id; } //7: if (!pluginContext) { pluginContext.reset(new ctkPluginContext(this)); } // start dependencies startDependencies(); //TODO plugin threading //ctkRuntimeException* e = bundleThread().callStart0(this); ctkRuntimeException* e = start0(); operation.fetchAndStoreOrdered(IDLE); operationLock.wakeAll(); if (e) { ctkRuntimeException re(*e); delete e; throw re; } break; } case ctkPlugin::ACTIVE: break; case ctkPlugin::STOPPING: // This happens if start is called from inside the ctkPluginActivator::stop method. // Don't allow it. throw ctkPluginException("start called from ctkPluginActivator::stop", ctkPluginException::ACTIVATOR_ERROR); case ctkPlugin::UNINSTALLED: throw ctkIllegalStateException("ctkPlugin is in UNINSTALLED state"); } }
//---------------------------------------------------------------------------- void ctkPluginPrivate::waitOnOperation(LockObject* lock, const QString& src, bool longWait) { if (operation.fetchAndAddOrdered(0) != IDLE) { qint64 left = longWait ? 20000 : 500; QDateTime waitUntil = QDateTime::currentDateTime().addMSecs(left); do { lock->wait(left); if (operation.fetchAndAddOrdered(0) == IDLE) { return; } // TODO use Qt 4.7 QDateTime::msecsTo() API //left = QDateTime::currentDateTime().msecsTo(waitUntil); left = ctk::msecsTo(QDateTime::currentDateTime(), waitUntil); } while (left > 0); QString op; switch (operation.fetchAndAddOrdered(0)) { case IDLE: // Should not happen! return; case ACTIVATING: op = "start"; break; case DEACTIVATING: op = "stop"; break; case RESOLVING: op = "resolve"; break; case UNINSTALLING: op = "uninstall"; break; case UNRESOLVING: op = "unresolve"; break; case UPDATING: op = "update"; break; default: op = "unknown operation"; break; } throw ctkPluginException(src + " called during " + op + " of plug-in", ctkPluginException::STATECHANGE_ERROR); } }
void ctkPluginFrameworkContext::checkRequirePlugin(ctkPluginPrivate *plugin) { if (!plugin->require.isEmpty()) { qDebug() << "checkRequirePlugin: check requiring plugin" << plugin->id; QListIterator<ctkRequirePlugin*> i(plugin->require); while (i.hasNext()) { ctkRequirePlugin* pr = i.next(); QList<ctkPlugin*> pl = plugins->getPlugins(pr->name, pr->pluginRange); ctkPluginPrivate* ok = 0; for (QListIterator<ctkPlugin*> pci(pl); pci.hasNext() && ok == 0; ) { ctkPluginPrivate* p2 = pci.next()->d_func(); if (tempResolved.contains(p2)) { ok = p2; } else if (ctkPluginPrivate::RESOLVED_FLAGS & p2->state) { ok = p2; } else if (p2->state == ctkPlugin::INSTALLED) { QSet<ctkPluginPrivate*> oldTempResolved = tempResolved; tempResolved.insert(p2); checkRequirePlugin(p2); tempResolved = oldTempResolved; ok = p2; } } if (!ok && pr->resolution == ctkPluginConstants::RESOLUTION_MANDATORY) { tempResolved.clear(); qDebug() << "checkRequirePlugin: failed to satisfy:" << pr->name; throw ctkPluginException(QString("Failed to resolve required plugin: %1").arg(pr->name)); } } } }
//---------------------------------------------------------------------------- void ctkPluginFramework::uninstall() { throw ctkPluginException("uninstall of System plugin is not allowed", ctkPluginException::INVALID_OPERATION); }
//---------------------------------------------------------------------------- void ctkPluginPrivate::update0(const QUrl& updateLocation, bool wasActive) { const bool wasResolved = state == ctkPlugin::RESOLVED; const int oldStartLevel = getStartLevel(); QSharedPointer<ctkPluginArchive> newArchive; operation.fetchAndStoreOrdered(UPDATING); try { // New plugin as stream supplied? QUrl updateUrl(updateLocation); if (updateUrl.isEmpty()) { // Try Plugin-UpdateLocation QString update = archive != 0 ? archive->getAttribute(ctkPluginConstants::PLUGIN_UPDATELOCATION) : QString(); if (update.isEmpty()) { // Take original location updateUrl = location; } } if(updateUrl.scheme() != "file") { QString msg = "Unsupported update URL:"; msg += updateUrl.toString(); throw ctkPluginException(msg); } newArchive = fwCtx->storage->updatePluginArchive(archive, updateUrl, updateUrl.toLocalFile()); //checkCertificates(newArchive); checkManifestHeaders(); newArchive->setStartLevel(oldStartLevel); fwCtx->storage->replacePluginArchive(archive, newArchive); } catch (const std::exception& e) { if (!newArchive.isNull()) { newArchive->purge(); } operation.fetchAndStoreOrdered(IDLE); if (wasActive) { try { this->q_func().data()->start(); } catch (const ctkPluginException& pe) { fwCtx->listeners.frameworkError(this->q_func(), pe); } } try { const ctkPluginException& pe = dynamic_cast<const ctkPluginException&>(e); throw pe; } catch (std::bad_cast) { throw ctkPluginException(QString("Failed to get update plugin: ") + e.what(), ctkPluginException::UNSPECIFIED); } } bool purgeOld = false; // TODO: check if dependent plug-ins are started. If not, set purgeOld to true. // Activate new plug-in QSharedPointer<ctkPluginArchive> oldArchive = archive; archive = newArchive; cachedRawHeaders.clear(); state = ctkPlugin::INSTALLED; // Purge old archive if (purgeOld) { //secure.purge(this, oldProtectionDomain); if (oldArchive != 0) { oldArchive->purge(); } } // Broadcast events if (wasResolved) { // TODO: use plugin threading //bundleThread().bundleChanged(new BundleEvent(BundleEvent.UNRESOLVED, this)); fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::UNRESOLVED, this->q_func())); } //bundleThread().bundleChanged(new BundleEvent(BundleEvent.UPDATED, this)); fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::UPDATED, this->q_func())); operation.fetchAndStoreOrdered(IDLE); // Restart plugin previously stopped in the operation if (wasActive) { try { this->q_func().data()->start(); } catch (const ctkPluginException& pe) { fwCtx->listeners.frameworkError(this->q_func(), pe); } } }
//---------------------------------------------------------------------------- QSharedPointer<ctkPlugin> ctkPlugins::install(const QUrl& location, QIODevice* in) { if (!fwCtx) { // This ctkPlugins instance has been closed! throw std::logic_error("ctkPlugins::install(location, inputStream) called on closed plugins object."); } { QWriteLocker lock(&pluginsLock); QHash<QString, QSharedPointer<ctkPlugin> >::const_iterator it = plugins.find(location.toString()); if (it != plugins.end()) { return it.value(); } // install new plugin ctkPluginArchive* pa = 0; QString localPluginPath; try { if (!in) { // extract the input stream from the given location // //TODO Support for http proxy authentication // //TODO put in update as well // String auth = fwCtx.props.getProperty("http.proxyAuth"); // if (auth != null && !"".equals(auth)) { // if ("http".equals(url.getProtocol()) || // "https".equals(url.getProtocol())) { // String base64 = Util.base64Encode(auth); // conn.setRequestProperty("Proxy-Authorization", // "Basic " + base64); // } // } // // Support for http basic authentication // String basicAuth = fwCtx.props.getProperty("http.basicAuth"); // if (basicAuth != null && !"".equals(basicAuth)) { // if ("http".equals(url.getProtocol()) || // "https".equals(url.getProtocol())) { // String base64 = Util.base64Encode(basicAuth); // conn.setRequestProperty("Authorization", // "Basic " +base64); // } // } if (location.scheme() != "file") { throw std::runtime_error(std::string("Unsupported url scheme: ") + qPrintable(location.scheme())); } else { qDebug() << QString("Trying to install file:") << location.path(); localPluginPath = location.toLocalFile(); } } else { //TODO copy the QIODevice to a local cache } pa = fwCtx->storage->insertPlugin(location, localPluginPath); QSharedPointer<ctkPlugin> res(new ctkPlugin()); res->init(res, fwCtx, pa); plugins.insert(location.toString(), res); fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::INSTALLED, res)); return res; } catch (const std::exception& e) { if (pa) { pa->purge(); } // if (dynamic_cast<const SecurityException&>(e)) { // throw; // } // else // { throw ctkPluginException(QString("Failed to install plugin: ") + QString(e.what()), ctkPluginException::UNSPECIFIED, &e); // } } } }