/*************************************************************************** soapmessage.cpp - description ------------------- begin : Sun Jul 24 2005 copyright : (C) 2005 by Diederik van der Boor email : vdboor --at-- codingdomain.com ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "soapmessage.h" #include "../../utils/xmlfunctions.h" #include "../../kmessdebug.h" #include <QStringList> #ifdef KMESSDEBUG_SOAPMESSAGE #define KMESSDEBUG_SOAPMESSAGE_GENERAL #endif #define XMLNS_XSD "http://www.w3.org/2001/XMLSchema" #define XMLNS_XSI "http://www.w3.org/2001/XMLSchema-instance" #define XMLNS_SOAP "http://schemas.xmlsoap.org/soap/envelope/" // The constructor SoapMessage::SoapMessage( const QString &endPointUrl, const QString &action, const QString &header, const QString &body, const MessageData &data ) : action_( action ) , data_( data ) , endPoint_( endPointUrl ) { // Assemble an essential envelope for the parser QString envelope( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<soap:Envelope xmlns:xsi=\"" XMLNS_XSI "\"" " xmlns:xsd=\"" XMLNS_XSD "\"" " xmlns:soap=\"" XMLNS_SOAP "\">\n" ); if( ! header.isEmpty() ) { envelope += "<soap:Header>" + header + "</soap:Header>"; } if( ! body.isEmpty() ) { envelope += "<soap:Body>" + body + "</soap:Body>"; } envelope += "</soap:Envelope>"; setMessage( envelope ); } // The copy constructor SoapMessage::SoapMessage( const SoapMessage &other ) : action_( other.action_ ) , body_( other.body_ ) , data_( other.data_ ) , endPoint_( other.endPoint_ ) , fault_( other.fault_ ) , faultCode_( other.faultCode_ ) , faultDescription_( other.faultDescription_ ) , isValid_( other.isValid_ ) , header_( other.header_ ) { } // The destructor SoapMessage::~SoapMessage() { } // Return the message action const QString& SoapMessage::getAction() const { return action_; } // Return the associated request data const MessageData& SoapMessage::getData() const { return data_; } // Return the URL of the SOAP endpoint to which the message will be sent const QString& SoapMessage::getEndPoint() const { return endPoint_; } // Return the message fault's xml tree const QDomNode& SoapMessage::getFault() const { return fault_; } // Return the error code const QString& SoapMessage::getFaultCode() const { return faultCode_; } // Return the error description const QString &SoapMessage::getFaultDescription() const { return faultDescription_; } // Return the entire message as a byte array QByteArray SoapMessage::getMessage() const { // Just do nothing if there's no data if( ! isValid_ ) { return QByteArray(); } QByteArray contents; QTextStream stream( &contents, QIODevice::Append ); // Write the header if( ! header_.isNull() ) { stream << header_ << "\n"; // stream << "<soap:Header>\n" << header_ << "</soap:Header>\n"; } // Write the body if( ! body_.isNull() ) { stream << body_ << "\n"; // stream << "<soap:Body>\n" << body_ << "</soap:Body>\n"; } // Other blocks are not included, since this method is used for common use, not corner cases // Return the complete data message return "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<soap:Envelope xmlns:xsi=\"" XMLNS_XSI "\"" " xmlns:xsd=\"" XMLNS_XSD "\"" " xmlns:soap=\"" XMLNS_SOAP "\">\n" + contents + "</soap:Envelope>\n"; } // Return the message body's xml tree const QDomNode& SoapMessage::getBody() const { return body_; } // Return the message header's xml tree QDomNode& SoapMessage::getHeader() { return header_; } // Return whether this was an error response. Note that you should only use this method on valid messages. bool SoapMessage::isFaultMessage() const { return ( ! faultCode_.isEmpty() ); } // Return whether this message contains valid useable data bool SoapMessage::isValid() const { return isValid_; } // Change the associated request data void SoapMessage::setData( const MessageData &data ) { data_ = data; } // Parse the incoming message void SoapMessage::setMessage( const QString &message ) { QDomDocument xml; // Reset the error indicator faultCode_ = QString(); // Parse the XML // see http://doc.trolltech.com/4.3/qdomdocument.html#setContent isValid_ = xml.setContent( message, true, &faultDescription_ ); // true for namespace processing. // Create an error message if the message can't be parsed if( ! isValid_ ) { faultCode_ = "parsingFailed"; body_ = QDomNode(); fault_ = QDomNode(); header_ = QDomNode(); kmWarning() << "XML parsing failed (code" << faultCode_ << "):" << faultDescription_ << "."; return; } // Get the message's child nodes header_ = XmlFunctions::getNode( xml, "/Envelope/Header" ); body_ = XmlFunctions::getNode( xml, "/Envelope/Body" ); // Verify if any faults are present in the message QDomNode rootFault = XmlFunctions::getNode( xml, "/Envelope/Fault" ); QDomNode bodyFault; // Only check body_ if it's not null, or the assert in getNode will fail if( ! body_.isNull() ) { bodyFault = XmlFunctions::getNode( body_, "/Fault" ); } if( ! rootFault.isNull() ) { fault_ = rootFault; faultCode_ = XmlFunctions::getNodeValue( rootFault, "/faultcode" ); faultDescription_ = XmlFunctions::getNodeValue( rootFault, "/faultstring" ); } else if( ! bodyFault.isNull() ) { fault_ = bodyFault; faultCode_ = XmlFunctions::getNodeValue( bodyFault, "/faultcode" ); faultDescription_ = XmlFunctions::getNodeValue( bodyFault, "/faultstring" ); } // Catch empty messages... unlikely if( fault_.isNull() && header_.isNull() && body_.isNull() ) { isValid_ = false; faultCode_ = "missingBody"; faultDescription_ = "message body is not present"; kmWarning() << "XML parsing failed (code" << faultCode_ << "):" << faultDescription_ << "."; return; } }