started on transactions
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 22 Feb 2009 19:43:55 +0000 (19:43 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 22 Feb 2009 19:43:55 +0000 (19:43 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@276 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

doc/prog_woc.html
src/wbase/WTransaction.h
woc/qtout.cpp
woc/qtout.h
woc/woc.pro

index 4400156..336a220 100644 (file)
@@ -141,11 +141,127 @@ The Value tags for enum types function similar to enums in C++. If a value attri
 
 <h2>Communication Abstraction Layer</h2>
 
-The Communication Abstraction Layer is the servers upper bound towards the client. It hides the complexities of serializing data onto the network transport protocol by providing communication classes that do this automatically. The configuration of this layer is split into two major components: communication classes and transactions. While the communication classes describe what data can be transported over the connection, the transactions describe what operations can be performed.
+The Communication Abstraction Layer is the servers upper bound towards the client. It hides the complexities of serializing data onto the network transport protocol by providing communication classes that do this automatically. The configuration of this layer is split into two major components: communication classes and transactions. While the communication classes describe what data can be transported over the connection, the transactions describe what operations can be performed.<p>
 
-<h2>Business Logic: Mapping - the Trivial Case</h2>
+<h3>Communication Classes</h3>
+
+An example class can be seen here:
+
+<pre>
+&lt;Class name="Ticket">
+  &lt;Enum name="TicketState" refColumn="ticket:status"/>
+  &lt;Property name="ticketid" type="astring" id="yes"/>
+  &lt;Property name="eventid" type="int"/>
+  &lt;Property name="price" type="int"/>
+  &lt;Property name="status" type="TicketState"/>
+  &lt;Property name="orderid" type="int"/>
+  
+  &lt;ToXml name="inOrder">ticketid eventid price status&lt;/ToXml>
+  &lt;ToXml name="Full">ticketid eventid price status orderid&lt;/ToXml>
+  
+  &lt;Mapping table="ticket">
+    &lt;Map column="ticketid"/>
+    &lt;Map column="price"/>
+    &lt;Map column="eventid"/>
+    &lt;Map column="status"/>
+    &lt;Map column="orderid" property="orderid"/>
+  &lt;/Mapping>
+&lt;/Class>
+</pre>
+
+The "name" attribute of the Class tag gives the communication class a name by which it can be referenced. The language converters will prefix it with "WO" to make it unique and postfix it with "Abstract" if the class is declared abstract - in this case the user must derive the non-abstract class to make it usable.<p>
+
+Class attributes:
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>name</td><td>the name of the class</td></tr>
+<tr><td>abstract</td><td>(optional) marks the class abstract</td></tr>
+</table><p>
+
+The Enum tag defines a local enumeration. In most cases they will simply reference an enumeration that has already been defined in a database table with a refColumn attribute (syntax: <tt><i>table</i>:<i>column</i></tt>), but it may also locally define its values by using the same Value tags used for database enums.<p>
+
+The Property tag defines a property of the class that can be read and written to:
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>name</td><td>the name of the property</td></tr>
+<tr><td>abstract</td><td>(optional) marks the property abstract - this automatically makes the class abstract and the user has to overwrite the getter and setter methods</td></tr>
+<tr><td>id</td><td>(optional, default=no) marks the property to identify the instance in a cache</td></tr>
+<tr><td>type</td><td>(mandatory) defines the type of the property, see below</td></tr>
+</table><p>
+
+Property types:
+<table frame="1" border="1">
+<tr><td><b>Type</b></td><td><b>Description</b></td></tr>
+<tr><td>int</td><td>an integer - it is at least a 32bit signed type; it is transported as attribute</td></tr>
+<tr><td>astring</td><td>a string that can be safely stored in a XML attribute</td></tr>
+<tr><td>string</td><td>a string that is transported as element and can reach any length</td></tr>
+<tr><td><i>EnumName</i></td>the name of an enum defined in the same class is possible, local storage is as integer, transport is as string equalling the symbolic name of the value in an attribute</td></tr>
+<tr><td><i>ClassName</i></td><td>the name of a defined class makes the property an instance of that class; they are transported as sub-elements of this class</td></tr>
+<tr><td>List:*</td><td>prefixing the type with "List:" makes the property a list of that type - any of the above types can be made into lists; on transport list values are always serialized as elements</td></tr>
+</table><p>
+
+The Mapping tag can be used to provide a shortcut cast between a database table type and the communication class type. This is provided for the trivial case in which no transformations between the database query result and the transport data is necessary. If the property attribute is ommitted a property with the same name as the listed column is looked for.<p>
+
+The ToXml tag provides valid serializations. Each serialization must have a name - the language converters prefix them with "toString" and "toXml" to build a method names. The text of the tag simply lists all properties that should be contained in the serialization separated by spaces. Properties that are communication classes (or lists thereof) must also list the proper serialization function of that communication class, eg. Order serialized thus:
+
+<pre>
+&lt;ToXml name="Full">orderid customerid seller amountpaid state amountdue tickets/inOrder vouchers/inOrder&lt;/ToXml>
+</pre>
+
+Above the property "tickets" is a list of Ticket and "inOrder" is a serialization defined above for Ticket.
+
+
+<h3>Transactions</h3>
+
+<pre>
+&lt;Transaction name="GetTicket">
+  &lt;Input>
+    &lt;Var name="ticketid" type="astring"/>
+    &lt;Call lang="php" method="getTicketFunction"/>
+  &lt;/Input>
+  &lt;Output>
+    &lt;Var name="ticket" type="Ticket/Full"/>
+  &lt;/Output>
+&lt;/Transaction>
+</pre>
+
+Each transaction must have a name that identifies it. This name is used in the wire protocol to correctly identify the currently requested transaction.
+
+Transaction attributes:
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>name</td><td>the name of the transaction</td></tr>
+<tr><td>mode</td><td>(optional, default=checked) can be used to require less restrictive privileges, see below for values</td></tr>
+</table><p>
+
+Transaction modes:
+<table frame="1" border="1">
+<tr><td><b>Mode</b></td><td><b>Description</b></td></tr>
+<tr><td>checked</td><td>the default mode: the session must be authenticated and the user must have the privilege to execute this query</td></tr>
+<tr><td>auth</td><td>the session must be authenticated, but no special privilege is required; this can for example be used for the logout function or a function query information about the session itself</td></tr>
+<tr><td>open</td><td>no session is necessary for this to work; usually this is only done for login</tr></tr>
+</table><p>
+
+Input defines the input parameters (Var tag) of the transaction (ie. what is sent to the server) and what function is called (Call tag) once the transaction has been checked and authenticated.<p>
+
+Output defines the data (Var tag) sent back to the client.<p>
+
+Var attributes:
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>name</td><td>the name of the variable</td></tr>
+<tr><td>type</td><td>type of the attribute; all types allowed for class properties (except enums) are allowed here</td></tr>
+</table><p>
+
+Call attributes:
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>lang</td><td>the language binding this refers to (currently only "php")</td></tr>
+<tr><td>method</td><td>the function to call - it must take exactly one argument: the transaction object</td></tr>
+</table><p>
+
+Transactions are represented as classes. On the client side they are used to execute the query and to represent the result. On the server side they internally verify the input and authenticate the transaction and are then used to take and encode the output or possible error conditions.
 
-In some cases the Business Logic is a trivial case of translating a database object into a communication object. For these cases a simple mapping can be formulated....
 
 <h2>Server Abstraction Layer</h2>
 
index 2f0b656..15e5a39 100644 (file)
@@ -20,6 +20,9 @@
 
 class WTransaction:public QObject
 {
+       protected:
+               WTransaction(){}
+               WTransaction(const WTransaction&){}
 };
 
 #endif
index 914f350..86401b2 100644 (file)
@@ -390,21 +390,100 @@ void WocQtClientOut::newTransaction(const WocTransaction&trn)
                emit errorFound();
                return;
        }
+       //basics
+       QStringList in=trn.inputNames();
+       QStringList out=trn.outputNames();
        //lead in
        hdr.write(QByteArray(HDRSTART).replace("%",cn.toAscii()));
        src.write(QByteArray(SRCSTART).replace("%",cn.toAscii()));
        QString hcd;
        QString scd;
-       hcd="#include \"WTransaction.h\"\n\n";
-       hcd+="class "+cn+":public WTransaction\n{\n public:\n";
+       hcd="#include \"WTransaction.h\"\n";
+       for(int i=0;i<in.size();i++){
+               QString tp=qtobjtype(trn,in[i],In);
+               if(tp!="")hcd+="#include <"+tp+".h>\n";
+       }
+       for(int i=0;i<out.size();i++){
+               QString tp=qtobjtype(trn,out[i],Out);
+               if(tp!="")hcd+="#include <"+tp+".h>\n";
+       }
+       hcd+="\nclass "+cn+":public WTransaction\n{\n";
        hdr.write(hcd.toAscii());
        
+       //create properties
+       QString inlist,clist;
+       hcd="  private:\n";
+       for(int i=0;i<in.size();i++){
+               hcd+="\t"+qttype(trn,in[i],In)+"in_"+in[i]+";\n";
+               if(i){inlist+=",";clist+=",";}
+               inlist+="const "+qttype(trn,in[i],In)+"&a"+in[i];
+               clist+="a"+in[i];
+       }
+       for(int i=0;i<out.size();i++)
+               hcd+="\t"+qttype(trn,out[i],Out)+"out_"+out[i]+";\n";
+       hdr.write(hcd.toAscii());
+               
+       //create constructor
+       hcd="\t"+cn+"("+inlist+");\n";
+       scd+=cn+"::"+cn+"("+inlist+")\n{\n";
+       for(int i=0;i<in.size();i++){
+               scd+="\tin_"+in[i]+"=a"+in[i]+";\n";
+       }
+       scd+="}\n";
+       hcd+="\tvoid netquery();\n";
+       scd+="void "+cn+"::netquery()\n{\n";
+       //TODO: encode input
+       for(int i=0;i<in.size();i++){
+       }
+       //TODO: query and decode output
+       scd+="}\n";
+       hdr.write(hcd.toAscii());
+       src.write(scd.toAscii());
+       
+       
+       //create queries
+       hcd="  public:\n";
+       scd="";
+       //TODO: query should optimize between local & web
+       hcd+="\tstatic "+cn+" query("+inlist+"){return queryWeb("+clist+");}\n";
+       hcd+="\tstatic "+cn+" queryWeb("+inlist+");\n";
+       scd+=cn+" "+cn+"::queryWeb("+inlist+")\n{\n";
+       scd+="\t"+cn;
+       if(clist!="")scd+=" r("+clist+");\n";else scd+=" r;";
+       scd+="\tr.netquery();\n\treturn r;\n}\n";
+       
        //lead out
+       hdr.write(hcd.toAscii());
+       src.write(scd.toAscii());
        hdr.write(QByteArray("\n};\n"));
        hdr.write(QByteArray(HDREND).replace("%",cn.toAscii()));
        src.write(QByteArray(SRCEND).replace("%",cn.toAscii()));
 }
 
+QString WocQtClientOut::qttype(const WocTransaction&trn,QString v,InOut io)
+{
+       QString tp=io==In?trn.inputType(v):trn.outputType(v);
+       QString r;
+       if(tp.startsWith("List:")){
+               r="QList<";
+               tp=tp.mid(5);
+       }else   r="Nullable<";
+       if(tp=="astring" || tp=="string")r+="QString";else
+       if(tp=="int")r+="qint64";
+       else r+="WO"+tp.split("/",QString::SkipEmptyParts).at(0);
+       r+=">";
+       return r;
+}
+
+QString WocQtClientOut::qtobjtype(const WocTransaction&trn,QString v,InOut io)
+{
+       QString tp=io==In?trn.inputType(v):trn.outputType(v);
+       if(tp.startsWith("List:"))
+               tp=tp.mid(5);
+       if(tp=="astring" || tp=="string"||tp=="int")return "";
+       else return "WO"+tp.split("/",QString::SkipEmptyParts).at(0);
+}
+
 void WocQtClientOut::addFile(QString bn)
 {
        QString code="HEADERS+="+m_subdir+"/"+bn+".h\nSOURCES+="+m_subdir+"/"+bn+".cpp\n";
index 01f0a51..91c485e 100644 (file)
@@ -43,6 +43,12 @@ class WocQtClientOut:public WocOutput
                void classSerializers(const WocClass&,QFile&,QFile&,QString);
                /**helper: generate a proper Qt type for a property*/
                QString qttype(const WocClass&,QString,bool dolist=true);
+               
+               enum InOut{In,Out};
+               /**helper: generate a proper QT type for a transaction variable*/
+               QString qttype(const WocTransaction&,QString,InOut);
+               /**helper: generate a proper QT type for a transaction variable, WO* only */
+               QString qtobjtype(const WocTransaction&,QString,InOut);
 };
 
 #endif
index ccadba0..d6f4919 100644 (file)
@@ -3,6 +3,13 @@ TARGET=../woc/woc
 QT-=gui
 QT+=xml
 
+#compilation output:
+DESTDIR = ../woc
+OBJECTS_DIR = .ctmp
+MOC_DIR = .ctmp
+RCC_DIR = .ctmp
+
+
 SOURCES+= \
        processor.cpp \
        woc.cpp \