diff options
Diffstat (limited to 'server')
| -rw-r--r-- | server/configure.in | 2 | ||||
| -rw-r--r-- | server/src/database.h | 55 | ||||
| -rw-r--r-- | server/src/environment.cc | 6 | ||||
| -rw-r--r-- | server/src/environment.h | 4 | ||||
| -rw-r--r-- | server/src/journalwriter.cc | 27 | ||||
| -rw-r--r-- | server/src/journalwriter.h | 3 | ||||
| -rw-r--r-- | server/src/pracrodao.h | 26 | ||||
| -rw-r--r-- | server/src/pracrodaopgsql.cc | 184 | ||||
| -rw-r--r-- | server/src/pracrodaopgsql.h | 30 | ||||
| -rw-r--r-- | server/src/pracrodaotest.h | 20 | ||||
| -rw-r--r-- | server/src/saxparser.cc | 1 | ||||
| -rw-r--r-- | server/src/session.cc | 23 | ||||
| -rw-r--r-- | server/src/session.h | 3 | ||||
| -rw-r--r-- | server/src/sessionparser.cc | 17 | ||||
| -rw-r--r-- | server/src/sessionparser.h | 3 | ||||
| -rw-r--r-- | server/src/sessionserialiser.cc | 27 | ||||
| -rw-r--r-- | server/src/transactionhandler.cc | 31 | ||||
| -rw-r--r-- | server/src/xml_encode_decode.cc | 13 | 
18 files changed, 380 insertions, 95 deletions
| 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 ¯o, Fields &fields, time_t now = time(NULL)) { +  void commitTransaction(std::string user, +                         std::string patientid, +                         Macro ¯o, +                         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 ¯o, 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 ¯o, 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 ¯o, +                                 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 ¯o, 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 ¯o, +                         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 ¯o, 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 ¯o, +                         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] =    {      { "&", "&" }, // & must be first @@ -36,6 +36,17 @@ char xml_map[][2][16] =      { "<", "<" },      { "", "" } // End marker    }; +*/ + +char xml_map[][2][16] = +  { +    { "&", "&" }, // & must be first +    { "\'", "'" }, +    { "\"", """ }, +    { ">", ">" }, +    { "<", "<" }, +    { "", "" } // End marker +  };  #define MAX_MAPS 5 | 
