00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00013 #include "wsdl.h"
00014 #include "xsd.h"
00015
00016 #include "servicehost.h"
00017
00019
00021
00022 Wsdl::Wsdl( ServiceHost *pServiceHost ) : m_pServiceHost( pServiceHost )
00023 {
00024
00025 }
00026
00028
00030
00031 bool Wsdl::GetWSDL( HTTPRequest *pRequest )
00032 {
00033 m_typesToInclude.clear();
00034
00035 if (!pRequest->m_mapParams.contains( "raw" ))
00036 {
00037 appendChild( createProcessingInstruction( "xml-stylesheet",
00038 "type=\"text/xsl\" href=\"/xslt/service.xslt\"" ));
00039 }
00040
00041 QDomElement oNode;
00042
00043 QString sClassName = m_pServiceHost->GetServiceMetaObject().className();
00044 QString sTargetNamespace = "http://mythtv.org";
00045
00046 m_oRoot = createElementNS( "http://schemas.xmlsoap.org/wsdl/", "definitions");
00047
00048 m_oRoot.setAttribute( "targetNamespace", sTargetNamespace );
00049
00050 m_oRoot.setAttribute( "xmlns:soap", "http://schemas.xmlsoap.org/wsdl/soap/" );
00051 m_oRoot.setAttribute( "xmlns:xs" , "http://www.w3.org/2001/XMLSchema" );
00052 m_oRoot.setAttribute( "xmlns:soap", "http://schemas.xmlsoap.org/wsdl/soap/" );
00053 m_oRoot.setAttribute( "xmlns:tns" , sTargetNamespace );
00054 m_oRoot.setAttribute( "xmlns:wsaw", "http://www.w3.org/2006/05/addressing/wsdl" );
00055
00056 m_oRoot.setAttribute( "name", QString( "%1Services" ).arg( sClassName ) );
00057
00058 m_oTypes = createElement( "types" );
00059 m_oLastMsg = m_oTypes;
00060 m_oPortType = createElement( "portType" );
00061 m_oBindings = createElement( "binding" );
00062 m_oService = createElement( "service" );
00063
00064 appendChild( m_oRoot );
00065 m_oRoot.appendChild( m_oTypes );
00066 m_oRoot.appendChild( m_oPortType );
00067 m_oRoot.appendChild( m_oBindings );
00068 m_oRoot.appendChild( m_oService );
00069
00070 m_oPortType.setAttribute( "name", sClassName );
00071
00072
00073
00074 QDomElement oImportNode = createElement( "xs:schema" );
00075 oImportNode.setAttribute( "targetNamespace" , "http://MythTV.org/Imports" );
00076
00077 m_oTypes.appendChild( oImportNode );
00078
00079
00080
00081 oNode = createElement( "xs:schema" );
00082 oNode.setAttribute( "targetNamespace" , sTargetNamespace );
00083 oNode.setAttribute( "elementFormDefault", "qualified" );
00084
00085 m_oTypes.appendChild( oNode );
00086 m_oTypes = oNode;
00087
00088
00089
00090
00091
00092 m_oBindings.setAttribute( "name", QString("BasicHttpBinding_%1").arg( sClassName ));
00093 m_oBindings.setAttribute( "type", QString( "tns:%1" ).arg( sClassName ));
00094
00095 oNode = createElement( "soap:binding" );
00096
00097 oNode.setAttribute( "transport", "http://schemas.xmlsoap.org/soap/http" );
00098
00099 m_oBindings.appendChild( oNode );
00100
00101
00102
00103
00104
00105 QMapIterator< QString, MethodInfo > it( m_pServiceHost->GetMethods() );
00106
00107 while( it.hasNext())
00108 {
00109 it.next();
00110
00111 MethodInfo oInfo = it.value();
00112
00113 QString sRequestTypeName = oInfo.m_sName;
00114 QString sResponseTypeName = oInfo.m_sName + "Response";
00115
00116 QString sInputMsgName = QString( "%1_%2_InputMessage" )
00117 .arg( sClassName )
00118 .arg( oInfo.m_sName );
00119 QString sOutputMsgName = QString( "%1_%2_OutputMessage" )
00120 .arg( sClassName )
00121 .arg( oInfo.m_sName );
00122
00123
00124
00125
00126
00127 QDomElement oOp = createElement( "operation" );
00128
00129 oOp.setAttribute( "name", oInfo.m_sName );
00130
00131
00132
00133
00134
00135 QString sDescription;
00136
00137 if ( oInfo.m_eRequestType == RequestTypePost )
00138 sDescription = "POST ";
00139 else
00140 sDescription = "GET ";
00141
00142 sDescription += ReadClassInfo( &m_pServiceHost->GetServiceMetaObject(),
00143 "description" );
00144
00145 oNode = createElement( "documentation" );
00146 oNode.appendChild( createTextNode( sDescription ));
00147
00148 oOp.appendChild( oNode );
00149
00150
00151
00152
00153
00154 oNode = createElement( "input" );
00155 oNode.setAttribute( "wsaw:Action", QString( "%1/%2/%3" )
00156 .arg( sTargetNamespace )
00157 .arg( sClassName )
00158 .arg( oInfo.m_sName ));
00159 oNode.setAttribute( "message" , "tns:" + sInputMsgName );
00160
00161 oOp.appendChild( oNode );
00162
00163
00164
00165
00166
00167 oNode = createElement( "output" );
00168 oNode.setAttribute( "wsaw:Action", QString( "%1/%2/%3Response" )
00169 .arg( sTargetNamespace )
00170 .arg( sClassName )
00171 .arg( oInfo.m_sName ));
00172 oNode.setAttribute( "message", "tns:" + sOutputMsgName );
00173
00174 oOp.appendChild( oNode );
00175
00176 m_oPortType.appendChild( oOp );
00177
00178
00179
00180
00181
00182 QDomElement oMsg = CreateMessage( oInfo, sInputMsgName, sRequestTypeName );
00183
00184 m_oRoot.insertAfter( oMsg, m_oLastMsg );
00185 m_oLastMsg = oMsg;
00186
00187
00188
00189
00190
00191 m_oTypes.appendChild( CreateMethodType( oInfo, sRequestTypeName ) );
00192
00193
00194
00195
00196
00197 oMsg = CreateMessage( oInfo, sOutputMsgName, sResponseTypeName );
00198
00199 m_oRoot.insertAfter( oMsg, m_oLastMsg );
00200 m_oLastMsg = oMsg;
00201
00202
00203
00204
00205
00206 m_oTypes.appendChild( CreateMethodType( oInfo, sResponseTypeName, true ) );
00207
00208
00209
00210
00211
00212 m_oBindings.appendChild( CreateBindingOperation( oInfo, sClassName ));
00213 }
00214
00215
00216
00217
00218
00219 QString sServiceName = QString( "%1Services" ).arg( sClassName );
00220
00221 m_oService.setAttribute( "name", sServiceName );
00222
00223
00224
00225
00226
00227 QString sDescription = "Interface Version " +
00228 ReadClassInfo( &m_pServiceHost->GetServiceMetaObject(),
00229 "version" );
00230
00231 sDescription += " - " + ReadClassInfo( &m_pServiceHost->GetServiceMetaObject(),
00232 "description" );
00233
00234 oNode = createElement( "documentation" );
00235 oNode.appendChild( createTextNode( sDescription ));
00236
00237 m_oService.appendChild( oNode );
00238
00239
00240
00241
00242
00243 QDomElement oPort = createElement( "port" );
00244
00245 oPort.setAttribute( "name" , QString("BasicHttpBinding_%1" ).arg( sClassName ));
00246 oPort.setAttribute( "binding", QString("tns:BasicHttpBinding_%1").arg( sClassName ));
00247
00248 oNode = createElement( "soap:address" );
00249 oNode.setAttribute( "location", "http://" +
00250 pRequest->m_mapHeaders[ "host" ] + "/" +
00251 m_pServiceHost->GetServiceControlURL() );
00252
00253 oPort.appendChild( oNode );
00254 m_oService.appendChild( oPort );
00255
00256
00257
00258
00259
00260 if (m_typesToInclude.count() > 0)
00261 {
00262
00263
00264
00265
00266
00267
00268 QString sBaseUri = "http://" + pRequest->m_mapHeaders[ "host" ] + pRequest->m_sBaseUrl + "/xsd?type=";
00269
00270 QMap<QString, bool>::const_iterator it = m_typesToInclude.constBegin();
00271 while( it != m_typesToInclude.constEnd())
00272 {
00273 QDomElement oIncNode = createElement( "xs:import" );
00274 QString sType = it.key();
00275
00276 sType.remove( "DTC::" );
00277
00278 oIncNode.setAttribute( "schemaLocation", sBaseUri + sType );
00279 oIncNode.setAttribute( "namespace", "http://mythtv.org" );
00280
00281 oImportNode.appendChild( oIncNode );
00282 ++it;
00283 }
00284 }
00285
00286
00287
00288
00289
00290
00291 QTextStream os( &(pRequest->m_response) );
00292
00293 pRequest->m_eResponseType = ResponseTypeXML;
00294
00295 save( os, 0 );
00296 return true;
00297 }
00298
00300
00302
00303 QDomElement Wsdl::CreateBindingOperation( MethodInfo &oInfo,
00304 const QString &sClassName)
00305 {
00306
00307
00308
00309
00310 QDomElement oOp = createElement( "operation" );
00311
00312 oOp.setAttribute( "name", oInfo.m_sName );
00313
00314 QDomElement oNode = createElement( "soap:operation" );
00315 oNode.setAttribute( "soapAction", QString( "http://mythtv.org/%1/%2" )
00316 .arg( sClassName )
00317 .arg( oInfo.m_sName ));
00318 oNode.setAttribute( "style" , "document" );
00319
00320 oOp.appendChild( oNode );
00321
00322
00323
00324
00325
00326 QDomElement oDirection = createElement( "input" );
00327 oNode = createElement( "soap:body" );
00328 oNode.setAttribute( "use", "literal" );
00329
00330 oDirection.appendChild( oNode );
00331 oOp.appendChild( oDirection );
00332
00333 if (QString::compare( oInfo.m_oMethod.typeName(), "void", Qt::CaseInsensitive ) != 0)
00334 {
00335
00336
00337 oDirection = createElement( "output" );
00338
00339 oNode = createElement( "soap:body" );
00340 oNode.setAttribute( "use", "literal" );
00341
00342 oDirection.appendChild( oNode );
00343 oOp.appendChild( oDirection );
00344
00345 }
00346
00347 return oOp;
00348 }
00349
00351
00353
00354 QDomElement Wsdl::CreateMessage( MethodInfo &oInfo,
00355 QString sMsgName,
00356 QString sTypeName )
00357 {
00358 QDomElement oMsg = createElement( "message" );
00359
00360 oMsg.setAttribute( "name", sMsgName );
00361
00362 QDomElement oNode = createElement( "part" );
00363
00364 oNode.setAttribute( "name" , "parameters" );
00365 oNode.setAttribute( "element", "tns:" + sTypeName );
00366
00367 oMsg.appendChild( oNode );
00368
00369 return oMsg;
00370 }
00371
00373
00375
00376 QDomElement Wsdl::CreateMethodType( MethodInfo &oInfo,
00377 QString sTypeName,
00378 bool bReturnType )
00379 {
00380 QDomElement oElementNode = createElement( "xs:element" );
00381
00382 oElementNode.setAttribute( "name", sTypeName );
00383
00384 QDomElement oTypeNode = createElement( "xs:complexType" );
00385 QDomElement oSeqNode = createElement( "xs:sequence" );
00386
00387 oElementNode.appendChild( oTypeNode );
00388 oTypeNode .appendChild( oSeqNode );
00389
00390
00391
00392
00393
00394 if (bReturnType)
00395 {
00396 QDomElement oNode = createElement( "xs:element" );
00397
00398 QString sType = oInfo.m_oMethod.typeName();
00399
00400 sType.remove( QChar('*') );
00401
00402 sTypeName.remove( "Response" );
00403
00404 oNode.setAttribute( "minOccurs", 0 );
00405 oNode.setAttribute( "name" , sTypeName + "Result" );
00406 oNode.setAttribute( "nillable" , true );
00407
00408 bool bCustomType = IsCustomType( sType );
00409
00410 sType = Xsd::ConvertTypeToXSD( sType, bCustomType );
00411
00412 QString sPrefix = "xs:";
00413
00414 if (bCustomType)
00415 {
00416 sPrefix = "tns:";
00417
00418
00419 m_typesToInclude.insert( sType, true );
00420 }
00421
00422 oNode.setAttribute( "type", sPrefix + sType );
00423
00424 oSeqNode.appendChild( oNode );
00425 }
00426 else
00427 {
00428 QList<QByteArray> paramNames = oInfo.m_oMethod.parameterNames();
00429 QList<QByteArray> paramTypes = oInfo.m_oMethod.parameterTypes();
00430
00431 for( int nIdx = 0; nIdx < paramNames.length(); nIdx++ )
00432 {
00433 QString sName = paramNames[ nIdx ];
00434 QString sParamType = paramTypes[ nIdx ];
00435
00436 QDomElement oNode = createElement( "xs:element" );
00437
00438 oNode.setAttribute( "minOccurs", 0 );
00439 oNode.setAttribute( "name" , sName );
00440 oNode.setAttribute( "nillable" , true );
00441 oNode.setAttribute( "type" , "xs:" + Xsd::ConvertTypeToXSD( sParamType ));
00442
00443 oSeqNode.appendChild( oNode );
00444 }
00445 }
00446
00447 return oElementNode;
00448 }
00449
00451
00453
00454 bool Wsdl::IsCustomType( QString &sTypeName )
00455 {
00456 sTypeName.remove( QChar('*') );
00457
00458 int id = QMetaType::type( sTypeName.toUtf8() );
00459
00460 switch( id )
00461 {
00462 case QMetaType::QStringList:
00463 case QMetaType::QVariantList:
00464 case QMetaType::QVariantMap:
00465 return true;
00466
00467 default:
00468
00469 if (id == QMetaType::type( "QFileInfo" ))
00470 return false;
00471 break;
00472 }
00473
00474 if ((id == -1) || (id < QMetaType::User))
00475 return false;
00476
00477 return true;
00478 }
00479
00481
00483
00484 QString Wsdl::ReadClassInfo( const QMetaObject *pMeta, const QString &sKey )
00485 {
00486 int nIdx = pMeta->indexOfClassInfo( sKey.toUtf8() );
00487
00488 if (nIdx >=0)
00489 return pMeta->classInfo( nIdx ).value();
00490
00491 return QString();
00492 }