move transaction code into private class
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 2 Oct 2010 18:16:31 +0000 (18:16 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 2 Oct 2010 18:16:31 +0000 (18:16 +0000)
git-svn-id: https://silmor.de/svn/softmagic/pack/trunk@597 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

qtbase/include/interface.h
qtbase/include/transaction.h
qtbase/include/transaction_p.h
qtbase/src/transaction.cpp
qtbase/wbase.pro

index 70531fe..b89e9ee 100644 (file)
@@ -30,6 +30,7 @@ class WInterface:public QObject
                WInterface(QString name);
                
                friend class WTransaction;
+               friend class WTransaction_Private;
                ///called by WTransaction to post a request
                QNetworkReply* post(const QNetworkRequest&request,const QByteArray&data);
                
index 576aed6..103e277 100644 (file)
@@ -20,6 +20,8 @@
 #include "nullable.h"
 #include "WHelper"
 
+class WTransaction_Private;
+
 /**base class of all transactions*/
 class WTransaction:public WHelper
 {
@@ -31,7 +33,6 @@ class WTransaction:public WHelper
                        Request,///<transaction is running
                        Success,///<transaction ended successfully
                        Error,///<transaction ended with an error
-//                     Timeout,///<transaction timed out
                };
                
                /**returns the stage the transaction is in*/
@@ -58,29 +59,22 @@ class WTransaction:public WHelper
                /**internal: copy the transaction*/
                virtual WTransaction& operator=(const WTransaction&);
                
-               /**internal: execute a query on the web, used by subclasses*/
+               /**internal: execute a query synchronously on the web, used by subclasses*/
                virtual QByteArray executeQuery(QString,QByteArray);
                
                /**internal: execute a query on the web asynchronously*/
                virtual void startQuery(QString,QByteArray);
                
-       private slots:
-               /**internal: triggers when the transaction times out*/
-               virtual void webTimeout();
-               /**internal: triggers when the response data is available*/
-               virtual void webReady();
-               /**internal: triggers when the response errors out*/
-               virtual void webError();
                /**internal: collect query data*/
                virtual void endQuery();
        signals:
-               /**this signal is raised when the transaction finished executing*/
-               void webFinished();
+               /** this signal is raised when the transaction is finished, data is available*/
+               void finished();
        protected:
                class Log;
-               class Private;
                friend class WTransaction::Log;
-               Private *d;
+               friend class WTransaction_Private;
+               WTransaction_Private *d;
 };
 
 #endif
index e29414a..6a7716b 100644 (file)
@@ -25,15 +25,28 @@ class QNetworkReply;
 ///\internal private logger class
 class WTransaction::Log{
        public:
-               Log(WTransaction*,const QString&);
+               /**instantiates the logger
+               
+               A logger object is used by transactions to output information about the message exchange that is going on. Depending on the log level of the interface the logger will log very tersely or verbosely. It can log messages immediately or store them to be logged in case of errors.
+               
+               \param parent the transaction this is about
+               \param request the name of the request this transaction issues
+               \param interface the name of the interface that is used */
+               Log(WTransaction*parent,const QString&request,const QString&interface=QString());
+               ///deletes the logger
                ~Log();
+               
+               ///logs/stores a request message
                void setRequ(const QString&,const QString&);
+               ///logs/stores a response message
                void setResp(const QString&,const QString&);
+               ///logs an error, if the interface is set up to log only on errors it also logs the stored request and response
                void setError(const QString&);
+               ///logs some informational message
                void setInfo(const QString&);
        private:
                QString req,rsp;
-               QString trn;
+               QString trn,ifc;
                WTransaction*parent;
                int lvl,cnt;
                
@@ -41,14 +54,45 @@ class WTransaction::Log{
 };
 
 ///\internal private iface
-class WTransaction::Private {
+class WTransaction_Private:public QObject {
+       Q_OBJECT
        public:
-               Stage m_stage;
+               WTransaction_Private(WTransaction*);
+               /**internal: execute a query synchronously on the web, used by subclasses*/
+               virtual QByteArray executeQuery(QString,QByteArray);
+               
+               /**internal: execute a query on the web asynchronously*/
+               virtual void startQuery(QString,QByteArray);
+               
+       public slots:
+               /**internal: triggers when the transaction times out*/
+               virtual void webTimeout();
+               /**internal: triggers when the response data is available*/
+               virtual void webReady();
+               /**internal: triggers when the response errors out*/
+               virtual void webError();
+               /**internal: collect query data*/
+               virtual void endQuery();
+       signals:
+               /** \internal this signal is raised when the transaction on the HTTP level finished*/
+               void webFinished();
+               
+       public:
+               WTransaction::Stage m_stage;
                QString m_errtype,m_errstr,m_iface,m_wobstatus;
-               Log*m_log;
+               WTransaction::Log*m_log;
                QPointer<QNetworkReply>m_rsp;
                QByteArray m_rspdata;
                QPointer<QTimer>m_qtimeout;
+               
+       public slots:
+               ///attach this private object to a master
+               WTransaction_Private* attach(WTransaction*);
+               ///detach this object from a master, delete it if there are no more masters
+               void detach(QObject*);
+       private:
+               ///internal reference counter
+               int m_refctr;
 };
 
 #endif
index 8e8f905..56fc80a 100644 (file)
 
 WTransaction::WTransaction(QString ifc)
 {
-       d=new Private;
+       d=new WTransaction_Private(this);
        d->m_stage=Uninitialized;
        d->m_iface=ifc;
        d->m_log=0;
-       connect(this,SIGNAL(webFinished()),this,SLOT(endQuery()));
 }
 WTransaction::WTransaction(const WTransaction&t)
        :WHelper()
 {
-       d=new Private;
-       d->m_stage=t.d->m_stage;
-       d->m_errstr=t.d->m_errstr;
-       d->m_errtype=t.d->m_errtype;
-       d->m_iface=t.d->m_iface;
-       d->m_log=0;
+       d=t.d->attach(this);
        connect(this,SIGNAL(webFinished()),this,SLOT(endQuery()));
 }
 
 WTransaction::~WTransaction()
 {
-       if(d)delete d;
        d=0;
 }
 
 WTransaction& WTransaction::operator=(const WTransaction&t)
 {
-       d->m_stage=t.d->m_stage;
-       d->m_errstr=t.d->m_errstr;
-       d->m_errtype=t.d->m_errtype;
-       d->m_iface=t.d->m_iface;
+       d->detach(this);
+       d=t.d->attach(this);
        return *this;
 }
 
@@ -88,17 +79,18 @@ static QList<QNetworkReply::RawHeaderPair> rqpairs(const QNetworkRequest&req)
        return ret;
 }
 
-void WTransaction::startQuery(QString hreq,QByteArray data)
+void WTransaction::startQuery(QString hreq,QByteArray data){d->startQuery(hreq,data);}
+void WTransaction_Private::startQuery(QString hreq,QByteArray data)
 {
        QNetworkRequest req;
        //find interface
-       WInterface *iface=WInterface::instance(d->m_iface);
+       WInterface *iface=WInterface::instance(m_iface);
        if(!iface){
-               if(d->m_log)d->m_log->setError("cannot find interface.");
+               if(m_log)m_log->setError("cannot find interface.");
                else qDebug("Error: transaction cannot find interface.");
-               d->m_stage=Error;
-               d->m_errtype="_iface";
-               d->m_errstr=tr("interface not found");
+               m_stage=WTransaction::Error;
+               m_errtype="_iface";
+               m_errstr=tr("interface not found");
                return;
        }
        //set target
@@ -108,7 +100,7 @@ void WTransaction::startQuery(QString hreq,QByteArray data)
                if(url.scheme().toLower()=="http")port=80;
                else port=443;
        }
-       if(d->m_log)d->m_log->setInfo(QString("New HTTP Request %1 URL %2\n\tto host=%3 port=%4 scheme=%5")
+       if(m_log)m_log->setInfo(QString("New HTTP Request %1 URL %2\n\tto host=%3 port=%4 scheme=%5")
                .arg(hreq)
                .arg(url.toString())
                .arg(url.host())
@@ -124,79 +116,85 @@ void WTransaction::startQuery(QString hreq,QByteArray data)
        req.setHeader(QNetworkRequest::ContentLengthHeader,QByteArray::number(data.size()));
        req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-webobject; charset=UTF-8");
        //send it (with body)
-       d->m_rsp=iface->post(req,data);
+       m_rsp=iface->post(req,data);
        //latest point of deletion: end of this transaction
-       d->m_rsp->setParent(this);
+       m_rsp->setParent(this);
        //log request
-       if(d->m_log){
-               d->m_log->setRequ(hd2str(rqpairs(req)),esc(data));
+       if(m_log){
+               m_log->setRequ(hd2str(rqpairs(req)),esc(data));
        }
        //we are requesting now...
-       d->m_stage=Request;
+       m_stage=WTransaction::Request;
        //schedule receiving
-       if(d->m_qtimeout.isNull()){
-               d->m_qtimeout=new QTimer(this);
-               connect(d->m_qtimeout,SIGNAL(timeout()),this,SLOT(webTimeout()));
+       if(m_qtimeout.isNull()){
+               m_qtimeout=new QTimer(this);
+               connect(m_qtimeout,SIGNAL(timeout()),this,SLOT(webTimeout()));
        }
-       d->m_qtimeout->setSingleShot(true);
-       d->m_qtimeout->start(iface->webTimeout()*1000);
-       connect(d->m_rsp,SIGNAL(finished()),this,SLOT(webReady()));
-       connect(d->m_rsp,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(webError()));
+       m_qtimeout->setSingleShot(true);
+       m_qtimeout->start(iface->webTimeout()*1000);
+       connect(m_rsp,SIGNAL(finished()),this,SLOT(webReady()));
+       connect(m_rsp,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(webError()));
 
 }
 
-void WTransaction::endQuery()
+void WTransaction::endQuery(){d->endQuery();}
+void WTransaction_Private::endQuery()
 {
        //sanity check
-       if(d->m_rsp.isNull())return;
-       d->m_rspdata=QByteArray();
+       if(m_rsp.isNull())return;
+       m_rspdata=QByteArray();
        //unschedule timeout
-       if(!d->m_qtimeout.isNull())
-               d->m_qtimeout->stop();
+       if(!m_qtimeout.isNull())
+               m_qtimeout->stop();
        //delete response object when done here
        QObject rspown;
-       connect(&rspown,SIGNAL(destroyed(QObject*)),d->m_rsp,SLOT(deleteLater()));
+       connect(&rspown,SIGNAL(destroyed(QObject*)),m_rsp,SLOT(deleteLater()));
        //process result
-       if(d->m_stage==Error && d->m_errtype=="_timeout"){
+       if(m_stage==WTransaction::Error && m_errtype=="_timeout"){
                //it did not finish yet, caught a timeout.
-               d->m_rsp->abort();
-               d->m_errstr=tr("Web Request timed out.");
-               if(d->m_log)d->m_log->setError("Request timed out.");
+               m_rsp->abort();
+               m_errstr=tr("Web Request timed out.");
+               if(m_log)m_log->setError("Request timed out.");
                return;
        }else
        //finished with low-level error?
-       if(d->m_stage==Error){
-               d->m_errstr="HTTP Error: "+d->m_rsp->errorString();
-               if(d->m_log)d->m_log->setError(QString("Request finished with HTTP level error: %1").arg(d->m_errstr));
+       if(m_stage==WTransaction::Error){
+               m_errstr="HTTP Error: "+m_rsp->errorString();
+               if(m_log)m_log->setError(QString("Request finished with HTTP level error: %1").arg(m_errstr));
                return;
        }
        //get data
-       d->m_wobstatus=d->m_rsp->rawHeader("X-WobResponse-Status");
-       d->m_wobstatus=d->m_wobstatus.replace("\"","").trimmed().toLower();
-       d->m_rspdata=d->m_rsp->readAll();
-       if(d->m_log)d->m_log->setResp(hd2str(d->m_rsp->rawHeaderPairs()),esc(d->m_rspdata));
+       m_wobstatus=m_rsp->rawHeader("X-WobResponse-Status");
+       m_wobstatus=m_wobstatus.replace("\"","").trimmed().toLower();
+       m_rspdata=m_rsp->readAll();
+       if(m_log)m_log->setResp(hd2str(m_rsp->rawHeaderPairs()),esc(m_rspdata));
        //check for high level error
-       int statcode=d->m_rsp->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+       int statcode=m_rsp->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        if(statcode!=200){
-               d->m_errstr=tr("HTTP Error, return code %1 %2") .arg(statcode).arg(d->m_rsp->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
-               d->m_errtype="_HTTP";
-               d->m_stage=Error;
-               if(d->m_log)d->m_log->setError(QString("Request finished with HTTP level error: %1").arg(d->m_errstr));
+               m_errstr=tr("HTTP Error, return code %1 %2") .arg(statcode).arg(m_rsp->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
+               m_errtype="_HTTP";
+               m_stage=WTransaction::Error;
+               if(m_log)m_log->setError(QString("Request finished with HTTP level error: %1").arg(m_errstr));
                return;
        }
-       if(d->m_stage==Request){
-               d->m_stage=Error;
-               d->m_errtype="_internal";
-               d->m_errstr="Ooops: still in Request phase at end of response handling.";
+       if(m_stage==WTransaction::Request){
+               m_stage=WTransaction::Error;
+               m_errtype="_internal";
+               m_errstr="Ooops: still in Request phase at end of response handling.";
        }
        //remaining high level errors are handled by the generated code
 }
 
-QByteArray WTransaction::executeQuery(QString hreq,QByteArray data)
+QByteArray WTransaction::executeQuery(QString hreq,QByteArray data){return d->executeQuery(hreq,data);}
+QByteArray WTransaction_Private::executeQuery(QString hreq,QByteArray data)
 {
+       //sanity check
+       if(!m_rsp.isNull() || m_stage==WTransaction::Request)
+               return QByteArray();
+       
        //set up request
        startQuery(hreq,data);
-       if(d->m_rsp.isNull() || d->m_stage!=Request)
+       if(m_rsp.isNull() || m_stage!=WTransaction::Request)
                return QByteArray();
        
        /////////////////////////////////////////////////////////////////////
@@ -206,37 +204,37 @@ QByteArray WTransaction::executeQuery(QString hreq,QByteArray data)
        loop.exec();
        /////////////////////////////////////////////////////////////////////
        
-       if(d->m_stage==Success)
-               return d->m_rspdata;
+       if(m_stage==WTransaction::Success)
+               return m_rspdata;
        else
                return QByteArray();
 }
 
-void WTransaction::webTimeout()
+void WTransaction_Private::webTimeout()
 {
-       if(d->m_stage!=Request)return;
+       if(m_stage!=WTransaction::Request)return;
 //     qDebug("web timeout");
-       if(d->m_log)d->m_log->setInfo(QString("timeout in request"));
-       d->m_stage=Error;
-       d->m_errtype="_timeout";
+       if(m_log)m_log->setInfo(QString("timeout in request"));
+       m_stage=WTransaction::Error;
+       m_errtype="_timeout";
        emit webFinished();
 }
 
-void WTransaction::webReady()
+void WTransaction_Private::webReady()
 {
-       if(d->m_stage!=Request)return;
-       if(d->m_log)d->m_log->setInfo(QString("finished request"));
-       d->m_stage=Success;
-       d->m_errtype="";
+       if(m_stage!=WTransaction::Request)return;
+       if(m_log)m_log->setInfo(QString("finished request"));
+       m_stage=WTransaction::Success;
+       m_errtype="";
        emit webFinished();
 }
 
-void WTransaction::webError()
+void WTransaction_Private::webError()
 {
-       if(d->m_stage!=Request)return;
-       if(d->m_log)d->m_log->setInfo(QString("error in request"));
-       d->m_stage=Error;
-       d->m_errtype="_web";
+       if(m_stage!=WTransaction::Request)return;
+       if(m_log)m_log->setInfo(QString("error in request"));
+       m_stage=WTransaction::Error;
+       m_errtype="_web";
        emit webFinished();
 }
 
@@ -251,24 +249,33 @@ QString WTransaction::errorType()const{return d->m_errtype;}
 QString WTransaction::interface()const{return d->m_iface;}
 
 
+/*****************************************************************************/
+
 static int logid=0;
 
-WTransaction::Log::Log(WTransaction*p,const QString&s)
+WTransaction::Log::Log(WTransaction*p,const QString&s,const QString&i)
 {
+       Q_ASSERT_X(p!=0,"WTransaction::Log constructor","Logger Parent must be a valid transaction object.");
        parent=p;
+       if(parent->d->m_log!=0)delete parent->d->m_log;
        parent->d->m_log=this;
        trn=s;
+       if(i.isNull())
+               ifc=p->interface();
+       else
+               ifc=i;
        cnt=logid++;
        WInterface*in=WInterface::instance(p->d->m_iface);
        if(in)lvl=in->logLevel();
        else lvl=WInterface::LogOnError;
        if(lvl>WInterface::LogNone)
-               outStr(QString("Running transaction %1").arg(s));
+               outStr(QString("Running transaction %1 on interface %2").arg(s).arg(ifc));
 }
 
 WTransaction::Log::~Log()
 {
-       parent->d->m_log=0;
+       if(parent->d->m_log==this)
+               parent->d->m_log=0;
 }
 
 void WTransaction::Log::outStr(const QString&s)
@@ -323,4 +330,33 @@ void WTransaction::Log::setError(const QString&s)
        }
        //show actual error
        outStr(QString("Transaction %1 Error: %2").arg(trn).arg(s));
-}
\ No newline at end of file
+}
+
+/*****************************************************************************/
+
+WTransaction_Private::WTransaction_Private(WTransaction*trn)
+{
+       m_stage=WTransaction::Uninitialized;
+       m_log=0;
+       m_refctr=0;
+       attach(trn);
+       connect(this,SIGNAL(webFinished()),this,SLOT(endQuery()));
+}
+
+WTransaction_Private* WTransaction_Private::attach(WTransaction*trn)
+{
+       m_refctr++;
+       connect(trn,SIGNAL(destroyed(QObject*)),this,SLOT(detach(QObject*)));
+       return this;
+}
+
+void WTransaction_Private::detach(QObject*trn)
+{
+       m_refctr--;
+       if(m_refctr==0)
+               deleteLater();
+       else if(trn){
+               disconnect(trn);
+               trn->disconnect(this);
+       }
+}
index c8c9ac3..5903c99 100644 (file)
@@ -14,6 +14,7 @@ HEADERS += \
        include/helper.h \
        include/object.h \
        include/transaction.h \
+       include/transaction_p.h \
        include/interface.h
 
 SOURCES += \