qthighway/xqserviceutil/src/xqservicemetadata/xqservicemetadata.cpp
changeset 1 2b40d63a9c3d
child 14 6fbed849b4f4
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 *
       
     5 * This program is free software: you can redistribute it and/or modify
       
     6 * it under the terms of the GNU Lesser General Public License as published by
       
     7 * the Free Software Foundation, version 2.1 of the License.
       
     8 * 
       
     9 * This program is distributed in the hope that it will be useful,
       
    10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 * GNU Lesser General Public License for more details.
       
    13 *
       
    14 * You should have received a copy of the GNU Lesser General Public License
       
    15 * along with this program.  If not, 
       
    16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
       
    17 *
       
    18 * Description:
       
    19 *
       
    20 */
       
    21 
       
    22 #include <QFile>
       
    23 #include "xqservicelog.h"
       
    24 #include "xqservicemetadata_p.h"
       
    25 #include <xqaiwinterfacedescriptor_p.h>
       
    26 
       
    27 //XML tags and attributes
       
    28 //General
       
    29 #define NAME_TAG  "name"
       
    30 #define DESCRIPTION_TAG "description"
       
    31 
       
    32 //Service related
       
    33 #define SERVICE_TAG "service" 
       
    34 #define SERVICE_FILEPATH "filepath"
       
    35 
       
    36 //Interface related
       
    37 #define INTERFACE_TAG "interface"
       
    38 #define INTERFACE_VERSION "version" 
       
    39 #define INTERFACE_CAPABILITY "capabilities"
       
    40 #define INTERFACE_CUSTOM_PROPERTY "customproperty"
       
    41 
       
    42 QT_BEGIN_NAMESPACE
       
    43 
       
    44 #ifndef QT_NO_DATASTREAM
       
    45 QDataStream &operator<<(QDataStream &out, const ServiceMetaDataResults &r)
       
    46 {
       
    47     out << r.name << r.location;
       
    48     out << r.description << r.interfaces << r.latestInterfaces;
       
    49 
       
    50     return out;
       
    51 }
       
    52 
       
    53 QDataStream &operator>>(QDataStream &in, ServiceMetaDataResults &r)
       
    54 {
       
    55     in >> r.name >> r.location;
       
    56     in >> r.description >> r.interfaces >> r.latestInterfaces;
       
    57 
       
    58     return in;
       
    59 }
       
    60 #endif
       
    61 
       
    62 /*
       
    63     \class ServiceMetaData
       
    64 
       
    65     Utility class (used by service database) that offers support for 
       
    66     parsing metadata service xml registry file during service registration. \n
       
    67     
       
    68     It uses QXMLStreamReader class for parsing. Supproted Operations are:
       
    69         - Parse the service and interfaces defined in XML file
       
    70         - name, version, capabilitiesList, description and filePath of service can be retrieved
       
    71         - each interface can be retrieved
       
    72 */
       
    73 
       
    74 /*
       
    75  *  Class constructor
       
    76  *
       
    77  * @param aXmlFilePath path to the xml file that describes the service. 
       
    78  */
       
    79 ServiceMetaData::ServiceMetaData(const QString &aXmlFilePath)
       
    80 {
       
    81     XQSERVICE_DEBUG_PRINT("ServiceMetaData::ServiceMetaData(1)");
       
    82     XQSERVICE_DEBUG_PRINT("aXmlFilePath: %s", qPrintable(aXmlFilePath));
       
    83     xmlDevice = new QFile(aXmlFilePath);
       
    84     ownsXmlDevice = true;
       
    85     latestError = 0;
       
    86 }
       
    87 
       
    88 /*
       
    89  *  Class constructor
       
    90  *
       
    91  * @param device QIODevice that contains the XML data that describes the service.
       
    92  */
       
    93 ServiceMetaData::ServiceMetaData(QIODevice *device)
       
    94 {
       
    95     XQSERVICE_DEBUG_PRINT("ServiceMetaData::ServiceMetaData(2)");
       
    96     xmlDevice = device;
       
    97     ownsXmlDevice = false;
       
    98     latestError = 0;
       
    99 }
       
   100 
       
   101 /*
       
   102  *  Class destructor
       
   103  * 
       
   104  */
       
   105 ServiceMetaData::~ServiceMetaData()
       
   106 {
       
   107     XQSERVICE_DEBUG_PRINT("ServiceMetaData::~ServiceMetaData");
       
   108     if (ownsXmlDevice)
       
   109         delete xmlDevice;
       
   110 }
       
   111 
       
   112 /*
       
   113     Sets the device containing the XML data that describes the service to \a device.
       
   114  */
       
   115 void ServiceMetaData::setDevice(QIODevice *device)
       
   116 {
       
   117     XQSERVICE_DEBUG_PRINT("ServiceMetaData::setDevice");
       
   118     clearMetadata();
       
   119     xmlDevice = device;
       
   120     ownsXmlDevice = false;
       
   121 }
       
   122 
       
   123 /*
       
   124     Returns the device containing the XML data that describes the service.
       
   125 */
       
   126 QIODevice *ServiceMetaData::device() const
       
   127 {
       
   128     XQSERVICE_DEBUG_PRINT("ServiceMetaData::device");
       
   129     return xmlDevice;
       
   130 }
       
   131 
       
   132 /*
       
   133  *  Gets the service name
       
   134  *
       
   135  * @return service name or default value (empty string) if it is not available
       
   136  */
       
   137 /*QString ServiceMetaData::name() const
       
   138 {
       
   139     return serviceName;
       
   140 }*/
       
   141  
       
   142 /*
       
   143  *  Gets the path of the service implementation file
       
   144  *
       
   145  * @return service implementation filepath
       
   146  */
       
   147 /*QString ServiceMetaData::location() const
       
   148 {
       
   149     return serviceLocation;
       
   150 }*/
       
   151  
       
   152 /*
       
   153  *  Gets the service description
       
   154  *
       
   155  * @return service description or default value (empty string) if it is not available
       
   156  */
       
   157 /*QString ServiceMetaData::description() const
       
   158 {
       
   159     return serviceDescription;
       
   160 }*/
       
   161  
       
   162 /*
       
   163    Returns the metadata of the interace at \a index; otherwise
       
   164    returns 0.
       
   165  */
       
   166 /*QList<XQServiceInterfaceDescriptor> ServiceMetaData::getInterfaces() const
       
   167 {
       
   168     return serviceInterfaces;
       
   169 } */
       
   170 
       
   171 /*!
       
   172     \internal
       
   173 
       
   174     Returns a streamable object containing the results of the parsing.
       
   175 */
       
   176 ServiceMetaDataResults ServiceMetaData::parseResults() const
       
   177 {
       
   178     XQSERVICE_DEBUG_PRINT("ServiceMetaData::parseResults");
       
   179     
       
   180     ServiceMetaDataResults results;
       
   181     results.location = serviceLocation;
       
   182     results.name = serviceName;
       
   183     results.description = serviceDescription;
       
   184     results.interfaces = serviceInterfaces;
       
   185     results.latestInterfaces = latestInterfaces();
       
   186     results.version = version;
       
   187 
       
   188     return results;
       
   189 }
       
   190 
       
   191 /*
       
   192     Parses the file and extracts the service metadata \n
       
   193     Custom error codes: \n
       
   194     SFW_ERROR_UNABLE_TO_OPEN_FILE in case can not open the XML file \n
       
   195     SFW_ERROR_INVALID_XML_FILE in case service registry is not a valid XML file \n
       
   196     SFW_ERROR_NO_SERVICE in case XML file has no service tag\n
       
   197     @return true if the metadata was read properly, false if there is an error
       
   198  */
       
   199 bool ServiceMetaData::extractMetadata()
       
   200 {
       
   201     XQSERVICE_DEBUG_PRINT("ServiceMetaData::extractMetadata");
       
   202     latestError = 0;
       
   203     clearMetadata();
       
   204     version = ServiceMetaDataResults::VERSION_2;  // default
       
   205     
       
   206     QXmlStreamReader xmlReader;
       
   207     bool parseError = false;
       
   208     //Open xml file
       
   209     if (!xmlDevice->isOpen() && !xmlDevice->open(QIODevice::ReadOnly)) {
       
   210         XQSERVICE_DEBUG_PRINT("XML error:Couldn't open the file");
       
   211         latestError = ServiceMetaData::SFW_ERROR_UNABLE_TO_OPEN_FILE;
       
   212         parseError = true;
       
   213     } else {
       
   214         //Load xml content
       
   215         xmlReader.setDevice(xmlDevice);
       
   216         // Read XML doc 
       
   217         while (!xmlReader.atEnd() && !parseError) {
       
   218             xmlReader.readNext();
       
   219             //Found a <service> node, read service related metadata
       
   220             if (xmlReader.isStartElement() && xmlReader.name() == SERVICE_TAG) {
       
   221 
       
   222                 // Support for previous XML version. Check if service element has name attribute
       
   223                 // If so, assume the old element
       
   224                 if (getAttributeValue(xmlReader, NAME_TAG, serviceName)) {
       
   225                     if (!processServiceElementPrevVersion(xmlReader)) {
       
   226                         XQSERVICE_DEBUG_PRINT("XML error: Couldn't process service element");
       
   227                         parseError = true;
       
   228                     }
       
   229                 }
       
   230                 else if (!processServiceElement(xmlReader)) {
       
   231                     XQSERVICE_DEBUG_PRINT("XML error: Couldn't process service element");
       
   232                     parseError = true;
       
   233                 }
       
   234             }
       
   235             else if (xmlReader.isStartElement() && xmlReader.name() != SERVICE_TAG) {
       
   236                 XQSERVICE_DEBUG_PRINT("XML error: No service");
       
   237                 latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE;
       
   238                 parseError = true;
       
   239             }
       
   240             else if (xmlReader.tokenType() == QXmlStreamReader::Invalid) {
       
   241                 XQSERVICE_DEBUG_PRINT("XML error: Invalid XML");
       
   242                 latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
       
   243                 parseError = true;
       
   244             }
       
   245         }
       
   246         if (ownsXmlDevice)
       
   247             xmlDevice->close();
       
   248     }
       
   249     if (parseError) {
       
   250         {
       
   251         XQSERVICE_DEBUG_PRINT("XML Parse error, line=%d,column=%d", xmlReader.lineNumber(), xmlReader.columnNumber());
       
   252         clearMetadata();
       
   253         }
       
   254     }
       
   255     XQSERVICE_DEBUG_PRINT("XML parseError: %d", parseError);
       
   256     return !parseError;
       
   257 }
       
   258  
       
   259 /*
       
   260     Gets the latest parsing error \n
       
   261     @return parsing error(negative value) or 0 in case there is none
       
   262  */
       
   263 int ServiceMetaData::getLatestError() const
       
   264 {
       
   265     XQSERVICE_DEBUG_PRINT("ServiceMetaData::getLatestError");
       
   266     XQSERVICE_DEBUG_PRINT("latestError: %d", latestError);
       
   267     return latestError;
       
   268 }
       
   269  
       
   270 /*
       
   271     Parses and extracts the service from the current xml <service> node
       
   272     using the new format (Version 2) \n
       
   273     Schema:    
       
   274      <!ELEMENT service ( name, filepath, description?, interface+ ) >
       
   275         <!ELEMENT description ( #CDATA ) >
       
   276         <!ELEMENT filepath ( #PCDATA ) >
       
   277         <!ELEMENT interface ( name, version, description?, capabilities?, customproperty* ) >
       
   278         <!ELEMENT capabilities ( #PCDATA ) >
       
   279         <!ELEMENT name ( #PCDATA ) >
       
   280         <!ELEMENT version ( #PCDATA ) >
       
   281         <!ELEMENT customproperty ( #CDATA ) >
       
   282         <!ATTLIST customproperty key NMTOKEN #REQUIRED >    
       
   283  */
       
   284 bool ServiceMetaData::processServiceElement(QXmlStreamReader &aXMLReader)
       
   285 {
       
   286     XQSERVICE_DEBUG_PRINT("ServiceMetaData::processServiceElement");
       
   287     Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == SERVICE_TAG);
       
   288     bool parseError = false;
       
   289 
       
   290     int dupSTags[3] = {0 //->tag name
       
   291         ,0 //-> service description
       
   292         ,0 //-> filepath
       
   293     };
       
   294     while(!parseError && !aXMLReader.atEnd()) {
       
   295         aXMLReader.readNext();
       
   296         if (aXMLReader.isStartElement() && aXMLReader.name() == DESCRIPTION_TAG) {
       
   297             //Found <description> tag
       
   298             serviceDescription = aXMLReader.readElementText();
       
   299             dupSTags[1]++;
       
   300         } else if (aXMLReader.isStartElement() && aXMLReader.name() == NAME_TAG) {
       
   301             serviceName = aXMLReader.readElementText();
       
   302             dupSTags[0]++;
       
   303         } else if (aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_TAG) {
       
   304             //Found a <interface> node, read module related metadata  
       
   305             if (!processInterfaceElement(aXMLReader)) 
       
   306                 parseError = true;
       
   307         } else if (aXMLReader.isStartElement() && aXMLReader.name() == SERVICE_FILEPATH ) {
       
   308             //Found <filepath> tag
       
   309             dupSTags[2]++;
       
   310             serviceLocation = aXMLReader.readElementText();
       
   311         } else if (aXMLReader.isStartElement() && aXMLReader.name() == "version") {
       
   312             //FOUND <version> tag on service level. We ignore this for now
       
   313             aXMLReader.readElementText();
       
   314         } else if (aXMLReader.isEndElement() && aXMLReader.name() == SERVICE_TAG) {
       
   315             //Found </service>, leave the loop
       
   316             break;
       
   317         } else if (aXMLReader.isEndElement() || aXMLReader.isStartElement()) {
       
   318             latestError = ServiceMetaData::SFW_ERROR_PARSE_SERVICE;
       
   319             parseError = true;            
       
   320         } else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
       
   321             latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
       
   322             parseError = true;
       
   323         }
       
   324     }
       
   325     if ( !parseError ) {
       
   326         if (serviceName.isEmpty()) {
       
   327             latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_NAME;
       
   328             parseError = true;
       
   329         } else if (serviceLocation.isEmpty()) {
       
   330             latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_FILEPATH;
       
   331             parseError = true;
       
   332         }
       
   333     }
       
   334 
       
   335     for(int i=0;!parseError && i<3;i++) {
       
   336         if (dupSTags[i] > 1) {
       
   337             parseError = true;
       
   338             latestError = SFW_ERROR_DUPLICATED_TAG;
       
   339             break;
       
   340         }
       
   341     }
       
   342         
       
   343     //update all interfaces with service data
       
   344     const int icount = serviceInterfaces.count();
       
   345     if (icount == 0 && latestError == 0) {
       
   346         latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_INTERFACE;
       
   347         parseError = true;
       
   348     }
       
   349     for (int i = 0; i<icount; i++) {
       
   350         serviceInterfaces.at(i).d->serviceName = serviceName;
       
   351         serviceInterfaces.at(i).d->properties[XQAiwInterfaceDescriptor::Location] = serviceLocation;
       
   352         serviceInterfaces.at(i).d->properties[XQAiwInterfaceDescriptor::ServiceDescription] = serviceDescription;
       
   353     }
       
   354 
       
   355     if (parseError) {
       
   356         clearMetadata();
       
   357     }
       
   358     XQSERVICE_DEBUG_PRINT("processServiceElement parseError: %d", parseError);
       
   359     return !parseError;
       
   360 }
       
   361 
       
   362 /*!
       
   363     Parses and extracts the service from the current xml <service> node
       
   364     using the new format (Version 1) \n
       
   365     
       
   366 <!ELEMENT service ( description?, interface+ ) >
       
   367 <!ATTLIST service name #CDATA  #REQUIRED >
       
   368 <!ATTLIST service filepath #CDATA  #REQUIRED >
       
   369 <!ELEMENT description ( #CDATA ) >
       
   370 <!ELEMENT interface ( description? ) >
       
   371 <!ATTLIST interface name #CDATA  #REQUIRED >
       
   372 <!ATTLIST interface version #CDATA  #REQUIRED >
       
   373 <!ATTLIST interface capabilities #CDATA  >
       
   374     
       
   375     Custom error codes: \n
       
   376     SFW_ERROR_NO_SERVICE_NAME in case no service name in XML file \n
       
   377     SFW_ERROR_NO_INTERFACE_VERSION in case no interface version in XML file \n
       
   378     SFW_ERROR_PARSE_SERVICE in case can not parse service section in XML file \n
       
   379     SFW_ERROR_NO_SERVICE_FILEPATH in case no service file path in XML file \n
       
   380     SFW_ERROR_INVALID_XML_FILE in case XML file is not valid \n
       
   381     SFW_ERROR_NO_SERVICE_INTERFACE in case no interface defined for service in XML file \n
       
   382     @param aXMLReader xml stream reader 
       
   383     @return true if the metadata was read properly, false if there is an error
       
   384 
       
   385     
       
   386  */
       
   387 bool ServiceMetaData::processServiceElementPrevVersion(QXmlStreamReader &aXMLReader)
       
   388 {
       
   389     version = ServiceMetaDataResults::VERSION_1;  // Previous version
       
   390     
       
   391     XQSERVICE_DEBUG_PRINT("ServiceMetaData::processServiceElementPrevVersion");
       
   392     Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == SERVICE_TAG);
       
   393     bool parseError = false;
       
   394 
       
   395     QString tmp;
       
   396     if (!getAttributeValue(aXMLReader, NAME_TAG, tmp)) {
       
   397         XQSERVICE_DEBUG_PRINT("No service name");
       
   398         latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_NAME;
       
   399         parseError = true;
       
   400     }
       
   401 
       
   402     if (!parseError) {
       
   403         if (!getAttributeValue(aXMLReader, SERVICE_FILEPATH, serviceLocation)) {
       
   404             XQSERVICE_DEBUG_PRINT("No service filepath");
       
   405             latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_FILEPATH;
       
   406             parseError = true;
       
   407         }
       
   408     }
       
   409 
       
   410     while (!parseError && !aXMLReader.atEnd()) {
       
   411         aXMLReader.readNext();  
       
   412         if (aXMLReader.name() == DESCRIPTION_TAG) {
       
   413             serviceDescription = aXMLReader.readElementText();
       
   414             XQSERVICE_DEBUG_PRINT("serviceDescription: %s", qPrintable(serviceDescription));
       
   415         //Found a <interface> node, read module related metadata  
       
   416         } else if (aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_TAG) {
       
   417             if (!processInterfaceElementPrevVersion(aXMLReader)){
       
   418                 XQSERVICE_DEBUG_PRINT("Couldn't process interface element");
       
   419                 parseError = true;
       
   420             }
       
   421         //Found </service>, leave the loop
       
   422         } else if (aXMLReader.isEndElement() && aXMLReader.name() == SERVICE_TAG) {
       
   423             XQSERVICE_DEBUG_PRINT("Service element handled");
       
   424             break;
       
   425         } else if (aXMLReader.isEndElement() || aXMLReader.isStartElement()) {
       
   426             XQSERVICE_DEBUG_PRINT("Service parse error");
       
   427             latestError = ServiceMetaData::SFW_ERROR_PARSE_SERVICE;
       
   428             parseError = true;            
       
   429         } else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
       
   430             XQSERVICE_DEBUG_PRINT("Invalid XML");
       
   431             latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
       
   432             parseError = true;
       
   433         }
       
   434     }
       
   435 
       
   436     if (serviceInterfaces.count() == 0 && latestError == 0) {
       
   437         XQSERVICE_DEBUG_PRINT("No service interface");
       
   438         latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_INTERFACE;
       
   439         parseError = true;
       
   440     }
       
   441     if (parseError) {
       
   442         clearMetadata();
       
   443     }
       
   444     XQSERVICE_DEBUG_PRINT("parseError: %d", parseError);
       
   445     return !parseError;
       
   446 }
       
   447 
       
   448 
       
   449 /*
       
   450     Parses and extracts the interface metadata from the current xml <interface> node \n
       
   451 */
       
   452 bool ServiceMetaData::processInterfaceElement(QXmlStreamReader &aXMLReader)
       
   453 {
       
   454     XQSERVICE_DEBUG_PRINT("ServiceMetaData::processInterfaceElement");
       
   455     Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_TAG);
       
   456     bool parseError = false;
       
   457 
       
   458     //Read interface parameter
       
   459     QString tmp;
       
   460     XQAiwInterfaceDescriptor aInterface;
       
   461     int dupITags[4] = {
       
   462         0,  //->iface name tag
       
   463         0,  //->version
       
   464         0,  //->capabilities
       
   465         0   //->description
       
   466     };
       
   467     aInterface.d = new XQAiwInterfaceDescriptorPrivate;
       
   468     while (!parseError && !aXMLReader.atEnd()) {
       
   469         aXMLReader.readNext();
       
   470         //Read interface description
       
   471         if (aXMLReader.isStartElement() && aXMLReader.name() == NAME_TAG) {
       
   472             aInterface.d->interfaceName = aXMLReader.readElementText();
       
   473             dupITags[0]++;
       
   474             //Found <name> tag for interface
       
   475         } else if (aXMLReader.isStartElement() && aXMLReader.name() == DESCRIPTION_TAG) {
       
   476             //Found <description> tag
       
   477             aInterface.d->properties[XQAiwInterfaceDescriptor::InterfaceDescription] = aXMLReader.readElementText();
       
   478             dupITags[3]++;
       
   479         //Found </interface>, leave the loop
       
   480         } else if (aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_VERSION) {
       
   481             tmp.clear();
       
   482             tmp = aXMLReader.readElementText();
       
   483             if (tmp.isEmpty())
       
   484                 continue;  //creates NO_INTERFACE_VERSION error further below
       
   485             bool success = checkVersion(tmp);
       
   486             if ( success ) {
       
   487                 int majorVer = -1;
       
   488                 int minorVer = -1;
       
   489                 transformVersion(tmp, &majorVer, &minorVer);
       
   490                 aInterface.d->major = majorVer;
       
   491                 aInterface.d->minor = minorVer;
       
   492                 dupITags[1]++;
       
   493             } else {
       
   494                 latestError = ServiceMetaData::SFW_ERROR_INVALID_VERSION;
       
   495                 parseError = true;
       
   496             }
       
   497         } else if (aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_CAPABILITY) {
       
   498             tmp.clear();
       
   499             tmp= aXMLReader.readElementText();
       
   500             aInterface.d->properties[XQAiwInterfaceDescriptor::Capabilities] = tmp.split(",", QString::SkipEmptyParts);
       
   501             dupITags[2]++;
       
   502         } else if (aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_CUSTOM_PROPERTY) {
       
   503             parseError = true;
       
   504             if (aXMLReader.attributes().hasAttribute("key")) {
       
   505                 const QString ref = aXMLReader.attributes().value("key").toString();
       
   506                 XQSERVICE_DEBUG_PRINT("Custom property key: %s", qPrintable(ref));
       
   507                 if (!ref.isEmpty()) {
       
   508                     if (aInterface.d->customProperties.contains(ref)) {
       
   509                         latestError = SFW_ERROR_DUPLICATED_CUSTOM_KEY;
       
   510                         continue;
       
   511                     } else {
       
   512                         QString value = aXMLReader.readElementText();
       
   513                         if (value.isEmpty() || value.isNull())
       
   514                             value = QString("");
       
   515                         XQSERVICE_DEBUG_PRINT("Custom property value: %s", qPrintable(value));
       
   516                         aInterface.d->customProperties[ref] = value;
       
   517                         parseError = false;
       
   518                     }
       
   519                 }
       
   520             }
       
   521             if (parseError)
       
   522                 latestError = SFW_ERROR_INVALID_CUSTOM_TAG;
       
   523         } else if (aXMLReader.isEndElement() && aXMLReader.name() == INTERFACE_TAG) {
       
   524             break;
       
   525         } else if (aXMLReader.isStartElement() || aXMLReader.isEndElement()) {
       
   526             latestError = ServiceMetaData::SFW_ERROR_PARSE_INTERFACE;
       
   527             parseError = true;
       
   528         } else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
       
   529             latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
       
   530             parseError = true;
       
   531         }
       
   532     }
       
   533 
       
   534     if (!parseError) {
       
   535         if (dupITags[1] == 0) { //no version tag found
       
   536             latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_VERSION;
       
   537             parseError = true;
       
   538         } else if (aInterface.d->interfaceName.isEmpty()) {
       
   539             latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_NAME;
       
   540             parseError = true;
       
   541         }
       
   542     }
       
   543     
       
   544     for(int i=0;!parseError && i<4;i++) {
       
   545         if (dupITags[i] > 1) {
       
   546             parseError = true;
       
   547             latestError = SFW_ERROR_DUPLICATED_TAG;
       
   548             break;
       
   549         }
       
   550     }
       
   551 
       
   552     if (!parseError) {
       
   553         const QString ident = aInterface.d->interfaceName
       
   554                                 + QString::number(aInterface.majorVersion())
       
   555                                 + "."
       
   556                                 + QString::number(aInterface.minorVersion());
       
   557         if (duplicates.contains(ident.toLower())) {
       
   558             latestError = ServiceMetaData::SFW_ERROR_DUPLICATED_INTERFACE;
       
   559             parseError = true;
       
   560         } else {
       
   561             duplicates.insert(ident.toLower());
       
   562             serviceInterfaces.append(aInterface);
       
   563             if (!m_latestIndex.contains(aInterface.d->interfaceName.toLower())
       
   564                     || lessThan(latestInterfaceVersion(aInterface.d->interfaceName), aInterface))
       
   565 
       
   566             {
       
   567                     m_latestIndex[aInterface.d->interfaceName.toLower()] = serviceInterfaces.count() - 1;
       
   568             }
       
   569         }
       
   570     }
       
   571 
       
   572     if (parseError)
       
   573     {
       
   574         // Delete garbage
       
   575         delete aInterface.d;
       
   576         aInterface.d = 0;
       
   577     }
       
   578    XQSERVICE_DEBUG_PRINT("processInterfaceElement parseError: %d", parseError);
       
   579     return !parseError;
       
   580 }
       
   581 
       
   582 /*!
       
   583     Parses and extracts the interface metadata from the current xml <interface> node \n
       
   584     Custome error codes: \n
       
   585     SFW_ERROR_NO_INTERFACE_NAME in case no interface name in XML file \n
       
   586     SFW_ERROR_PARSE_INTERFACE in case error parsing interface section \n
       
   587     SFW_ERROR_INVALID_XML_FILE in case XML file is not valid \n
       
   588     @param aXMLReader xml stream reader 
       
   589     @return true if the metadata was read properly, false if there is an error
       
   590  */
       
   591 bool ServiceMetaData::processInterfaceElementPrevVersion(QXmlStreamReader &aXMLReader)
       
   592 {
       
   593     XQSERVICE_DEBUG_PRINT("ServiceMetaData::processInterfaceElementPrevVersion");
       
   594     Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == INTERFACE_TAG);
       
   595     bool parseError = false;
       
   596 
       
   597     //Read interface parameter
       
   598     QString tmp;
       
   599     XQAiwInterfaceDescriptor aInterface;
       
   600     aInterface.d = new XQAiwInterfaceDescriptorPrivate;
       
   601     aInterface.d->serviceName = serviceName;  // picked earlier !!!
       
   602     XQSERVICE_DEBUG_PRINT("Service name  %s", qPrintable(serviceName));
       
   603     
       
   604     int dupITags[4] = {
       
   605         0,  //->iface name tag
       
   606         0,  //->version
       
   607         0,  //->capabilities
       
   608         0   //->description
       
   609     };
       
   610     
       
   611     if (getAttributeValue(aXMLReader, NAME_TAG, tmp)) {
       
   612         XQSERVICE_DEBUG_PRINT("Name attribute value");
       
   613         aInterface.d->interfaceName = tmp;
       
   614         tmp.clear();
       
   615         if (getAttributeValue(aXMLReader, INTERFACE_VERSION, tmp)) {
       
   616             XQSERVICE_DEBUG_PRINT("Interface version value");
       
   617             bool success = checkVersion(tmp);
       
   618             if ( success ) {
       
   619                 int majorVer = -1;
       
   620                 int minorVer = -1;
       
   621                 transformVersion(tmp, &majorVer, &minorVer);
       
   622                 aInterface.d->major = majorVer;
       
   623                 aInterface.d->minor = minorVer;
       
   624                 dupITags[1]++;
       
   625                 
       
   626                 if (getAttributeValue(aXMLReader, INTERFACE_CAPABILITY, tmp)) {
       
   627                     XQSERVICE_DEBUG_PRINT("Interface capability value");
       
   628                     aInterface.d->properties[XQAiwInterfaceDescriptor::Capabilities] = tmp.split(",", QString::SkipEmptyParts);
       
   629                 }
       
   630             } else {
       
   631                 XQSERVICE_DEBUG_PRINT("Invalid interface version");
       
   632                 latestError = ServiceMetaData::SFW_ERROR_INVALID_VERSION;
       
   633                 parseError = true;
       
   634             }
       
   635         }
       
   636         else{
       
   637             XQSERVICE_DEBUG_PRINT("No interface version");
       
   638             latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_VERSION;
       
   639             parseError = true;
       
   640         }
       
   641     } else {
       
   642         XQSERVICE_DEBUG_PRINT("No interface name");
       
   643         latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_NAME;
       
   644         parseError = true;
       
   645     }
       
   646 
       
   647     while (!parseError && !aXMLReader.atEnd()) {
       
   648         aXMLReader.readNext();
       
   649         //Read interface description
       
   650         if (aXMLReader.isStartElement() && aXMLReader.name() == DESCRIPTION_TAG) {
       
   651             XQSERVICE_DEBUG_PRINT("Interface description");
       
   652             aInterface.d->properties[XQAiwInterfaceDescriptor::InterfaceDescription] = aXMLReader.readElementText();
       
   653         //Found </interface>, leave the loop
       
   654         } else if (aXMLReader.isEndElement() && aXMLReader.name() == INTERFACE_TAG) {
       
   655             XQSERVICE_DEBUG_PRINT("Interface handled");
       
   656             break;  
       
   657         } else if (aXMLReader.isStartElement() || aXMLReader.isEndElement()) {
       
   658             XQSERVICE_DEBUG_PRINT("Interface parse error");
       
   659             latestError = ServiceMetaData::SFW_ERROR_PARSE_INTERFACE;
       
   660             parseError = true;
       
   661         } else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
       
   662             XQSERVICE_DEBUG_PRINT("Invalid XML");
       
   663             latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
       
   664             parseError = true;
       
   665         }
       
   666     }
       
   667 
       
   668     // Consistency check
       
   669     if (!parseError) {
       
   670         if (dupITags[1] == 0) { //no version tag found
       
   671             latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_VERSION;
       
   672             parseError = true;
       
   673         } else if (aInterface.d->interfaceName.isEmpty()) {
       
   674             latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_NAME;
       
   675             parseError = true;
       
   676         }
       
   677     }
       
   678 
       
   679     if (!parseError) {
       
   680         const QString ident = aInterface.d->interfaceName
       
   681                               + QString::number(aInterface.majorVersion())
       
   682                               + "."
       
   683                               + QString::number(aInterface.minorVersion());
       
   684         XQSERVICE_DEBUG_PRINT("ident: %s", qPrintable(ident));
       
   685         if (duplicates.contains(ident.toLower())) {
       
   686             XQSERVICE_DEBUG_PRINT("Duplicate interface");
       
   687             latestError = ServiceMetaData::SFW_ERROR_DUPLICATED_INTERFACE;
       
   688             parseError = true;
       
   689         } else {
       
   690             duplicates.insert(ident.toLower());
       
   691             serviceInterfaces.append(aInterface);
       
   692             if (!m_latestIndex.contains(aInterface.d->interfaceName.toLower())
       
   693                 || lessThan(latestInterfaceVersion(aInterface.d->interfaceName), aInterface))
       
   694 
       
   695             {
       
   696                 m_latestIndex[aInterface.d->interfaceName.toLower()] = serviceInterfaces.count() - 1;
       
   697             }
       
   698         }
       
   699     }
       
   700 
       
   701     if (parseError)
       
   702     {
       
   703         // Delete garbage
       
   704         delete aInterface.d;
       
   705         aInterface.d = 0;
       
   706     }
       
   707     
       
   708     XQSERVICE_DEBUG_PRINT("processInterfaceElementPrevVersion parseError: %d", parseError);
       
   709     return !parseError;
       
   710 }
       
   711 
       
   712 
       
   713 /*!
       
   714     Gets the value of the attribute from the XML node \n
       
   715     @param aDomElement xml node
       
   716     @param aAttributeName attribute name
       
   717     @param aValue [out] attribute value
       
   718     @return true if the value was read, false otherwise
       
   719  */
       
   720 bool ServiceMetaData::getAttributeValue(const QXmlStreamReader &aXMLReader, const QString &aAttributeName, QString &aValue)
       
   721 {
       
   722     XQSERVICE_DEBUG_PRINT("ServiceMetaData::getAttributeValue");
       
   723     XQSERVICE_DEBUG_PRINT("aAttributeName: %s", qPrintable(aAttributeName));
       
   724     bool result = false;
       
   725     for (int i = 0; i < aXMLReader.attributes().count(); i++){
       
   726         QXmlStreamAttribute att = aXMLReader.attributes()[i];
       
   727         if (att.name() == aAttributeName) {
       
   728             if (att.value().isNull() || att.value().isEmpty()) {
       
   729                 result = false;
       
   730             } else {
       
   731                 result = true;
       
   732                 aValue = att.value().toString();
       
   733                 XQSERVICE_DEBUG_PRINT("aValue: %s", qPrintable(aValue));
       
   734             }
       
   735         }
       
   736     }
       
   737     // Capability attribute is allowed to be empty
       
   738     if (aAttributeName == INTERFACE_CAPABILITY) {
       
   739         result = true;
       
   740     }
       
   741     XQSERVICE_DEBUG_PRINT("result: %d", result);
       
   742     return result;
       
   743 }
       
   744 
       
   745 
       
   746 XQAiwInterfaceDescriptor ServiceMetaData::latestInterfaceVersion(const QString &interfaceName)
       
   747 {
       
   748     XQAiwInterfaceDescriptor ret;
       
   749     if (m_latestIndex.contains(interfaceName.toLower()))
       
   750         return serviceInterfaces[m_latestIndex[interfaceName.toLower()]];
       
   751     else
       
   752         return ret;
       
   753 }
       
   754 
       
   755 QList<XQAiwInterfaceDescriptor> ServiceMetaData::latestInterfaces() const
       
   756 {
       
   757     XQSERVICE_DEBUG_PRINT("ServiceMetaData::latestInterfaces");
       
   758     QList<XQAiwInterfaceDescriptor> interfaces;
       
   759     QHash<QString,int>::const_iterator i = m_latestIndex.constBegin();
       
   760     while(i != m_latestIndex.constEnd())
       
   761     {
       
   762         interfaces.append(serviceInterfaces[i.value()]);
       
   763         ++i;
       
   764     }
       
   765     return interfaces;
       
   766 }
       
   767 
       
   768 bool ServiceMetaData::lessThan(const XQAiwInterfaceDescriptor &d1,
       
   769                                 const XQAiwInterfaceDescriptor &d2) const
       
   770 {
       
   771     return (d1.majorVersion() < d2.majorVersion())
       
   772             || ( d1.majorVersion() == d2.majorVersion()
       
   773                     && d1.minorVersion() < d2.minorVersion());
       
   774 
       
   775 }
       
   776 
       
   777 bool ServiceMetaData::checkVersion(const QString &version) const
       
   778 {
       
   779     XQSERVICE_DEBUG_PRINT("ServiceMetaData::checkVersion");
       
   780     //match x.y as version format
       
   781     QRegExp rx("^([1-9][0-9]*)\\.(0+|[1-9][0-9]*)$");
       
   782     int pos = rx.indexIn(version);
       
   783     QStringList list = rx.capturedTexts();
       
   784     bool success = false;
       
   785     if (pos == 0 && list.count() == 3
       
   786             && rx.matchedLength() == version.length() )
       
   787     {
       
   788         list[1].toInt(&success);
       
   789         if ( success ) {
       
   790             list[2].toInt(&success);
       
   791         }
       
   792     }
       
   793     XQSERVICE_DEBUG_PRINT("success: %d", success);
       
   794     return success;
       
   795 }
       
   796 
       
   797 void ServiceMetaData::transformVersion(const QString &version, int *major, int *minor) const
       
   798 {
       
   799     Q_ASSERT(major != NULL);
       
   800     Q_ASSERT(minor != NULL);
       
   801     if(!checkVersion(version)) {
       
   802         *major = -1;
       
   803         *minor = -1;
       
   804     } else {
       
   805         QRegExp rx("^([1-9][0-9]*)\\.(0+|[1-9][0-9]*)$");
       
   806         rx.indexIn(version);
       
   807         QStringList list = rx.capturedTexts();
       
   808         Q_ASSERT(list.count() == 3);
       
   809         *major = list[1].toInt();
       
   810         *minor = list[2].toInt();
       
   811     }
       
   812 }
       
   813 
       
   814 /*
       
   815  *  Clears the service metadata
       
   816  *
       
   817  */
       
   818 void ServiceMetaData::clearMetadata()
       
   819 {
       
   820     XQSERVICE_DEBUG_PRINT("ServiceMetaData::clearMetadata");
       
   821     serviceName.clear();
       
   822     serviceLocation.clear();
       
   823     serviceDescription.clear();
       
   824     serviceInterfaces.clear();
       
   825     duplicates.clear();
       
   826     m_latestIndex.clear();
       
   827     version = 0;
       
   828 }
       
   829 
       
   830 
       
   831 
       
   832 QT_END_NAMESPACE