summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordeva <deva>2010-06-10 07:03:06 +0000
committerdeva <deva>2010-06-10 07:03:06 +0000
commit198b0d886817f2c5bc97cfd11857d4b314dffae3 (patch)
tree4fc2d51de46ab69b9e67149abf0ab6a332032f27
parent730eb796bbce6f124be9194f1565b7dda1daddf1 (diff)
Add transaction support on database pr. pracro session. Makes it possible to discard all edited macros.
-rw-r--r--client/client.pro2
-rw-r--r--client/macrowindow.cc9
-rw-r--r--client/mainwindow.cc9
-rw-r--r--client/pracro.cc8
-rw-r--r--client/resumewidget.cc13
-rw-r--r--client/resumewidget.h8
-rw-r--r--client/viewer.cc25
-rw-r--r--client/viewer.h9
-rw-r--r--server/configure.in2
-rw-r--r--server/src/database.h55
-rw-r--r--server/src/environment.cc6
-rw-r--r--server/src/environment.h4
-rw-r--r--server/src/journalwriter.cc27
-rw-r--r--server/src/journalwriter.h3
-rw-r--r--server/src/pracrodao.h26
-rw-r--r--server/src/pracrodaopgsql.cc184
-rw-r--r--server/src/pracrodaopgsql.h30
-rw-r--r--server/src/pracrodaotest.h20
-rw-r--r--server/src/saxparser.cc1
-rw-r--r--server/src/session.cc23
-rw-r--r--server/src/session.h3
-rw-r--r--server/src/sessionparser.cc17
-rw-r--r--server/src/sessionparser.h3
-rw-r--r--server/src/sessionserialiser.cc27
-rw-r--r--server/src/transactionhandler.cc31
-rw-r--r--server/src/xml_encode_decode.cc13
26 files changed, 451 insertions, 107 deletions
diff --git a/client/client.pro b/client/client.pro
index 7db485e..90e0b66 100644
--- a/client/client.pro
+++ b/client/client.pro
@@ -15,7 +15,7 @@ debug {
CONFIG += debug
}
-DEFINES+=VERSION=\\\"2.0.0-beta1\\\"
+DEFINES+=VERSION=\\\"2.0.0-beta2\\\"
win32 {
LIBPATH += lua/lib
diff --git a/client/macrowindow.cc b/client/macrowindow.cc
index d9060b0..b37fe5f 100644
--- a/client/macrowindow.cc
+++ b/client/macrowindow.cc
@@ -93,7 +93,14 @@ void MacroWindow::initMacro(QDomNode &node)
// Nothing to do here
} else if(xml_elem.tagName() == "resume") {
QString resume = xml_elem.text();
- ((ResumeWidget*)collapsedWidget())->setText(resume);
+ ResumeWidget::state_t state = ResumeWidget::OLD;
+ if(xml_elem.hasAttribute("state")) {
+ if(xml_elem.attribute("state") == "old") state = ResumeWidget::OLD;
+ if(xml_elem.attribute("state") == "new") state = ResumeWidget::NEW;
+ if(xml_elem.attribute("state") == "dirty") state = ResumeWidget::DIRTY;
+ }
+
+ ((ResumeWidget*)collapsedWidget())->setText(resume, state);
} else if(xml_elem.tagName() == "script") {
if(xml_elem.hasAttribute("language") &&
diff --git a/client/mainwindow.cc b/client/mainwindow.cc
index 3d49752..40daad8 100644
--- a/client/mainwindow.cc
+++ b/client/mainwindow.cc
@@ -142,6 +142,8 @@ void MainWindow::showSessions()
sessions.show();
}
+extern QWidget *viewer;
+//#include <QApplication>
void MainWindow::closeEvent(QCloseEvent *event)
{
if(isStored || QMessageBox::question(this,
@@ -150,6 +152,11 @@ void MainWindow::closeEvent(QCloseEvent *event)
"Are you sure you want to continue?",
QMessageBox::Yes | QMessageBox::No)
== QMessageBox::Yes) {
+ if(!isStored) {
+ netcom.discard();
+ sessions.remove(cpr);
+ }
+
QSettings settings("Aasimon.org", "Pracro");
settings.beginGroup("MainWindow");
@@ -159,6 +166,8 @@ void MainWindow::closeEvent(QCloseEvent *event)
settings.endGroup();
event->accept();
+ if(viewer) viewer->close();
+ // qApp->quit();
} else {
event->ignore();
}
diff --git a/client/pracro.cc b/client/pracro.cc
index bb2d952..ad46085 100644
--- a/client/pracro.cc
+++ b/client/pracro.cc
@@ -54,7 +54,7 @@ QString host;
quint16 port;
QFont *fixedfont;
-
+QWidget *viewer = NULL;
static void print_usage()
{
printf("Usage: pracro -m MACRO -c CPR -U USER\n");
@@ -173,9 +173,9 @@ int main(int argc, char *argv[])
MainWindow mainwindow(cpr, templ, host, port, user);
mainwindow.show();
- Viewer viewer(cpr, templs, host, port, user, journalpath);
- viewer.show();
-
+ Viewer v(cpr, templs, host, port, user, journalpath);
+ viewer = &v;
+ v.show();
return app.exec();
}
diff --git a/client/resumewidget.cc b/client/resumewidget.cc
index ac18578..81e3f2c 100644
--- a/client/resumewidget.cc
+++ b/client/resumewidget.cc
@@ -83,7 +83,7 @@ static QString reformatString(QString help)
return output;
}
-void ResumeWidget::setText(QString text)
+void ResumeWidget::setText(QString text, state_t state)
{
QString f;
@@ -120,6 +120,17 @@ void ResumeWidget::setText(QString text)
}
}
+ switch(state) {
+ case NEW:
+ f = "<font style='color: #00F;'>" + f + "</font>";
+ break;
+ case OLD:
+ break;
+ case DIRTY:
+ f = "<font style='color: #F00;'>" + f + "</font>";
+ break;
+ }
+
resume->setText(f);
}
diff --git a/client/resumewidget.h b/client/resumewidget.h
index fe8beb1..22f4d58 100644
--- a/client/resumewidget.h
+++ b/client/resumewidget.h
@@ -36,7 +36,13 @@ Q_OBJECT
public:
ResumeWidget(bool compact);
- void setText(QString text);
+ typedef enum {
+ NEW,
+ OLD,
+ DIRTY
+ } state_t;
+
+ void setText(QString text, state_t state);
public slots:
void showFull(const QString &);
diff --git a/client/viewer.cc b/client/viewer.cc
index c4bd3f5..eabcf16 100644
--- a/client/viewer.cc
+++ b/client/viewer.cc
@@ -35,6 +35,7 @@
#include <QSettings>
#include <QTextCodec>
+#ifdef WITH_FROGS
Status::Status()
{
QVBoxLayout *vl = new QVBoxLayout();
@@ -73,6 +74,9 @@ void Status::setStatus(QString macro, QString caption, bool done)
icons[macro]->setPixmap(QPixmap(done?":/icons/done.png":":icons/undone.png"));
}
+#endif
+
+extern QFont *fixedfont; // Defined in pracro.cc
Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
QString user, QString journalpath)
@@ -81,11 +85,14 @@ Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
this->templs = templs.split(QRegExp("\\W+"), QString::SkipEmptyParts);
connect(&updatetimer, SIGNAL(timeout()), this, SLOT(update()));
+
+#ifdef WITH_FROGS
netcom = new NetCom(host, port);
netcom->user = user;
netcom->patientid = cpr;
netcom->sessionid = "";
netcom->initConnection();
+#endif
host = host; port = port; user = user;
this->cpr = cpr;
@@ -95,6 +102,7 @@ Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
QVBoxLayout *l = new QVBoxLayout();
setLayout(l);
+#ifdef WITH_FROGS
QStringList::iterator ti = this->templs.begin();
while(ti != this->templs.end()) {
Status *s = new Status();
@@ -102,10 +110,11 @@ Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
statuses[*ti] = s;
ti++;
}
+#endif
journal = new QTextEdit();
journal->setReadOnly(true);
- journal->setFontFamily("Courier New");
+ journal->setFont(*fixedfont);
l->addWidget(journal);
init();
@@ -114,12 +123,13 @@ Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
Viewer::~Viewer()
{
- updatetimer.stop();
- netcom->discard(); // Make sure sessionid is removed.
+#ifdef WITH_FROGS
delete netcom;
+#endif
delete journal;
}
+extern QWidget *viewer;
void Viewer::closeEvent(QCloseEvent *)
{
QSettings settings("Aasimon.org", "Pracro");
@@ -128,6 +138,13 @@ void Viewer::closeEvent(QCloseEvent *)
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
+ viewer = NULL;
+
+ updatetimer.stop();
+
+#ifdef WITH_FROGS
+ netcom->discard(); // Make sure sessionid is removed.
+#endif
}
void Viewer::init()
@@ -143,6 +160,7 @@ void Viewer::init()
void Viewer::update()
{
+#ifdef WITH_FROGS
QStringList::iterator ti = templs.begin();
while(ti != templs.end()) {
QDomDocument xml_doc = netcom->send(*ti, "", false);
@@ -171,6 +189,7 @@ void Viewer::update()
ti++;
}
+#endif
// re-read journal file:
QString crypt;
diff --git a/client/viewer.h b/client/viewer.h
index 7877b8e..c9f1b41 100644
--- a/client/viewer.h
+++ b/client/viewer.h
@@ -36,6 +36,9 @@
#include <QMap>
#include <QHBoxLayout>
+//#define WITH_FROGS
+
+#ifdef WITH_FROGS
#include "netcom.h"
class Status : public QWidget {
@@ -49,6 +52,7 @@ private:
QMap<QString, QLabel*> icons;
QHBoxLayout *hl;
};
+#endif
class Viewer : public QWidget {
Q_OBJECT
@@ -71,10 +75,13 @@ private:
QString cpr;
QString journalpath;
QStringList templs;
- NetCom *netcom;
QTextEdit *journal;
+
+#ifdef WITH_FROGS
+ NetCom *netcom;
QMap<QString, Status* > statuses;
+#endif
};
#endif/*__PRACRO_VIEWER_H__*/
diff --git a/server/configure.in b/server/configure.in
index 23a7172..3469af2 100644
--- a/server/configure.in
+++ b/server/configure.in
@@ -1,7 +1,7 @@
# Filename: configure.in
AC_INIT(src/pracrod.cc)
-AM_INIT_AUTOMAKE( pracrod, 1.1.0 )
+AM_INIT_AUTOMAKE( pracrod, 2.0.0-beta2 )
dnl ======================
dnl Compile with debug options
diff --git a/server/src/database.h b/server/src/database.h
index f253ba5..9b08801 100644
--- a/server/src/database.h
+++ b/server/src/database.h
@@ -37,31 +37,45 @@
class Database {
public:
- Database(std::string _backend, std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname);
+ Database(std::string _backend, std::string _host,
+ std::string _port, std::string _user,
+ std::string _passwd, std::string _dbname);
~Database();
// Make a commit to the db
- void commitTransaction(std::string user, std::string patientid, Macro &macro, Fields &fields, time_t now = time(NULL)) {
+ void commitTransaction(std::string user,
+ std::string patientid,
+ Macro &macro,
+ Fields &fields,
+ time_t now = time(NULL)) {
if(!dao) return;
mutex.lock();
- PRACRO_DEBUG(db, "%s, %s, %s,...\n", user.c_str(), patientid.c_str(), macro.attributes["name"].c_str());
+ PRACRO_DEBUG(db, "%s, %s, %s,...\n",
+ user.c_str(), patientid.c_str(),
+ macro.attributes["name"].c_str());
dao->commitTransaction(user, patientid, macro, fields, now);
mutex.unlock();
}
// Get a list of values from the db
- Values getValues(std::string patientid, Fieldnames &fieldnames, time_t oldest = 0) {
+ Values getValues(std::string patientid,
+ Fieldnames &fieldnames,
+ time_t oldest = 0) {
if(!dao) return Values();
mutex.lock();
- PRACRO_DEBUG(db, "%s, <%u fieldnames>, %ld\n", patientid.c_str(), fieldnames.size(), oldest);
+ PRACRO_DEBUG(db, "%s, <%u fieldnames>, %ld\n",
+ patientid.c_str(), fieldnames.size(), oldest);
Values values = dao->getLatestValues(patientid, NULL, fieldnames, oldest);
mutex.unlock();
return values;
}
// Check if a macro has been committed.
- bool checkMacro(std::string patientid, std::string macro, time_t oldest = 0) {
- PRACRO_DEBUG(db, "%s, %s, %ld\n", patientid.c_str(), macro.c_str(), oldest);
+ bool checkMacro(std::string patientid,
+ std::string macro,
+ time_t oldest = 0) {
+ PRACRO_DEBUG(db, "%s, %s, %ld\n",
+ patientid.c_str(), macro.c_str(), oldest);
if(!dao) return false;
mutex.lock();
bool res = dao->nrOfCommits(patientid, macro, oldest) > 0;
@@ -71,7 +85,8 @@ public:
// Get latest resume of a given macro
std::string getResume(std::string patientid, Macro &macro, time_t oldest) {
- PRACRO_DEBUG(db, "%s, %s, %ld\n", patientid.c_str(), macro.attributes["name"].c_str(), oldest);
+ PRACRO_DEBUG(db, "%s, %s, %ld\n",
+ patientid.c_str(), macro.attributes["name"].c_str(), oldest);
if(!dao) return "";
Fieldnames fn;
fn.push_back("journal.resume");
@@ -111,6 +126,30 @@ public:
return fieldnames;
}
+ void commit()
+ {
+ if(!dao) return;
+ return dao->commit();
+ }
+
+ void discard()
+ {
+ if(!dao) return;
+ return dao->discard();
+ }
+
+ std::string serialise()
+ {
+ if(!dao) return "";
+ return dao->serialise();
+ }
+
+ void restore(const std::string &data)
+ {
+ if(!dao) return;
+ return dao->restore(data);
+ }
+
private:
PracroDAO *dao;
Mutex mutex;
diff --git a/server/src/environment.cc b/server/src/environment.cc
index 9904afc..f1e035e 100644
--- a/server/src/environment.cc
+++ b/server/src/environment.cc
@@ -34,11 +34,12 @@ Environment::Environment()
: macrolist(Conf::xml_basedir + "/macros"),
templatelist(Conf::xml_basedir + "/templates")
{
+ /*
for(int i = 0; i < Conf::database_poolsize; i++) {
dbpool.add(new Database(Conf::database_backend, Conf::database_addr,
"", Conf::database_user, Conf::database_passwd, ""));
}
-
+ */
for(int i = 0; i < Conf::artefact_poolsize; i++) {
atfpool.add(new Artefact);
}
@@ -46,6 +47,7 @@ Environment::Environment()
Environment::~Environment()
{
+ /*
// Remove, but wait until resources are released
std::list<Database*> dblst = dbpool.clear(false);
std::list<Database*>::iterator i = dblst.begin();
@@ -53,7 +55,7 @@ Environment::~Environment()
delete *i;
i++;
}
-
+ */
// Remove, but wait until resources are released
std::list<Artefact*> atflst = atfpool.clear(false);
std::list<Artefact*>::iterator j = atflst.begin();
diff --git a/server/src/environment.h b/server/src/environment.h
index a7b9677..3e2ac95 100644
--- a/server/src/environment.h
+++ b/server/src/environment.h
@@ -28,7 +28,7 @@
#ifndef __PRACRO_ENVIRONMENT_H__
#define __PRACRO_ENVIRONMENT_H__
-#include "database.h"
+//#include "database.h"
#include "artefact.h"
#include "connectionpool.h"
#include "session.h"
@@ -40,7 +40,7 @@ public:
Environment();
~Environment();
- ConnectionPool<Database*> dbpool;
+ // ConnectionPool<Database*> dbpool;
ConnectionPool<Artefact*> atfpool;
Sessions sessions;
MacroList macrolist;
diff --git a/server/src/journalwriter.cc b/server/src/journalwriter.cc
index 4b2b4be..5858de4 100644
--- a/server/src/journalwriter.cc
+++ b/server/src/journalwriter.cc
@@ -217,7 +217,7 @@ void JournalWriter::addEntry(Transaction &transaction, Commit &commit,
void JournalWriter::addEntry(std::string resume, std::string macro, int index)
{
// Strip trailing whitespace, and add newlines.
- std::string r = stripTrailingWhitepace(addNewlines(resume, 60));
+ std::string r = resume;
std::string m = macro;
ResumeEntry re;
@@ -235,7 +235,7 @@ void JournalWriter::commit()
while(i != entrylist.end()) {
if(resume != "") resume += "\n\n";
// resume += i->macro + "\n";
- resume += i->second.resume;
+ resume += stripTrailingWhitepace(addNewlines(i->second.resume, 60));
i++;
}
@@ -247,6 +247,29 @@ void JournalWriter::commit()
resume.c_str(), resume.size());
}
+std::string JournalWriter::getEntry(std::string macro)
+{
+ std::map< int, ResumeEntry >::iterator i = entrylist.begin();
+ while(i != entrylist.end()) {
+ if(i->second.macro == macro) return i->second.resume;
+ i++;
+ }
+ return "";
+}
+
+void JournalWriter::removeEntry(std::string macro)
+{
+ std::map< int, ResumeEntry >::iterator i = entrylist.begin();
+ while(i != entrylist.end()) {
+ if(i->second.macro == macro) {
+ entrylist.erase(i);
+ break;
+ }
+ i++;
+ }
+}
+
+
#ifdef TEST_JOURNALWRITER
//deps: debug.cc journal_commit.cc
//cflags: -I..
diff --git a/server/src/journalwriter.h b/server/src/journalwriter.h
index 2cd191d..ea1b514 100644
--- a/server/src/journalwriter.h
+++ b/server/src/journalwriter.h
@@ -48,6 +48,9 @@ public:
void commit();
+ std::string getEntry(std::string macro);
+ void removeEntry(std::string macro);
+
private:
std::string host;
unsigned short int port;
diff --git a/server/src/pracrodao.h b/server/src/pracrodao.h
index 1ef9686..7825dee 100644
--- a/server/src/pracrodao.h
+++ b/server/src/pracrodao.h
@@ -38,17 +38,33 @@
class PracroDAO
{
public:
- PracroDAO(std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname);
+ PracroDAO(std::string _host, std::string _port,
+ std::string _user, std::string _passwd, std::string _dbname);
virtual ~PracroDAO();
- virtual void commitTransaction(std::string user, std::string patientid, Macro &macro, Fields &fields, time_t now) = 0;
- virtual Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) = 0;
- virtual unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest) = 0;
+ virtual void commitTransaction(std::string user,
+ std::string patientid,
+ Macro &macro,
+ Fields &fields,
+ time_t now) = 0;
+ virtual Values getLatestValues(std::string patientid,
+ Macro *macro,
+ Fieldnames &fieldnames,
+ time_t oldest) = 0;
+ virtual unsigned nrOfCommits(std::string patientid,
+ std::string macroname,
+ time_t oldest) = 0;
- virtual void addFieldname(std::string name, std::string description) = 0;
+ virtual void addFieldname(std::string name,
+ std::string description) = 0;
virtual void delFieldname(std::string name) = 0;
virtual std::vector<Fieldname> getFieldnames() = 0;
+ virtual void commit() = 0;
+ virtual void discard() = 0;
+ virtual std::string serialise() = 0;
+ virtual void restore(const std::string &data) = 0;
+
protected:
std::string host;
std::string port;
diff --git a/server/src/pracrodaopgsql.cc b/server/src/pracrodaopgsql.cc
index d1ba517..6d7afe8 100644
--- a/server/src/pracrodaopgsql.cc
+++ b/server/src/pracrodaopgsql.cc
@@ -34,7 +34,9 @@
* CREATE SEQUENCE 'trseq';
* SELECT setval('trseq', (SELECT MAX(oid) FROM transactions));
* UPDATE transactions SET uid = oid;
- * INSERT INTO fieldnames (name, description, timestamp) VALUES ('journal.resume', 'Journal resume text', (SELECT EXTRACT(EPOCH FROM now())::integer));
+ * INSERT INTO fieldnames (name, description, timestamp)
+ * VALUES ('journal.resume', 'Journal resume text',
+ * (SELECT EXTRACT(EPOCH FROM now())::integer));
*/
#include <config.h>
@@ -44,7 +46,9 @@
#include "debug.h"
-PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname)
+PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port,
+ std::string _user, std::string _passwd,
+ std::string _dbname)
: PracroDAO(_host, _port, _user, _passwd, _dbname)
{
conn = NULL;
@@ -56,6 +60,15 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, std::string
cs += " dbname=" + (dbname.size() ? dbname : "pracro");
try {
conn = new pqxx::connection(cs);
+ W = new pqxx::work(*conn);
+
+ std::string ts;
+ try {
+ ts = "BEGIN;";
+ PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str());
+ pqxx::result R = W->exec(ts);
+ } catch(...) {
+ }
} catch(std::exception &e) {
PRACRO_ERR_LOG(db, "Postgresql init failed: %s\n", e.what());
conn = NULL;
@@ -66,12 +79,23 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, std::string
PracroDAOPgsql::~PracroDAOPgsql()
{
- if(conn) delete conn;
+ if(conn) {
+ if(W) delete W;
+ delete conn;
+ }
}
-void PracroDAOPgsql::commitTransaction(std::string user, std::string patientid, Macro &_macro, Fields &fields, time_t now)
+void PracroDAOPgsql::commitTransaction(std::string user,
+ std::string patientid,
+ Macro &_macro,
+ Fields &fields,
+ time_t now)
{
- PRACRO_DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n", user.c_str(), patientid.c_str(), _macro.attributes["name"].c_str(), fields.size(), now);
+ PRACRO_DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n",
+ user.c_str(), patientid.c_str(),
+ _macro.attributes["name"].c_str(),
+ fields.size(), now);
+
if(!conn) PRACRO_DEBUG(db, "No pgsql connection\n");
if(fields.size() == 0) return;
@@ -81,54 +105,66 @@ void PracroDAOPgsql::commitTransaction(std::string user, std::string patientid,
std::string ts;
try {
- pqxx::work W(*conn);
- ts = "INSERT INTO transactions (uid, patientid, macro, version, \"timestamp\", \"user\") VALUES ("
+ ts = "INSERT INTO transactions (uid, patientid, macro, version,"
+ " \"timestamp\", \"user\") VALUES ("
" nextval('trseq'), "
- " '" + W.esc(patientid) + "', "
- " '" + W.esc(macro) + "', "
- " '" + W.esc(version) + "', "
- " '" + W.esc(timestamp.str()) + "', "
- " '" + W.esc(user) + "' "
- ")"
+ " '" + W->esc(patientid) + "', "
+ " '" + W->esc(macro) + "', "
+ " '" + W->esc(version) + "', "
+ " '" + W->esc(timestamp.str()) + "', "
+ " '" + W->esc(user) + "' "
+ ");"
;
PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str());
- pqxx::result R = W.exec(ts);
+ pqxx::result R = W->exec(ts);
+ statements += ts + "\n";
if(fields.size() > 0) {
// field table lookup
ts = "SELECT name FROM fieldnames WHERE name IN ( ";
std::map< std::string, std::string >::iterator i = fields.begin();
- ts += "'" + W.esc(i->first) + "'";
+ ts += "'" + W->esc(i->first) + "'";
i++;
while(i != fields.end()) {
- ts += ", '" + W.esc(i->first) + "'";
+ ts += ", '" + W->esc(i->first) + "'";
i++;
}
- ts += ")";
+ ts += ");";
PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str());
- R = W.exec(ts);
- PRACRO_DEBUG(db, "input fields: %d, output fields: %lu\n", fields.size(), R.size());
+ R = W->exec(ts);
+ // statements += ts + "\n";
+
+ PRACRO_DEBUG(db, "input fields: %d, output fields: %lu\n",
+ fields.size(), R.size());
// Store known fields
pqxx::result::const_iterator ri = R.begin();
if(ri != R.end()) {
std::string name = (*ri)[0].c_str();
- PRACRO_DEBUG(db, "Storing: %s with value %s\n", name.c_str(), fields[name].c_str());
- ts = "INSERT INTO fields (transaction, name, value) VALUES ( currval('trseq'), '" + W.esc(name) + "', '" + W.esc(fields[name]) + "')";
+ PRACRO_DEBUG(db, "Storing: %s with value %s\n",
+ name.c_str(), fields[name].c_str());
+ ts = "INSERT INTO fields (transaction, name, value) "
+ "VALUES ( currval('trseq'), '" + W->esc(name) + "', '" +
+ W->esc(fields[name]) + "')";
ri++;
while(ri != R.end()) {
name = (*ri)[0].c_str();
- PRACRO_DEBUG(db, "Storing: %s with value %s\n", name.c_str(), fields[name].c_str());
+ PRACRO_DEBUG(db, "Storing: %s with value %s\n",
+ name.c_str(), fields[name].c_str());
- ts += ", (currval('trseq'), '" + W.esc(name) + "', '" + W.esc(fields[name]) + "')";
+ ts += ", (currval('trseq'), '" + W->esc(name) + "', '" +
+ W->esc(fields[name]) + "')";
ri++;
}
+ ts += ";";
PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str());
- W.exec(ts);
+ W->exec(ts);
+ statements += ts + "\n";
+
}
}
- W.commit();
+ // W->commit();
} catch(std::exception &e) {
PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str());
}
@@ -156,9 +192,15 @@ void PracroDAOPgsql::commitTransaction(std::string user, std::string patientid,
* AND tt.uid = ff.transaction
* AND tt.patientid = '1505050505'
*/
-Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest)
+Values PracroDAOPgsql::getLatestValues(std::string patientid,
+ Macro *macro,
+ Fieldnames &fieldnames,
+ time_t oldest)
{
- PRACRO_DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n", patientid.c_str(), macro ? macro->attributes["name"].c_str() : "(null)", fieldnames.size(), oldest);
+ PRACRO_DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n",
+ patientid.c_str(),
+ macro ? macro->attributes["name"].c_str() : "(null)",
+ fieldnames.size(), oldest);
if(!conn) PRACRO_DEBUG(db, "No pgsql connection\n");
Values values;
@@ -167,13 +209,12 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel
try {
std::string namecond;
- pqxx::work W(*conn);
if(fieldnames.size() > 0) {
std::vector< std::string >::iterator i = fieldnames.begin();
- namecond += " AND f.name IN ('" + W.esc(*i) + "'";
+ namecond += " AND f.name IN ('" + W->esc(*i) + "'";
i++;
while(i != fieldnames.end()) {
- namecond += ", '" + W.esc(*i) + "'";
+ namecond += ", '" + W->esc(*i) + "'";
i++;
}
namecond += ')';
@@ -182,7 +223,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel
// Begin inner query
" (SELECT f.name, MAX(t.timestamp) AS ts FROM fields f, transactions t "
" WHERE t.uid = f.transaction AND t.timestamp >= " + soldest.str() +
- " AND t.patientid = '" + W.esc(patientid) + "' "
+ " AND t.patientid = '" + W->esc(patientid) + "' "
+ namecond;
if(macro) {
query += " AND t.macro = '" + macro->attributes["name"] + "'";
@@ -195,7 +236,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel
" WHERE xx.ts = tt.timestamp "
" AND xx.name = ff.name "
" AND tt.uid = ff.transaction "
- " AND tt.patientid = '" + W.esc(patientid) + "' "
+ " AND tt.patientid = '" + W->esc(patientid) + "' "
;
if(macro) {
query += " AND tt.macro = '" + macro->attributes["name"] + "'";
@@ -204,7 +245,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel
}
PRACRO_DEBUG(sql, "Query: %s\n", query.c_str());
- pqxx::result R = W.exec(query);
+ pqxx::result R = W->exec(query);
pqxx::result::const_iterator ri = R.begin();
while(ri != R.end()) {
Value v;
@@ -221,25 +262,27 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel
}
-unsigned PracroDAOPgsql::nrOfCommits(std::string patientid, std::string macroname, time_t oldest)
+unsigned PracroDAOPgsql::nrOfCommits(std::string patientid,
+ std::string macroname,
+ time_t oldest)
{
std::string query;
std::stringstream soldest; soldest << oldest;
try {
- pqxx::work W(*conn);
query = "SELECT count(*) FROM transactions "
- " WHERE patientid = '" + W.esc(patientid) + "' "
- " AND macro = '" + W.esc(macroname) + "' "
+ " WHERE patientid = '" + W->esc(patientid) + "' "
+ " AND macro = '" + W->esc(macroname) + "' "
" AND timestamp >= " + soldest.str()
;
PRACRO_DEBUG(sql, "Query: %s\n", query.c_str());
- pqxx::result R = W.exec(query);
+ pqxx::result R = W->exec(query);
if(R.size() != 1) {
PRACRO_ERR_LOG(db, "No result set; expected one row with one column\n");
return 0;
}
unsigned n = (unsigned)atol((*R.begin())[0].c_str());
- PRACRO_DEBUG(db, "Found %u commits for %s(%s) from %ld\n", n, patientid.c_str(), macroname.c_str(), oldest);
+ PRACRO_DEBUG(db, "Found %u commits for %s(%s) from %ld\n",
+ n, patientid.c_str(), macroname.c_str(), oldest);
return n;
} catch (std::exception &e) {
PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str());
@@ -253,16 +296,15 @@ void PracroDAOPgsql::addFieldname(std::string name, std::string description)
std::stringstream timestamp; timestamp << time(NULL);
std::string ts;
try {
- pqxx::work W(*conn);
ts = "INSERT INTO fieldnames (name, description, \"timestamp\") VALUES ("
- " '" + W.esc(name) + "', "
- " '" + W.esc(description) + "', "
- " '" + W.esc(timestamp.str()) + "' "
+ " '" + W->esc(name) + "', "
+ " '" + W->esc(description) + "', "
+ " '" + W->esc(timestamp.str()) + "' "
")"
;
PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str());
- pqxx::result R = W.exec(ts);
- W.commit();
+ pqxx::result R = W->exec(ts);
+ W->commit();
} catch (std::exception &e) {
PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str());
}
@@ -272,12 +314,11 @@ void PracroDAOPgsql::delFieldname(std::string name)
{
std::string ts;
try {
- pqxx::work W(*conn);
ts = "DELETE FROM fieldnames WHERE name="
- "'" + W.esc(name) + "' ";
+ "'" + W->esc(name) + "' ";
PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str());
- pqxx::result R = W.exec(ts);
- W.commit();
+ pqxx::result R = W->exec(ts);
+ W->commit();
} catch (std::exception &e) {
PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str());
}
@@ -290,10 +331,9 @@ std::vector<Fieldname> PracroDAOPgsql::getFieldnames()
std::string query;
try {
- pqxx::work W(*conn);
query = "SELECT * FROM fieldnames";
PRACRO_DEBUG(sql, "Query: %s\n", query.c_str());
- pqxx::result R = W.exec(query);
+ pqxx::result R = W->exec(query);
pqxx::result::const_iterator ri = R.begin();
while(ri != R.end()) {
Fieldname f;
@@ -310,6 +350,45 @@ std::vector<Fieldname> PracroDAOPgsql::getFieldnames()
return fieldnames;
}
+void PracroDAOPgsql::commit()
+{
+ std::string ts;
+ try {
+ W->commit();
+ statements = "";
+ } catch (std::exception &e) {
+ PRACRO_ERR_LOG(db, "Commit failed: %s: %s\n", e.what(), ts.c_str());
+ }
+}
+
+void PracroDAOPgsql::discard()
+{
+ std::string ts;
+ try {
+ W->abort();
+ statements = "";
+ } catch (std::exception &e) {
+ PRACRO_ERR_LOG(db, "Abort (rollback) failed: %s: %s\n",
+ e.what(), ts.c_str());
+ }
+}
+
+std::string PracroDAOPgsql::serialise()
+{
+ return statements;
+}
+
+void PracroDAOPgsql::restore(const std::string &data)
+{
+ std::string ts;
+ try {
+ PRACRO_DEBUG(sql, "Restore: %s\n", data.c_str());
+ pqxx::result R = W->exec(data);
+ statements = data;
+ } catch( ... ) {
+ }
+}
+
#endif/*WITHOUT_DB*/
#ifdef TEST_PRACRODAOPGSQL
@@ -321,7 +400,8 @@ int main()
{
#ifndef WITHOUT_DB
try {
- PracroDAOPgsql db(Conf::database_addr, "", Conf::database_user, Conf::database_passwd, "");
+ PracroDAOPgsql db(Conf::database_addr, "", Conf::database_user,
+ Conf::database_passwd, "");
} catch(Exception &e) {
printf("ERROR: %s\n", e.what());
return 1;
diff --git a/server/src/pracrodaopgsql.h b/server/src/pracrodaopgsql.h
index b226cfd..b3e0c86 100644
--- a/server/src/pracrodaopgsql.h
+++ b/server/src/pracrodaopgsql.h
@@ -32,25 +32,45 @@
#ifndef WITHOUT_DB
-#include "pracrodao.h"
+#include <string>
#include <pqxx/pqxx>
+#include "pracrodao.h"
+
class PracroDAOPgsql : public PracroDAO
{
public:
- PracroDAOPgsql(std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname);
+ PracroDAOPgsql(std::string _host, std::string _port,
+ std::string _user, std::string _passwd, std::string _dbname);
~PracroDAOPgsql();
- void commitTransaction(std::string user, std::string patientid, Macro &macro, Fields &fields, time_t now);
- Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest);
- unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest);
+ void commitTransaction(std::string user,
+ std::string patientid,
+ Macro &macro,
+ Fields &fields,
+ time_t now);
+ Values getLatestValues(std::string patientid,
+ Macro *macro,
+ Fieldnames &fieldnames,
+ time_t oldest);
+ unsigned nrOfCommits(std::string patientid,
+ std::string macroname,
+ time_t oldest);
void addFieldname(std::string name, std::string description);
void delFieldname(std::string name);
std::vector<Fieldname> getFieldnames();
+ void commit();
+ void discard();
+ std::string serialise();
+ void restore(const std::string &data);
+
private:
pqxx::connection *conn;
+ pqxx::work *W;
+
+ std::string statements;
};
#endif/*WITHOUT_DB*/
diff --git a/server/src/pracrodaotest.h b/server/src/pracrodaotest.h
index 8dd4655..9278b3f 100644
--- a/server/src/pracrodaotest.h
+++ b/server/src/pracrodaotest.h
@@ -77,14 +77,28 @@ public:
PracroDAOTest(Data &data, bool ignore_fieldnames = false);
~PracroDAOTest();
- void commitTransaction(std::string user, std::string patientid, Macro &macro, Fields &fields, time_t now);
- Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest);
- unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest);
+ void commitTransaction(std::string user,
+ std::string patientid,
+ Macro &macro,
+ Fields &fields,
+ time_t now);
+ Values getLatestValues(std::string patientid,
+ Macro *macro,
+ Fieldnames &fieldnames,
+ time_t oldest);
+ unsigned nrOfCommits(std::string patientid,
+ std::string macroname,
+ time_t oldest);
void addFieldname(std::string name, std::string description);
void delFieldname(std::string name);
std::vector<Fieldname> getFieldnames();
+ void commit() {}
+ void discard() {}
+ std::string serialise() { return ""; }
+ void restore(const std::string &data) {}
+
private:
Data data;
bool ignore_fieldnames;
diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc
index f26c965..6861fab 100644
--- a/server/src/saxparser.cc
+++ b/server/src/saxparser.cc
@@ -79,6 +79,7 @@ SAXParser::SAXParser()
return;
}
+ // XML_SetEncoding(p, "UTF-8");
XML_SetUserData(p, this);
XML_UseParserAsHandlerArg(p);
XML_SetElementHandler(p, start_hndl, end_hndl);
diff --git a/server/src/session.cc b/server/src/session.cc
index 803a515..e53565b 100644
--- a/server/src/session.cc
+++ b/server/src/session.cc
@@ -36,6 +36,7 @@
#include <errno.h>
#include "journalwriter.h"
+#include "database.h"
#include "configuration.h"
#include "connectionpool.h"
#include "sessionserialiser.h"
@@ -44,11 +45,13 @@ Session::Session(std::string sessionid)
{
_id = sessionid;
_journal = NULL;
+ _database = NULL;
}
Session::~Session()
{
if(_journal) delete _journal;
+ if(_database) delete _database;
}
std::string Session::id()
@@ -73,6 +76,11 @@ void Session::commit()
delete _journal;
_journal = NULL;
}
+ if(_database != NULL) {
+ _database->commit();
+ delete _database;
+ _database = NULL;
+ }
}
void Session::discard()
@@ -81,6 +89,11 @@ void Session::discard()
delete _journal;
_journal = NULL;
}
+ if(_database != NULL) {
+ _database->discard();
+ delete _database;
+ _database = NULL;
+ }
}
JournalWriter *Session::journal()
@@ -92,6 +105,16 @@ JournalWriter *Session::journal()
return _journal;
}
+Database *Session::database()
+{
+ if(_database == NULL) {
+ _database =
+ new Database(Conf::database_backend, Conf::database_addr, "",
+ Conf::database_user, Conf::database_passwd, "");
+ }
+ return _database;
+}
+
Sessions::Sessions()
{
}
diff --git a/server/src/session.h b/server/src/session.h
index 6c614c7..cd13aa8 100644
--- a/server/src/session.h
+++ b/server/src/session.h
@@ -33,6 +33,7 @@
#include "mutex.h"
+class Database;
class JournalWriter;
class Session {
@@ -49,9 +50,11 @@ public:
void discard();
JournalWriter *journal();
+ Database *database();
private:
JournalWriter *_journal;
+ Database *_database;
std::string _id;
Mutex mutex;
};
diff --git a/server/src/sessionparser.cc b/server/src/sessionparser.cc
index ba3693d..0edb26a 100644
--- a/server/src/sessionparser.cc
+++ b/server/src/sessionparser.cc
@@ -34,6 +34,7 @@ SessionParser::SessionParser()
done = false;
totalbytes = 0;
inresume = false;
+ indatabase = false;
}
SessionParser::~SessionParser()
@@ -45,6 +46,10 @@ void SessionParser::characterData(std::string &data)
if(inresume) {
entries[entries.size()-1].resume += data;
}
+
+ if(indatabase) {
+ database += data;
+ }
}
void SessionParser::startTag(std::string name,
@@ -61,6 +66,11 @@ void SessionParser::startTag(std::string name,
userid = attributes["userid"];
}
+ if(name == "database") {
+ dbtype = attributes["type"];
+ indatabase = true;
+ }
+
if(name == "entry") {
Entry e;
e.index = atoi(attributes["index"].c_str());
@@ -78,6 +88,9 @@ void SessionParser::endTag(std::string name)
if(name == "resume") {
inresume = false;
}
+ if(name == "database") {
+ indatabase = false;
+ }
}
void SessionParser::parseError(const char *buf, size_t len,
@@ -87,11 +100,13 @@ void SessionParser::parseError(const char *buf, size_t len,
lineno, error.c_str());
std::string xml;
- xml.append(buf, len);
+ if(buf && len) xml.append(buf, len);
PRACRO_ERR(sessionparser, "\tBuffer %u bytes: [%s]\n",
len, xml.c_str());
+ fflush(stderr);
+
throw std::exception();
}
diff --git a/server/src/sessionparser.h b/server/src/sessionparser.h
index 37899aa..f364a28 100644
--- a/server/src/sessionparser.h
+++ b/server/src/sessionparser.h
@@ -47,6 +47,8 @@ public:
std::string sessionid;
std::string patientid;
std::string userid;
+ std::string database;
+ std::string dbtype;
class Entry {
public:
@@ -59,6 +61,7 @@ public:
private:
bool inresume;
+ bool indatabase;
};
#endif/*__PRACRO_SESSIONPARSER_H__*/
diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc
index 10d449d..2c35d2a 100644
--- a/server/src/sessionserialiser.cc
+++ b/server/src/sessionserialiser.cc
@@ -30,6 +30,9 @@
#include "journalwriter.h"
#include "sessionparser.h"
+#include "database.h"
+
+#include "xml_encode_decode.h"
#include <stdio.h>
#include <string.h>
@@ -54,19 +57,25 @@ SessionSerialiser::SessionSerialiser(std::string path, Session *session)
this->path = path;
}
+#define XENC(s) xml_encode(s)
+#define XDEC(s) xml_decode(s)
+
void SessionSerialiser::loadStr(const std::string &xml)
{
// SessionAutolock lock(*session);
SessionParser parser;
parser.parse(xml.data(), xml.length());
+
JournalWriter *j = session->journal();
- j->currentuser = parser.userid;
- j->currentcpr = parser.patientid;
+ j->currentuser = XDEC(parser.userid);
+ j->currentcpr = XDEC(parser.patientid);
std::vector<SessionParser::Entry>::iterator i = parser.entries.begin();
while(i != parser.entries.end()) {
- j->addEntry(i->resume, i->macro, i->index);
+ j->addEntry(XDEC(i->resume), xml_decode(i->macro), i->index);
i++;
}
+
+ session->database()->restore(XDEC(parser.database));
}
std::string SessionSerialiser::saveStr()
@@ -81,8 +90,8 @@ std::string SessionSerialiser::saveStr()
JournalWriter *journal = session->journal();
- xml += " <journal patientid=\"" + journal->currentcpr +
- "\" userid=\"" + journal->currentuser + "\">\n";
+ xml += " <journal patientid=\"" + XENC(journal->currentcpr) +
+ "\" userid=\"" + XENC(journal->currentuser) + "\">\n";
std::map< int, JournalWriter::ResumeEntry >::iterator i =
journal->entrylist.begin();
@@ -90,13 +99,19 @@ std::string SessionSerialiser::saveStr()
xml += " <entry index=\""+itostr(i->first) + "\""
" macro=\"" + i->second.macro + "\">\n";
- xml += " <resume>" + i->second.resume + "</resume>\n";
+ xml += " <resume>" + XENC(i->second.resume) + "</resume>\n";
xml += " </entry>\n";
i++;
}
xml += " </journal>\n";
+
+ std::string dbtype = "pgsql";
+ xml += " <database type=\""+dbtype+"\">"+
+ XENC(session->database()->serialise())+
+ "</database>\n";
+
xml += "</session>\n";
return xml;
diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc
index c9c58b6..1658713 100644
--- a/server/src/transactionhandler.cc
+++ b/server/src/transactionhandler.cc
@@ -54,8 +54,9 @@ static std::string handleCommits(Transaction &transaction, Environment &env,
std::string answer;
if(transaction.commits.size() > 0) {
- AutoBorrower<Database*> borrower(env.dbpool);
- Database *db = borrower.get();
+ // AutoBorrower<Database*> borrower(env.dbpool);
+ // Database *db = borrower.get();
+ Database *db = session.database();
Commits::iterator i = transaction.commits.begin();
while(i != transaction.commits.end()) {
@@ -93,8 +94,9 @@ static std::string handleRequest(Transaction &transaction, Environment &env,
if(transaction.requests.size() > 0) {
- AutoBorrower<Database*> borrower(env.dbpool);
- Database *db = borrower.get();
+ // AutoBorrower<Database*> borrower(env.dbpool);
+ // Database *db = borrower.get();
+ Database *db = session.database();
Requests::iterator i = transaction.requests.begin();
while(i != transaction.requests.end()) {
@@ -218,10 +220,25 @@ static std::string handleRequest(Transaction &transaction, Environment &env,
}
if(completed) {
- answer += " <resume>";
- answer += xml_encode(db->getResume(transaction.cpr,
+ std::string jresume =
+ session.journal()->getEntry(macro.attributes["name"]);
+
+ std::string state = "old";
+ std::string resume = db->getResume(transaction.cpr,
macro,
- time(NULL) - Conf::db_max_ttl));
+ time(NULL) - Conf::db_max_ttl);
+
+ if(resume == jresume) state = "new";
+
+ if(jresume != "" && resume != jresume) {
+ state = "dirty";
+ session.journal()->removeEntry(macro.attributes["name"]);
+ }
+
+ if(jresume == "" && resume != jresume) state = "old";
+
+ answer += " <resume state=\""+state+"\">";
+ answer += xml_encode(resume);
answer += "</resume>\n";
}
diff --git a/server/src/xml_encode_decode.cc b/server/src/xml_encode_decode.cc
index 5ed61f2..427e451 100644
--- a/server/src/xml_encode_decode.cc
+++ b/server/src/xml_encode_decode.cc
@@ -26,7 +26,7 @@
*/
#include "xml_encode_decode.h"
#include <string.h>
-
+/*
char xml_map[][2][16] =
{
{ "&", "&amp;" }, // & must be first
@@ -36,6 +36,17 @@ char xml_map[][2][16] =
{ "<", "&lt;" },
{ "", "" } // End marker
};
+*/
+
+char xml_map[][2][16] =
+ {
+ { "&", "&#38;" }, // & must be first
+ { "\'", "&#39;" },
+ { "\"", "&#34;" },
+ { ">", "&#62;" },
+ { "<", "&#60;" },
+ { "", "" } // End marker
+ };
#define MAX_MAPS 5