summaryrefslogtreecommitdiffstats
path: root/kode/kwsdl/converter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kode/kwsdl/converter.cpp')
-rw-r--r--kode/kwsdl/converter.cpp998
1 files changed, 998 insertions, 0 deletions
diff --git a/kode/kwsdl/converter.cpp b/kode/kwsdl/converter.cpp
new file mode 100644
index 000000000..fc255d74e
--- /dev/null
+++ b/kode/kwsdl/converter.cpp
@@ -0,0 +1,998 @@
+/*
+ This file is part of KDE.
+
+ Copyright (c) 2005 Tobias Koenig <tokoe@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "converter.h"
+
+using namespace KWSDL;
+
+static QString capitalize( const QString &str )
+{
+ return str[ 0 ].upper() + str.mid( 1 );
+}
+
+static QString escapeEnum( const QString &str )
+{
+ QString enumStr = capitalize( str );
+
+ return enumStr.replace( "-", "_" );
+}
+
+Converter::Converter()
+{
+ mQObject = KODE::Class( "QObject" );
+}
+
+void Converter::setWSDL( const WSDL &wsdl )
+{
+ mWSDL = wsdl;
+ mTypeMapper.setTypes( wsdl.types() );
+}
+
+KODE::Class::List Converter::classes() const
+{
+ return mClasses;
+}
+
+void Converter::convert()
+{
+ createUtilClasses();
+ createTransportClass();
+
+ convertTypes( mWSDL.types() );
+
+ mClasses.append( mSerializer );
+
+ convertService( mWSDL.service() );
+}
+
+void Converter::convertTypes( const Schema::Types &types )
+{
+ Schema::SimpleType::List simpleTypes = types.simpleTypes();
+ Schema::SimpleType::List::ConstIterator simpleIt;
+ for ( simpleIt = simpleTypes.begin(); simpleIt != simpleTypes.end(); ++simpleIt )
+ convertSimpleType( &(*simpleIt) );
+
+ Schema::ComplexType::List complexTypes = types.complexTypes();
+ Schema::ComplexType::List::ConstIterator complexIt;
+ for ( complexIt = complexTypes.begin(); complexIt != complexTypes.end(); ++complexIt )
+ convertComplexType( &(*complexIt) );
+}
+
+void Converter::convertSimpleType( const Schema::SimpleType *type )
+{
+ KODE::Class newClass( type->name() );
+ newClass.addInclude( "serializer.h" );
+
+ KODE::Code ctorCode, dtorCode;
+
+ if ( !type->documentation().isEmpty() )
+ newClass.setDocs( type->documentation().simplifyWhiteSpace() );
+
+ if ( type->subType() == Schema::SimpleType::TypeRestriction ) {
+ /**
+ Use setter and getter method for enums as well.
+ */
+ if ( type->facetType() & Schema::SimpleType::ENUM ) {
+ QStringList enums = type->facetEnums();
+ for ( uint i = 0; i < enums.count(); ++i )
+ enums[ i ] = escapeEnum( enums[ i ] );
+
+ newClass.addEnum( KODE::Enum( "Type", enums ) );
+
+ // member variables
+ KODE::MemberVariable variable( "type", "Type" );
+ newClass.addMemberVariable( variable );
+
+ // setter method
+ KODE::Function setter( "setType", "void" );
+ setter.addArgument( "Type type" );
+ setter.setBody( variable.name() + " = type;" );
+
+ // getter method
+ KODE::Function getter( "type", capitalize( newClass.name() ) + "::Type" );
+ getter.setBody( " return " + variable.name() + ";" );
+ getter.setConst( true );
+
+ newClass.addFunction( setter );
+ newClass.addFunction( getter );
+ }
+
+ /**
+ A class can't derive from basic types (e.g. int or unsigned char), so
+ we add setter and getter methods to set the value of this class.
+ */
+ if ( type->baseType() != Schema::XSDType::ANYTYPE &&
+ type->baseType() != Schema::XSDType::INVALID &&
+ !(type->facetType() & Schema::SimpleType::ENUM) ) {
+
+ const QString baseName = type->baseTypeName();
+ const QString typeName = mTypeMapper.type( baseName );
+
+ // include header
+ QMap<QString, QString> headerDec = mTypeMapper.headerDec( baseName );
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = headerDec.begin(); it != headerDec.end(); ++it ) {
+ if ( !it.key().isEmpty() )
+ newClass.addInclude( it.key(), it.data() );
+
+ if ( it.data().isEmpty() )
+ newClass.addHeaderInclude( it.key() );
+ }
+
+ // member variables
+ KODE::MemberVariable variable( "value", typeName + "*" );
+ newClass.addMemberVariable( variable );
+
+ ctorCode += variable.name() + " = 0;";
+ dtorCode += "delete " + variable.name() + ";";
+ dtorCode += variable.name() + " = 0;";
+
+ // setter method
+ KODE::Function setter( "setValue", "void" );
+ setter.addArgument( mTypeMapper.argument( "value", baseName ) );
+ setter.setBody( variable.name() + " = value;" );
+
+ // getter method
+ KODE::Function getter( "value", typeName + "*" );
+ getter.setBody( " return " + variable.name() + ";" );
+ getter.setConst( true );
+
+ newClass.addFunction( setter );
+ newClass.addFunction( getter );
+ }
+ } else if ( type->subType() == Schema::SimpleType::TypeList ) {
+ newClass.addHeaderInclude( "qptrlist.h" );
+ const QString baseName = type->listTypeName();
+ const QString typeName = mTypeMapper.type( baseName );
+
+ // include header
+ QMap<QString, QString> headerDec = mTypeMapper.headerDec( baseName );
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = headerDec.begin(); it != headerDec.end(); ++it ) {
+ if ( !it.key().isEmpty() )
+ newClass.addInclude( it.key(), it.data() );
+
+ if ( it.data().isEmpty() )
+ newClass.addHeaderInclude( it.key() );
+ }
+
+ // member variables
+ KODE::MemberVariable variable( "entries", "QPtrList<" + typeName + ">*" );
+ newClass.addMemberVariable( variable );
+
+ ctorCode += variable.name() + " = 0;";
+ dtorCode += "delete " + variable.name() + ";";
+ dtorCode += variable.name() + " = 0;";
+
+ // setter method
+ KODE::Function setter( "setEntries", "void" );
+ setter.addArgument( mTypeMapper.argument( "entries", baseName, true ) );
+ setter.setBody( variable.name() + " = entries;" );
+
+ // getter method
+ KODE::Function getter( "entries", "QPtrList<" + typeName + ">*" );
+ getter.setBody( " return " + variable.name() + ";" );
+ getter.setConst( true );
+
+ newClass.addFunction( setter );
+ newClass.addFunction( getter );
+ }
+
+ createSimpleTypeSerializer( type );
+
+ KODE::Function ctor( capitalize( newClass.name() ) );
+ KODE::Function dtor( "~" + capitalize( newClass.name() ) );
+
+ ctor.setBody( ctorCode );
+ dtor.setBody( dtorCode );
+
+ newClass.addFunction( ctor );
+ newClass.addFunction( dtor );
+
+ mClasses.append( newClass );
+}
+
+void Converter::createSimpleTypeSerializer( const Schema::SimpleType *type )
+{
+ const QString typeName = mTypeMapper.type( type );
+ const QString baseType = mTypeMapper.type( type->baseTypeName() );
+
+ KODE::Function marshal( "marshal", "void" );
+ marshal.setStatic( true );
+ marshal.addArgument( "QDomDocument &doc" );
+ marshal.addArgument( "QDomElement &parent" );
+ marshal.addArgument( "const QString &name" );
+ marshal.addArgument( "const " + typeName + "* value" );
+
+ KODE::Function demarshal( "demarshal", "void" );
+ demarshal.setStatic( true );
+ demarshal.addArgument( "const QDomElement &parent" );
+ demarshal.addArgument( typeName + "* value" );
+
+ KODE::Code marshalCode, demarshalCode, code;
+
+ // include header
+ QMap<QString, QString> headerDec = mTypeMapper.headerDec( type->name() );
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = headerDec.begin(); it != headerDec.end(); ++it ) {
+ if ( !it.key().isEmpty() )
+ mSerializer.addInclude( it.key(), it.data() );
+
+ if ( it.data().isEmpty() )
+ mSerializer.addHeaderInclude( it.key() );
+ }
+
+ if ( type->subType() == Schema::SimpleType::TypeRestriction ) {
+ // is an enumeration
+ if ( type->facetType() & Schema::SimpleType::ENUM ) {
+ QStringList enums = type->facetEnums();
+ QStringList escapedEnums;
+ for ( uint i = 0; i < enums.count(); ++i )
+ escapedEnums.append( escapeEnum( enums[ i ] ) );
+
+ // marshal value
+ KODE::Function marshalValue( "marshalValue", "QString" );
+ marshalValue.setStatic( true );
+ marshalValue.addArgument( "const " + typeName + "* value" );
+ code += "switch ( value->type() ) {";
+ code.indent();
+ for ( uint i = 0; i < enums.count(); ++i ) {
+ code += "case " + typeName + "::" + escapedEnums[ i ] + ":";
+ code.indent();
+ code += "return \"" + enums[ i ] + "\";";
+ code += "break;";
+ code.unindent();
+ }
+ code += "default:";
+ code.indent();
+ code += "qDebug( \"Unknown enum %d passed.\", value->type() );";
+ code += "break;";
+ code.unindent();
+ code.unindent();
+ code += "}";
+ code.newLine();
+ code += "return QString();";
+ marshalValue.setBody( code );
+
+ // marshal
+ marshalCode += "QDomElement root = doc.createElement( name );";
+ marshalCode += "root.setAttribute( \"xsi:type\", \"ns1:" + type->name() + "\" );";
+ marshalCode += "parent.appendChild( root );";
+ marshalCode += "root.appendChild( doc.createTextNode( Serializer::marshalValue( value ) ) );";
+
+ // demarshal value
+ KODE::Function demarshalValue( "demarshalValue", "void" );
+ demarshalValue.setStatic( true );
+ demarshalValue.addArgument( "const QString &str" );
+ demarshalValue.addArgument( typeName + "* value" );
+ code.clear();
+ for ( uint i = 0; i < enums.count(); ++i ) {
+ code += "if ( str == \"" + enums[ i ] + "\" )";
+ code.indent();
+ code += "value->setType( " + typeName + "::" + escapedEnums[ i ] + " );";
+ code.unindent();
+ code.newLine();
+ }
+ demarshalValue.setBody( code );
+
+ // demarshal
+ demarshalCode += "Serializer::demarshalValue( parent.text(), value );";
+
+ mSerializer.addFunction( marshalValue );
+ mSerializer.addFunction( demarshalValue );
+ } else if ( type->baseType() != Schema::XSDType::INVALID ) {
+ marshalCode += "if ( value->value() ) {";
+ marshalCode.indent();
+ marshalCode += "Serializer::marshal( doc, parent, name, value->value() );";
+ marshalCode.unindent();
+ marshalCode += "}";
+
+ demarshalCode += "const QString text = parent.text();";
+ demarshalCode.newLine();
+ demarshalCode += "if ( !text.isEmpty() ) {";
+ demarshalCode.indent();
+ demarshalCode += baseType + "* data = new " + baseType + ";";
+ demarshalCode += "Serializer::demarshal( parent, value );";
+ demarshalCode += "value->setValue( data );";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+
+ KODE::Function marshalValue( "marshalValue", "QString" );
+ marshalValue.setStatic( true );
+ marshalValue.addArgument( "const " + typeName + "* value" );
+ marshalValue.setBody( "return Serializer::marshalValue( value->value() );" );
+
+ mSerializer.addFunction( marshalValue );
+
+ KODE::Function demarshalValue( "demarshalValue", "void" );
+ demarshalValue.setStatic( true );
+ demarshalValue.addArgument( "const QString &str" );
+ demarshalValue.addArgument( typeName + "* value" );
+ KODE::Code code;
+ code += baseType + "* data = new " + baseType + ";";
+ code += "Serializer::demarshalValue( str, data );";
+ code += "value->setValue( data );";
+ demarshalValue.setBody( code );
+
+ mSerializer.addFunction( demarshalValue );
+ }
+ } else if ( type->subType() == Schema::SimpleType::TypeList ) {
+ const QString listType = mTypeMapper.type( type->listTypeName() );
+
+ mSerializer.addInclude( "qstringlist.h" );
+
+ marshalCode += "if ( value->entries() ) {";
+ marshalCode.indent();
+ marshalCode += "QStringList list;";
+ marshalCode += "QPtrList<" + listType + ">* entries = value->entries();";
+ marshalCode += "QPtrListIterator<" + listType + "> it( *entries );";
+ marshalCode += "while ( it.current() != 0 ) {";
+ marshalCode.indent();
+ marshalCode += "list.append( Serializer::marshalValue( it.current() ) );";
+ marshalCode += "++it;";
+ marshalCode.unindent();
+ marshalCode += "}";
+ marshalCode.newLine();
+ marshalCode += "QDomElement element = doc.createElement( name );";
+ marshalCode += "parent.appendChild( element );";
+ marshalCode += "element.appendChild( doc.createTextNode( list.join( \" \" ) ) );";
+ marshalCode.unindent();
+ marshalCode += "}";
+
+ demarshalCode += "const QStringList list = QStringList::split( \" \", parent.text(), false );";
+ demarshalCode += "if ( !list.isEmpty() ) {";
+ demarshalCode.indent();
+ demarshalCode += "QPtrList<" + listType + ">* entries = new QPtrList<" + listType + ">;";
+ demarshalCode += "entries->setAutoDelete( true );";
+ demarshalCode += "QStringList::ConstIterator it;";
+ demarshalCode += "for ( it = list.begin(); it != list.end(); ++it ) {";
+ demarshalCode.indent();
+ demarshalCode += listType + " *entry = new " + listType + ";";
+ demarshalCode += "Serializer::demarshalValue( *it, entry );";
+ demarshalCode += "entries->append( entry );";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+ demarshalCode.newLine();
+ demarshalCode += "value->setEntries( entries );";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+ }
+
+ marshal.setBody( marshalCode );
+ mSerializer.addFunction( marshal );
+
+ demarshal.setBody( demarshalCode );
+ mSerializer.addFunction( demarshal );
+}
+
+void Converter::convertComplexType( const Schema::ComplexType *type )
+{
+ KODE::Class newClass( type->name() );
+ newClass.addInclude( "serializer.h" );
+
+ KODE::Code ctorCode, dtorCode;
+
+ if ( type->baseType() != Schema::XSDType::ANYTYPE && !type->isArray() ) {
+ QString baseName = mTypeMapper.type( type->baseTypeName() );
+ newClass.addBaseClass( KODE::Class( baseName ) );
+ newClass.addHeaderIncludes( mTypeMapper.header( type->baseTypeName() ) );
+ }
+
+ if ( !type->documentation().isEmpty() )
+ newClass.setDocs( type->documentation().simplifyWhiteSpace() );
+
+ // elements
+ Schema::Element::List elements = type->elements();
+ Schema::Element::List::ConstIterator elemIt;
+ for ( elemIt = elements.begin(); elemIt != elements.end(); ++elemIt ) {
+ QString typeName = mTypeMapper.type( &*elemIt );
+
+ if ( (*elemIt).maxOccurs() > 1 )
+ typeName = "QPtrList<" + typeName + ">";
+
+ // member variables
+ KODE::MemberVariable variable( (*elemIt).name(), typeName + "*" );
+ newClass.addMemberVariable( variable );
+
+ ctorCode += variable.name() + " = 0;";
+ dtorCode += "delete " + variable.name() + ";";
+ dtorCode += variable.name() + " = 0;";
+
+ QString upperName = (*elemIt).name();
+ QString lowerName = (*elemIt).name();
+ upperName[ 0 ] = upperName[ 0 ].upper();
+ lowerName[ 0 ] = lowerName[ 0 ].lower();
+
+ // setter method
+ KODE::Function setter( "set" + upperName, "void" );
+ setter.addArgument( mTypeMapper.argument( mNameMapper.escape( lowerName ), &*elemIt ) );
+ setter.setBody( variable.name() + " = " + mNameMapper.escape( lowerName ) + ";" );
+
+ // getter method
+ KODE::Function getter( mNameMapper.escape( lowerName ), typeName + "*" );
+ getter.setBody( " return " + variable.name() + ";" );
+ getter.setConst( true );
+
+ newClass.addFunction( setter );
+ newClass.addFunction( getter );
+
+ // include header
+ QMap<QString, QString> headerDec = mTypeMapper.headerDec( &*elemIt);
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = headerDec.begin(); it != headerDec.end(); ++it ) {
+ if ( !it.key().isEmpty() )
+ newClass.addInclude( it.key(), it.data() );
+
+ if ( it.data().isEmpty() )
+ newClass.addHeaderInclude( it.key() );
+ }
+ }
+
+ // attributes
+ Schema::Attribute::List attributes = type->attributes();
+ Schema::Attribute::List::ConstIterator attrIt;
+ for ( attrIt = attributes.begin(); attrIt != attributes.end(); ++attrIt ) {
+ const QString typeName = mTypeMapper.type( &*attrIt );
+
+ // member variables
+ KODE::MemberVariable variable( (*attrIt).name(), typeName + "*" );
+ newClass.addMemberVariable( variable );
+
+ ctorCode += variable.name() + " = 0;";
+ dtorCode += "delete " + variable.name() + ";";
+ dtorCode += variable.name() + " = 0;";
+
+ QString upperName = (*attrIt).name();
+ QString lowerName = (*attrIt).name();
+ upperName[ 0 ] = upperName[ 0 ].upper();
+ lowerName[ 0 ] = lowerName[ 0 ].lower();
+
+ // setter method
+ KODE::Function setter( "set" + upperName, "void" );
+ setter.addArgument( mTypeMapper.argument( mNameMapper.escape( lowerName ), &*attrIt ) );
+ setter.setBody( variable.name() + " = " + mNameMapper.escape( lowerName ) + ";" );
+
+ // getter method
+ KODE::Function getter( mNameMapper.escape( lowerName ), typeName + "*" );
+ getter.setBody( " return " + variable.name() + ";" );
+ getter.setConst( true );
+
+ newClass.addFunction( setter );
+ newClass.addFunction( getter );
+
+ // include header
+ QMap<QString, QString> headerDec = mTypeMapper.headerDec( &*attrIt);
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = headerDec.begin(); it != headerDec.end(); ++it ) {
+ if ( !it.key().isEmpty() )
+ newClass.addInclude( it.key(), it.data() );
+
+ if ( it.data().isEmpty() )
+ newClass.addHeaderInclude( it.key() );
+ }
+ }
+
+ createComplexTypeSerializer( type );
+
+ KODE::Function ctor( capitalize( newClass.name() ) );
+ KODE::Function dtor( "~" + capitalize( newClass.name() ) );
+
+ ctor.setBody( ctorCode );
+ dtor.setBody( dtorCode );
+
+ newClass.addFunction( ctor );
+ newClass.addFunction( dtor );
+
+ mClasses.append( newClass );
+}
+
+void Converter::createComplexTypeSerializer( const Schema::ComplexType *type )
+{
+ const QString typeName = mTypeMapper.type( type );
+
+ KODE::Function marshal( "marshal", "void" );
+ marshal.setStatic( true );
+ marshal.addArgument( "QDomDocument &doc" );
+ marshal.addArgument( "QDomElement &parent" );
+ marshal.addArgument( "const QString &name" );
+ marshal.addArgument( "const " + typeName + "* value" );
+
+ KODE::Function demarshal( "demarshal", "void" );
+ demarshal.setStatic( true );
+ demarshal.addArgument( "const QDomElement &parent" );
+ demarshal.addArgument( typeName + "* value" );
+
+ KODE::Code marshalCode, demarshalCode, demarshalFinalCode;
+
+ // include header
+ QMap<QString, QString> headerDec = mTypeMapper.headerDec( type->name() );
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = headerDec.begin(); it != headerDec.end(); ++it ) {
+ if ( !it.key().isEmpty() )
+ mSerializer.addInclude( it.key(), it.data() );
+
+ if ( it.data().isEmpty() )
+ mSerializer.addHeaderInclude( it.key() );
+ }
+
+ marshalCode += "QDomElement root = doc.createElement( name );";
+ marshalCode += "root.setAttribute( \"xsi:type\", \"ns1:" + typeName + "\" );";
+ marshalCode += "parent.appendChild( root );";
+
+ demarshalCode += "QDomNode node = parent.firstChild();";
+ demarshalCode += "while ( !node.isNull() ) {";
+ demarshalCode.indent();
+ demarshalCode += "QDomElement element = node.toElement();";
+ demarshalCode += "if ( !element.isNull() ) {";
+ demarshalCode.indent();
+
+ // elements
+ Schema::Element::List elements = type->elements();
+ Schema::Element::List::ConstIterator elemIt;
+ for ( elemIt = elements.begin(); elemIt != elements.end(); ++elemIt ) {
+ const QString typeName = mTypeMapper.type( &*elemIt );
+
+ QString upperName = (*elemIt).name();
+ QString lowerName = (*elemIt).name();
+ upperName[ 0 ] = upperName[ 0 ].upper();
+ lowerName[ 0 ] = lowerName[ 0 ].lower();
+
+ KODE::Function setter( "set" + upperName, "void" );
+ KODE::Function getter( mNameMapper.escape( lowerName ), typeName + "*" );
+
+ if ( (*elemIt).maxOccurs() > 1 ) {
+ marshalCode += "if ( value->" + mNameMapper.escape( lowerName ) + "() ) {";
+ marshalCode.indent();
+ marshalCode += "const QPtrList<" + typeName + ">* list = value->" + mNameMapper.escape( lowerName ) + "();";
+ marshalCode.newLine();
+ marshalCode += "QDomElement element = doc.createElement( name );";
+ // no idea about the namespaces here...
+ marshalCode += "element.setAttribute( \"xmlns:ns1\", \"http://schemas.xmlsoap.org/soap/encoding/\" );";
+ marshalCode += "element.setAttribute( \"xsi:type\", \"ns1:Array\" );";
+ marshalCode += "element.setAttribute( \"ns1:arrayType\", \"ns1:" + typeName + "[\" + QString::number( list->count() ) + \"]\" );";
+ marshalCode += "parent.appendChild( element );";
+ marshalCode.newLine();
+ marshalCode += "QPtrListIterator<" + typeName + "> it( *list );";
+ marshalCode += "while ( it.current() != 0 ) {";
+ marshalCode.indent();
+ marshalCode += "Serializer::marshal( doc, element, \"item\", it.current() );";
+ marshalCode += "++it;";
+ marshalCode.unindent();
+ marshalCode += "}";
+ marshalCode.unindent();
+ marshalCode += "}";
+
+ const QString listName = mNameMapper.escape( lowerName ) + "List";
+ // TODO: prepend the code somehow
+ KODE::Code code;
+ code += "QPtrList<" + typeName + ">* " + listName + " = new QPtrList<" + typeName + ">();";
+ code += listName + "->setAutoDelete( true );";
+ code += demarshalCode;
+ demarshalCode = code;
+ demarshalCode += "if ( element.tagName() == \"item\" ) {";
+ demarshalCode.indent();
+ demarshalCode += typeName + " *item = new " + typeName + ";";
+ demarshalCode += "Serializer::demarshal( element, item );";
+ demarshalCode += listName + "->append( item );";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+
+ demarshalFinalCode += "value->" + setter.name() + "( " + listName + " );";
+ } else {
+ marshalCode += "if ( value->" + getter.name() + "() ) {";
+ marshalCode.indent();
+ marshalCode += "Serializer::marshal( doc, root, \"" + (*elemIt).name() + "\", value->" + getter.name() + "() );";
+ marshalCode.unindent();
+ marshalCode += "}";
+
+ demarshalCode += "if ( element.tagName() == \"" + (*elemIt).name() + "\" ) {";
+ demarshalCode.indent();
+ demarshalCode += typeName + "* item = new " + typeName + ";";
+ demarshalCode += "Serializer::demarshal( element, item );";
+ demarshalCode += "value->" + setter.name() + "( item );";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+ }
+ }
+
+ // attributes
+ Schema::Attribute::List attributes = type->attributes();
+ Schema::Attribute::List::ConstIterator attrIt;
+ for ( attrIt = attributes.begin(); attrIt != attributes.end(); ++attrIt ) {
+ const QString typeName = mTypeMapper.type( &*attrIt );
+
+ QString upperName = (*attrIt).name();
+ QString lowerName = (*attrIt).name();
+ upperName[ 0 ] = upperName[ 0 ].upper();
+ lowerName[ 0 ] = lowerName[ 0 ].lower();
+
+ KODE::Function setter( "set" + upperName, "void" );
+ KODE::Function getter( mNameMapper.escape( lowerName ), typeName + "*" );
+
+ marshalCode += "if ( value->" + mNameMapper.escape( lowerName ) + "() )";
+ marshalCode.indent();
+ marshalCode += "parent.setAttribute( \"" + (*attrIt).name() + "\","
+ "Serializer::marshalValue( value->" + mNameMapper.escape( lowerName ) + "() ) );";
+ marshalCode.newLine();
+
+ demarshalCode += "if ( element.hasAttribute( \"" + (*attrIt).name() + "\" ) ) {";
+ demarshalCode.indent();
+ demarshalCode += typeName + "* item = new " + typeName + ";";
+ demarshalCode += "Serializer::demarshalValue( element.attribute( \"" + (*attrIt).name() + "\" ), item );";
+ demarshalCode += "value->" + setter.name() + "( item );";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+ }
+
+ demarshalCode.unindent();
+ demarshalCode += "}";
+ demarshalCode += "node = node.nextSibling();";
+ demarshalCode.unindent();
+ demarshalCode += "}";
+ demarshalCode.newLine();
+ demarshalCode += demarshalFinalCode;
+
+ marshal.setBody( marshalCode );
+ mSerializer.addFunction( marshal );
+
+ demarshal.setBody( demarshalCode );
+ mSerializer.addFunction( demarshal );
+}
+
+void Converter::convertService( const Service &service )
+{
+ KODE::Class newClass( service.name() );
+ newClass.addBaseClass( mQObject );
+ newClass.addHeaderInclude( "qobject.h" );
+ newClass.addHeaderInclude( "qstring.h" );
+ newClass.addHeaderInclude( "transport.h" );
+
+ newClass.addInclude( "serializer.h" );
+
+ KODE::Function ctor( service.name() );
+ KODE::Function dtor( "~" + service.name() );
+ KODE::Code ctorCode, dtorCode;
+
+ const Service::Port::List servicePorts = service.ports();
+ Service::Port::List::ConstIterator it;
+ for ( it = servicePorts.begin(); it != servicePorts.end(); ++it ) {
+ Binding binding = mWSDL.findBinding( (*it).mBinding );
+
+ Port port = mWSDL.findPort( binding.type() );
+ const Port::Operation::List operations = port.operations();
+ Port::Operation::List::ConstIterator opIt;
+ for ( opIt = operations.begin(); opIt != operations.end(); ++opIt ) {
+ Message inputMessage = mWSDL.findMessage( (*opIt).input() );
+ Message outputMessage = mWSDL.findMessage( (*opIt).output() );
+
+ convertInputMessage( port, inputMessage, newClass );
+ convertOutputMessage( port, outputMessage, newClass );
+
+ KODE::MemberVariable transport( inputMessage.name() + "Transport", "Transport" );
+ ctorCode += transport.name() + " = new Transport( \"" + (*it).mLocation + "\" );";
+
+ ctorCode += "connect( " + transport.name() + ", SIGNAL( result( const QString& ) ),";
+ ctorCode.indent();
+ ctorCode += "this, SLOT( " + outputMessage.name() + "Slot( const QString& ) ) );";
+ ctorCode.unindent();
+
+ dtorCode += "delete " + transport.name() + ";";
+ dtorCode += transport.name() + " = 0;";
+ }
+ }
+
+ ctor.setBody( ctorCode );
+ newClass.addFunction( ctor );
+
+ dtor.setBody( dtorCode );
+ newClass.addFunction( dtor );
+
+ mClasses.append( newClass );
+}
+
+void Converter::convertInputMessage( const Port &port, const Message &message, KODE::Class &newClass )
+{
+ KODE::MemberVariable transport( message.name() + "Transport", "Transport*" );
+ newClass.addMemberVariable( transport );
+
+ // call
+ QString messageName = message.name();
+ messageName[ 0 ] = messageName[ 0 ].lower();
+ KODE::Function callFunc( mNameMapper.escape( messageName ), "void", KODE::Function::Public );
+
+ const Message::Part::List parts = message.parts();
+ Message::Part::List::ConstIterator it;
+ for ( it = parts.begin(); it != parts.end(); ++it ) {
+ newClass.addHeaderIncludes( mTypeMapper.header( (*it).type() ) );
+ QString lowerName = (*it).name();
+ lowerName[ 0 ] = lowerName[ 0 ].lower();
+ callFunc.addArgument( mTypeMapper.argument( mNameMapper.escape( lowerName ), (*it).type() ) );
+ }
+
+ KODE::Code code;
+ code += "QDomDocument doc( \"kwsdl\" );";
+ code += "doc.appendChild( doc.createProcessingInstruction( \"xml\", \"version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"\" ) );";
+ code += "QDomElement env = doc.createElement( \"SOAP-ENV:Envelope\" );";
+ code += "env.setAttribute( \"xmlns:SOAP-ENV\", \"http://schemas.xmlsoap.org/soap/envelope/\" );";
+ code += "env.setAttribute( \"xmlns:xsi\", \"http://www.w3.org/1999/XMLSchema-instance\" );";
+ code += "env.setAttribute( \"xmlns:xsd\", \"http://www.w3.org/1999/XMLSchema\" );";
+ code += "doc.appendChild( env );";
+ code += "QDomElement body = doc.createElement( \"SOAP-ENV:Body\" );";
+ code += "env.appendChild( body );";
+ code += "QDomElement method = doc.createElement( \"ns1:" + message.name() + "\" );";
+ QString nameSpace = mWSDL.findBindingOperation( port.name(), message.name() ).input().nameSpace();
+ code += "method.setAttribute( \"xmlns:ns1\", \"" + nameSpace + "\" );";
+ code += "method.setAttribute( \"SOAP-ENV:encodingStyle\", \"http://schemas.xmlsoap.org/soap/encoding/\" );";
+ code += "body.appendChild( method );";
+ code.newLine();
+
+ for ( it = parts.begin(); it != parts.end(); ++it ) {
+ QString lowerName = (*it).name();
+ lowerName[ 0 ] = lowerName[ 0 ].lower();
+ code += "Serializer::marshal( doc, method, \"" + (*it).name() + "\", " + mNameMapper.escape( lowerName ) + " );";
+ code += "delete " + mNameMapper.escape( lowerName ) + ";";
+ }
+
+ code += "qDebug( \"%s\", doc.toString().latin1() );";
+ code += transport.name() + "->query( doc.toString() );";
+ callFunc.setBody( code );
+
+ newClass.addFunction( callFunc );
+}
+
+void Converter::convertOutputMessage( const Port&, const Message &message, KODE::Class &newClass )
+{
+ Message::Part part = message.parts().first();
+
+ // signal
+ QString messageName = message.name();
+ messageName[ 0 ] = messageName[ 0 ].lower();
+ KODE::Function respSignal( messageName, "void", KODE::Function::Signal );
+
+ /**
+ If one output message is used by two input messages, don't define
+ it twice.
+ */
+ if ( newClass.hasFunction( respSignal.name() ) )
+ return;
+
+ const Message::Part::List parts = message.parts();
+ Message::Part::List::ConstIterator it;
+ for ( it = parts.begin(); it != parts.end(); ++it ) {
+ QStringList headers = mTypeMapper.header( (*it).type() );
+ for ( uint i = 0; i < headers.count(); ++i )
+ if ( !headers[ i ].isEmpty() )
+ newClass.addHeaderInclude( headers[ i ] );
+
+ respSignal.addArgument( mTypeMapper.argument( "value", (*it).type() ) );
+ }
+
+ newClass.addFunction( respSignal );
+
+ // slot
+ KODE::Function respSlot( messageName + "Slot", "void", KODE::Function::Slot | KODE::Function::Private );
+ respSlot.addArgument( "const QString &xml" );
+
+ KODE::Code code;
+ code += "QDomDocument doc;";
+ code += "QString errorMsg;";
+ code += "int column, row;";
+ code.newLine();
+ code += "qDebug( \"%s\", xml.latin1() );";
+ code.newLine();
+ code += "if ( !doc.setContent( xml, true, &errorMsg, &row, &column ) ) {";
+ code.indent();
+ code += "qDebug( \"Unable to parse xml: %s (%d:%d)\", errorMsg.latin1(), row, column );";
+ code += "return;";
+ code.unindent();
+ code += "}";
+ code.newLine();
+ code += mTypeMapper.type( part.type() ) + "* value = new " + mTypeMapper.type( part.type() ) + ";";
+ code += "QDomElement envelope = doc.documentElement();";
+ code += "QDomElement body = envelope.firstChild().toElement();";
+ code += "QDomElement method = body.firstChild().toElement();";
+ code += "Serializer::demarshal( method.firstChild().toElement(), value );";
+ code.newLine();
+ code += "emit " + respSignal.name() + "( value );";
+ respSlot.setBody( code );
+
+ newClass.addFunction( respSlot );
+}
+
+void Converter::createUtilClasses()
+{
+ mSerializer = KODE::Class( "Serializer" );
+ mSerializer.addHeaderInclude( "qcstring.h" );
+ mSerializer.addHeaderInclude( "qdom.h" );
+ mSerializer.addHeaderInclude( "qdatetime.h" );
+ mSerializer.addHeaderInclude( "qstring.h" );
+ mSerializer.addHeaderInclude( "qptrlist.h" );
+ mSerializer.addInclude( "kmdcodec.h" );
+
+ typedef struct {
+ QString type;
+ QString xsdType;
+ QString marshalCode;
+ QString demarshalCode;
+ } TypeEntry;
+
+ /**
+ I know the following code looks a bit ugly, but it saves us a lot
+ of typing and is easier to maintain at the end ;)
+ */
+ TypeEntry types[] = {
+ { "QString", "xsd:string", "*value", "str" },
+ { "bool", "xsd:boolean", "(*value ? \"true\" : \"false\")", "(str.lower() == \"true\" ? true : false)" },
+ { "float", "xsd:TODO", "QString::number( *value )", "str.toFloat()" },
+ { "int", "xsd:int", "QString::number( *value )", "str.toInt()" },
+ { "unsigned int", "xsd:unsignedByte", "QString::number( *value )", "str.toUInt()" },
+ { "double", "xsd:double", "QString::number( *value )", "str.toDouble()" },
+ { "char", "xsd:byte", "QString( QChar( *value ) )", "str[ 0 ].latin1()" },
+ { "unsigned char", "xsd:unsignedByte", "QString( QChar( *value ) )", "str[ 0 ].latin1()" },
+ { "short", "xsd:short", "QString::number( *value )", "str.toShort()" },
+ { "QByteArray", "xsd:base64Binary", "QString::fromUtf8( KCodecs::base64Encode( *value ) )", "KCodecs::base64Decode( str.utf8() )" },
+ { "QDateTime", "xsd:dateTime", "value->toString( Qt::ISODate )", "QDateTime::fromString( str, Qt::ISODate )" },
+ { "QDate", "xsd:date", "value->toString( Qt::ISODate )", "QDate::fromString( str, Qt::ISODate )" }
+ };
+
+ for ( uint i = 0; i < sizeof( types ) / sizeof( TypeEntry ); ++i ) {
+ KODE::Function marshal, demarshal;
+ KODE::Code code;
+
+ TypeEntry entry = types[ i ];
+
+ marshal = KODE::Function( "marshalValue", "QString" );
+ marshal.setStatic( true );
+ marshal.addArgument( "const " + entry.type + "* value" );
+
+ code.clear();
+ marshal.setBody( "return " + entry.marshalCode + ";" );
+
+ mSerializer.addFunction( marshal );
+
+ demarshal = KODE::Function( "demarshalValue", "void" );
+ demarshal.setStatic( true );
+ demarshal.addArgument( "const QString &str" );
+ demarshal.addArgument( entry.type + " *value" );
+ demarshal.setBody( "*value = " + entry.demarshalCode + ";" );
+
+ mSerializer.addFunction( demarshal );
+
+ marshal = KODE::Function( "marshal", "void" );
+ marshal.setStatic( true );
+ marshal.addArgument( "QDomDocument &doc" );
+ marshal.addArgument( "QDomElement &parent" );
+ marshal.addArgument( "const QString &name" );
+ marshal.addArgument( "const " + entry.type + "* value" );
+
+ code.clear();
+ code += "QDomElement element = doc.createElement( name );";
+ code += "element.setAttribute( \"xsi:type\", \"" + entry.xsdType + "\" );";
+ code += "element.appendChild( doc.createTextNode( Serializer::marshalValue( value ) ) );";
+ code += "parent.appendChild( element );";
+ marshal.setBody( code );
+
+ mSerializer.addFunction( marshal );
+
+ demarshal = KODE::Function( "demarshal", "void" );
+ demarshal.setStatic( true );
+ demarshal.addArgument( "const QDomElement &element" );
+ demarshal.addArgument( entry.type + "* value" );
+ demarshal.setBody( "Serializer::demarshalValue( element.text(), value );" );
+
+ mSerializer.addFunction( demarshal );
+ }
+}
+
+void Converter::createTransportClass()
+{
+ KODE::Class transport( "Transport" );
+ transport.addBaseClass( mQObject );
+ transport.addHeaderInclude( "qobject.h" );
+ transport.addHeaderInclude( "kio/job.h" );
+
+ transport.addInclude( "kdebug.h" );
+
+ KODE::MemberVariable url( "url", "QString" );
+ transport.addMemberVariable( url );
+
+ KODE::MemberVariable slotDataVar( "data", "QByteArray" );
+ transport.addMemberVariable( slotDataVar );
+
+ // ctor
+ KODE::Function ctor( "Transport" );
+ ctor.addArgument( "const QString &url" );
+ ctor.setBody( url.name() + " = url;" );
+
+ transport.addFunction( ctor );
+
+ // query
+ KODE::Function query( "query", "void" );
+ query.addArgument( "const QString &xml" );
+
+ KODE::Code queryCode;
+ queryCode += slotDataVar.name() + ".truncate( 0 );";
+ queryCode.newLine();
+ queryCode += "QByteArray postData;";
+ queryCode += "QDataStream stream( postData, IO_WriteOnly );";
+ queryCode += "stream.writeRawBytes( xml.utf8(), xml.utf8().length() );";
+ queryCode.newLine();
+ queryCode += "KIO::TransferJob* job = KIO::http_post( KURL( " + url.name() + " ), postData, false );";
+ queryCode += "if ( !job ) {";
+ queryCode.indent();
+ queryCode += "kdWarning() << \"Unable to create KIO job for \" << " + url.name() + " << endl;";
+ queryCode += "return;";
+ queryCode.unindent();
+ queryCode += "}";
+ queryCode.newLine();
+ queryCode += "job->addMetaData( \"UserAgent\", \"KWSDL\" );";
+ queryCode += "job->addMetaData( \"content-type\", \"Content-Type: text/xml; charset=utf-8\" );";
+ queryCode.newLine();
+ queryCode += "connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );";
+ queryCode += "connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );";
+
+ query.setBody( queryCode );
+
+ transport.addFunction( query );
+
+ // signal
+ KODE::Function result( "result", "void", KODE::Function::Signal );
+ result.addArgument( "const QString &xml" );
+
+ transport.addFunction( result );
+
+ // data slot
+ KODE::Function slotData( "slotData", "void", KODE::Function::Private | KODE::Function::Slot );
+
+ slotData.addArgument( "KIO::Job*" );
+ slotData.addArgument( "const QByteArray &data" );
+
+ KODE::Code slotDataCode;
+ slotDataCode += "unsigned int oldSize = " + slotDataVar.name() + ".size();";
+ slotDataCode += slotDataVar.name() + ".resize( oldSize + data.size() );";
+ slotDataCode += "memcpy( " + slotDataVar.name() + ".data() + oldSize, data.data(), data.size() );";
+
+ slotData.setBody( slotDataCode );
+
+ transport.addFunction( slotData );
+
+ // result slot
+ KODE::Function slotResult( "slotResult", "void", KODE::Function::Private | KODE::Function::Slot );
+ slotResult.addArgument( "KIO::Job* job" );
+
+ KODE::Code slotResultCode;
+ slotResultCode += "if ( job->error() != 0 ) {";
+ slotResultCode.indent();
+ slotResultCode += "kdWarning() << \"Error occurred \" << job->errorText() << endl;";
+ slotResultCode += "kdWarning() << " + slotDataVar.name() + " << endl;";
+ slotResultCode += "return;";
+ slotResultCode.unindent();
+ slotResultCode += "}";
+ slotResultCode.newLine();
+
+ slotResultCode += "emit result( QString::fromUtf8( " + slotDataVar.name() + ".data(), " + slotDataVar.name() + ".size() ) );";
+
+ slotResult.setBody( slotResultCode );
+
+ transport.addFunction( slotResult );
+
+ mClasses.append( transport );
+}