--- /dev/null
+//
+// C++ Implementation: WHelper
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "WHelper.h"
+
+#include <QDomElement>
+#include <QDomNode>
+
+QList<QDomElement>WHelper::elementsByTagName(const QDomElement&root,QString tag)
+{
+ QDomNodeList cn=root.childNodes();
+ QList<QDomElement>ret;
+ for(int i=0;i<cn.size();i++){
+ QDomElement e=cn.at(i).toElement();
+ if(e.isNull())continue;
+ if(e.tagName()!=tag)continue;
+ ret<<e;
+ }
+ return ret;
+}
--- /dev/null
+//
+// C++ Interface: WHelper
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_HELPER_H
+#define WOLF_HELPER_H
+
+#include <QList>
+#include <QObject>
+
+class QDomElement;
+class QDomNode;
+
+class WHelper:public QObject
+{
+ protected:
+ /**helper for de-serializers: returns direct child elements with given tag name (necessary because QDomElement::elementsByTagName traverses all children)*/
+ static QList<QDomElement>elementsByTagName(const QDomElement&,QString);
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: WInterface
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "WInterface.h"
+
+#include <QHttp>
+#include <QMutex>
+#include <QMutexLocker>
+
+QMap<QString,WInterface*> WInterface::inst;
+
+static QMutex mtx(QMutex::Recursive);
+
+WInterface*WInterface::instance(QString name)
+{
+ QMutexLocker ml(&mtx);
+ if(inst.contains(name))return inst[name];
+ else return 0;
+}
+
+WInterface::WInterface(QString name)
+{
+ m_proxyport=0;
+ m_wtimeout=30;
+ loglvl=LogOnError;
+ QMutexLocker ml(&mtx);
+ if(inst.contains(name)){
+ delete inst[name];
+ }
+ inst.insert(name,this);
+}
+
+QString WInterface::name()const
+{
+ QMutexLocker ml(&mtx);
+ return inst.key((WInterface*)this);
+}
+
+WInterface::~WInterface()
+{
+ QMutexLocker ml(&mtx);
+ inst.remove(inst.key((WInterface*)this));
+}
+
+QMap<QString,QString> WInterface::headers(QString)const
+{
+ return QMap<QString,QString>();
+}
+
+void WInterface::sslErrors(const QList<QSslError>&)
+{
+ QHttp*src=qobject_cast<QHttp*>(sender());
+ if(!src)return;
+ src->ignoreSslErrors();
+}
--- /dev/null
+//
+// C++ Interface: WInterface
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOB_INTERFACE_H
+#define WOB_INTERFACE_H
+
+#include <QMap>
+#include <QObject>
+#include <QUrl>
+#include <QSslError>
+
+class WInterface:public QObject
+{
+ Q_OBJECT
+ protected:
+ WInterface(QString name);
+
+ public:
+ virtual ~WInterface();
+ /**overwrite if you need additional headers (eg. session-ids) for certain transactions (transaction name is handed in as string argument); per default returns empty map*/
+ virtual QMap<QString,QString> headers(QString)const;
+
+ /**returns the URL of the interface*/
+ QUrl url()const{return m_url;}
+
+ /**returns whether the interface uses a proxy*/
+ bool useProxy()const{return m_proxyhost!="";}
+ /**returns whether the proxy needs authentication*/
+ bool useProxyAuth()const{return m_proxyuser!="";}
+ /**returns the proxy host name*/
+ QString proxyHost()const{return m_proxyhost;}
+ /**returns the proxy port*/
+ unsigned short proxyPort()const{return m_proxyport;}
+ /**returns the proxy user name*/
+ QString proxyUser()const{return m_proxyuser;}
+ /**returns the proxy password*/
+ QString proxyPassword()const{return m_proxypass;}
+
+ /**return timeout in seconds*/
+ int webTimeout()const{return m_wtimeout;}
+
+ /**get the name for this interface (returns empty string if not registered*/
+ QString name()const;
+
+ /**returns the instance registered under that name*/
+ static WInterface*instance(QString);
+
+ /**log settings*/
+ enum LogLevel {
+ /**no logging*/
+ LogNone=0,
+ /**minimal logging*/
+ LogMinimal=1,
+ /**informational logging (more than minimal, not much yet)*/
+ LogInfo=2,
+ /**like LogInfo, but logs additional details on error*/
+ LogOnError=0x12,
+ /**always log details*/
+ LogDetailed=0xff
+ };
+
+ /**returns the current log level*/
+ LogLevel logLevel()const{return loglvl;}
+
+ public slots:
+ /**set log level*/
+ void setLogLevel(WInterface::LogLevel l){loglvl=l;}
+
+ /**set timeout for page loads in seconds*/
+ void setWebTimeout(int t){if(t>0)m_wtimeout=t;}
+
+ /**resets the proxy settings to no proxy use*/
+ void resetProxy(){m_proxyhost="";m_proxyport=0;m_proxyuser="";m_proxypass="";}
+ /**sets the proxy settings*/
+ void setProxy(QString proxyhost,unsigned short proxyport,QString proxyuser="",QString proxypassword=""){m_proxyhost=proxyhost;m_proxyport=proxyport;m_proxyuser=proxyuser;m_proxypass=proxypassword;}
+
+ /**sets the URL of the interface*/
+ void setUrl(QUrl u){m_url=u;}
+
+ /**handles SSL errors, per default ignores them, overwrite it if you need more sophisticated behavior*/
+ virtual void sslErrors(const QList<QSslError>&);
+
+ private:
+ static QMap<QString,WInterface*>inst;
+ QUrl m_url;
+ QString m_proxyhost,m_proxyuser,m_proxypass;
+ unsigned short m_proxyport;
+ int m_wtimeout;
+ LogLevel loglvl;
+};
+
+#endif
--- /dev/null
+//
+// C++ Implementation: wobject
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "WObject.h"
\ No newline at end of file
--- /dev/null
+//
+// C++ Interface: wobject
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_WOBJECT_H
+#define WOLF_WOBJECT_H
+
+#include <QObject>
+#include <QList>
+
+#include "nullable.h"
+#include "exception.h"
+#include "WHelper.h"
+
+class QDomElement;
+class QDomDocument;
+
+/**base class of all web based objects*/
+class WObject:public WHelper
+{
+ protected:
+ WObject(){}
+};
+
+/**this exception is thrown if the deserialization of an object fails on the XML parser level*/
+class WDeserializerException:public WException
+{
+ public:
+ WDeserializerException(QString e):WException(e,"Deserializer"){}
+};
+
+/**the WOBJECT macro defines the necessary constructors if you just want to extend an abstract class without overwriting the constructors yourself*/
+#define WOBJECT(wob) public: \
+ wob():wob ## Abstract(){} \
+ wob(const wob&w):wob ## Abstract(w){} \
+ wob(const wob ## Abstract&w):wob ## Abstract(w){} \
+ wob(const QDomElement&w):wob ## Abstract(w){} \
+ wob& operator=(const wob&w){wob ## Abstract::operator=(w);return *this;} \
+ wob& operator=(const wob ## Abstract&w){wob ## Abstract::operator=(w);return *this;} \
+ private:
+
+#endif
--- /dev/null
+//
+// C++ Implementation: wtransaction
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "WTransaction.h"
+#include "WInterface.h"
+
+#include "waitcursor.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QEventLoop>
+#include <QHttp>
+#include <QTimer>
+#include <QUrl>
+
+WTransaction::WTransaction(QString ifc)
+{
+ m_stage=Uninitialized;
+ m_httpid=-1;
+ m_iface=ifc;
+ m_log=0;
+}
+WTransaction::WTransaction(const WTransaction&t)
+ :WHelper()
+{
+ m_stage=t.m_stage;
+ m_errstr=t.m_errstr;
+ m_errtype=t.m_errtype;
+ m_iface=t.m_iface;
+ m_httpid=-1;
+ m_log=0;
+}
+
+WTransaction& WTransaction::operator=(const WTransaction&t)
+{
+ m_stage=t.m_stage;
+ m_errstr=t.m_errstr;
+ m_errtype=t.m_errtype;
+ m_iface=t.m_iface;
+ m_httpid=-1;
+ return *this;
+}
+
+static inline QString esc(const QByteArray ar)
+{
+ QString r;
+ for(int i=0;i<ar.size();i++){
+ unsigned char a=ar[i];
+ if(a=='\\')r+="\\\\";else
+ if(a=='\n' || a=='\r' || (a>=32 && a<=127))r+=(char)a;
+ else r+="\\x"+QByteArray((char*)&a,1).toHex();
+ }
+ return r;
+}
+
+QByteArray WTransaction::executeQuery(QString hreq,QByteArray data)
+{
+ QHttp req;
+ connect(&req,SIGNAL(requestFinished(int,bool)),this,SLOT(webReady(int,bool)));
+ //show the user we are waiting
+ WaitCursor wc;
+ //set up request
+ QEventLoop loop(this);
+ connect(this,SIGNAL(webFinished()),&loop,SLOT(quit()));
+ WInterface *iface=WInterface::instance(m_iface);
+ if(!iface){
+ if(m_log)m_log->setError("cannot find interface.");
+ else qDebug("Error: transaction cannot find interface.");
+ m_stage=Error;
+ m_errtype="_iface";
+ m_errstr=tr("interface not found");
+ return QByteArray();
+ }
+ connect(&req,SIGNAL(sslErrors(const QList<QSslError>&)),iface,SLOT(sslErrors(const QList<QSslError>&)));
+ QUrl url=iface->url();
+ int port=url.port();
+ if(port<=0){
+ if(url.scheme().toLower()=="http")port=80;
+ else port=443;
+ }
+ 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())
+ .arg(port)
+ .arg(url.scheme()));
+ QHttp::ConnectionMode conm;
+ if(url.scheme().toLower()=="http")conm=QHttp::ConnectionModeHttp;
+ else conm=QHttp::ConnectionModeHttps;
+ req.setHost(url.host(),conm,port);
+ if(iface->useProxy())req.setProxy(iface->proxyHost(),iface->proxyPort(),iface->proxyUser(),iface->proxyPassword());
+ QString pathspec=url.path();
+ if(pathspec=="")pathspec="/";
+ if(url.encodedQuery()!="")pathspec+="?"+url.encodedQuery();
+ QHttpRequestHeader hrh("POST",pathspec);
+ QString hostspec=url.host();
+ if(url.port()>0)hostspec+=":"+QString::number(port);
+ hrh.setValue("Host",hostspec);
+ QMap<QString,QString>hdrs=iface->headers(hreq);
+ QStringList hdrn=hdrs.keys();
+ for(int i=0;i<hdrn.size();i++)
+ hrh.setValue("X-"+hdrn[i],hdrs[hdrn[i]]);
+ hrh.setValue("X-WobRequest",hreq);
+ hrh.setContentLength(data.size());
+ hrh.setContentType("application/x-webobject; charset=UTF-8");
+ m_httpid=req.request(hrh,data);
+ if(m_log){
+ m_log->setRequ(hrh.toString(),esc(data),m_httpid);
+ m_log->setInfo(QString("HTTP ID %1").arg(m_httpid));
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ //start loop
+ QTimer tmr;
+ tmr.setSingleShot(true);tmr.start(iface->webTimeout()*1000);
+ connect(&tmr,SIGNAL(timeout()),this,SLOT(webTimeout()));
+ loop.exec();
+ tmr.stop();tmr.disconnect(SIGNAL(timeout()),this,SLOT(webTimeout()));
+ /////////////////////////////////////////////////////////////////////
+
+ //process result
+ if(m_stage==Error && m_errtype=="_timeout"){
+ //it did not finish yet, caught a timeout.
+ req.abort();
+ m_errstr=tr("Web Request timed out.");
+ if(m_log)m_log->setError(QString("Request %1 timed out.").arg(m_httpid));
+ return QByteArray();
+ }else
+ //finished with low-level error?
+ if(m_stage==Error){
+ m_errstr="HTTP Error: "+req.errorString();
+ if(m_log)m_log->setError(QString("Request %2 finished with HTTP level error: %1").arg(m_errstr).arg(m_httpid));
+ return QByteArray();
+ }
+ //get data
+ QHttpResponseHeader rsph=req.lastResponse();
+ m_wobstatus=rsph.value("X-WobResponse-Status");
+ m_wobstatus=m_wobstatus.replace("\"","").trimmed().toLower();
+ QByteArray rspdata=req.readAll();
+ if(m_log)m_log->setResp(rsph.toString(),esc(rspdata),m_httpid);
+ //check for high level error
+ if(rsph.statusCode()!=200){
+ m_errstr=tr("HTTP Error, return code %1 %2") .arg(rsph.statusCode()).arg(rsph.reasonPhrase());
+ m_errtype="_HTTP";
+ m_stage=Error;
+ if(m_log)m_log->setError(QString("Request %2 finished with HTTP level error: %1").arg(m_errstr).arg(m_httpid));
+ return QByteArray();
+ }
+ if(m_stage!=Error)m_stage=Success;
+ //remaining high level errors are handled by the generated code
+ return rspdata;
+}
+
+void WTransaction::webTimeout()
+{
+ if(m_httpid<0)return;
+// qDebug("web timeout");
+ m_stage=Error;
+ m_errtype="_timeout";
+ emit webFinished();
+}
+
+void WTransaction::webReady(int i,bool e)
+{
+ if(i!=m_httpid)return;
+ if(m_log)m_log->setInfo(QString("finished request %1").arg(i));
+ if(e){
+ m_stage=Error;
+ m_errtype="_web";
+ }
+ emit webFinished();
+}
+
+QString WTransaction::errorString()const
+{
+ return QCoreApplication::translate("php::",m_errstr.toUtf8(),0,QCoreApplication::UnicodeUTF8);
+}
+
+
+WTransaction::WTLog::WTLog(WTransaction*p,const QString&s)
+{
+ parent=p;
+ parent->m_log=this;
+ trn=s;
+ WInterface*in=WInterface::instance(p->m_iface);
+ if(in)lvl=in->logLevel();
+ else lvl=WInterface::LogOnError;
+ if(lvl>WInterface::LogNone)
+ qDebug("Running transaction %s",s.toAscii().data());
+}
+
+WTransaction::WTLog::~WTLog()
+{
+ parent->m_log=0;
+}
+
+void WTransaction::WTLog::setRequ(const QString&h,const QString&d,int i)
+{
+ if(lvl<=WInterface::LogInfo)return;
+ QByteArray r="RequestID="+QString::number(i).toAscii()
+ +"\n--Header--\n"+h.trimmed().toAscii()
+ +"\n--Body--\n"+d.trimmed().toAscii()+"\n--End--";
+ if(lvl==WInterface::LogDetailed)
+ qDebug("Transaction %s request: %s",trn.toAscii().data(),r.data());
+ else
+ if(lvl==WInterface::LogOnError)
+ req=r;
+}
+
+void WTransaction::WTLog::setResp(const QString&h,const QString&d,int i)
+{
+ if(lvl<=WInterface::LogInfo)return;
+ QByteArray r="RequestID="+QString::number(i).toAscii()
+ +"\n--Header--\n"+h.trimmed().toAscii()
+ +"\n--Body--\n"+d.trimmed().toAscii()+"\n--End--";
+ if(lvl==WInterface::LogDetailed)
+ qDebug("Transaction %s response: %s",trn.toAscii().data(),r.data());
+ else
+ if(lvl==WInterface::LogOnError)
+ rsp=r;
+}
+
+void WTransaction::WTLog::setInfo(const QString&s)
+{
+ if(lvl>=WInterface::LogInfo)
+ qDebug("Transaction %s info: %s",trn.toAscii().data(),s.toAscii().data());
+}
+
+void WTransaction::WTLog::setError(const QString&s)
+{
+ //bail out if no logging
+ if(lvl<WInterface::LogMinimal)return;
+ //only for LogOnError, these have been stored, replay them:
+ if(req.size()>0){
+ qDebug("Transaction %s on error, request was: %s",trn.toAscii().data(),req.data());
+ req=QByteArray();
+ }
+ if(rsp.size()>0){
+ qDebug("Transaction %s on error, response was: %s",trn.toAscii().data(),rsp.data());
+ rsp=QByteArray();
+ }
+ //show actual error
+ qDebug("Transaction %s Error: %s",trn.toAscii().data(),s.toAscii().data());
+}
\ No newline at end of file
--- /dev/null
+//
+// C++ Interface: wtransaction
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_TRANSACTION_H
+#define WOLF_TRANSACTION_H
+
+#include <QObject>
+#include <QList>
+#include <QString>
+
+#include "nullable.h"
+#include "WHelper.h"
+
+/**base class of all transactions*/
+class WTransaction:public WHelper
+{
+ Q_OBJECT
+ public:
+ /**stage the transaction is in*/
+ enum Stage {
+ Uninitialized,///<transaction has not started yet
+ Success,///<transaction ended successfully
+ Error///<transaction ended with an error
+ };
+
+ /**returns the stage the transaction is in*/
+ Stage stage()const{return m_stage;}
+
+ /**returns whether the transaction had an error while executing*/
+ bool hasError()const{return m_stage==Error;}
+ /**returns the error type (usually the component causing it)*/
+ QString errorType()const{return m_errtype;}
+ /**returns the (translated) human readable error string*/
+ QString errorString()const;
+
+ /**returns the interface that is used for the transaction*/
+ QString interface()const{return m_iface;}
+ protected:
+ /**internal: construct the transaction*/
+ WTransaction(QString iface=QString());
+ /**internal: copy the transaction*/
+ WTransaction(const WTransaction&);
+
+ /**internal: copy the transaction*/
+ WTransaction& operator=(const WTransaction&);
+
+ /**internal: execute a query on the web, used by subclasses*/
+ QByteArray executeQuery(QString,QByteArray);
+
+ /**internal logger class*/
+ class WTLog{
+ public:
+ WTLog(WTransaction*,const QString&);
+ ~WTLog();
+ void setRequ(const QString&,const QString&,int);
+ void setResp(const QString&,const QString&,int);
+ void setError(const QString&);
+ void setInfo(const QString&);
+ private:
+ QByteArray req,rsp;
+ QString trn;
+ WTransaction*parent;
+ int lvl;
+ };
+ private slots:
+ /**internal: triggers when the transaction times out*/
+ void webTimeout();
+ /**internal: triggers when the response data is available*/
+ void webReady(int,bool);
+ signals:
+ /**this signal is raised when the transaction finished executing*/
+ void webFinished();
+ protected:
+ friend class WTransaction::WTLog;
+ Stage m_stage;
+ QString m_errtype,m_errstr,m_iface,m_wobstatus;
+ int m_httpid;
+ WTLog*m_log;
+};
+
+#endif
--- /dev/null
+//
+// C++ Interface: exception
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef WOLF_EXCEPTION_H
+#define WOLF_EXCEPTION_H
+
+#include <QString>
+
+class WException
+{
+ protected:
+ WException(QString e,QString c){err=e;comp=c;}
+ public:
+ QString error()const{return err;}
+ QString component()const{return comp;}
+ private:
+ QString err,comp;
+};
+
+#endif
--- /dev/null
+//
+// C++ Interface: nullable
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+
+#ifndef WOLF_NULLABLE_H
+#define WOLF_NULLABLE_H
+
+template<class T>class Nullable
+{
+ public:
+ Nullable(){isnull=true;elem=T();}
+ Nullable(const T&t){isnull=false;elem=t;}
+ Nullable(const Nullable<T>&t){isnull=t.isnull;elem=t.elem;}
+
+ Nullable<T>& operator=(const T&t){isnull=false;elem=t;return *this;}
+ Nullable<T>& operator=(const Nullable<T>&t){isnull=t.isnull;elem=t.elem;return *this;}
+
+ bool isNull()const{return isnull;}
+
+ operator T()const{if(isnull)return T();else return elem;}
+
+ T& value(){return elem;}
+ T value()const{if(isnull)return T();else return elem;}
+
+ bool operator==(const T&t){if(isnull)return false;else return elem == t;}
+ bool operator!=(const T&t){if(isnull)return true;else return elem != t;}
+
+ bool operator==(const Nullable<T>&t){
+ if(isnull != t.isnull)return false;
+ if(isnull)return true;
+ else return elem == t.elem;}
+ bool operator!=(const Nullable<T>&t){
+ if(isnull != t.isnull)return true;
+ if(isnull)return false;
+ else return elem != t.elem;}
+ private:
+ bool isnull;
+ T elem;
+};
+
+typedef Nullable<int> Int;
+typedef Nullable<qint32> Int32;
+typedef Nullable<qint64> Int64;
+typedef Nullable<quint32> UInt32;
+typedef Nullable<quint64> UInt64;
+typedef Nullable<QString> NString;
+
+#endif
--- /dev/null
+HEADERS += \
+ wbase/nullable.h \
+ wbase/WHelper.h \
+ wbase/WObject.h \
+ wbase/WTransaction.h \
+ wbase/WInterface.h
+
+SOURCES += \
+ wbase/WObject.cpp \
+ wbase/WHelper.cpp \
+ wbase/WTransaction.cpp \
+ wbase/WInterface.cpp
+
+INCLUDEPATH += ./wbase ./wob
\ No newline at end of file