ctkServices.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 "ctkServices_p.h"
00023 
00024 #include <QStringListIterator>
00025 #include <QMutexLocker>
00026 #include <QBuffer>
00027 
00028 #include <algorithm>
00029 
00030 #include "ctkServiceFactory.h"
00031 #include "ctkPluginConstants.h"
00032 #include "ctkServiceRegistrationPrivate.h"
00033 #include "ctkQtServiceRegistration_p.h"
00034 #include "ctkLDAPExpr.h"
00035 
00036 
00037   using namespace QtMobility;
00038 
00039 
00040 
00041   struct ServiceRegistrationComparator
00042   {
00043     bool operator()(const ctkServiceRegistration* a, const ctkServiceRegistration* b) const
00044     {
00045       return *a < *b;
00046     }
00047   };
00048 
00049   ServiceProperties ctkServices::createServiceProperties(const ServiceProperties& in,
00050                                                       const QStringList& classes,
00051                                                       long sid)
00052   {
00053     static qlonglong nextServiceID = 1;
00054     ServiceProperties props;
00055 
00056     if (!in.isEmpty())
00057     {
00058       for (ServiceProperties::const_iterator it = in.begin(); it != in.end(); ++it)
00059       {
00060         const QString key = it.key();
00061         const QString lcKey = it.key().toLower();
00062         for (QListIterator<QString> i(props.keys()); i.hasNext(); )
00063         {
00064           if (lcKey == i.next())
00065           {
00066             throw std::invalid_argument(std::string("Several entries for property: ") + key.toStdString());
00067           }
00068         }
00069 
00070         props.insert(lcKey, in.value(key));
00071       }
00072     }
00073 
00074     if (!classes.isEmpty())
00075     {
00076       props.insert(PluginConstants::OBJECTCLASS, classes);
00077     }
00078 
00079     props.insert(PluginConstants::SERVICE_ID, sid != -1 ? sid : nextServiceID++);
00080 
00081     return props;
00082   }
00083 
00084 
00085 ctkServices::ctkServices(ctkPluginFrameworkContext* fwCtx)
00086   : mutex(QMutex::Recursive), framework(fwCtx)
00087 {
00088 
00089 }
00090 
00091 ctkServices::~ctkServices()
00092 {
00093   clear();
00094 }
00095 
00096 void ctkServices::clear()
00097 {
00098   QList<ctkServiceRegistration*> serviceRegs = services.keys();
00099   qDeleteAll(serviceRegs);
00100   services.clear();
00101   classServices.clear();
00102   framework = 0;
00103 }
00104 
00105 ctkServiceRegistration* ctkServices::registerService(ctkPluginPrivate* plugin,
00106                              const QStringList& classes,
00107                              QObject* service,
00108                              const ServiceProperties& properties)
00109 {
00110   if (service == 0)
00111   {
00112     throw std::invalid_argument("Can't register 0 as a service");
00113   }
00114 
00115   // Check if service implements claimed classes and that they exist.
00116   for (QStringListIterator i(classes); i.hasNext();)
00117   {
00118     QString cls = i.next();
00119     if (cls.isEmpty())
00120     {
00121       throw std::invalid_argument("Can't register as null class");
00122     }
00123 
00124     if (!(qobject_cast<ctkServiceFactory*>(service)))
00125     {
00126       if (!checkServiceClass(service, cls))
00127       {
00128         throw std::invalid_argument
00129             (std::string("Service object is not an instance of ") + cls.toStdString());
00130       }
00131     }
00132   }
00133 
00134   ctkServiceRegistration* res = new ctkServiceRegistration(plugin, service,
00135                                 createServiceProperties(properties, classes));
00136   {
00137     QMutexLocker lock(&mutex);
00138     services.insert(res, classes);
00139     for (QStringListIterator i(classes); i.hasNext(); )
00140     {
00141       QString currClass = i.next();
00142       QList<ctkServiceRegistration*>& s = classServices[currClass];
00143       QList<ctkServiceRegistration*>::iterator ip =
00144           std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator());
00145       s.insert(ip, res);
00146     }
00147   }
00148 
00149   ctkServiceReference* r = res->getReference();
00150   // TODO
00151   //Listeners l = bundle.fwCtx.listeners;
00152   //l.serviceChanged(l.getMatchingServiceListeners(r),
00153   //                 new ServiceEvent(ServiceEvent.REGISTERED, r),
00154   //                 null);
00155   return res;
00156 }
00157 
00158 void ctkServices::registerService(ctkPluginPrivate* plugin, QByteArray serviceDescription)
00159 {
00160   QMutexLocker lock(&mutex);
00161 
00162   QBuffer serviceBuffer(&serviceDescription);
00163   qServiceManager.addService(&serviceBuffer);
00164   QServiceManager::Error error = qServiceManager.error();
00165   if (!(error == QServiceManager::NoError || error == QServiceManager::ServiceAlreadyExists))
00166   {
00167     throw std::invalid_argument(std::string("Registering the service descriptor for plugin ")
00168                                 + plugin->symbolicName.toStdString() + " failed: " +
00169                                 getQServiceManagerErrorString(error).toStdString());
00170   }
00171 
00172   QString serviceName = plugin->symbolicName + "_" + plugin->version.toString();
00173   QList<QServiceInterfaceDescriptor> descriptors = qServiceManager.findInterfaces(serviceName);
00174 
00175   if (descriptors.isEmpty())
00176   {
00177     qDebug().nospace() << "Warning: No interfaces found for service name " << serviceName
00178         << " in plugin " << plugin->symbolicName << " (ctkVersion " << plugin->version.toString() << ")";
00179   }
00180 
00181   QListIterator<QServiceInterfaceDescriptor> it(descriptors);
00182   while (it.hasNext())
00183   {
00184     QServiceInterfaceDescriptor descr = it.next();
00185     qDebug() << "Registering:" << descr.interfaceName();
00186     QStringList classes;
00187     ServiceProperties props;
00188 
00189     QStringList customKeys = descr.customAttributes();
00190     QStringListIterator keyIt(customKeys);
00191     bool classAttrFound = false;
00192     while (keyIt.hasNext())
00193     {
00194       QString key = keyIt.next();
00195       if (key == PluginConstants::OBJECTCLASS)
00196       {
00197         classAttrFound = true;
00198         classes << descr.customAttribute(key);
00199       }
00200       else
00201       {
00202         props.insert(key, descr.customAttribute(key));
00203       }
00204     }
00205 
00206     if (!classAttrFound)
00207     {
00208       throw std::invalid_argument(std::string("The custom attribute \"") +
00209                                   PluginConstants::OBJECTCLASS.toStdString() +
00210                                   "\" is missing in the interface description of \"" +
00211                                   descr.interfaceName().toStdString());
00212     }
00213 
00214     ctkServiceRegistration* res = new ctkQtServiceRegistration(plugin,
00215                                                          descr,
00216                                                          createServiceProperties(props, classes));
00217     services.insert(res, classes);
00218     for (QStringListIterator i(classes); i.hasNext(); )
00219     {
00220       QString currClass = i.next();
00221       QList<ctkServiceRegistration*>& s = classServices[currClass];
00222       QList<ctkServiceRegistration*>::iterator ip =
00223           std::lower_bound(s.begin(), s.end(), res, ServiceRegistrationComparator());
00224       s.insert(ip, res);
00225     }
00226 
00227     //ctkServiceReference* r = res->getReference();
00228     // TODO
00229     //Listeners l = bundle.fwCtx.listeners;
00230     //l.serviceChanged(l.getMatchingServiceListeners(r),
00231     //                 new ServiceEvent(ServiceEvent.REGISTERED, r),
00232     //                 null);
00233   }
00234 }
00235 
00236 QString ctkServices::getQServiceManagerErrorString(QServiceManager::Error error)
00237 {
00238   switch (error)
00239   {
00240   case QServiceManager::NoError:
00241     return QString("No error occurred.");
00242   case QServiceManager::StorageAccessError:
00243     return QString("The service data storage is not accessible. This could be because the caller does not have the required permissions.");
00244   case QServiceManager::InvalidServiceLocation:
00245     return QString("The service was not found at its specified location.");
00246   case QServiceManager::InvalidServiceXml:
00247     return QString("The XML defining the service metadata is invalid.");
00248   case QServiceManager::InvalidServiceInterfaceDescriptor:
00249     return QString("The service interface descriptor is invalid, or refers to an interface implementation that cannot be accessed in the current scope.");
00250   case QServiceManager::ServiceAlreadyExists:
00251     return QString("Another service has previously been registered with the same location.");
00252   case QServiceManager::ImplementationAlreadyExists:
00253     return QString("Another service that implements the same interface version has previously been registered.");
00254   case QServiceManager::PluginLoadingFailed:
00255     return QString("The service plugin cannot be loaded.");
00256   case QServiceManager::ComponentNotFound:
00257     return QString("The service or interface implementation has not been registered.");
00258   case QServiceManager::ServiceCapabilityDenied:
00259     return QString("The security session does not allow the service based on its capabilities.");
00260   case QServiceManager::UnknownError:
00261     return QString("An unknown error occurred.");
00262   default:
00263     return QString("Unknown error enum.");
00264   }
00265 }
00266 
00267 void ctkServices::updateServiceRegistrationOrder(ctkServiceRegistration* sr,
00268                                               const QStringList& classes)
00269 {
00270   QMutexLocker lock(&mutex);
00271   for (QStringListIterator i(classes); i.hasNext(); )
00272   {
00273     QList<ctkServiceRegistration*>& s = classServices[i.next()];
00274     s.removeAll(sr);
00275     s.insert(std::lower_bound(s.begin(), s.end(), sr, ServiceRegistrationComparator()), sr);
00276   }
00277 }
00278 
00279 bool ctkServices::checkServiceClass(QObject* service, const QString& cls) const
00280 {
00281   return service->inherits(cls.toAscii());
00282 }
00283 
00284 
00285 QList<ctkServiceRegistration*> ctkServices::get(const QString& clazz) const
00286 {
00287   QMutexLocker lock(&mutex);
00288   return classServices.value(clazz);
00289 }
00290 
00291 
00292 ctkServiceReference* ctkServices::get(ctkPluginPrivate* plugin, const QString& clazz) const
00293 {
00294   QMutexLocker lock(&mutex);
00295   try {
00296     QList<ctkServiceReference*> srs = get(clazz, QString());
00297     qDebug() << "get service ref" << clazz << "for plugin"
00298              << plugin->location << " = " << srs;
00299 
00300     if (!srs.isEmpty()) {
00301       return srs.front();
00302     }
00303   }
00304   catch (const std::invalid_argument& )
00305   { }
00306 
00307   return 0;
00308 }
00309 
00310 
00311 QList<ctkServiceReference*> ctkServices::get(const QString& clazz, const QString& filter) const
00312 {
00313   QMutexLocker lock(&mutex);
00314 
00315   QListIterator<ctkServiceRegistration*>* s = 0;
00316   ctkLDAPExpr* ldap = 0;
00317   if (clazz.isEmpty())
00318   {
00319     if (!filter.isEmpty())
00320     {
00321       ldap = new ctkLDAPExpr(filter);
00322       QSet<QString> matched = ldap->getMatchedObjectClasses();
00323       if (!matched.isEmpty())
00324       {
00325         //TODO
00326 //        ArrayList v = null;
00327 //        boolean vReadOnly = true;;
00328 //        for (Iterator i = matched.iterator(); i.hasNext(); ) {
00329 //          ArrayList cl = (ArrayList) classServices.get(i.next());
00330 //          if (cl != null) {
00331 //            if (v == null) {
00332 //              v = cl;
00333 //            } else {
00334 //              if (vReadOnly) {
00335 //                v = new ArrayList(v);
00336 //                vReadOnly = false;
00337 //              }
00338 //              v.addAll(cl);
00339 //            }
00340 //          }
00341 //        }
00342 //        if (v != null) {
00343 //          s = v.iterator();
00344 //        } else {
00345 //          return null;
00346 //        }
00347       }
00348       else
00349       {
00350         s = new QListIterator<ctkServiceRegistration*>(services.keys());
00351       }
00352     }
00353     else
00354     {
00355       s = new QListIterator<ctkServiceRegistration*>(services.keys());
00356     }
00357   }
00358   else
00359   {
00360     QList<ctkServiceRegistration*> v = classServices.value(clazz);
00361     if (!v.isEmpty())
00362     {
00363       s = new QListIterator<ctkServiceRegistration*>(v);
00364     }
00365     else
00366     {
00367       return QList<ctkServiceReference*>();
00368     }
00369     if (!filter.isEmpty())
00370     {
00371       ldap = new ctkLDAPExpr(filter);
00372     }
00373   }
00374 
00375   QList<ctkServiceReference*> res;
00376   while (s->hasNext())
00377   {
00378     ctkServiceRegistration* sr = s->next();
00379     ctkServiceReference* sri = sr->getReference();
00380 
00381     if (filter.isEmpty() || ldap->evaluate(sr->d_func()->properties, false))
00382     {
00383       res.push_back(sri);
00384     }
00385   }
00386 
00387   delete s;
00388   delete ldap;
00389 
00390   return res;
00391 }
00392 
00393 
00394 void ctkServices::removeServiceRegistration(ctkServiceRegistration* sr)
00395 {
00396   QMutexLocker lock(&mutex);
00397 
00398   QStringList classes = sr->d_func()->properties.value(PluginConstants::OBJECTCLASS).toStringList();
00399   services.remove(sr);
00400   for (QStringListIterator i(classes); i.hasNext(); )
00401   {
00402     QString currClass = i.next();
00403     QList<ctkServiceRegistration*>& s = classServices[currClass];
00404     if (s.size() > 1)
00405     {
00406       s.removeAll(sr);
00407     }
00408     else
00409     {
00410       classServices.remove(currClass);
00411     }
00412   }
00413 }
00414 
00415 
00416 QList<ctkServiceRegistration*> ctkServices::getRegisteredByPlugin(ctkPluginPrivate* p) const
00417 {
00418   QMutexLocker lock(&mutex);
00419 
00420   QList<ctkServiceRegistration*> res;
00421   for (QHashIterator<ctkServiceRegistration*, QStringList> i(services); i.hasNext(); )
00422   {
00423     ctkServiceRegistration* sr = i.next().key();
00424     if (sr->d_func()->plugin = p)
00425     {
00426       res.push_back(sr);
00427     }
00428   }
00429   return res;
00430 }
00431 
00432 
00433 QList<ctkServiceRegistration*> ctkServices::getUsedByPlugin(ctkPlugin* p) const
00434 {
00435   QMutexLocker lock(&mutex);
00436 
00437   QList<ctkServiceRegistration*> res;
00438   for (QHashIterator<ctkServiceRegistration*, QStringList> i(services); i.hasNext(); )
00439   {
00440     ctkServiceRegistration* sr = i.next().key();
00441     if (sr->d_func()->isUsedByPlugin(p))
00442     {
00443       res.push_back(sr);
00444     }
00445   }
00446   return res;
00447 }
00448 
00449 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated on 21 May 2010 for CTK by  doxygen 1.6.1