getting closer to SOAP support
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Mon, 2 Aug 2010 20:27:24 +0000 (20:27 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Mon, 2 Aug 2010 20:27:24 +0000 (20:27 +0000)
git-svn-id: https://silmor.de/svn/softmagic/pack/trunk@583 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

13 files changed:
doc/wolf.html
phpbase/exception.php
phpbase/transaction.php
qtbase/nullable.h
woc/php/phpstrans.cpp
woc/php/phptrans.cpp
woc/proc/processor.cpp
woc/proc/processor.h
woc/soap/schemaout.cpp
woc/soap/schemaout.h
woc/soap/soapout.cpp [new file with mode: 0644]
woc/soap/soapout.h [new file with mode: 0644]
woc/soap/wob-header.xsd [new file with mode: 0644]

index 898f96f..1145352 100644 (file)
@@ -12,12 +12,21 @@ Each wolf file must be enclosed in the &lt;Wolf> and &lt;/Wolf> tags. The first
 <pre>
 &lt;Wolf>
   &lt;Doc>Documentation...&lt;/Doc>
-  &lt;Project baseDir=".." wobDir="wob" name="MyProject"/>
+  &lt;Project baseDir=".." wobDir="wob" name="MyProject" encoding="wob" xml-namespace="ns:MyProject" auth="none"/>
   &lt;Version comm="0100" needcomm="0100" humanReadable="1.1 alpha" svnTarget="."/>
 &lt;/Wolf>
 </pre>
 
-Above the &lt;Project> tag tells woc what the overall project directory is (relative to its current working directory) and where, relative to the baseDir, it will find all wolf files. The <tt>name</tt> attribute tells Woc what the exact name of the project is - among other things this property is used as default interface name in the client.<p>
+Above the &lt;Project> tag tells woc about the project as a whole:
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>baseDir</td><td>the overall project directory (relative to its current working directory); default: current working directory</td></tr>
+<tr><td>wobDir</td><td>relative to the baseDir, where to find all wolf files, default: baseDir itself</td></tr>
+<tr><td>name</td><td>the exact name of the project - among other things this property is used as default interface name in the client</td></tr>
+<tr><td>encoding</td><td>the encoding of the communication: <tt>wob</tt> the default encoding, transaction objects are transmitted directly, header information is transmitted in the HTTP headers, <tt>soap12</tt> a SOAP 1.2 wrapper is put around the transaction, header information is transmitted in the SOAP header, <tt>soap</tt> shortcut for the currently newest supported SOAP version</td></tr>
+<tr><td>xml-namespace</td><td>the XML namespace that all transmitted objects are put into, PACK does not validate the namespace, but if you are working in SOAP mode this is mandatory to maintain compatibility with other SOAP implementations; default: "ns:" plus the project name in URL encoding, it is recommended to set a more unique namespace</td></tr>
+<tr><td>auth</td><td>Authentication mode, default none; valid values are: "none" - no authentication at all, the auth property of transactions is ignored, "session" - one of the transactions generates a session ID that can be verified, "basic" - each authenticated transaction transmits the user name and password</td></tr>
+</table><p>
 
 The &lt;Doc> tag can be used to create project documentation. Each tag generates one paragraph. HTML can be embedded by escaping the "&lt;" character as "&amp;lt;".<p>
 
@@ -29,7 +38,7 @@ The &lt;Version> tag describes the communication protocol:
 <tr><td>needcomm</td><td>the minimum communication protocol this wolf file is compatible with (attention: the processor uses ASCII string comparison, not int comparison)</td></tr>
 <tr><td>humanReadable</td><td>the version number shown to the user</td></tr>
 <tr><td>svnTarget</td><td>optional; if given: woc will call SVN to find out which repository revision was used</td></tr>
-<tr><td>svnExe</td><td>optional; executable to call for subversion (default: svn)</td></tr>
+<tr><td>svnExe</td><td>optional; executable to call for subversion (default: svn); if empty or not a reachable executable the SVN related fields in the generated code will be set to empty or defaults</td></tr>
 </table><p>
 
 The Include tag can be used to include other wolf files in the processing:
@@ -43,25 +52,34 @@ Boolean attributes in wolf files allow integers (0 is false, non-zere is true) o
 
 Integers can be entered in C notation - if it starts with 1 through 9 it is decimal, if it starts with 0 it is octal, if it starts with 0x it is hexadecimal. All integers are interpreted by woc - the generated source will always contain decimal numbers.<p>
 
-Woc is case-sensitive.
+Woc itself handles all names as case-sensitive. Some target languages (eg. PHP) may work case-insensitive.
 
 <h2>Chosing Outputs</h2>
 
 Outputs should be declared after the basics have been declared, but before any tables, classes or transactions are declared.
 
 <pre>
-&lt;QtClientOutput sourceDir="src" subDir="wob" priInclude="wob.pri" transactionBase="WTransaction"/>
-&lt;PHPServerOutput sourceDir="www" subDir="inc/wob" extension=".php" clean="yes" transactionBase="WobTransaction"/>
+&lt;QtClientOutput sourceDir="src" subDir="wob" priInclude="wob.pri" transactionBase="WTransaction" validate="no"/>
+&lt;PHPServerOutput sourceDir="www" subDir="inc/wob" extension=".php" clean="yes" transactionBase="WobTransaction" validate="no"/>
 &lt;HtmlOutput sourceDir="doc" subDir="wob"/>
+&lt;SchemaOutput sourceDir="schema" filename="project.xsd" compound="compound.xsd"/>
+&lt;SoapOutput sourceDir="soapdir" fileprefix="myproject"/>
 </pre>
 
 The attribute "sourceDir" tells woc which directory (above baseDir) is the root source directory for each sub-project, the "subDir" attribute tells it which subdirectory below the sourceDir should be used for woc's generated output. The attribute "clean" tells woc to first delete all files from that sub-directory before starting the generator. Multiple generators of the same type can be used, but should have different target directories.<p>
 
+The optional validate attribute lets you decide whether incoming messages should be validated against the schema file before processing them. It defaults to "no", which means Schema support is not generated. The value "optional" generates schema support, but does not switch it on, you can control it programmatically. The value "lax" generates schema support, switches it on, but does not stop processing if validation fails. The value "strict" switches schema support on and stops processing if a message fails validation.<p>
+
+
 The QtClientOutput tag tells woc to create a generator for a Qt based client - the priInclude attribute tells woc which name it should give to the QMake include for its generated output. The <tt>transactionBase</tt> attribute allows to chose an extended class as base class of generated transactions - usually this should not be necessary for Qt client targets.<p>
 
 The PHPServerOutput tag tells woc to create a generator for a PHP based server. The "extension" attribute tells woc which file extension to use for the generated files (default is .php). Woc will automatically create a "autoload" (plus extension) file that should be included from the main body of the PHP project to load the automatically generated classes. The <tt>transactionBase</tt> attribute allows to chose an extended class as base class of generated transactions - it is recommended to overwrite some protected functions in order to be able to get more information inside transactions.<p>
 
-The HtmlOutput tag tells woc where to generate API documentation.
+The HtmlOutput tag tells woc where to generate API documentation. This target generates generic high level documentation for all configured tables, classes, and transactions. Use doxygen or a similar tool to generate language target specific documentation.<p>
+
+The SchemaOutput tag tells woc to generate XML Schema files that validate the projects generated communication XML documents. The filename tag tells woc which file name to use for the classes and transactions - it will contain a complex type for each class (name: <tt>class-<i>ClassName</i></tt>), and a simple type for each enum (<tt>enum-<i>ClassName-enumName</i></tt>). For each transaction it will generate two global elements, one for the request and one for the responds, including the corresponding complex types. Normal wob encoded communication can be validated directly against this file. If you want to validate errors or SOAP encoded communication you have to specify a compound file name - if specified woc will also copy the relevant Schema files and link them together in the given compound file, which you can use to validate all messages. This output ignores database tables.<p>
+
+The SoapOutput tag tells woc to generate SOAP WSDL and Schema files. This tag generates an error if the project communication mode is not set to use SOAP. This output ignores database tables. The <tt>fileprefix</tt> attribute is used to construct the WSDL and Schema files by adding the proper extension (".wsdl" and ".xsd") to it.<p>
 
 <hr>
 <a href="wolf-db.html">Next: DataBase Layer</a>
index 747f81f..ca0d834 100644 (file)
@@ -19,6 +19,7 @@ class WobTransactionError extends Exception
        protected $etype="_system";
        protected $estr="";
        protected $trans=null;
+       protected $mode=WobTransactionBase::WobEncoding;
        
        public function __construct(WobTransactionBase $trans,$errorString,$errorType="_system")
        {
@@ -26,11 +27,23 @@ class WobTransactionError extends Exception
                $this->etype=$errorType;
                $this->estr=$errorString;
                $this->trans=$trans;
+               if($trans!==null){
+                       $this->mode=$trans->messageEncoding();
+               }
        }
        
        /**used by machine oriented transaction to print the proper XML representation of the error*/
        public function printXml()
        {
+               switch($this->mode){
+                       case WobTransactionBase::Soap12Encoding:$this->printXmlSchema();break;
+                       default: $this->printXmlWob();break;
+               }
+       }
+       
+       /**used by machine oriented transaction to print the proper XML representation of the error in Wob Encoding*/
+       public function printXmlWob()
+       {
                header("X-WobResponse-Status: Error");
                $xml=new DOMDocument;
                $root=$xml->createElementNS($this->trans->xmlPackNamespace(),"WobError",$this->estr);
@@ -47,4 +60,24 @@ class WobTransactionError extends Exception
        
 };
 
+/**specific Wob Error - thrown where we know we use Wob protocol*/
+class WobWobTransactionError extends WobTransactionError
+{
+       public function __construct($errorString,$errorType="_system")
+       {
+               parent::__construct(null,$errorString,$errorType);
+               $this->mode=WobTransactionBase::WobEncoding;
+       }
+};
+
+/**specific Wob Error - thrown where we know we use SOAP protocol*/
+class WobSoapTransactionError extends WobTransactionError
+{
+       public function __construct($errorString,$errorType="_system")
+       {
+               parent::__construct(null,$errorString,$errorType);
+               $this->mode=WobTransactionBase::Soap12Encoding;
+       }
+};
+
 ?>
\ No newline at end of file
index 25cd9dd..4b2aa14 100644 (file)
@@ -19,6 +19,7 @@ class WobTransactionBase {
        protected $tinput;
        protected $aoutput;
        protected $toutput;
+       protected $headers=array();
        
        //these encoding constants must match the WocProcessor::MessageEncoding enum
        /**encode messages according to PACK standard - with minimal XML levels*/
@@ -31,27 +32,89 @@ class WobTransactionBase {
        /**returns the name of the currently running transaction*/
        static public function getExecutingName(){return self::$running;}
        
-       /**called to determine the correct transaction, aborts the script if there is none.*/
-       static public function getTransactionName(){
+       /**Wob message encoding: called to determine the correct transaction, aborts the script if there is none.*/
+       static public function getTransactionNameWob()
+       {
                global $_SERVER;
                if($_SERVER["REQUEST_METHOD"] != "POST"){
-                       throw new WobTransactionError($this,tr("Request is not a POST Request, Aborting."),"non-post");
+                       throw new WobWobTransactionError(tr("Request is not a POST Request, Aborting."),"non-post");
                        exit();
                }
                if(!isset($_SERVER["HTTP_X_WOBREQUEST"])){
-                       throw new WobTransactionError($this,tr("Request is not a Wob Request, Aborting."),"non-wob");
+                       throw new WobWobTransactionError(tr("Request is not a Wob Request, Aborting."),"non-wob");
                        exit();
                }
                self::$running=$_SERVER["HTTP_X_WOBREQUEST"];
                return self::$running;
        }
-       /**called to determine the session id*/
-       static public function getHeader($hd)
+       /**called to determine the correct transaction, aborts the script if there is none.*/
+       static public function getTransactionNameSoap()
+       {
+               global $_SERVER;
+               $this->headers=array();
+               if($_SERVER["REQUEST_METHOD"] != "POST"){
+                       throw new WobTransactionError($this,tr("Request is not a POST Request, Aborting."),"non-post");
+                       exit();
+               }
+               if($this->messageEncoding()==self::WobEncoding){
+                       if(!isset($_SERVER["HTTP_X_WOBREQUEST"])){
+                               throw new WobTransactionError($this,tr("Request is not a Wob Request, Aborting."),"non-wob");
+                               exit();
+                       }
+                       self::$running=$_SERVER["HTTP_X_WOBREQUEST"];
+                       foreach(array_keys($_SERVER) as $k){
+                               if(substr($k,0,11)=="HTTP_X_WOB_")
+                                       $this->headers[substr($k,11)]=$_SERVER[$k];
+                       }
+               }else
+               if($this->messageEncoding()==self::Soap12Encoding){
+                       //parse soapAction
+                       if(!isset($_SERVER["HTTP_SOAPACTION"])){
+                               throw new WobTransactionError($this,tr("Wob SOAP mode, missing SOAPAction header."),"soap");
+                               exit();
+                       }
+                       //parse SOAP headers
+                       $sact=explode(":",$_SERVER["HTTP_SOAPACTION"]);
+                       if(count($sact)<2){
+                               throw new WobTransactionError($this,tr("Wob SOAP mode, invalid SOAPAction header."),"soap");
+                               exit();
+                       }
+                       self::$running=$sact[count($sact)-1];
+                       //parse SOAP headers
+                       //TODO
+               }
+               return self::$running;
+       }
+       /**called to determine the session id or other headers*/
+       public function getHeader($hd)
        {
-               $hd="HTTP_X_".strtoupper(str_replace("-","_",$hd));
-               if(isset($_SERVER[$hd]))return $_SERVER[$hd];
+               $idx=strtoupper($hd);
+//             echo "gethd ".$hd."\n";
+               if(isset($this->headers[$idx]))return $this->headers[$idx];
                else return "";
        }
+       
+       /**retrieves the XML data from the request and parses headers*/
+       protected function getRequestXml()
+       {
+               /*low level XML parsing*/
+               global $HTTP_RAW_POST_DATA;
+               if(isset($HTTP_RAW_POST_DATA))$txt=$HTTP_RAW_POST_DATA;else $txt="";
+               $xml=new DOMDocument;
+               if(!$xml->loadXML($txt))$this->xmlParserError();
+               if($this->messageEncoding()==self::WobEncoding){
+                       foreach(array_keys($_SERVER) as $k){
+                               if(substr($k,0,11)=="HTTP_X_WOB_"){
+                                       $this->headers[substr($k,11)]=$_SERVER[$k];
+//                                     echo("new hd ".substr($k,11)."\n");
+                               }
+                       }
+               }else{
+                       $root=$xml->documentElement;
+                       //TODO: parse header element
+               }
+               return $xml;
+       }
        /**called if the transaction is not known. aborts the script.*/
        static public function noSuchTransaction()
        {
index 7a1410c..ed82877 100644 (file)
@@ -38,8 +38,8 @@ template<class T>class Nullable
                
                /**returns a reference to the wrapped value - the result is undefined if it us currently NULL*/
                T& value(){return elem;}
-               /**returns the original value, uses an instance created with the default constructor if it is currently NULL*/
-               T value()const{if(isnull)return T();else return elem;}
+               /**returns the original value, if it is currently NULL it returns the given default value, if no default is given an instance created with the default constructor is returned*/
+               T value(const T&defaultval=T())const{if(isnull)return defaultval;else return elem;}
                
                /**compares this instance with a value of the original class, NULL is different from ANY instance of the original class*/
                bool operator==(const T&t)const{if(isnull)return false;else return elem == t;}
@@ -61,6 +61,7 @@ template<class T>class Nullable
                T elem;
 };
 
+#include<QString>
 //convenience wrappers
 typedef Nullable<int> Int;
 typedef Nullable<qint32> Int32;
index 2a396b3..6d53632 100644 (file)
@@ -25,6 +25,7 @@ WocPHPServerTransaction::WocPHPServerTransaction(WocPHPOut*p )
 
 QString WocPHPServerTransaction::trnHandlers(const WocTransaction&trn)
 {
+       WocProcessor*woc=WocProcessor::instance();
        //create file
        QString cn=trnClassName(trn);
        QString fn="wtr_"+trn.name();
@@ -33,6 +34,12 @@ QString WocPHPServerTransaction::trnHandlers(const WocTransaction&trn)
        QString code;
        //request handler:
        code="public function handleRequest(){\n";
+       
+       //parse headers, get XML
+       code+="\t/*low level XML parsing*/\n";
+       code+="\t$xml=$this->getRequestXml();\n";
+       
+       //get DB transaction started
        code+="\t$this->startTransaction("+QString(trn.isDbUpdating()?"true":"false")+");\n";
        
        //security handling
@@ -50,11 +57,19 @@ QString WocPHPServerTransaction::trnHandlers(const WocTransaction&trn)
                        break;//none
        }
        
-       //parse low level XML
-       code+="\t/*low level XML parsing*/\n";
-       code+="\tglobal $HTTP_RAW_POST_DATA;\n\tif(isset($HTTP_RAW_POST_DATA))$txt=$HTTP_RAW_POST_DATA;else $txt=\"\";\n";
-       code+="\t$xml=new DOMDocument;\n\tif(!$xml->loadXML($txt))$this->xmlParserError();\n";
+       //Wob Encoding: parse low level XML and header
+       code+="\t/*get body element*/\n";
        code+="\t$root=$xml->documentElement;\n";
+       if(woc->messageEncoding()==WocProcessor::Soap12Encoding){
+               code+="\t$list=$root->getElementsByTagName(\"Body\");\n";
+               code+="\tif($list->length<1)throw WobSoapTransactionError(tr(\"SOAP: missing body\").\"soap\");\n";
+               code+="\t$root=$list->item(0);\n";
+               code+="\t$list=$root->childNodes;$root=false;\n";
+               code+="\tforeach($list as $e){\n";
+               code+="\t\tif($e->nodeType!=XML_ELEMENT_NODE)continue;\n";
+               code+="\t\tif($e->localName==\"WobRequest-"+trn.name()+"\"){$root=$e;break}\n\t}\n";
+               code+="\tif($root===false)throw WobSoapTransactionError(tr(\"SOAP: missing message content\").\"soap\");\n";
+       }
        
        //parse inputs
        code+=trnInput(trn);
index 594d65d..eadc11c 100644 (file)
@@ -19,7 +19,7 @@
 #include "phpconst.h"
 
 static const QByteArray TRANSACTCLASS("class WobTransaction extends WobTransactionBase\n{\n");
-static const QByteArray TRANSACTSTART("  static public function handle(){\n    try{switch(WobTransactionBase::getTransactionName()){\n");
+static const QByteArray TRANSACTSTART("  static public function handle(){\n    try{switch(self::getTransactionName()){\n");
 static const QByteArray TRANSACTEND("\tdefault:WobTransactionBase::noSuchTransaction();break;\n    }}catch(WobTransactionError $er){$er->printXml();}\n  }\n");
 
 WocPHPTransaction::WocPHPTransaction(WocPHPOut*p ): QObject(p)
@@ -60,6 +60,12 @@ void WocPHPTransaction::transInfo()
        code+="  static public function messageEncoding(){return "+ 
                QString::number((int)woc->messageEncoding())+";}\n";
        code+="\n";
+       code+="  static public function getTransactionName(){return parent::getTransactionName";
+       switch(woc->messageEncoding()){
+               case WocProcessor::Soap12Encoding:code+="Soap12";break;
+               default:code+="Wob";break;
+       }
+       code+="();}\n\n";
        m_transact.write(code.toAscii());
        
 }
index 3903f8b..b5b9a6a 100644 (file)
@@ -23,6 +23,7 @@
 #include <QDomDocument>
 #include <QDomElement>
 #include <QProcess>
+#include <QUrl>
 
 QList<QDomElement>elementsByTagName(const QDomElement&root,QString tag)
 {
@@ -136,6 +137,7 @@ bool WocProcessor::processFile(QString fn)
                        QString enc=el.attribute("encoding","wob").toLower();
                        if(enc=="soap"||enc=="soap12")m_encmode=Soap12Encoding;
                        else m_encmode=WobEncoding;
+                       if(m_xmlNS=="")m_xmlNS="ns:"+QUrl::toPercentEncoding(m_projname);
                }else
                if(tn=="Include"){
                        if(!processFile(m_baseDir+"/"+m_wobDir+"/"+el.attribute("file")))
@@ -175,7 +177,7 @@ bool WocProcessor::processFile(QString fn)
                        if(m_error)return false;
                }else
                if(tn=="SchemaOutput"){
-                       new WocSchemaOut(el.attribute("filename"));
+                       new WocSchemaOut(el);
                        if(m_error)return false;
                }else
                if(tn=="Version"){
index 1bdc55b..ec35a91 100644 (file)
@@ -114,9 +114,14 @@ class WocProcessor:public QObject
                
                /**describes the way message are encoded in transport*/
                enum MessageEncoding{
+                       /**encode as standard WOB transactions*/
                        WobEncoding=0,
+                       /**encode as SOAP 1.2 */
                        Soap12Encoding=1,
-                       SoapEncoding=1
+                       /**encode according to the current SOAP standard*/
+                       SoapEncoding=1,
+                       /** \private helper value: used in some parts of the code to simply query the processor for the encoding, never used in the processor itself*/
+                       DefaultEncoding=-1
                };
                /**returns the message encoding mode*/
                MessageEncoding messageEncoding()const{return m_encmode;}
index 77f9fdb..6f37677 100644 (file)
 
 #include <QDebug>
 #include <QDir>
-#include <QFileInfo>
 
-WocSchemaOut::WocSchemaOut(QString fname): WocOutput()
+WocSchemaOut::WocSchemaOut(QString dname,QString fname): WocOutput()
 {
+       m_dir=WocProcessor::instance()->baseDir()+"/"+dname;
        m_name=fname;
+}
+
+WocSchemaOut::WocSchemaOut(const QDomElement& el): WocOutput()
+{
        WocProcessor*woc=WocProcessor::instance();
-       m_doc.appendChild(m_doc.createComment("Automatically generated Schema file for project "+woc->projectName()));
+       m_name=el.attribute("filename");
+       m_dir=woc->baseDir()+"/"+el.attribute("sourceDir");
+       initialize();
+       if(el.hasAttribute("compound"))
+               addStaticSchemas(el.attribute("compound"));
+}
+
+
+void WocSchemaOut::initialize()
+{
+       //make sure directory exists
+       QDir().mkpath(m_dir);
+       //create document and root node
+       WocProcessor*woc=WocProcessor::instance();
+       m_doc.appendChild(m_doc.createComment("Automatically generated main Schema file for project "+woc->projectName()+"\nThis file covers all classes and transactions defined in the project.\nDO NOT CHANGE THIS FILE DIRECTLY!"));
        m_root=m_doc.createElementNS(woc->xmlSchemaNamespace(),"xs:schema");
        m_root.setAttribute("targetNamespace",woc->xmlProjectNamespace());
        m_root.setAttribute("xmlns",woc->xmlProjectNamespace());
        m_root.setAttribute("elementFormDefault","qualified");
-       QDomElement el=m_doc.createElement("xs:import");
-       el.setAttribute("namespace",woc->xmlPackNamespace());
-       el.setAttribute("schemaLocation","wob-base.xsd");
-       m_root.appendChild(el);
+}
+
+static inline void copyFile(QString dir,QString file,QDomDocument*doc=0)
+{
+       QFile in(":/"+file);
+       in.open(QIODevice::ReadOnly);
+       if(doc){
+               doc->setContent(&in);
+               in.seek(0);
+       }
+       MFile out(dir+"/"+file);
+       out.open(QIODevice::WriteOnly);
+       out.write(in.readAll());
+}
+
+static inline void copyAndImport(QString dir,QString file,QDomElement&root)
+{
+       //copy it
+       QDomDocument doc;
+       copyFile(dir,file,&doc);
+       //get namespace
+       QString dns=doc.documentElement().attribute("targetNamespace");
+       //create import
+       QDomElement el=root.ownerDocument().createElement("xs:import");
+       el.setAttribute("namespace",dns);
+       el.setAttribute("schemaLocation",file);
+       root.appendChild(el);
+}
+
+void WocSchemaOut::addStaticSchemas(QString compound, WocProcessor::MessageEncoding encoding)
+{
+       //create compound document
+       WocProcessor*woc=WocProcessor::instance();
+       QDomDocument doc;
+       doc.appendChild(doc.createComment("Automatically generated compound Schema file for project "+woc->projectName()+"\nThis file simply imports all relevant schema files.\nDO NOT CHANGE THIS FILE DIRECTLY!"));
+       QDomElement root=doc.createElementNS(woc->xmlSchemaNamespace(),"xs:schema");
+       QString cns=woc->xmlPackNamespace()+"/CompoundNameSpace";
+       root.setAttribute("targetNamespace",cns);
+       root.setAttribute("xmlns",cns);
+       root.setAttribute("elementFormDefault","qualified");
+       doc.appendChild(root);
+       //import project
+       QDomElement el=doc.createElement("xs:import");
+       el.setAttribute("namespace",woc->xmlProjectNamespace());
+       el.setAttribute("schemaLocation",m_name);
+       root.appendChild(el);
+       //copy parts
+       if(encoding==WocProcessor::DefaultEncoding)
+               encoding=woc->messageEncoding();
+       copyAndImport(m_dir,"wob-base.xsd",root);
+       if(encoding==WocProcessor::Soap12Encoding){
+               copyAndImport(m_dir,"soap12.xsd",root);
+               copyFile(m_dir,"xml.xsd");//already imported from soap12.xsd
+       }
+       //write compound
+       MFile cfd(m_dir+"/"+compound);
+       cfd.open(QIODevice::WriteOnly);
+       cfd.write(doc.toByteArray());
 }
 
 void WocSchemaOut::finalize()
@@ -38,17 +110,9 @@ void WocSchemaOut::finalize()
        //finish off
        m_doc.appendChild(m_root);
        //write
-       MFile fd(WocProcessor::instance()->baseDir()+"/"+m_name);
+       MFile fd(m_dir+"/"+m_name);
        fd.open(QIODevice::WriteOnly);
        fd.write(m_doc.toByteArray());
-       fd.close();
-       //copy 
-       QString s=QFileInfo(WocProcessor::instance()->baseDir()+"/"+m_name).dir().path();
-       MFile wfd(s+"/wob-base.xsd");
-       QFile bfd(":/wob-base.xsd");
-       wfd.open(QIODevice::WriteOnly);
-       bfd.open(QIODevice::ReadOnly);
-       wfd.write(bfd.readAll());
 }
 
 void WocSchemaOut::newClass(const WocClass& cls)
@@ -167,7 +231,8 @@ void WocSchemaOut::newTransaction(const WocTransaction& trn)
 }
 
 void WocSchemaOut::newTable(const WocTable& )
-{}
+{/*tables are not exposed to the network, hence no XML schema*/
+}
 
 QString WocSchemaOut::schemaType(QString tp)
 {
index 75753cc..9cb726d 100644 (file)
 class WocSchemaOut:public WocOutput
 {
        public:
-               /**initializes the output object with the given file name that will receive the schema for this project*/
-               WocSchemaOut(QString);
+               /**initializes the output object with the given directory and file name that will receive the schema for this project
+               \param dirname the directory below the base directory to store all Schema files in
+               \param filename the file that will contain the projects own XML Schema, per default "project.xsd" */
+               WocSchemaOut(QString dirname,QString filename="project.xsd");
+               
+               /**initializes the output object with the given DOM element*/
+               WocSchemaOut(const QDomElement&);
+               
+               /**copies the static parts of the schemas into the target directory
+               \param compound if not empty: the file name of a schema file that includes all schema files copied and created in the target directory
+               \param encoding if given the encoding that will be validated by the compound schema file*/
+               void addStaticSchemas(QString compound=QString(),WocProcessor::MessageEncoding encoding=WocProcessor::DefaultEncoding);
        protected:
                /**writes any last words after parsing finished*/
                virtual void finalize();
@@ -34,10 +44,13 @@ class WocSchemaOut:public WocOutput
                /**creates a transaction*/
                virtual void newTransaction(const WocTransaction&);
        private:
-               QString m_name;
+               QString m_name,m_dir;
                QDomDocument m_doc;
                QDomElement m_root;
                
+               /**helper for the constructor*/
+               void initialize();
+               
                /**helper: returns the corresponding schema type for a WOB type*/
                QString schemaType(QString);
                /**helper: returns the corresponding schema type for a WOB type*/
diff --git a/woc/soap/soapout.cpp b/woc/soap/soapout.cpp
new file mode 100644 (file)
index 0000000..bb302eb
--- /dev/null
@@ -0,0 +1,122 @@
+//
+// C++ Interface: schemaout
+//
+// Description: XML Schema file generator
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "soapout.h"
+
+#include "mfile.h"
+
+#include <QDebug>
+#include <QDir>
+
+WocSchemaOut::WocSchemaOut(const QDomElement& el): WocOutput()
+{
+       WocProcessor*woc=WocProcessor::instance();
+       m_name=el.attribute("filename");
+       m_dir=woc->baseDir()+"/"+el.attribute("sourceDir");
+       initialize();
+       if(el.hasAttribute("compound"))
+               addStaticSchemas(el.attribute("compound"));
+       //make sure directory exists
+       QDir().mkpath(m_dir);
+       //create document and root node
+       WocProcessor*woc=WocProcessor::instance();
+       m_doc.appendChild(m_doc.createComment("Automatically generated WSDL file for project "+woc->projectName()+"\nDO NOT CHANGE THIS FILE DIRECTLY!"));
+       m_root=m_doc.createElementNS(woc->xmlSchemaNamespace(),"ws:wsdl");
+       m_root.setAttribute("targetNamespace",woc->xmlProjectNamespace());
+       m_root.setAttribute("xmlns",woc->xmlProjectNamespace());
+       m_root.setAttribute("elementFormDefault","qualified");
+}
+
+void WocSchemaOut::finalize()
+{
+       //finish off
+       m_doc.appendChild(m_root);
+       //write
+       MFile fd(m_dir+"/"+m_name);
+       fd.open(QIODevice::WriteOnly);
+       fd.write(m_doc.toByteArray());
+}
+
+void WocSchemaOut::newTransaction(const WocTransaction& trn)
+{
+       m_root.appendChild(m_doc.createComment("Transaction "+trn.name()));
+       //create elements
+       QDomElement tel=m_doc.createElement("xs:element");
+       tel.setAttribute("name","WobRequest-"+trn.name());
+       tel.setAttribute("type",trn.name()+"-Request");
+       m_root.appendChild(tel);
+       tel=m_doc.createElement("xs:element");
+       tel.setAttribute("name","WobResponse-"+trn.name());
+       tel.setAttribute("type",trn.name()+"-Response");
+       m_root.appendChild(tel);
+       
+       //create type: req
+       tel=m_doc.createElement("xs:complexType");
+       tel.setAttribute("name",trn.name()+"-Request");
+       QDomElement wel=m_doc.createElement("xs:sequence");
+       tel.appendChild(wel);
+       QStringList vars=trn.inputNames();
+       for(int i=0;i<vars.size();i++){
+               QString tp=trn.inputType(vars[i]);
+               if(trn.isAttributeType(tp)){
+                       QDomElement at=m_doc.createElement("xs:attribute");
+                       at.setAttribute("name",vars[i]);
+                       at.setAttribute("type",schemaType(tp));
+                       at.setAttribute("use","optional");
+                       tel.appendChild(at);
+               }else{
+                       QDomElement el=m_doc.createElement("xs:element");
+                       el.setAttribute("name",vars[i]);
+                       el.setAttribute("type",schemaType(tp));
+                       el.setAttribute("minOccurs","0");
+                       if(trn.isListType(tp))
+                               el.setAttribute("maxOccurs","unbounded");
+                       wel.appendChild(el);
+               }
+       }
+       m_root.appendChild(tel);
+       //create type: rsp
+       tel=m_doc.createElement("xs:complexType");
+       tel.setAttribute("name",trn.name()+"-Response");
+       wel=m_doc.createElement("xs:sequence");
+       tel.appendChild(wel);
+       vars=trn.outputNames();
+       for(int i=0;i<vars.size();i++){
+               QString tp=trn.outputType(vars[i]);
+               if(trn.isAttributeType(tp)){
+                       QDomElement at=m_doc.createElement("xs:attribute");
+                       at.setAttribute("name",vars[i]);
+                       at.setAttribute("type",schemaType(tp));
+                       at.setAttribute("use","optional");
+                       tel.appendChild(at);
+               }else{
+                       QDomElement el=m_doc.createElement("xs:element");
+                       el.setAttribute("name",vars[i]);
+                       el.setAttribute("type",schemaType(tp));
+                       el.setAttribute("minOccurs","0");
+                       if(trn.isListType(tp))
+                               el.setAttribute("maxOccurs","unbounded");
+                       wel.appendChild(el);
+               }
+       }
+       m_root.appendChild(tel);
+}
+
+void WocSchemaOut::newClass(const WocClass& cls)
+{
+       /*classes are not reflected in the WSDL*/
+}
+
+void WocSchemaOut::newTable(const WocTable& )
+{
+       /*tables are not exposed to the network, hence no WSDL*/
+}
diff --git a/woc/soap/soapout.h b/woc/soap/soapout.h
new file mode 100644 (file)
index 0000000..2018661
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// C++ Interface: schemaout
+//
+// Description: XML Schema file generator
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOC_SOAPOUT_H
+#define WOC_SOAPOUT_H
+
+#include "schemaout.h"
+
+/**generates output for a schema file*/
+class WocSoapOut:public WocOutput
+{
+       public:
+               /**initializes the output object with the given DOM element*/
+               WocSoapOut(const QDomElement&);
+               
+       protected:
+               /**writes any last words after parsing finished*/
+               virtual void finalize();
+               /**creates a class*/
+               virtual void newClass(const WocClass&);
+               /**creates a table*/
+               virtual void newTable(const WocTable&);
+               /**creates a transaction*/
+               virtual void newTransaction(const WocTransaction&);
+       private:
+               QString m_name,m_dir;
+               QDomDocument m_doc;
+               QDomElement m_root;
+};
+
+#endif
diff --git a/woc/soap/wob-header.xsd b/woc/soap/wob-header.xsd
new file mode 100644 (file)
index 0000000..77acf6f
--- /dev/null
@@ -0,0 +1,19 @@
+<!-- Schema for Wob header elements in SOAP encoding -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns="http://silmor.de/PACK/v0.5/Header"
+           targetNamespace="http://silmor.de/PACK/v0.5/Header" 
+          elementFormDefault="qualified" >
+
+  <!-- simple session ID -->
+  <xs:element name="SessionAuth" type="SessionAuth" />
+  <xs:complexType name="SessionAuth">
+    <xs:attribute name="sessionId" type="xs:string"/>
+  </xs:complexType>
+
+  <!-- basic user/password auth -->
+  <xs:element name="BasicAuth" type="BasicAuth" />
+  <xs:complexType name="BasicAuth" >
+    <xs:attribute name="username" type="xs:string"/>
+    <xs:attribute name="password" type="xs:string"/>
+  </xs:complexType>
+</xs:schema>
\ No newline at end of file