From a3cb015e6b69821062306981924a43a5487f3b5d Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 24 Sep 2007 12:47:16 +0000 Subject: Server now parses XML and handles include. --- server/src/Makefile.am | 3 + server/src/database.cc | 20 +++--- server/src/macro.h | 58 ++++++++++++++++ server/src/macro_parser.cc | 170 +++++++++++++++++++++++++++++++++++++++++++++ server/src/macro_parser.h | 36 ++++++++++ server/src/server.cc | 76 ++++++++------------ server/src/transaction.h | 2 +- server/src/xmlparser.cc | 8 +-- server/xml/Makefile.am | 6 +- server/xml/example.xml | 56 ++++++++------- server/xml/patient.xml | 10 +++ 11 files changed, 354 insertions(+), 91 deletions(-) create mode 100644 server/src/macro.h create mode 100644 server/src/macro_parser.cc create mode 100644 server/src/macro_parser.h create mode 100644 server/xml/patient.xml diff --git a/server/src/Makefile.am b/server/src/Makefile.am index ac5ed0a..43fa560 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -11,6 +11,7 @@ pracrod_SOURCES = \ configuration.cc \ exception.cc \ log.cc \ + macro_parser.cc \ server.cc \ tcpsocket.cc \ tostring.cc \ @@ -23,6 +24,8 @@ EXTRA_DIST = \ debug.h \ exception.h \ log.h \ + macro.h \ + macro_parser.h \ server.h \ tcpsocket.h \ tostring.h \ diff --git a/server/src/database.cc b/server/src/database.cc index 1d4915e..1a48925 100644 --- a/server/src/database.cc +++ b/server/src/database.cc @@ -62,7 +62,7 @@ int Database::post(Transaction &transaction) commit.macro + "', '" + commit.version + "', '" + now + "', '" + - commit.user + "')"; + transaction.user + "')"; W.exec(sql); // Insert field entries @@ -124,21 +124,21 @@ CREATE DATABASE pracro CREATE TABLE transactions ( - "cpr" varchar(255), - "transaction" varchar(255), - "makro" varchar(255), - "version" varchar(255), - "timestamp" varchar(255), - "user" varchar(255) + "cpr" varchar(11), + "transaction" text, + "makro" text, + "version" text, + "timestamp" bigint, + "user" text ) WITH OIDS; ALTER TABLE transactions OWNER TO pracro; CREATE TABLE fields ( - "transaction" varchar(255), - "name" varchar(255), - "value" varchar(255) + "transaction" text, + "name" text, + "value" text ) WITH OIDS; ALTER TABLE fields OWNER TO pracro; diff --git a/server/src/macro.h b/server/src/macro.h new file mode 100644 index 0000000..af9749d --- /dev/null +++ b/server/src/macro.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * macro.h + * + * Mon Sep 24 10:51:43 CEST 2007 + * Copyright 2007 Bent Bisballe Nyeng, Lars Bisballe Jensen and Peter Skaarup + * deva@aasimon.org, elsenator@gmail.com and piparum@piparum.dk + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_MACRO_H__ +#define __PRACRO_MACRO_H__ + +#include +#include + +class WidgetProperty { +public: + std::string name; + std::string value; +}; +typedef std::vector< WidgetProperty > WidgetPropertyList; + +class Widget; +typedef std::vector< Widget > WidgetList; + +class Widget { +public: + std::string type; + WidgetPropertyList properties; + WidgetList widgets; +}; + +class Macro { +public: + std::string name; + std::string version; + + WidgetList widgets; +}; + +#endif/*__PRACRO_MACRO_H__*/ diff --git a/server/src/macro_parser.cc b/server/src/macro_parser.cc new file mode 100644 index 0000000..c317482 --- /dev/null +++ b/server/src/macro_parser.cc @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * macro_parser.cc + * + * Mon Sep 24 10:49:55 CEST 2007 + * Copyright 2007 Bent Bisballe Nyeng, Lars Bisballe Jensen and Peter Skaarup + * deva@aasimon.org, elsenator@gmail.com and piparum@piparum.dk + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "macro_parser.h" + +// For XML +#include + +// For open, read and close +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +class MacroParser { +public: + Macro *macro; + std::vector< Widget* > stack; + bool done; +}; + +static void start_hndl(void *p, const char *el, const char **attr) +{ + MacroParser *parser = (MacroParser*)XML_GetUserData(p); + + printf("Start tag [%s]\n", el); + + // Convert to comfy C++ values... + std::string name = el; + std::map< std::string, std::string > attributes; + + while(*attr) { + std::string at_name = *attr; + attr++; + std::string at_value = *attr; + attr++; + + attributes.insert(make_pair(at_name, at_value)); + } + + // Do something reasonable with them... + + if(name == "include") { + + Macro inc; + parse_macro(attributes["name"], inc); + + WidgetList::iterator w = inc.widgets.front().widgets.begin(); + while(w != inc.widgets.front().widgets.end()) { + parser->stack.back()->widgets.push_back(*w); + w++; + } + + return; // Don't do further parsing of this tag. + } + + Widget widget; + widget.type = name; + + Widget *wp; + + if(parser->stack.size() > 0) {// We only pushback the child if there is a parent. + parser->stack.back()->widgets.push_back(widget); + wp = &parser->stack.back()->widgets.back(); + } else { + parser->macro->widgets.push_back(widget); + wp = &parser->macro->widgets.back(); + } + parser->stack.push_back(wp); + + std::map< std::string, std::string >::iterator i = attributes.begin(); + while(i != attributes.end()) { + WidgetProperty prop; + prop.name = i->first; + prop.value = i->second; + + wp->properties.push_back(prop); + + i++; + } +} + +static void end_hndl(void *p, const char *el) +{ + MacroParser *parser = (MacroParser*)XML_GetUserData(p); + + printf("End tag [%s]\n", el); + + if(std::string("include") != el) parser->stack.pop_back(); + + if(!strcmp(el, "macro")) parser->done = true; +} + +void parse_macro(std::string name, Macro ¯o) +{ + + XML_Parser p = XML_ParserCreate(NULL); + if (! p) { + fprintf(stderr, "Couldn't allocate memory for parser\n"); + // throw Exception(...); + return; + } + + MacroParser parser; + parser.macro = ¯o; + parser.done = false; + + XML_SetUserData(p, &parser); + XML_UseParserAsHandlerArg(p); + XML_SetElementHandler(p, start_hndl, end_hndl); + + std::string macrofile = std::string(XML) + "/" + name + ".xml"; + int fd = open(macrofile.c_str(), O_RDONLY); + + if(fd == -1) { + printf("Cannot open file \"%s\"...", macrofile.c_str()); + printf("failed!\n"); + return; + } + + while(!parser.done) { + char buf[32]; + int len; + + memset(buf, 0, sizeof(buf)); + len = read(fd, buf, sizeof(buf) - 1); + + parser.done = len == 0; + + if (! XML_Parse(p, buf, len, parser.done)) { + fprintf(stderr, "Parse error at line %d:\n%s\n", + XML_GetCurrentLineNumber(p), + XML_ErrorString(XML_GetErrorCode(p))); + // throw Exception(...); + return; + } + } + + // printf("%d requests\n", transaction.requests.size()); +} diff --git a/server/src/macro_parser.h b/server/src/macro_parser.h new file mode 100644 index 0000000..9f701d4 --- /dev/null +++ b/server/src/macro_parser.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * macro_parser.h + * + * Mon Sep 24 10:49:55 CEST 2007 + * Copyright 2007 Bent Bisballe Nyeng, Lars Bisballe Jensen and Peter Skaarup + * deva@aasimon.org, elsenator@gmail.com and piparum@piparum.dk + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_MACRO_PARSER_H__ +#define __PRACRO_MACRO_PARSER_H__ + +#include + +#include "macro.h" + +void parse_macro(std::string name, Macro ¯o); + +#endif/*__PRACRO_MACRO_PARSER_H__*/ diff --git a/server/src/server.cc b/server/src/server.cc index 24f55ef..064d8b9 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -26,9 +26,6 @@ */ #include "server.h" -// For XML -#include - #include "tcpsocket.h" #include @@ -40,40 +37,33 @@ #include "configuration.h" -// For open, read and close -#include -#include -#include -#include - #include "transaction.h" #include "xmlparser.h" #include "database.h" -/** -\section{Data transmission} -En transmission består af en række deltransmissioner som afhænger af -brugerens handling. -\begin{itemize} -\item Klienten beder om en XMLMakro by-name. -\item Serveren genererer makroen og sender den til klienten i en XML - stream. Forbindelsen lukkes efter end overførsel. -\item Brugeren udfylder input felterne og trykker på ``commit'' eller - ``abort'' knappen. -\item Hvis der blev trykket ``abort'' lukkes vinduet. -\item Hvis der blev trykket ``commit'' genereres et XML dokument på - klienten indeholdene alle input felternes navne og deres tilhørende - værdier. -\item Dette XML dokument sendes til serveren via en nyoprettet forbindelse. -\item Serveren producerer en plaintext klump som repræsenterer -\item Teksten sendes til klienten som appender til den PC-Praxis - journalfilen. -\item Klienten svarer til serveren at alt gik godt (eller det modsatte) og - makrovinduet lukkes. -\item Serveren lagrer dataene i en database hvis det gik godt. -\end{itemize} -*/ +#include "macro.h" +#include "macro_parser.h" + +static void send_macro_widget(Widget &widget, TCPSocket &socket, std::string tabs) +{ + socket.write(tabs + "<" + widget.type); + WidgetPropertyList::iterator p = widget.properties.begin(); + while(p != widget.properties.end()) { + WidgetProperty &property = *p; + socket.write(" " + property.name + "=\"" + property.value + "\""); + p++; + } + socket.write(">\n"); + + WidgetList::iterator w = widget.widgets.begin(); + while(w != widget.widgets.end()) { + send_macro_widget(*w, socket, tabs + " "); + w++; + } + socket.write(tabs + "\n"); +} + static void connection(TCPSocket &socket) { printf("Got connection...\n"); @@ -91,24 +81,14 @@ static void connection(TCPSocket &socket) printf("Handling request for \"%s\"...", request.macro.c_str()); - // Now handle the request. - char outbuf[3]; - int bytes; - - std::string macro = std::string(XML) + "/" + request.macro + ".xml"; - - int fd = open(macro.c_str(), O_RDONLY); - if(fd == -1) { - printf("Cannot open file \"%s\"...", macro.c_str()); - printf("failed!\n"); - i++; - continue; - } + Macro macro; + parse_macro(request.macro, macro); - while((bytes = read(fd, outbuf, sizeof(outbuf))) ) { - socket.write(outbuf, bytes); + WidgetList::iterator w = macro.widgets.begin(); + while(w != macro.widgets.end()) { + send_macro_widget(*w, socket, " "); + w++; } - close(fd); printf("done.\n"); diff --git a/server/src/transaction.h b/server/src/transaction.h index 04d83b3..97bb556 100644 --- a/server/src/transaction.h +++ b/server/src/transaction.h @@ -48,7 +48,6 @@ typedef std::vector< Field > Fields; class Commit { public: - std::string user; std::string macro; std::string version; Fields fields; @@ -58,6 +57,7 @@ typedef std::vector< Commit > Commits; class Transaction { public: + std::string user; std::string cpr; std::string version; diff --git a/server/src/xmlparser.cc b/server/src/xmlparser.cc index d4a6bd8..31ffbed 100644 --- a/server/src/xmlparser.cc +++ b/server/src/xmlparser.cc @@ -33,9 +33,9 @@ #include #include -bool done = false; +static bool done = false; -void start_hndl(void *p, const char *el, const char **attr) +static void start_hndl(void *p, const char *el, const char **attr) { Transaction *transaction = (Transaction*)XML_GetUserData(p); @@ -63,6 +63,7 @@ void start_hndl(void *p, const char *el, const char **attr) // Do something reasonable with them... if(name == "pracro") { + transaction->user = attributes["user"]; transaction->cpr = attributes["cpr"]; transaction->version = attributes["version"]; } @@ -75,7 +76,6 @@ void start_hndl(void *p, const char *el, const char **attr) if(name == "commit") { Commit c; - c.user = attributes["user"]; c.macro = attributes["macro"]; c.version = attributes["version"]; transaction->commits.push_back(c); @@ -90,7 +90,7 @@ void start_hndl(void *p, const char *el, const char **attr) } -void end_hndl(void *p, const char *el) +static void end_hndl(void *p, const char *el) { // printf("End tag [%s]\n", el); if(!strcmp(el, "pracro")) done = true; diff --git a/server/xml/Makefile.am b/server/xml/Makefile.am index 3ad491e..0e86339 100644 --- a/server/xml/Makefile.am +++ b/server/xml/Makefile.am @@ -1,7 +1,9 @@ EXTRA_DIST = \ - example.xml + example.xml \ + patient.xml xmldir = $(datadir)/xml xml_DATA = \ - example.xml + example.xml \ + patient.xml diff --git a/server/xml/example.xml b/server/xml/example.xml index 3e31f56..60068ca 100644 --- a/server/xml/example.xml +++ b/server/xml/example.xml @@ -1,27 +1,31 @@ - - - - - + + + + + + + + + + + + +