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::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::convertSimpleType(const XSD::SimpleType *type, const XSD::SimpleType::List &simpleTypeList) { const QString typeName(mTypeMap.localType(type->qualifiedName())); //qDebug() << "convertSimpleType:" << type->qualifiedName() << typeName; KODE::Class newClass; newClass.setNamespaceAndName(typeName); if (!Settings::self()->exportDeclaration().isEmpty()) { newClass.setExportDeclaration(Settings::self()->exportDeclaration()); } newClass.setNameSpace(Settings::self()->nameSpace()); QString classDocumentation; switch (type->subType()) { case XSD::SimpleType::TypeRestriction: { /** Use setter and getter method for enums as well. */ if (type->facetType() & XSD::SimpleType::ENUM) { classDocumentation = "This class is a wrapper for an enumeration.\n"; NameMapper nameMapper; QStringList enums = type->facetEnums(); for (int i = 0; i < enums.count(); ++i) { enums[ i ] = nameMapper.escape(escapeEnum(enums[ i ])); } newClass.addEnum(KODE::Enum("Type", enums)); classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the enum directly. Example:\n" + "someMethod(" + newClass.name() + "::" + enums.first() + ")."; // member variables KODE::MemberVariable variable("type", "Type"); variable.setInitializer("Type(0)"); 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", newClass.qualifiedName() + "::Type"); getter.setBody("return " + variable.name() + ';'); getter.setConst(true); // convenience constructor KODE::Function conctor(newClass.name()); conctor.addArgument("const Type &type"); KODE::Code code; code += variable.name() + " = type;"; conctor.setBody(code); // type operator KODE::Function op("operator Type"); op.setBody("return " + variable.name() + ';'); op.setConst(true); newClass.addFunction(conctor); newClass.addFunction(setter); newClass.addFunction(getter); newClass.addFunction(op); } /** 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->baseTypeName() != XmlAnyType && !type->baseTypeName().isEmpty() && !(type->facetType() & XSD::SimpleType::ENUM)) { classDocumentation = "This class encapsulates a simple type.\n"; const QName baseName = type->baseTypeName(); const QString baseTypeName = mTypeMap.localType(baseName); Q_ASSERT(!baseTypeName.isEmpty()); QList<QName> parentBasicTypes; parentBasicTypes.append(baseName); QName currentType = baseName; Q_FOREVER { const XSD::SimpleType simpleType = simpleTypeList.simpleType(currentType); if (!simpleType.isNull() && simpleType.isRestriction()) { currentType = simpleType.baseTypeName(); parentBasicTypes.append(currentType); continue; } break; } classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the value directly as a " + mTypeMap.localType(currentType) + '.'; // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(baseName)); newClass.addHeaderIncludes(mTypeMap.headerIncludes(baseName)); // member variables KODE::MemberVariable variable("value", baseTypeName); addVariableInitializer(variable); newClass.addMemberVariable(variable); // setter method KODE::Function setter("setValue", "void"); const QString inputType = mTypeMap.localInputType(baseName, QName()); setter.addArgument(inputType + " value"); KODE::Code setterBody; if (type->facetType() != XSD::SimpleType::NONE) { const XSD::SimpleType baseSimpleType = simpleTypeList.simpleType(baseName); setterBody += createRangeCheckCode(type, baseTypeName, "value", newClass, baseSimpleType); setterBody.newLine(); setterBody += "if (!rangeOk)"; setterBody.indent(); setterBody += "qDebug( \"Invalid range in " + newClass.name() + "::" + setter.name() + "()\" );"; setterBody.unindent(); setterBody.newLine(); } setterBody += variable.name() + " = value;"; // ### call setValue in base class? setter.setBody(setterBody); newClass.addFunction(setter); // getter method KODE::Function getter("value", baseTypeName); getter.setBody("return " + variable.name() + ';'); getter.setConst(true); newClass.addFunction(getter); // convenience constructor KODE::Function conctor(newClass.name()); conctor.addArgument(inputType + " value"); conctor.addBodyLine("setValue(value);"); newClass.addFunction(conctor); // even more convenient constructor, for the case of multiple-level simple-type restrictions //qDebug() << typeName << ": baseName=" << baseName << "further up:" << parentBasicTypes; if (parentBasicTypes.count() > 1) { parentBasicTypes.removeLast(); // the top-most one is in "currentType", so it's the input arg. KODE::Function baseCtor(conctor.name()); baseCtor.addArgument(mTypeMap.localInputType(currentType, QName()) + " value"); QString beginLine = "setValue("; QString endLine = ")"; Q_FOREACH (const QName &base, parentBasicTypes) { beginLine += mTypeMap.localType(base) + '('; endLine += ')'; } baseCtor.addBodyLine(beginLine + "value" + endLine + ';'); newClass.addFunction(baseCtor); } // type operator KODE::Function op("operator " + baseTypeName); op.setBody("return " + variable.name() + ';'); op.setConst(true); newClass.addFunction(op); }
void Converter::convertComplexType(const XSD::ComplexType *type) { // An empty type is still useful, in document mode: it serializes the element name //if ( type->isEmpty() ) // return; // Skip the Array types we added in Parser::init... if (NSManager::soapEncNamespaces().contains(type->nameSpace())) { return; } const QString className(mTypeMap.localType(type->qualifiedName())); KODE::Class newClass; newClass.setNamespaceAndName(className); if (!Settings::self()->exportDeclaration().isEmpty()) { newClass.setExportDeclaration(Settings::self()->exportDeclaration()); } newClass.setUseSharedData(true, QLatin1String("d_ptr") /*avoid clash with possible d() method */); const bool doDebug = (qgetenv("KDSOAP_TYPE_DEBUG").toInt()); if (doDebug) { qDebug() << "Generating complex type" << className; } // subclass handling if (!type->baseTypeName().isEmpty()) { // this class extends something /** * A class can't subclass basic type (e.g. int, unsigned char), so we * add setValue() and value() methods to access the base type. * * In fact, let's do the same with string */ if (type->baseTypeName().localName() == QLatin1String("Array")) { // this is handled in the attribute section } else { const QName baseName = type->baseTypeName(); const QString typeName = mTypeMap.localType(baseName); const QString inputTypeName = mTypeMap.localInputType(baseName, QName()); // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(baseName)); newClass.addHeaderIncludes(mTypeMap.headerIncludes(baseName)); if (mTypeMap.isComplexType(baseName)) { newClass.addBaseClass(typeName); } else { const QString variableName = generateMemberVariable("value", typeName, inputTypeName, newClass, XSD::Attribute::Required, false, false); // convenience constructor KODE::Function conctor(upperlize(newClass.name())); conctor.addArgument(inputTypeName + QLatin1String(" value")); conctor.setBody(variableName + QLatin1String(" = value;")); // type operator KODE::Function op(QLatin1String("operator ") + typeName); op.setBody(QLatin1String("return ") + variableName + QLatin1Char(';')); op.setConst(true); newClass.addFunction(conctor); newClass.addFunction(op); } } } if (!type->documentation().isEmpty()) { newClass.setDocs(type->documentation().simplified()); } QVector<QString> seenElements; // elements in the complex type const XSD::Element::List elements = type->elements(); Q_FOREACH (const XSD::Element &elemIt, elements) { if (elemIt.type().isEmpty()) { qDebug() << "ERROR: Element from" << *type << "with no type:" << elemIt << "(skipping)"; Q_ASSERT(false); continue; } // When having <choice> // <sequence>A,B(opt)</sequence> // B // <sequence>C,B(opt)</sequence> // </choice> // we don't want to emit setB() three times, that's not valid C++ // (testcase in wsdl_document.wsdl TestRepeatedChildren) if (seenElements.contains(elemIt.name())) { continue; } seenElements.append(elemIt.name()); QString typeName = mTypeMap.localType(elemIt.type()); Q_ASSERT(!typeName.isEmpty()); if (typeName != QLatin1String("void")) { // void means empty element, probably just here for later extensions (testcase: SetPasswordResult in salesforce) QString inputTypeName = mTypeMap.localInputType(elemIt.type(), QName()); bool isList = false; if (elemIt.maxOccurs() > 1 || elemIt.compositor().maxOccurs() > 1) { QString itemType = mTypeMap.isPolymorphic(elemIt.type()) ? pointerStorageType(typeName) : typeName; typeName = listTypeFor(itemType, newClass); inputTypeName = QLatin1String("const ") + typeName + QLatin1String("&"); isList = true; } if (type->isArray()) { QString arrayTypeName = mTypeMap.localType(type->arrayType()); Q_ASSERT(!arrayTypeName.isEmpty()); if (mTypeMap.isPolymorphic(type->arrayType())) { arrayTypeName = pointerStorageType(arrayTypeName); } //qDebug() << "array of" << attribute.arrayType() << "->" << arrayTypeName; typeName = listTypeFor(arrayTypeName, newClass); if (!mTypeMap.isBasicType(type->arrayType())) { newClass.addInclude(QString(), arrayTypeName); // add forward declaration } newClass.addHeaderIncludes(QStringList() << QLatin1String("QtCore/QList")); inputTypeName = QLatin1String("const ") + typeName + QLatin1Char('&'); isList = true; } XSD::Attribute::AttributeUse use = isElementOptional(elemIt) ? XSD::Attribute::Optional : XSD::Attribute::Required; const bool polymorphic = isElementPolymorphic(elemIt, mTypeMap, isList); const bool usePointer = usePointerForElement(elemIt, newClass, mTypeMap, isList); generateMemberVariable(KODE::Style::makeIdentifier(elemIt.name()), typeName, inputTypeName, newClass, use, usePointer, polymorphic); } // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(elemIt.type())); newClass.addHeaderIncludes(mTypeMap.headerIncludes(elemIt.type())); if (elemIt.maxOccurs() > 1 || elemIt.compositor().maxOccurs() > 1) { newClass.addHeaderIncludes(QStringList() << QLatin1String("QtCore/QList")); } } // attributes in the complex type XSD::Attribute::List attributes = type->attributes(); Q_FOREACH (const XSD::Attribute &attribute, attributes) { QString typeName, inputTypeName; typeName = mTypeMap.localType(attribute.type()); if (typeName.isEmpty()) { qDebug() << "ERROR: attribute with unknown type:" << attribute.name() << attribute.type() << "in" << typeName; } inputTypeName = mTypeMap.localInputType(attribute.type(), QName()); //qDebug() << "Attribute" << attribute.name(); generateMemberVariable(KODE::Style::makeIdentifier(attribute.name()), typeName, inputTypeName, newClass, attribute.attributeUse(), false, false); // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(attribute.type())); newClass.addHeaderIncludes(mTypeMap.headerIncludes(attribute.type())); }