[dss-commits] digitalSTROM Server branch, master, updated. eb7d1b50ef45d83196ccad9c9c71ed2520decf62

git version control dss-commits at forum.digitalstrom.org
Thu Jan 7 19:34:10 CET 2010


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "digitalSTROM Server".

The branch, master has been updated
       via  eb7d1b50ef45d83196ccad9c9c71ed2520decf62 (commit)
       via  a978e19b762eba31f751f5d963a26c5ff42d830b (commit)
      from  29ef16581b96daf7b10ceee0231b2f19c23d1acf (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit eb7d1b50ef45d83196ccad9c9c71ed2520decf62
Merge: a978e19b762eba31f751f5d963a26c5ff42d830b 29ef16581b96daf7b10ceee0231b2f19c23d1acf
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 7 19:34:02 2010 +0100

    Merge branch 'master' of ssh://developer.digitalstrom.org/home/git/sources/dss

commit a978e19b762eba31f751f5d963a26c5ff42d830b
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 7 19:31:10 2010 +0100

    More work on webserver
    
    Pass results through JSON objects
    * Every call returns {ok:true/false} now
    * Some responses have changed
    
    I've fixed model.js to restore basic functionality buy the setup
    interface might still be broken.

-----------------------------------------------------------------------

Changes:
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 0454d5a..72df81f 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -9,8 +9,12 @@ add_library(core ${files} scripting/modeljs.cpp sim/dssim.cpp sim/dsidsim.cpp
 sim/dsid_js.cpp sim/dsid_plugin.cpp web/webserverapi.cpp web/webrequests.cpp 
 metering/metering.cpp metering/series.cpp metering/seriespersistence.cpp
 metering/fake_meter.cpp vfs/vfs.cpp web/restful.cpp web/restfulapiwriter.cpp
-web/webserverplugin.cpp web/webserver.cpp)
+web/webserverplugin.cpp web/webserver.cpp web/json.cpp
+web/handler/debugrequesthandler.cpp web/handler/simrequesthandler.cpp
+web/handler/systemrequesthandler.cpp web/handler/meteringrequesthandler.cpp
+web/handler/structurerequesthandler.cpp web/handler/eventrequesthandler.cpp
+web/handler/propertyrequesthandler.cpp)
 
 
 add_subdirectory(ds485)
-add_subdirectory(model)
\ No newline at end of file
+add_subdirectory(model)
diff --git a/core/model/devicereference.cpp b/core/model/devicereference.cpp
index 22ac410..6bf7436 100644
--- a/core/model/devicereference.cpp
+++ b/core/model/devicereference.cpp
@@ -59,6 +59,10 @@ namespace dss {
     return m_DSID;
   } // getID
 
+  int DeviceReference::getFunctionID() const {
+    return getDevice().getFunctionID();
+  } // getFunctionID
+
   std::string DeviceReference::getName() const {
     return getDevice().getName();
   } //getName
diff --git a/core/web/handler/debugrequesthandler.cpp b/core/web/handler/debugrequesthandler.cpp
new file mode 100644
index 0000000..6774c63
--- /dev/null
+++ b/core/web/handler/debugrequesthandler.cpp
@@ -0,0 +1,198 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "debugrequesthandler.h"
+
+#include "core/web/json.h"
+
+#include "core/ds485/ds485.h"
+#include "core/ds485/ds485proxy.h"
+#include "core/ds485/framebucketcollector.h"
+
+#include "core/dss.h"
+#include "core/ds485const.h"
+
+#include "core/model/apartment.h"
+#include "core/model/device.h"
+
+
+namespace dss {
+
+
+  //=========================================== DebugRequestHandler
+
+  boost::shared_ptr<JSONObject> DebugRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    if(_request.getMethod() == "sendFrame") {
+      int destination = strToIntDef(_request.getParameter("destination"),0) & 0x3F;
+      bool broadcast = _request.getParameter("broadcast") == "true";
+      int counter = strToIntDef(_request.getParameter("counter"), 0x00) & 0x03;
+      int command = strToIntDef(_request.getParameter("command"), 0x09 /* request */) & 0x00FF;
+      int length = strToIntDef(_request.getParameter("length"), 0x00) & 0x0F;
+
+      std::cout
+          << "sending frame: "
+          << "\ndest:    " << destination
+          << "\nbcst:    " << broadcast
+          << "\ncntr:    " << counter
+          << "\ncmd :    " << command
+          << "\nlen :    " << length << std::endl;
+
+      DS485CommandFrame* frame = new DS485CommandFrame();
+      frame->getHeader().setBroadcast(broadcast);
+      frame->getHeader().setDestination(destination);
+      frame->getHeader().setCounter(counter);
+      frame->setCommand(command);
+      for(int iByte = 0; iByte < length; iByte++) {
+        uint8_t byte = strToIntDef(_request.getParameter(std::string("payload_") + intToString(iByte+1)), 0xFF);
+        std::cout << "b" << std::dec << iByte << ": " << std::hex << (int)byte << "\n";
+        frame->getPayload().add<uint8_t>(byte);
+      }
+      std::cout << std::dec << "done" << std::endl;
+      DS485Interface* intf = &DSS::getInstance()->getDS485Interface();
+      DS485Proxy* proxy = dynamic_cast<DS485Proxy*>(intf);
+      if(proxy != NULL) {
+        proxy->sendFrame(*frame);
+      } else {
+        delete frame;
+      }
+      return success();
+    } else if(_request.getMethod() == "dSLinkSend") {
+      std::string deviceDSIDString =_request.getParameter("dsid");
+      Device* pDevice = NULL;
+      if(!deviceDSIDString.empty()) {
+        dsid_t deviceDSID = dsid_t::fromString(deviceDSIDString);
+        if(!(deviceDSID == NullDSID)) {
+          try {
+            Device& device = getDSS().getApartment().getDeviceByDSID(deviceDSID);
+            pDevice = &device;
+          } catch(std::runtime_error& e) {
+            return failure("Could not find device with dsid '" + deviceDSIDString + "'");
+          }
+        } else {
+          return failure("Could not parse dsid '" + deviceDSIDString + "'");
+        }
+      } else {
+        return failure("Missing parameter 'dsid'");
+      }
+
+      int iValue = strToIntDef(_request.getParameter("value"), -1);
+      if(iValue == -1) {
+        return failure("Missing parameter 'value'");
+      }
+      if(iValue < 0 || iValue > 0x00ff) {
+        return failure("Parameter 'value' is out of range (0-0xff)");
+      }
+      bool writeOnly = false;
+      bool lastValue = false;
+      if(_request.getParameter("writeOnly") == "true") {
+        writeOnly = true;
+      }
+      if(_request.getParameter("lastValue") == "true") {
+        lastValue = true;
+      }
+      uint8_t result;
+      try {
+        result = pDevice->dsLinkSend(iValue, lastValue, writeOnly);
+      } catch(std::runtime_error& e) {
+        return failure(std::string("Error: ") + e.what());
+      }
+      if(writeOnly) {
+        return success();
+      } else {
+        boost::shared_ptr<JSONObject> obj(new JSONObject());
+        obj->addProperty("value", result);
+        return success(obj);
+      }
+    } else if(_request.getMethod() == "pingDevice") {
+      std::string deviceDSIDString = _request.getParameter("dsid");
+      if(deviceDSIDString.empty()) {
+        return failure("Missing parameter 'dsid'");
+      }
+      try {
+        dsid_t deviceDSID = dsid_t::fromString(deviceDSIDString);
+        Device& device = getDSS().getApartment().getDeviceByDSID(deviceDSID);
+        DS485CommandFrame* frame = new DS485CommandFrame();
+        frame->getHeader().setBroadcast(true);
+        frame->getHeader().setDestination(device.getDSMeterID());
+        frame->setCommand(CommandRequest);
+        frame->getPayload().add<uint8_t>(FunctionDeviceGetTransmissionQuality);
+        frame->getPayload().add<uint16_t>(device.getShortAddress());
+        DS485Interface* intf = &DSS::getInstance()->getDS485Interface();
+        DS485Proxy* proxy = dynamic_cast<DS485Proxy*>(intf);
+        if(proxy != NULL) {
+          boost::shared_ptr<FrameBucketCollector> bucket = proxy->sendFrameAndInstallBucket(*frame, FunctionDeviceGetTransmissionQuality);
+          bucket->waitForFrame(2000);
+
+          boost::shared_ptr<DS485CommandFrame> recFrame = bucket->popFrame();
+          if(recFrame == NULL) {
+            return failure("No result received");
+          }
+          PayloadDissector pd(recFrame->getPayload());
+          pd.get<uint8_t>();
+          int errC = int(pd.get<uint16_t>());
+          if(errC < 0) {
+            return failure("dSM reported error-code: " + intToString(errC));
+          }
+          pd.get<uint16_t>(); // device address
+          int qualityHK = pd.get<uint16_t>();
+          int qualityRK = pd.get<uint16_t>();
+          boost::shared_ptr<JSONObject> obj(new JSONObject());
+          obj->addProperty("qualityHK", qualityHK);
+          obj->addProperty("qualityRK", qualityRK);
+          return success(obj);
+        } else {
+          delete frame;
+          return failure("Proxy has a wrong type or is null");
+        }
+      } catch(ItemNotFoundException&) {
+        return failure("Could not find device with dsid '" + deviceDSIDString + "'");
+      } catch(std::invalid_argument&) {
+        return failure( "Could not parse dsid '" + deviceDSIDString + "'");
+      }
+    } else if(_request.getMethod() == "resetZone") {
+      std::string zoneIDStr = _request.getParameter("zoneID");
+      int zoneID;
+      try {
+        zoneID = strToInt(zoneIDStr);
+      } catch(std::runtime_error&) {
+        return failure("Could not parse Zone ID");
+      }
+      DS485CommandFrame* frame = new DS485CommandFrame();
+      frame->getHeader().setBroadcast(true);
+      frame->getHeader().setDestination(0);
+      frame->setCommand(CommandRequest);
+      frame->getPayload().add<uint8_t>(FunctionZoneRemoveAllDevicesFromZone);
+      frame->getPayload().add<uint8_t>(zoneID);
+      DS485Interface* intf = &DSS::getInstance()->getDS485Interface();
+      DS485Proxy* proxy = dynamic_cast<DS485Proxy*>(intf);
+      if(proxy != NULL) {
+        proxy->sendFrame(*frame);
+        return success("Please restart your dSMs");
+      } else {
+        delete frame;
+        return failure("Proxy has a wrong type or is null");
+      }
+    }
+    throw std::runtime_error("Unhandled function");
+  } // handleRequest
+
+} // namespace dss
diff --git a/core/web/handler/debugrequesthandler.h b/core/web/handler/debugrequesthandler.h
new file mode 100644
index 0000000..4707386
--- /dev/null
+++ b/core/web/handler/debugrequesthandler.h
@@ -0,0 +1,37 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DEBUGREQUESTHANDLER_H_
+#define DEBUGREQUESTHANDLER_H_
+
+#include "core/web/webrequests.h"
+
+namespace dss {
+
+  class DebugRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // DebugRequestHandler
+
+} // namespace dss
+
+#endif /* DEBUGREQUESTHANDLER_H_ */
diff --git a/core/web/handler/eventrequesthandler.cpp b/core/web/handler/eventrequesthandler.cpp
new file mode 100644
index 0000000..bad6460
--- /dev/null
+++ b/core/web/handler/eventrequesthandler.cpp
@@ -0,0 +1,69 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "eventrequesthandler.h"
+
+#include "core/web/json.h"
+#include "core/event.h"
+#include "core/base.h"
+#include "core/dss.h"
+
+namespace dss {
+
+  //=========================================== EventRequestHandler
+
+  boost::shared_ptr<JSONObject> EventRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    if(_request.getMethod() == "raise") {
+      std::string name = _request.getParameter("name");
+      std::string location = _request.getParameter("location");
+      std::string context = _request.getParameter("context");
+      std::string parameter = _request.getParameter("parameter");
+
+      boost::shared_ptr<Event> evt(new Event(name));
+      if(!context.empty()) {
+        evt->setContext(context);
+      }
+      if(!location.empty()) {
+        evt->setLocation(location);
+      }
+      std::vector<std::string> params = dss::splitString(parameter, ';');
+      for(std::vector<std::string>::iterator iParam = params.begin(), e = params.end();
+          iParam != e; ++iParam)
+      {
+        std::vector<std::string> nameValue = dss::splitString(*iParam, '=');
+        if(nameValue.size() == 2) {
+          dss::Logger::getInstance()->log("WebServer::handleEventCall: Got parameter '" + nameValue[0] + "'='" + nameValue[1] + "'");
+          evt->setProperty(nameValue[0], nameValue[1]);
+        } else {
+          dss::Logger::getInstance()->log(std::string("Invalid parameter found WebServer::handleEventCall: ") + *iParam );
+        }
+      }
+
+      getDSS().getEventQueue().pushEvent(evt);
+      return success();
+    }
+    throw std::runtime_error("Unhandled function");
+  } // handleRequest
+
+
+
+} // namespace dss
diff --git a/core/web/handler/eventrequesthandler.h b/core/web/handler/eventrequesthandler.h
new file mode 100644
index 0000000..0cc4c50
--- /dev/null
+++ b/core/web/handler/eventrequesthandler.h
@@ -0,0 +1,37 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef EVENTREQUESTHANDLER_H_
+#define EVENTREQUESTHANDLER_H_
+
+#include "core/web/webrequests.h"
+
+namespace dss {
+
+  class EventRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // StructureRequestHandler
+
+} // namespace dss
+
+#endif /* EVENTREQUESTHANDLER_H_ */
diff --git a/core/web/handler/meteringrequesthandler.cpp b/core/web/handler/meteringrequesthandler.cpp
new file mode 100644
index 0000000..3671bcd
--- /dev/null
+++ b/core/web/handler/meteringrequesthandler.cpp
@@ -0,0 +1,172 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "meteringrequesthandler.h"
+
+#include <boost/filesystem.hpp>
+#include <vector>
+
+#include "core/foreach.h"
+#include "core/dss.h"
+
+#include "core/metering/metering.h"
+#include "core/metering/series.h"
+#include "core/metering/seriespersistence.h"
+
+#include "core/model/modulator.h"
+#include "core/model/apartment.h"
+
+
+#include "core/web/json.h"
+
+namespace dss {
+
+
+  //=========================================== MeteringRequestHandler
+
+  boost::shared_ptr<JSONObject> MeteringRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    if(_request.getMethod() == "getResolutions") {
+      std::vector<boost::shared_ptr<MeteringConfigChain> > meteringConfig = getDSS().getMetering().getConfig();
+      boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+      boost::shared_ptr<JSONArrayBase> resolutions(new JSONArrayBase());
+      resultObj->addElement("resolutions", resolutions);
+
+      foreach(boost::shared_ptr<MeteringConfigChain> pChain, meteringConfig) {
+        for(int iConfig = 0; iConfig < pChain->size(); iConfig++) {
+          boost::shared_ptr<JSONObject> resolution(new JSONObject());
+          resolutions->addElement("", resolution);
+
+          resolution->addProperty("type", pChain->isEnergy() ? "energy" : "consumption");
+          resolution->addProperty("unit", pChain->getUnit());
+          resolution->addProperty("resolution", pChain->getResolution(iConfig));
+        }
+      }
+
+      return success(resultObj);
+    } else if(_request.getMethod() == "getSeries") {
+      boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+      boost::shared_ptr<JSONArrayBase> series(new JSONArrayBase());
+      resultObj->addElement("series", series);
+
+      std::vector<DSMeter*>& dsMeters = getDSS().getApartment().getDSMeters();
+      foreach(DSMeter* dsMeter, dsMeters) {
+        boost::shared_ptr<JSONObject> energyEntry(new JSONObject());
+        series->addElement("", energyEntry);
+        energyEntry->addProperty("dsid", dsMeter->getDSID().toString());
+        energyEntry->addProperty("type", "energy");
+        boost::shared_ptr<JSONObject> consumptionEntry(new JSONObject());
+        series->addElement("", consumptionEntry);
+        consumptionEntry->addProperty("dsid", dsMeter->getDSID().toString());
+        consumptionEntry->addProperty("type", "consumption");
+      }
+      return success(resultObj);
+    } else if(_request.getMethod() == "getValues") { //?dsid=;n=,resolution=,type=
+      std::string errorMessage;
+      std::string deviceDSIDString = _request.getParameter("dsid");
+      std::string resolutionString = _request.getParameter("resolution");
+      std::string typeString = _request.getParameter("type");
+      std::string fileSuffix;
+      std::string storageLocation;
+      std::string seriesPath;
+      int resolution;
+      bool energy;
+      if(!deviceDSIDString.empty()) {
+        dsid_t deviceDSID = dsid_t::fromString(deviceDSIDString);
+        if(!(deviceDSID == NullDSID)) {
+          try {
+            getDSS().getApartment().getDSMeterByDSID(deviceDSID);
+          } catch(std::runtime_error& e) {
+            return failure("Could not find device with dsid '" + deviceDSIDString + "'");
+          }
+        } else {
+        return failure("Could not parse dsid '" + deviceDSIDString + "'");
+        }
+      } else {
+        return failure("Could not parse dsid '" + deviceDSIDString + "'");
+      }
+      resolution = strToIntDef(resolutionString, -1);
+      if(resolution == -1) {
+        return failure("Need could not parse resolution '" + resolutionString + "'");
+      }
+      if(typeString.empty()) {
+        return failure("Need a type, 'energy' or 'consumption'");
+      } else {
+        if(typeString == "consumption") {
+          energy = false;
+        } else if(typeString == "energy") {
+          energy = true;
+        } else {
+          return failure("Invalide type '" + typeString + "'");
+        }
+      }
+      if(!resolutionString.empty()) {
+        std::vector<boost::shared_ptr<MeteringConfigChain> > meteringConfig = getDSS().getMetering().getConfig();
+        storageLocation = getDSS().getMetering().getStorageLocation();
+        for(unsigned int iConfig = 0; iConfig < meteringConfig.size(); iConfig++) {
+          boost::shared_ptr<MeteringConfigChain> cConfig = meteringConfig[iConfig];
+          for(int jConfig = 0; jConfig < cConfig->size(); jConfig++) {
+            if(cConfig->isEnergy() == energy && cConfig->getResolution(jConfig) == resolution) {
+              fileSuffix = cConfig->getFilenameSuffix(jConfig);
+            }
+          }
+        }
+        if(fileSuffix.empty()) {
+          return failure("No data for '" + typeString + "' and resolution '" + resolutionString + "'");
+        } else {
+          seriesPath = storageLocation + deviceDSIDString + "_" + fileSuffix + ".xml";
+          log("_Trying to load series from " + seriesPath);
+          if(boost::filesystem::exists(seriesPath)) {
+            SeriesReader<CurrentValue> reader;
+            boost::shared_ptr<Series<CurrentValue> > s = boost::shared_ptr<Series<CurrentValue> >(reader.readFromXML(seriesPath));
+            boost::shared_ptr<std::deque<CurrentValue> > values = s->getExpandedValues();
+
+            boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+            resultObj->addProperty("dsimid", deviceDSIDString);
+            resultObj->addProperty("type", typeString);
+            resultObj->addProperty("resolution", resolutionString);
+            boost::shared_ptr<JSONArrayBase> valuesArray(new JSONArrayBase);
+            resultObj->addElement("values", valuesArray);
+            for(std::deque<CurrentValue>::iterator iValue = values->begin(), e = values->end(); iValue != e; iValue++)
+            {
+              boost::shared_ptr<JSONArrayBase> valuePair(new JSONArrayBase());
+              valuesArray->addElement("", valuePair);
+              boost::shared_ptr<JSONValue<int> > timeVal(new JSONValue<int>(iValue->getTimeStamp().secondsSinceEpoch()));
+              boost::shared_ptr<JSONValue<double> > valueVal(new JSONValue<double>(iValue->getValue()));
+              valuePair->addElement("", timeVal);
+              valuePair->addElement("", valueVal);
+            }
+
+            return success(resultObj);
+          } else {
+            return failure("No data-file for '" + typeString + "' and resolution '" + resolutionString + "'");
+          }
+        }
+      } else {
+        return failure("Could not parse resolution '" + resolutionString + "'");
+      }
+    } else if(_request.getMethod() == "getAggregatedValues") { //?set=;n=,resolution=;type=
+      // TODO: implement
+    }
+    throw std::runtime_error("Unhandled function");
+  } // handleRequest
+
+} // namespace dss
diff --git a/core/web/handler/meteringrequesthandler.h b/core/web/handler/meteringrequesthandler.h
new file mode 100644
index 0000000..03b93c4
--- /dev/null
+++ b/core/web/handler/meteringrequesthandler.h
@@ -0,0 +1,38 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef METERINGREQUESTHANDLER_H_
+#define METERINGREQUESTHANDLER_H_
+
+#include "core/web/webrequests.h"
+
+namespace dss {
+
+  class MeteringRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // MeteringRequestHandler
+
+} // namespace dss
+
+#endif /* METERINGREQUESTHANDLER_H_ */
diff --git a/core/web/handler/propertyrequesthandler.cpp b/core/web/handler/propertyrequesthandler.cpp
new file mode 100644
index 0000000..77eb29a
--- /dev/null
+++ b/core/web/handler/propertyrequesthandler.cpp
@@ -0,0 +1,146 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "propertyrequesthandler.h"
+
+#include "core/propertysystem.h"
+#include "core/dss.h"
+
+#include "core/web/json.h"
+
+namespace dss {
+
+
+  //=========================================== PropertyRequestHandler
+
+  boost::shared_ptr<JSONObject> PropertyRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    std::string propName = _request.getParameter("path");
+    if(propName.empty()) {
+      return failure("Need parameter 'path' for property operations");
+    }
+    PropertyNodePtr node = getDSS().getPropertySystem().getProperty(propName);
+
+    if(_request.getMethod() == "getString") {
+      if(node == NULL) {
+        return failure("Could not find node named '" + propName + "'");
+      }
+      try {
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("value", node->getStringValue());
+        return success(resultObj);
+      } catch(PropertyTypeMismatch& ex) {
+        return failure(std::string("Error getting property: '") + ex.what() + "'");
+      }
+    } else if(_request.getMethod() == "getInteger") {
+      if(node == NULL) {
+        return failure("Could not find node named '" + propName + "'");
+      }
+      try {
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("value", node->getIntegerValue());
+        return success(resultObj);
+      } catch(PropertyTypeMismatch& ex) {
+        return failure(std::string("Error getting property: '") + ex.what() + "'");
+      }
+    } else if(_request.getMethod() == "getBoolean") {
+      if(node == NULL) {
+        return failure("Could not find node named '" + propName + "'");
+      }
+      try {
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("value", node->getBoolValue());
+        return success(resultObj);
+      } catch(PropertyTypeMismatch& ex) {
+        return failure(std::string("Error getting property: '") + ex.what() + "'");
+      }
+    } else if(_request.getMethod() == "setString") {
+      std::string value = _request.getParameter("value");
+      if(node == NULL) {
+        node = getDSS().getPropertySystem().createProperty(propName);
+      }
+      try {
+        node->setStringValue(value);
+      } catch(PropertyTypeMismatch& ex) {
+        return failure(std::string("Error setting property: '") + ex.what() + "'");
+      }
+      return success();
+    } else if(_request.getMethod() == "setBoolean") {
+      std::string strValue = _request.getParameter("value");
+      bool value;
+      if(strValue == "true") {
+        value = true;
+      } else if(strValue == "false") {
+        value = false;
+      } else {
+        return failure("Expected 'true' or 'false' for parameter 'value' but got: '" + strValue + "'");
+      }
+      if(node == NULL) {
+        node = getDSS().getPropertySystem().createProperty(propName);
+      }
+      try {
+        node->setBooleanValue(value);
+      } catch(PropertyTypeMismatch& ex) {
+        return failure(std::string("Error setting property: '") + ex.what() + "'");
+      }
+      return success();
+    } else if(_request.getMethod() == "setInteger") {
+      std::string strValue = _request.getParameter("value");
+      int value;
+      try {
+        value = strToInt(strValue);
+      } catch(...) {
+        return failure("Could not convert parameter 'value' to std::string. Got: '" + strValue + "'");
+      }
+      if(node == NULL) {
+        node = getDSS().getPropertySystem().createProperty(propName);
+      }
+      try {
+        node->setIntegerValue(value);
+      } catch(PropertyTypeMismatch& ex) {
+        return failure(std::string("Error setting property: '") + ex.what() + "'");
+      }
+      return success();
+    } else if(_request.getMethod() == "getChildren") {
+      if(node == NULL) {
+        return failure("Could not find node named '" + propName + "'");
+      }
+      boost::shared_ptr<JSONArrayBase> resultObj(new JSONArrayBase());
+      for(int iChild = 0; iChild < node->getChildCount(); iChild++) {
+        boost::shared_ptr<JSONObject> prop(new JSONObject());
+        resultObj->addElement("", prop);
+        PropertyNodePtr cnode = node->getChild(iChild);
+        prop->addProperty("name", cnode->getName());
+        prop->addProperty("type", getValueTypeAsString(cnode->getValueType()));
+      }
+      return success(resultObj);
+    } else if(_request.getMethod() == "getType") {
+      if(node == NULL) {
+        return failure("Could not find node named '" + propName + "'");
+      }
+      boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+      resultObj->addProperty("type", getValueTypeAsString(node->getValueType()));
+      return success(resultObj);
+    }
+    throw std::runtime_error("Unhandled function");
+  } // handleRequest
+
+} // namespace dss
diff --git a/core/web/handler/propertyrequesthandler.h b/core/web/handler/propertyrequesthandler.h
new file mode 100644
index 0000000..f3a412a
--- /dev/null
+++ b/core/web/handler/propertyrequesthandler.h
@@ -0,0 +1,37 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PROPERTYREQUESTHANDLER_H_
+#define PROPERTYREQUESTHANDLER_H_
+
+#include "core/web/webrequests.h"
+
+namespace dss {
+
+  class PropertyRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // PropertyRequestHandler
+
+} // namespace dss
+
+#endif /* PROPERTYREQUESTHANDLER_H_ */
diff --git a/core/web/handler/simrequesthandler.cpp b/core/web/handler/simrequesthandler.cpp
new file mode 100644
index 0000000..f859204
--- /dev/null
+++ b/core/web/handler/simrequesthandler.cpp
@@ -0,0 +1,114 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "simrequesthandler.h"
+
+#include "core/dss.h"
+#include "core/ds485const.h"
+#include "core/model/group.h"
+#include "core/model/zone.h"
+#include "core/model/apartment.h"
+
+namespace dss {
+
+
+  //=========================================== SimRequestHandler
+
+  boost::shared_ptr<JSONObject> SimRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    if(_request.getMethod() == "switch") {
+      if(_request.getMethod() == "switch/pressed") {
+        int buttonNr = strToIntDef(_request.getParameter("buttonnr"), -1);
+        if(buttonNr == -1) {
+          return failure("Invalid button number");
+        }
+
+        int zoneID = strToIntDef(_request.getParameter("zoneID"), -1);
+        if(zoneID == -1) {
+          return failure("Could not parse zoneID");
+        }
+        int groupID = strToIntDef(_request.getParameter("groupID"), -1);
+        if(groupID == -1) {
+          return failure("Could not parse groupID");
+        }
+        try {
+          Zone& zone = getDSS().getApartment().getZone(zoneID);
+          Group* pGroup = zone.getGroup(groupID);
+
+          if(pGroup == NULL) {
+            return failure("Could not find group");
+          }
+
+          switch(buttonNr) {
+          case 1: // upper-left
+          case 3: // upper-right
+          case 7: // lower-left
+          case 9: // lower-right
+            break;
+          case 2: // up
+            pGroup->increaseValue();
+            break;
+          case 8: // down
+            pGroup->decreaseValue();
+            break;
+          case 4: // left
+            pGroup->previousScene();
+            break;
+          case 6: // right
+            pGroup->nextScene();
+            break;
+          case 5:
+            {
+              if(groupID == GroupIDGreen) {
+                getDSS().getApartment().getGroup(0).callScene(SceneBell);
+              } else if(groupID == GroupIDRed){
+                getDSS().getApartment().getGroup(0).callScene(SceneAlarm);
+              } else {
+                const int lastScene = pGroup->getLastCalledScene();
+                if(lastScene == SceneOff || lastScene == SceneDeepOff ||
+                  lastScene == SceneStandBy || lastScene == ScenePanic)
+                {
+                  pGroup->callScene(Scene1);
+                } else {
+                  pGroup->callScene(SceneOff);
+                }
+              }
+            }
+            break;
+          default:
+            return failure("Invalid button nr (range is 1..9)");
+          }
+        } catch(std::runtime_error&) {
+          return failure("Could not find zone");
+        }
+        return success();
+      }
+    } else if(_request.getMethod() == "addDevice") {
+      //std::string type = _parameter["type"];
+      //std::string dsidStr = _parameter["dsid"];
+      // TODO: not finished yet ;)
+      return failure("not yet implemented");
+    }
+    throw std::runtime_error("Unhandled function");
+  } // handleRequest
+
+
+} // namespace dss
diff --git a/core/web/handler/simrequesthandler.h b/core/web/handler/simrequesthandler.h
new file mode 100644
index 0000000..3d3a254
--- /dev/null
+++ b/core/web/handler/simrequesthandler.h
@@ -0,0 +1,36 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef SIMREQUESTHANDLER_H_
+#define SIMREQUESTHANDLER_H_
+
+#include "core/web/webrequests.h"
+
+namespace dss {
+
+  class SimRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // SimRequestHandler
+
+} // namespace dss
+#endif /* SIMREQUESTHANDLER_H_ */
diff --git a/core/web/handler/structurerequesthandler.cpp b/core/web/handler/structurerequesthandler.cpp
new file mode 100644
index 0000000..1e65e4d
--- /dev/null
+++ b/core/web/handler/structurerequesthandler.cpp
@@ -0,0 +1,118 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "structurerequesthandler.h"
+
+#include "core/web/json.h"
+
+#include "core/dss.h"
+#include "core/DS485Interface.h"
+#include "core/structuremanipulator.h"
+
+#include "core/model/apartment.h"
+#include "core/model/zone.h"
+#include "core/model/set.h"
+#include "core/model/device.h"
+#include "core/model/devicereference.h"
+#include "core/model/modelmaintenance.h"
+
+namespace dss {
+
+
+  //=========================================== StructureRequestHandler
+
+  boost::shared_ptr<JSONObject> StructureRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    StructureManipulator manipulator(*getDSS().getDS485Interface().getStructureModifyingBusInterface(), getDSS().getApartment());
+    if(_request.getMethod() == "zoneAddDevice") {
+      std::string devidStr = _request.getParameter("devid");
+      if(!devidStr.empty()) {
+        dsid_t devid = dsid::fromString(devidStr);
+
+        Device& dev = DSS::getInstance()->getApartment().getDeviceByDSID(devid);
+        if(!dev.isPresent()) {
+          return failure("cannot add nonexisting device to a zone");
+        }
+
+        std::string zoneIDStr = _request.getParameter("zone");
+        if(!zoneIDStr.empty()) {
+          try {
+            int zoneID = strToInt(zoneIDStr);
+            DeviceReference devRef(dev, &DSS::getInstance()->getApartment());
+            try {
+              Zone& zone = getDSS().getApartment().getZone(zoneID);
+              manipulator.addDeviceToZone(dev, zone);
+            } catch(ItemNotFoundException&) {
+              return failure("Could not find zone");
+            }
+          } catch(std::runtime_error& err) {
+            return failure(err.what());
+          }
+        }
+        return success();
+      } else {
+        return failure("Need parameter devid");
+      }
+    } else if(_request.getMethod() == "addZone") {
+      int zoneID = -1;
+
+      std::string zoneIDStr = _request.getParameter("zoneID");
+      if(!zoneIDStr.empty()) {
+        zoneID = strToIntDef(zoneIDStr, -1);
+      }
+      if(zoneID != -1) {
+        getDSS().getApartment().allocateZone(zoneID);
+      } else {
+        return failure("could not find zone");
+      }
+      return success();
+    } else if(_request.getMethod() == "removeZone") {
+      int zoneID = -1;
+
+      std::string zoneIDStr = _request.getParameter("zoneID");
+      if(!zoneIDStr.empty()) {
+        zoneID = strToIntDef(zoneIDStr, -1);
+      }
+      if(zoneID != -1) {
+        try {
+          Zone& zone = getDSS().getApartment().getZone(zoneID);
+          if(zone.getFirstZoneOnDSMeter() != -1) {
+            return failure("Cannot delete a primary zone");
+          }
+          if(zone.getDevices().length() > 0) {
+            return failure("Cannot delete a non-empty zone");
+          }
+          getDSS().getApartment().removeZone(zoneID);
+          getDSS().getModelMaintenance().addModelEvent(new ModelEvent(ModelEvent::etModelDirty));
+          return success();
+        } catch(ItemNotFoundException&) {
+          return failure("Could not find zone");
+        }
+      } else {
+        return failure("Missing parameter zoneID");
+      }
+    } else {
+      throw std::runtime_error("Unhandled function");
+    }
+  } // handleRequest
+
+
+} // namespace dss
diff --git a/core/web/handler/structurerequesthandler.h b/core/web/handler/structurerequesthandler.h
new file mode 100644
index 0000000..4e75ae6
--- /dev/null
+++ b/core/web/handler/structurerequesthandler.h
@@ -0,0 +1,37 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef STRUCTUREREQUESTHANDLER_H_
+#define STRUCTUREREQUESTHANDLER_H_
+
+#include "core/web/webrequests.h"
+
+namespace dss {
+
+  class StructureRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // StructureRequestHandler
+
+} // namespace dss
+
+#endif /* STRUCTUREREQUESTHANDLER_H_ */
diff --git a/core/web/handler/systemrequesthandler.cpp b/core/web/handler/systemrequesthandler.cpp
new file mode 100644
index 0000000..d53a356
--- /dev/null
+++ b/core/web/handler/systemrequesthandler.cpp
@@ -0,0 +1,40 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "systemrequesthandler.h"
+
+#include "core/web/json.h"
+#include "core/dss.h"
+
+namespace dss {
+
+  //=========================================== SystemRequestHandler
+
+  boost::shared_ptr<JSONObject> SystemRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
+    if(_request.getMethod() == "version") {
+      return success(DSS::getInstance()->versionString());
+    }
+    throw std::runtime_error("Unhandled function");
+  } // handleRequest
+
+
+} // namespace dss
diff --git a/core/web/handler/systemrequesthandler.h b/core/web/handler/systemrequesthandler.h
new file mode 100644
index 0000000..f649284
--- /dev/null
+++ b/core/web/handler/systemrequesthandler.h
@@ -0,0 +1,37 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "core/web/webrequests.h"
+
+#ifndef SYSTEMREQUESTHANDLER_H_
+#define SYSTEMREQUESTHANDLER_H_
+
+namespace dss {
+
+  class SystemRequestHandler : public WebServerRequestHandlerJSON {
+  public:
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
+  }; // SystemRequestHandler
+
+} // namespace dss
+
+#endif /* SYSTEMREQUESTHANDLER_H_ */
diff --git a/core/web/json.cpp b/core/web/json.cpp
new file mode 100644
index 0000000..91dff35
--- /dev/null
+++ b/core/web/json.cpp
@@ -0,0 +1,141 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "json.h"
+
+#include <sstream>
+
+#include "core/foreach.h"
+
+namespace dss {
+
+
+  //================================================== JSONElement
+
+  void JSONElement::addElement(const std::string& _name, boost::shared_ptr<JSONElement> _element) {
+    m_Elements.push_back(std::make_pair(_name, _element));
+  } // addElement
+
+  std::string JSONElement::toString() {
+    std::stringstream sstream;
+    writeTo(sstream);
+    return sstream.str();
+  }
+
+  void JSONElement::writeElementsTo(std::stringstream& _out) {
+    bool first = true;
+    foreach(NamedElement& namedElement, m_Elements) {
+      if(!first) {
+        _out << ',';
+      }
+      first = false;
+      _out << '"' << namedElement.first << '"' << ':';
+      namedElement.second->writeTo(_out);
+    }
+  }
+
+  void JSONElement::writeElementsNoNamesTo(std::stringstream& _out) {
+    bool first = true;
+    foreach(NamedElement& namedElement, m_Elements) {
+      if(!first) {
+        _out << ',';
+      }
+      first = false;
+      namedElement.second->writeTo(_out);
+    }
+  }
+
+
+  //================================================== JSONObject
+
+  void JSONObject::addProperty(const std::string& _name, const std::string& _value) {
+    boost::shared_ptr<JSONValue<std::string> > elem(new JSONValue<std::string>(_value));
+    addElement(_name, elem);
+  } // addProperty
+
+  void JSONObject::addProperty(const std::string& _name, const char* _value) {
+    boost::shared_ptr<JSONValue<std::string> > elem(new JSONValue<std::string>(_value));
+    addElement(_name, elem);
+  } // addProperty
+
+  void JSONObject::addProperty(const std::string& _name, const int _value) {
+    boost::shared_ptr<JSONValue<int> > elem(new JSONValue<int>(_value));
+    addElement(_name, elem);
+  } // addProperty
+
+  void JSONObject::addProperty(const std::string& _name, const unsigned long int _value) {
+    boost::shared_ptr<JSONValue<unsigned long int> > elem(new JSONValue<unsigned long int>(_value));
+    addElement(_name, elem);
+  } // addProperty
+
+  void JSONObject::addProperty(const std::string& _name, const bool _value) {
+    boost::shared_ptr<JSONValue<bool> > elem(new JSONValue<bool>(_value));
+    addElement(_name, elem);
+  }
+
+  void JSONObject::writeTo(std::stringstream& _out) {
+    _out << "{";
+    writeElementsTo(_out);
+    _out << "}";
+  }
+
+
+  //================================================== JSONValue
+
+  template<>
+  void JSONValue<int>::writeTo(std::stringstream& _out) {
+    _out << m_Value;
+  }
+
+  template<>
+  void JSONValue<unsigned long int>::writeTo(std::stringstream& _out) {
+    _out << m_Value;
+  }
+
+  template<>
+  void JSONValue<std::string>::writeTo(std::stringstream& _out) {
+    _out << '"' << m_Value << '"';
+  }
+
+  template<>
+  void JSONValue<bool>::writeTo(std::stringstream& _out) {
+    if(m_Value) {
+      _out << "true";
+    } else {
+      _out << "false";
+    }
+  }
+
+  template<>
+  void JSONValue<double>::writeTo(std::stringstream& _out) {
+    _out << m_Value;
+  }
+
+  //================================================== JSONArrayBase
+
+  void JSONArrayBase::writeTo(std::stringstream& _out) {
+    _out << "[";
+    writeElementsNoNamesTo(_out);
+    _out << "]";
+  }
+
+} // namespace dss
diff --git a/core/web/json.h b/core/web/json.h
new file mode 100644
index 0000000..cfbb3f8
--- /dev/null
+++ b/core/web/json.h
@@ -0,0 +1,86 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef JSON_H_
+#define JSON_H_
+
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+#include <boost/shared_ptr.hpp>
+
+
+namespace dss {
+
+  class JSONElement {
+  public:
+    void addElement(const std::string& _name, boost::shared_ptr<JSONElement> _object);
+    virtual ~JSONElement() {}
+    std::string toString();
+  protected:
+    virtual void writeTo(std::stringstream& _out) = 0;
+    virtual void writeElementsTo(std::stringstream& _out);
+    virtual void writeElementsNoNamesTo(std::stringstream& _out);
+  private:
+    typedef std::pair<std::string, boost::shared_ptr<JSONElement> > NamedElement;
+    std::vector<NamedElement> m_Elements;
+  };
+
+  class JSONObject : public JSONElement {
+  public:
+    virtual void addProperty(const std::string& _name, const char* _value);
+    virtual void addProperty(const std::string& _name, const std::string& _value);
+    virtual void addProperty(const std::string& _name, const int _value);
+    virtual void addProperty(const std::string& _name, const unsigned long int _value);
+    virtual void addProperty(const std::string& _name, const bool _value);
+  protected:
+    virtual void writeTo(std::stringstream& _out);
+  };
+
+  template<class T>
+  class JSONValue : public JSONElement {
+  public:
+    JSONValue(T _value) : m_Value(_value) {}
+  protected:
+    virtual void writeTo(std::stringstream& _out);
+  private:
+    T m_Value;
+  };
+
+  class JSONArrayBase : public JSONElement {
+  protected:
+    virtual void writeTo(std::stringstream& _out);
+  }; // JSONArrayBase
+
+  template<class T>
+  class JSONArray : public JSONArrayBase {
+  public:
+    void add(T _value) {
+      boost::shared_ptr<JSONValue<T> > elem(new JSONValue<T>(_value));
+      addElement("", elem);
+    }
+  };
+
+} // namespace dss
+
+#endif /* JSON_H_ */
diff --git a/core/web/webrequests.cpp b/core/web/webrequests.cpp
index b997e72..eb1d832 100644
--- a/core/web/webrequests.cpp
+++ b/core/web/webrequests.cpp
@@ -26,7 +26,6 @@
 #include <vector>
 
 #include <boost/shared_ptr.hpp>
-#include <boost/filesystem.hpp>
 
 #include "core/event.h"
 #include "core/ds485/ds485proxy.h"
@@ -45,168 +44,95 @@
 #include "core/model/modelevent.h"
 #include "core/model/modelmaintenance.h"
 
-#include "core/metering/metering.h"
-#include "core/metering/series.h"
-#include "core/metering/seriespersistence.h"
 #include "core/setbuilder.h"
 #include "core/structuremanipulator.h"
 
+#include "json.h"
 
-namespace dss {
-
-  //=========================================== Globals
-
-  std::string ToJSONValue(const int& _value) {
-    return intToString(_value);
-  } // toJSONValue(int)
-
-  std::string ToJSONValue(const double& _value) {
-    return doubleToString(_value);
-  } // toJSONValue(double)
-
-  std::string ToJSONValue(const bool& _value) {
-    if(_value) {
-      return "true";
-    } else {
-      return "false";
-    }
-  } // toJSONValue(bool)
 
-  std::string ToJSONValue(const std::string& _value) {
-    return std::string("\"") + _value + '"';
-  } // toJSONValue(const std::string&)
+namespace dss {
 
-  std::string ToJSONValue(const char* _value) {
-    return ToJSONValue(std::string(_value));
-  } // toJSONValue(const char*)
 
-  std::string ResultToJSON(const bool _ok, const std::string& _message = "") {
-    std::ostringstream sstream;
-    sstream << "{ " << ToJSONValue("ok") << ":" << ToJSONValue(_ok);
-    if(!_message.empty()) {
-      sstream << ", " << ToJSONValue("message") << ":" << ToJSONValue(_message);
-    }
-    sstream << "}";
-    if(!_ok) {
-      Logger::getInstance()->log("JSON call failed: '" + _message + "'");
-    }
-    return sstream.str();
-  } // resultToJSON
-
-  std::string JSONOk(const std::string& _innerResult = "") {
-    std::ostringstream sstream;
-    sstream << "{ " << ToJSONValue("ok") << ":" << ToJSONValue(true);
-    if(!_innerResult.empty()) {
-      sstream << ", " << ToJSONValue("result")<<  ": " << _innerResult;
-    }
-    sstream << " }";
-    return sstream.str();
-  }
+  //=========================================== Globals
 
-  std::string ToJSONValue(const DeviceReference& _device) {
-    std::ostringstream sstream;
-    sstream << "{ \"id\": \"" << _device.getDSID().toString() << "\""
-            << ", \"isSwitch\": " << ToJSONValue(_device.hasSwitch())
-            << ", \"name\": " << ToJSONValue(_device.getDevice().getName())
-            << ", \"fid\": " << ToJSONValue(_device.getDevice().getFunctionID())
-            << ", \"circuitID\":" << ToJSONValue(_device.getDevice().getDSMeterID())
-            << ", \"busID\":"  << ToJSONValue(_device.getDevice().getShortAddress())
-            << ", \"isPresent\":"  << ToJSONValue(_device.getDevice().isPresent())
-            << ", \"lastDiscovered\":"  << ToJSONValue(int(_device.getDevice().getLastDiscovered().secondsSinceEpoch()))
-            << ", \"firstSeen\":"  << ToJSONValue(int(_device.getDevice().getFirstSeen().secondsSinceEpoch()))
-            << ", \"on\": " << ToJSONValue(_device.isOn()) << " }";
-    return sstream.str();
+  boost::shared_ptr<JSONObject> ToJSONValue(const DeviceReference& _device) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    result->addProperty("id", _device.getDSID().toString());
+    result->addProperty("isSwitch", _device.hasSwitch());
+    result->addProperty("name", _device.getName());
+    result->addProperty("fid", _device.getFunctionID());
+    result->addProperty("circuitID", _device.getDevice().getDSMeterID());
+    result->addProperty("busID", _device.getDevice().getShortAddress());
+    result->addProperty("isPresent", _device.getDevice().isPresent());
+    result->addProperty("lastDiscovered", _device.getDevice().getLastDiscovered());
+    result->addProperty("firstSeen", _device.getDevice().getFirstSeen());
+    result->addProperty("on", _device.getDevice().isOn());
+    return result;
   } // toJSONValue(DeviceReference)
 
-  std::string ToJSONValue(const Set& _set, const std::string& _arrayName) {
-    std::ostringstream sstream;
-    sstream << ToJSONValue(_arrayName) << ":[";
-    bool firstDevice = true;
+  boost::shared_ptr<JSONArrayBase> ToJSONValue(const Set& _set) {
+    boost::shared_ptr<JSONArrayBase> result(new JSONArrayBase());
+
     for(int iDevice = 0; iDevice < _set.length(); iDevice++) {
       const DeviceReference& d = _set.get(iDevice);
-      if(firstDevice) {
-        firstDevice = false;
-      } else {
-        sstream << ",";
-      }
-      sstream << ToJSONValue(d);
+      result->addElement("", ToJSONValue(d));
     }
-    sstream << "]";
-    return sstream.str();
+    return result;
   } // toJSONValue(Set,Name)
 
-  std::string ToJSONValue(const Group& _group) {
-    std::ostringstream sstream;
-    sstream << "{ " << ToJSONValue("id") << ": " << ToJSONValue(_group.getID()) << ",";
-    sstream << ToJSONValue("name") << ": " << ToJSONValue(_group.getName()) << ", ";
-    sstream << ToJSONValue("isPresent") << ": " << ToJSONValue(_group.isPresent()) << ", ";
-    sstream << ToJSONValue("devices") << ": [";
+  boost::shared_ptr<JSONObject> ToJSONValue(const Group& _group) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    result->addProperty("id", _group.getID());
+    result->addProperty("name", _group.getName());
+    result->addProperty("isPresent", _group.isPresent());
+
+    boost::shared_ptr<JSONArrayBase> devicesArr(new JSONArrayBase());
+    result->addElement("devices", devicesArr);
     Set devices = _group.getDevices();
-    bool first = true;
     for(int iDevice = 0; iDevice < devices.length(); iDevice++) {
-      if(!first) {
-        sstream << " , ";
-      } else {
-        first = false;
-      }
-      sstream << " { " << ToJSONValue("id") << ": " << ToJSONValue(devices[iDevice].getDSID().toString()) << " }";
+      boost::shared_ptr<JSONObject> dev(new JSONObject());
+      dev->addProperty("id", devices[iDevice].getDSID().toString());
     }
-    sstream << "]} ";
-    return sstream.str();
+    return result;
   } // toJSONValue(Group)
 
-  std::string ToJSONValue(Zone& _zone, bool _includeDevices = true) {
-    std::ostringstream sstream;
-    sstream << "{ \"id\": " << _zone.getID() << ",";
+  boost::shared_ptr<JSONObject> ToJSONValue(Zone& _zone, bool _includeDevices = true) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    result->addProperty("id", _zone.getID());
     std::string name = _zone.getName();
-    if(name.size() == 0) {
+    if(name.empty()) {
       name = std::string("Zone ") + intToString(_zone.getID());
     }
-    sstream << ToJSONValue("name") << ": " << ToJSONValue(name) << ", ";
-    sstream << ToJSONValue("isPresent") << ": " << ToJSONValue(_zone.isPresent());
+    result->addProperty("name", name);
+    result->addProperty("isPresent", _zone.isPresent());
     if(_zone.getFirstZoneOnDSMeter() != -1) {
-      sstream << ", " << ToJSONValue("firstZoneOnDSMeter")
-              << ": " << ToJSONValue(_zone.getFirstZoneOnDSMeter());
+      result->addProperty("firstZoneOnDSMeter", _zone.getFirstZoneOnDSMeter());
     }
 
     if(_includeDevices) {
-      sstream << ", ";
-      Set devices = _zone.getDevices();
-      sstream << ToJSONValue(devices, "devices");
-      sstream << "," << ToJSONValue("groups") << ": [";
-      bool first = true;
+      result->addElement("devices", ToJSONValue(_zone.getDevices()));
+      boost::shared_ptr<JSONArrayBase> groups(new JSONArrayBase());
+      result->addElement("groups", groups);
       foreach(Group* pGroup, _zone.getGroups()) {
-        if(!first) {
-          sstream << ",";
-        }
-        first = false;
-        sstream  << ToJSONValue(*pGroup);
+        groups->addElement("", ToJSONValue(*pGroup));
       }
-      sstream << "] ";
     }
 
-    sstream << "} ";
-    return sstream.str();
+    return result;
   } // toJSONValue(Zone)
 
-  std::string ToJSONValue(Apartment& _apartment) {
-    std::ostringstream sstream;
-    sstream << "{ \"apartment\": { \"zones\": [";
+  boost::shared_ptr<JSONObject> ToJSONValue(Apartment& _apartment) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    boost::shared_ptr<JSONObject> apartment(new JSONObject());
+    result->addElement("apartment", apartment);
+    boost::shared_ptr<JSONArrayBase> zonesArr(new JSONArrayBase());
+    apartment->addElement("zones", zonesArr);
+
     vector<Zone*>& zones = _apartment.getZones();
-    bool first = true;
-    for(vector<Zone*>::iterator ipZone = zones.begin(), e = zones.end();
-        ipZone != e; ++ipZone)
-    {
-      Zone* pZone = *ipZone;
-      if(!first) {
-        sstream << ", ";
-      } else {
-        first = false;
-      }
-      sstream << ToJSONValue(*pZone);
+    foreach(Zone* pZone, zones) {
+      zonesArr->addElement("", ToJSONValue(*pZone));
     }
-    sstream << "]} }";
-    return sstream.str();
+    return result;
   } // toJSONValue(Apartment)
 
   Set GetUnassignedDevices() {
@@ -229,43 +155,23 @@ namespace dss {
     return devices;
   } // getUnassignedDevices
 
-  template<class t>
-  std::string ToJSONArray(const vector<t>& _v);
-
-  template<>
-  std::string ToJSONArray(const vector<int>& _v) {
-    std::ostringstream arr;
-    arr << "[";
-    bool first = true;
-    vector<int>::const_iterator iV;
-    vector<int>::const_iterator e;
-    for(iV = _v.begin(), e = _v.end();
-        iV != e; ++iV)
-    {
-      if(!first) {
-        arr << ",";
-      }
-      arr << ToJSONValue(*iV);
-      first = false;
-    }
-    arr << "]";
-    return arr.str();
-  } // toJSONArray<int>
-  
+
   //=========================================== DeviceInterfaceRequestHandler
 
-  std::string DeviceInterfaceRequestHandler::handleDeviceInterfaceRequest(const RestfulRequest& _request, IDeviceInterface* _interface) {
-    bool ok = true;
-    std::string errorString;
+  boost::shared_ptr<JSONObject> DeviceInterfaceRequestHandler::handleDeviceInterfaceRequest(const RestfulRequest& _request, IDeviceInterface* _interface) {
     assert(_interface != NULL);
     if(_request.getMethod() == "turnOn") {
       _interface->turnOn();
+      return success();
     } else if(_request.getMethod() == "turnOff") {
       _interface->turnOff();
+      return success();
     } else if(_request.getMethod() == "increaseValue") {
       _interface->increaseValue();
+      return success();
     } else if(_request.getMethod() == "decreaseValue") {
       _interface->decreaseValue();
+      return success();
     } else if(_request.getMethod() == "startDim") {
       std::string direction = _request.getParameter("direction");
       if(direction == "up") {
@@ -273,48 +179,52 @@ namespace dss {
       } else {
         _interface->startDim(false);
       }
+      return success();
     } else if(_request.getMethod() == "endDim") {
       _interface->endDim();
+      return success();
     } else if(_request.getMethod() == "setValue") {
       std::string valueStr = _request.getParameter("value");
       int value = strToIntDef(valueStr, -1);
       if(value == -1) {
-        errorString = "invalid or missing parameter value: '" + valueStr + "'";
-        ok = false;
+        return failure("invalid or missing parameter value: '" + valueStr + "'");
       } else {
         _interface->setValue(value);
       }
+      return success();
     } else if(_request.getMethod() == "callScene") {
       std::string sceneStr = _request.getParameter("sceneNr");
       int sceneID = strToIntDef(sceneStr, -1);
       if(sceneID != -1) {
         _interface->callScene(sceneID);
       } else {
-        errorString = "invalid sceneNr: '" + sceneStr + "'";
-        ok = false;
+        return failure("invalid sceneNr: '" + sceneStr + "'");
       }
+      return success();
     } else if(_request.getMethod() == "saveScene") {
       std::string sceneStr = _request.getParameter("sceneNr");
       int sceneID = strToIntDef(sceneStr, -1);
       if(sceneID != -1) {
         _interface->saveScene(sceneID);
       } else {
-        errorString = "invalid sceneNr: '" + sceneStr + "'";
-        ok = false;
+        return failure("invalid sceneNr: '" + sceneStr + "'");
       }
+      return success();
     } else if(_request.getMethod() == "undoScene") {
       std::string sceneStr = _request.getParameter("sceneNr");
       int sceneID = strToIntDef(sceneStr, -1);
       if(sceneID != -1) {
         _interface->undoScene(sceneID);
       } else {
-        errorString = "invalid sceneNr: '" + sceneStr + "'";
-        ok = false;
+        return failure("invalid sceneNr: '" + sceneStr + "'");
       }
+      return success();
     } else if(_request.getMethod() == "getConsumption") {
-      return "{ " + ToJSONValue("consumption") + ": " +  uintToString(_interface->getPowerConsumption()) +"}";
+      boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+      resultObj->addProperty("consumption", _interface->getPowerConsumption());
+      return success(resultObj);
     }
-    return ResultToJSON(ok, errorString);
+    throw std::runtime_error("Unknown function");
   } // handleRequest
 
   bool DeviceInterfaceRequestHandler::isDeviceInterfaceCall(const RestfulRequest& _request) {
@@ -334,15 +244,16 @@ namespace dss {
 
   //=========================================== ApartmentRequestHandler
   
-  std::string ApartmentRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    bool ok = true;
+  boost::shared_ptr<JSONObject> ApartmentRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
     std::string errorMessage;
     if(_request.getMethod() == "getConsumption") {
       int accumulatedConsumption = 0;
       foreach(DSMeter* pDSMeter, getDSS().getApartment().getDSMeters()) {
         accumulatedConsumption += pDSMeter->getPowerConsumption();
       }
-      return "{ " + ToJSONValue("consumption") + ": " +  uintToString(accumulatedConsumption) +"}";
+      boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+      resultObj->addProperty("consumption", accumulatedConsumption);
+      return success(resultObj);
     } else if(isDeviceInterfaceCall(_request)) {
       IDeviceInterface* interface = NULL;
       std::string groupName = _request.getParameter("groupName");
@@ -352,8 +263,7 @@ namespace dss {
           Group& grp = getDSS().getApartment().getGroup(groupName);
           interface = &grp;
         } catch(std::runtime_error& e) {
-          errorMessage = "Could not find group with name '" + groupName + "'";
-          ok = false;
+          return failure("Could not find group with name '" + groupName + "'");
         }
       } else if(!groupIDString.empty()) {
         try {
@@ -362,28 +272,20 @@ namespace dss {
             Group& grp = getDSS().getApartment().getGroup(groupID);
             interface = &grp;
           } else {
-            errorMessage = "Could not parse group id '" + groupIDString + "'";
-            ok = false;
+            return failure("Could not parse group id '" + groupIDString + "'");
           }
         } catch(std::runtime_error& e) {
-          errorMessage = "Could not find group with ID '" + groupIDString + "'";
-          ok = false;
+          return failure("Could not find group with ID '" + groupIDString + "'");
         }
       }
-      if(ok) {
-        if(interface == NULL) {
-          interface = &getDSS().getApartment().getGroup(GroupIDBroadcast);
-        }
-        return handleDeviceInterfaceRequest(_request, interface);
-      } else {
-        std::ostringstream sstream;
-        sstream << "{ ok: " << ToJSONValue(ok) << ", message: " << ToJSONValue(errorMessage) << " }";
-        return sstream.str();
+      if(interface != NULL) {
+        interface = &getDSS().getApartment().getGroup(GroupIDBroadcast);
+        return success();
       }
+      return failure("No interface");
     } else {
-      std::string result;
       if(_request.getMethod() == "getStructure") {
-        result = ToJSONValue(getDSS().getApartment());
+        return success(ToJSONValue(getDSS().getApartment()));
       } else if(_request.getMethod() == "getDevices") {
         Set devices;
         if(_request.getParameter("unassigned").empty()) {
@@ -392,7 +294,7 @@ namespace dss {
           devices = GetUnassignedDevices();
         }
 
-        result = "{" + ToJSONValue(devices, "devices") + "}";
+        return success(ToJSONValue(devices));
 /* TODO: re-enable
       } else if(_request.getMethod() == "login") {
         int token = m_LastSessionID;
@@ -400,51 +302,46 @@ namespace dss {
         return "{" + ToJSONValue("token") + ": " + ToJSONValue(token) + "}";
 */
       } else if(_request.getMethod() == "getCircuits") {
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("circuits") << ": [";
-        bool first = true;
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        boost::shared_ptr<JSONArrayBase> circuits;
+
+        resultObj->addProperty("circuits", circuits);
         vector<DSMeter*>& dsMeters = getDSS().getApartment().getDSMeters();
         foreach(DSMeter* dsMeter, dsMeters) {
-          if(!first) {
-            sstream << ",";
-          }
-          first = false;
-          sstream << "{ " << ToJSONValue("name") << ": " << ToJSONValue(dsMeter->getName());
-          sstream << ", " << ToJSONValue("dsid") << ": " << ToJSONValue(dsMeter->getDSID().toString());
-          sstream << ", " << ToJSONValue("busid") << ": " << ToJSONValue(dsMeter->getBusID());
-          sstream << ", " << ToJSONValue("hwVersion") << ": " << ToJSONValue(dsMeter->getHardwareVersion());
-          sstream << ", " << ToJSONValue("swVersion") << ": " << ToJSONValue(dsMeter->getSoftwareVersion());
-          sstream << ", " << ToJSONValue("hwName") << ": " << ToJSONValue(dsMeter->getHardwareName());
-          sstream << ", " << ToJSONValue("deviceType") << ": " << ToJSONValue(dsMeter->getDeviceType());
-          sstream << ", " << ToJSONValue("isPresent") << ": " << ToJSONValue(dsMeter->isPresent());
-          sstream << "}";
-        }
-        sstream << "]}";
-        return JSONOk(sstream.str());
+          boost::shared_ptr<JSONObject> circuit(new JSONObject());
+          circuit->addProperty("name", dsMeter->getName());
+          circuit->addProperty("dsid", dsMeter->getDSID().toString());
+          circuit->addProperty("busid", dsMeter->getBusID());
+          circuit->addProperty("hwVersion", dsMeter->getHardwareVersion());
+          circuit->addProperty("swVersion", dsMeter->getSoftwareVersion());
+          circuit->addProperty("hwName", dsMeter->getHardwareName());
+          circuit->addProperty("deviceType", dsMeter->getDeviceType());
+          circuit->addProperty("isPresent", dsMeter->isPresent());
+        }
+        return success(resultObj);
       } else if(_request.getMethod() == "getName") {
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("name") << ":" << ToJSONValue(getDSS().getApartment().getName()) << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("name", getDSS().getApartment().getName());
+        return success(resultObj);
       } else if(_request.getMethod() == "setName") {
         getDSS().getApartment().setName(_request.getParameter("newName"));
-        result = ResultToJSON(true);
+        return success();
       } else if(_request.getMethod() == "rescan") {
         std::vector<DSMeter*> mods = getDSS().getApartment().getDSMeters();
         foreach(DSMeter* pDSMeter, mods) {
           pDSMeter->setIsValid(false);
         }
-        result = ResultToJSON(true);
+        return success();
       } else {
         throw std::runtime_error("Unhandled function");
       }
-      return result;
     }
   } // handleApartmentCall
 
 
   //=========================================== ZoneRequestHandler
 
-  std::string ZoneRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
+  boost::shared_ptr<JSONObject> ZoneRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
     bool ok = true;
     std::string errorMessage;
     std::string zoneName = _request.getParameter("name");
@@ -531,32 +428,32 @@ namespace dss {
             // should never reach here because ok, would be false
             assert(false);
           }
-          std::ostringstream sstream;
-          sstream << "{" << ToJSONValue("scene") << ":" << ToJSONValue(lastScene) << "}";
-          return JSONOk(sstream.str());
+          boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+          resultObj->addProperty("scene", lastScene);
+          return success(resultObj);
         } else if(_request.getMethod() == "getName") {
-          std::ostringstream sstream;
-          sstream << "{" << ToJSONValue("name") << ":" << ToJSONValue(pZone->getName()) << "}";
-          return JSONOk(sstream.str());
+          boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+          resultObj->addProperty("name", pZone->getName());
+          return success(resultObj);
         } else if(_request.getMethod() == "setName") {
           pZone->setName(_request.getParameter("newName"));
-          return ResultToJSON(true);
+          return success();
         } else {
           throw std::runtime_error("Unhandled function");
         }
       }
     }
     if(!ok) {
-      return ResultToJSON(ok, errorMessage);
+      return failure(errorMessage);
     } else {
-      return "";
+      return success(); // TODO: check this, we shouldn't get here
     }
   } // handleRequest
 
 
   //=========================================== DeviceRequestHandler
 
-  std::string DeviceRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
+  boost::shared_ptr<JSONObject> DeviceRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
     bool ok = true;
     std::string errorMessage;
     std::string deviceName = _request.getParameter("name");
@@ -592,120 +489,128 @@ namespace dss {
       if(isDeviceInterfaceCall(_request)) {
         return handleDeviceInterfaceRequest(_request, pDevice);
       } else if(_request.getMethod() == "getGroups") {
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
         int numGroups = pDevice->getGroupsCount();
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("groups") << ": [";
-        bool first = true;
+
+        boost::shared_ptr<JSONArrayBase> groups(new JSONArrayBase());
+        resultObj->addElement("groups", groups);
         for(int iGroup = 0; iGroup < numGroups; iGroup++) {
-          if(!first) {
-            sstream << ", ";
-          }
-          first = false;
           try {
             Group& group = pDevice->getGroupByIndex(iGroup);
-            sstream << "{ " << ToJSONValue("id") << ":" << group.getID();
+            boost::shared_ptr<JSONObject> groupObj(new JSONObject());
+            groups->addElement("", groupObj);
+
+            groupObj->addProperty("id", group.getID());
             if(!group.getName().empty()) {
-              sstream << ", " << ToJSONValue("name") << ":" << ToJSONValue(group.getName());
+              groupObj->addProperty("name", group.getName());
             }
           } catch(std::runtime_error&) {
             Logger::getInstance()->log("DeviceRequestHandler: Group only present at device level");
           }
-          sstream << "}";
         }
-        sstream << "]}";
-        return sstream.str();
+        return success(resultObj);
       } else if(_request.getMethod() == "getState") {
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("isOn") << ":" << ToJSONValue(pDevice->isOn()) << " }";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("isOn", pDevice->isOn());
+        return success(resultObj);
       } else if(_request.getMethod() == "getName") {
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("name") << ":" << ToJSONValue(pDevice->getName()) << " }";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("name", pDevice->getName());
+        return success(resultObj);
       } else if(_request.getMethod() == "setName") {
         pDevice->setName(_request.getParameter("newName"));
-        return ResultToJSON(true);
+        return success();
       } else if(_request.getMethod() == "enable") {
         pDevice->enable();
-        return ResultToJSON(true);
+        return success();
       } else if(_request.getMethod() == "disable") {
         pDevice->disable();
-        return ResultToJSON(true);
+        return success();
       } else if(_request.getMethod() == "setRawValue") {
         int value = strToIntDef(_request.getParameter("value"), -1);
         if(value == -1) {
-          return ResultToJSON(false, "Invalid or missing parameter 'value'");
+          return failure("Invalid or missing parameter 'value'");
         }
         int parameterID = strToIntDef(_request.getParameter("parameterID"), -1);
         if(parameterID == -1) {
-          return ResultToJSON(false, "Invalid or missing parameter 'parameterID'");
+          return failure("Invalid or missing parameter 'parameterID'");
         }
         int size = strToIntDef(_request.getParameter("size"), -1);
         if(size == -1) {
-          return ResultToJSON(false, "Invalid or missing parameter 'size'");
+          return failure("Invalid or missing parameter 'size'");
         }
 
         pDevice->setRawValue(value, parameterID, size);
-        return JSONOk();
+        return success();
       } else {
         throw std::runtime_error("Unhandled function");
       }
     } else {
-      return ResultToJSON(ok, errorMessage);
+      if(ok) {
+        return success();
+      } else {
+        return failure(errorMessage);
+      }
     }
   } // handleRequest
 
 
   //=========================================== CircuitRequestHandler
 
-  std::string CircuitRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
+  boost::shared_ptr<JSONObject> CircuitRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
     std::string idString = _request.getParameter("id");
     if(idString.empty()) {
-      return ResultToJSON(false, "missing parameter id");
+      return failure("missing parameter id");
     }
     dsid_t dsid = dsid_t::fromString(idString);
     if(dsid == NullDSID) {
-      return ResultToJSON(false, "could not parse dsid");
+      return failure("could not parse dsid");
     }
     try {
       DSMeter& dsMeter = getDSS().getApartment().getDSMeterByDSID(dsid);
       if(_request.getMethod() == "getName") {
-        return JSONOk("{ " + ToJSONValue("name") + ": " + ToJSONValue(dsMeter.getName()) + "}");
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("name", dsMeter.getName());
+        return success(resultObj);
       } else if(_request.getMethod() == "setName") {
         dsMeter.setName(_request.getParameter("newName"));
-        return ResultToJSON(true);
+        return success();
       } else if(_request.getMethod() == "getEnergyBorder") {
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("orange") << ":" << ToJSONValue(dsMeter.getEnergyLevelOrange());
-        sstream << "," << ToJSONValue("red") << ":" << ToJSONValue(dsMeter.getEnergyLevelRed());
-        sstream << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("orange", dsMeter.getEnergyLevelOrange());
+        resultObj->addProperty("red", dsMeter.getEnergyLevelRed());
+        return success(resultObj);
       } else if(_request.getMethod() == "getConsumption") {
-        return JSONOk("{ " + ToJSONValue("consumption") + ": " +  uintToString(dsMeter.getPowerConsumption()) +"}");
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("consumption", dsMeter.getPowerConsumption());
+        return success(resultObj);
       } else if(_request.getMethod() == "getEnergyMeterValue") {
-        return JSONOk("{ " + ToJSONValue("metervalue") + ": " +  uintToString(dsMeter.getEnergyMeterValue()) +"}");
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("metervalue", dsMeter.getEnergyMeterValue());
+        return success(resultObj);
       } else if(_request.getMethod() == "rescan") {
         dsMeter.setIsValid(false);
-        return ResultToJSON(true);
+        return success();
       } else {
         throw std::runtime_error("Unhandled function");
       }
     } catch(std::runtime_error&) {
-      return ResultToJSON(false, "could not find dsMeter with given dsid");
+      return failure("could not find dsMeter with given dsid");
     }
-    return "";
   } // handleRequest
 
 
   //=========================================== SetRequestHandler
 
-  std::string SetRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
+  boost::shared_ptr<JSONObject> SetRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
     if(_request.getMethod() == "fromApartment") {
-      return JSONOk("{'self': '.'}");
+      boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+      resultObj->addProperty("self", ".");
+      return success(resultObj);
     } else {
       std::string self = trim(_request.getParameter("self"));
       if(self.empty()) {
-        return ResultToJSON(false, "missing parameter 'self'");
+        return failure("missing parameter 'self'");
       }
 
       if(_request.getMethod() == "byZone") {
@@ -718,12 +623,12 @@ namespace dss {
         } else if(!_request.getParameter("zoneName").empty()) {
           additionalPart += _request.getParameter("zoneName");
         } else {
-          return ResultToJSON(false, "missing either zoneID or zoneName");
+          return failure("missing either zoneID or zoneName");
         }
 
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("self") << ":" << ToJSONValue(self + additionalPart) << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("self", self + additionalPart);
+        return success(resultObj);
       } else if(_request.getMethod() == "byGroup") {
         std::string additionalPart;
         if(self != ".") {
@@ -734,12 +639,12 @@ namespace dss {
         } else if(!_request.getParameter("groupName").empty()) {
           additionalPart += _request.getParameter("groupName");
         } else {
-          return ResultToJSON(false, "missing either groupID or groupName");
+          return failure("missing either groupID or groupName");
         }
 
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("self") << ":" << ToJSONValue(self + additionalPart) << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("self", self + additionalPart);
+        return success(resultObj);
       } else if(_request.getMethod() == "byDSID") {
         std::string additionalPart;
         if(self != ".") {
@@ -748,20 +653,20 @@ namespace dss {
         if(!_request.getParameter("dsid").empty()) {
           additionalPart += "dsid(" + _request.getParameter("dsid") + ")";
         } else {
-          return ResultToJSON(false, "missing parameter dsid");
+          return failure("missing parameter dsid");
         }
 
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("self") << ":" << ToJSONValue(self + additionalPart) << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("self", self + additionalPart);
+        return success(resultObj);
       } else if(_request.getMethod() == "getDevices") {
         SetBuilder builder(getDSS().getApartment());
         Set set = builder.buildSet(self, NULL);
-        return JSONOk("{" + ToJSONValue(set, "devices") + "}");
+        return success(ToJSONValue(set));
       } else if(_request.getMethod() == "add") {
         std::string other = _request.getParameter("other");
         if(other.empty()) {
-          return ResultToJSON(false, "missing parameter other");
+          return failure("missing parameter other");
         }
         std::string additionalPart;
         if(self != ".") {
@@ -769,13 +674,13 @@ namespace dss {
         }
         additionalPart += "add(" + other + ")";
 
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("self") << ":" << ToJSONValue(self + additionalPart) << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("self", self + additionalPart);
+        return success(resultObj);
       } else if(_request.getMethod() == "subtract") {
         std::string other = _request.getParameter("other");
         if(other.empty()) {
-          return ResultToJSON(false, "missing parameter other");
+          return failure("missing parameter other");
         }
         std::string additionalPart;
         if(self != ".") {
@@ -783,9 +688,9 @@ namespace dss {
         }
         additionalPart += "subtract(" + other + ")";
 
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("self") << ":" << ToJSONValue(self + additionalPart) << "}";
-        return JSONOk(sstream.str());
+        boost::shared_ptr<JSONObject> resultObj(new JSONObject());
+        resultObj->addProperty("self", self + additionalPart);
+        return success(resultObj);
       } else if(isDeviceInterfaceCall(_request)) {
         SetBuilder builder(getDSS().getApartment());
         Set set = builder.buildSet(self, NULL);
@@ -793,621 +698,49 @@ namespace dss {
       } else {
         throw std::runtime_error("Unhandled function");
       }
-
     }
-    return "";
   } // handleRequest
 
 
-  //=========================================== PropertyRequestHandler
 
-  std::string PropertyRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    std::string propName = _request.getParameter("path");
-    if(propName.empty()) {
-      return ResultToJSON(false, "Need parameter \'path\' for property operations");
-    }
-    PropertyNodePtr node = getDSS().getPropertySystem().getProperty(propName);
+  //================================================== WebServerRequestHandlerJSON
 
-    if(_request.getMethod() == "getString") {
-      if(node == NULL) {
-        return ResultToJSON(false, "Could not find node named '" + propName + "'");
-      }
-      try {
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("value") << ": " << ToJSONValue(node->getStringValue()) << "}";
-        return JSONOk(sstream.str());
-      } catch(PropertyTypeMismatch& ex) {
-        return ResultToJSON(false, std::string("Error getting property: '") + ex.what() + "'");
-      }
-    } else if(_request.getMethod() == "getInteger") {
-      if(node == NULL) {
-        return ResultToJSON(false, "Could not find node named '" + propName + "'");
-      }
-      try {
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("value") << ": " << ToJSONValue(node->getIntegerValue()) << "}";
-        return JSONOk(sstream.str());
-      } catch(PropertyTypeMismatch& ex) {
-        return ResultToJSON(false, std::string("Error getting property: '") + ex.what() + "'");
-      }
-    } else if(_request.getMethod() == "getBoolean") {
-      if(node == NULL) {
-        return ResultToJSON(false, "Could not find node named '" + propName + "'");
-      }
-      try {
-        std::ostringstream sstream;
-        sstream << "{ " << ToJSONValue("value") << ": " << ToJSONValue(node->getBoolValue()) << "}";
-        return JSONOk(sstream.str());
-      } catch(PropertyTypeMismatch& ex) {
-        return ResultToJSON(false, std::string("Error getting property: '") + ex.what() + "'");
-      }
-    } else if(_request.getMethod() == "setString") {
-      std::string value = _request.getParameter("value");
-      if(node == NULL) {
-        node = getDSS().getPropertySystem().createProperty(propName);
-      }
-      try {
-        node->setStringValue(value);
-      } catch(PropertyTypeMismatch& ex) {
-        return ResultToJSON(false, std::string("Error setting property: '") + ex.what() + "'");
-      }
-      return JSONOk();
-    } else if(_request.getMethod() == "setBoolean") {
-      std::string strValue = _request.getParameter("value");
-      bool value;
-      if(strValue == "true") {
-        value = true;
-      } else if(strValue == "false") {
-        value = false;
-      } else {
-        return ResultToJSON(false, "Expected 'true' or 'false' for parameter 'value' but got: '" + strValue + "'");
-      }
-      if(node == NULL) {
-        node = getDSS().getPropertySystem().createProperty(propName);
-      }
-      try {
-        node->setBooleanValue(value);
-      } catch(PropertyTypeMismatch& ex) {
-        return ResultToJSON(false, std::string("Error setting property: '") + ex.what() + "'");
-      }
-      return JSONOk();
-    } else if(_request.getMethod() == "setInteger") {
-      std::string strValue = _request.getParameter("value");
-      int value;
-      try {
-        value = strToInt(strValue);
-      } catch(...) {
-        return ResultToJSON(false, "Could not convert parameter 'value' to std::string. Got: '" + strValue + "'");
-      }
-      if(node == NULL) {
-        node = getDSS().getPropertySystem().createProperty(propName);
-      }
-      try {
-        node->setIntegerValue(value);
-      } catch(PropertyTypeMismatch& ex) {
-        return ResultToJSON(false, std::string("Error setting property: '") + ex.what() + "'");
-      }
-      return JSONOk();
-    } else if(_request.getMethod() == "getChildren") {
-      if(node == NULL) {
-        return ResultToJSON(false, "Could not find node named '" + propName + "'");
-      }
-      std::ostringstream sstream;
-      sstream << "[";
-      bool first = true;
-      for(int iChild = 0; iChild < node->getChildCount(); iChild++) {
-        if(!first) {
-          sstream << ",";
-        }
-        first = false;
-        PropertyNodePtr cnode = node->getChild(iChild);
-        sstream << "{" << ToJSONValue("name") << ":" << ToJSONValue(cnode->getName());
-        sstream << "," << ToJSONValue("type") << ":" << ToJSONValue(getValueTypeAsString(cnode->getValueType()));
-        sstream << "}";
-      }
-      sstream << "]";
-      return JSONOk(sstream.str());
-    } else if(_request.getMethod() == "getType") {
-      if(node == NULL) {
-        return ResultToJSON(false, "Could not find node named '" + propName + "'");
-      }
-      std::ostringstream sstream;
-      sstream << ":" << ToJSONValue("type") << ":" << ToJSONValue(getValueTypeAsString(node->getValueType())) << "}";
-      return JSONOk(sstream.str());
-    } else {
-      throw std::runtime_error("Unhandled function");
+  std::string WebServerRequestHandlerJSON::handleRequest(const RestfulRequest& _request, Session* _session) {
+    boost::shared_ptr<JSONObject> response = jsonHandleRequest(_request, _session);
+    if(response != NULL) {
+      return response->toString();
     }
     return "";
   } // handleRequest
 
+  boost::shared_ptr<JSONObject> WebServerRequestHandlerJSON::success() {
+    return success(boost::shared_ptr<JSONObject>());
+  }
 
-  //=========================================== EventRequestHandler
-
-  std::string EventRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    if(_request.getMethod() == "raise") {
-      std::string name = _request.getParameter("name");
-      std::string location = _request.getParameter("location");
-      std::string context = _request.getParameter("context");
-      std::string parameter = _request.getParameter("parameter");
-
-      boost::shared_ptr<Event> evt(new Event(name));
-      if(!context.empty()) {
-        evt->setContext(context);
-      }
-      if(!location.empty()) {
-        evt->setLocation(location);
-      }
-      std::vector<std::string> params = dss::splitString(parameter, ';');
-      for(std::vector<std::string>::iterator iParam = params.begin(), e = params.end();
-          iParam != e; ++iParam)
-      {
-        std::vector<std::string> nameValue = dss::splitString(*iParam, '=');
-        if(nameValue.size() == 2) {
-          dss::Logger::getInstance()->log("WebServer::handleEventCall: Got parameter '" + nameValue[0] + "'='" + nameValue[1] + "'");
-          evt->setProperty(nameValue[0], nameValue[1]);
-        } else {
-          dss::Logger::getInstance()->log(std::string("Invalid parameter found WebServer::handleEventCall: ") + *iParam );
-        }
-      }
-
-      getDSS().getEventQueue().pushEvent(evt);
-      return ResultToJSON(true);
-    } else {
-      throw std::runtime_error("Unhandled function");
-    }
-  } // handleRequest
-  
-
-  //=========================================== SystemRequestHandler
-
-  std::string SystemRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    if(_request.getMethod() == "version") {
-      return ResultToJSON(true, DSS::getInstance()->versionString());
-    }
-    throw std::runtime_error("Unhandled function");
-  } // handleRequest
-
-
-  //=========================================== StructureRequestHandler
-
-  std::string StructureRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    StructureManipulator manipulator(*getDSS().getDS485Interface().getStructureModifyingBusInterface(), getDSS().getApartment());
-    if(_request.getMethod() == "zoneAddDevice") {
-      std::string devidStr = _request.getParameter("devid");
-      if(!devidStr.empty()) {
-        dsid_t devid = dsid::fromString(devidStr);
-
-        Device& dev = DSS::getInstance()->getApartment().getDeviceByDSID(devid);
-        if(!dev.isPresent()) {
-          return ResultToJSON(false, "cannot add nonexisting device to a zone");
-        }
-
-        std::string zoneIDStr = _request.getParameter("zone");
-        if(!zoneIDStr.empty()) {
-          try {
-            int zoneID = strToInt(zoneIDStr);
-            DeviceReference devRef(dev, &DSS::getInstance()->getApartment());
-            try {
-              Zone& zone = getDSS().getApartment().getZone(zoneID);
-              manipulator.addDeviceToZone(dev, zone);
-            } catch(ItemNotFoundException&) {
-              return ResultToJSON(false, "Could not find zone");
-            }
-          } catch(std::runtime_error& err) {
-            return ResultToJSON(false, err.what());
-          }
-        }
-        return ResultToJSON(true);
-      } else {
-        return ResultToJSON(false, "Need parameter devid");
-      }
-    } else if(_request.getMethod() == "addZone") {
-      int zoneID = -1;
-
-      std::string zoneIDStr = _request.getParameter("zoneID");
-      if(!zoneIDStr.empty()) {
-        zoneID = strToIntDef(zoneIDStr, -1);
-      }
-      if(zoneID != -1) {
-        getDSS().getApartment().allocateZone(zoneID);
-      } else {
-        return ResultToJSON(false, "could not find zone");
-      }
-      return ResultToJSON(true, "");
-    } else if(_request.getMethod() == "removeZone") {
-      int zoneID = -1;
-
-      std::string zoneIDStr = _request.getParameter("zoneID");
-      if(!zoneIDStr.empty()) {
-        zoneID = strToIntDef(zoneIDStr, -1);
-      }
-      if(zoneID != -1) {
-        try {
-          Zone& zone = getDSS().getApartment().getZone(zoneID);
-          if(zone.getFirstZoneOnDSMeter() != -1) {
-            return ResultToJSON(false, "Cannot delete a primary zone");
-          }
-          if(zone.getDevices().length() > 0) {
-            return ResultToJSON(false, "Cannot delete a non-empty zone");
-          }
-          getDSS().getApartment().removeZone(zoneID);
-          getDSS().getModelMaintenance().addModelEvent(new ModelEvent(ModelEvent::etModelDirty));
-          return JSONOk();
-        } catch(ItemNotFoundException&) {
-          return ResultToJSON(false, "Could not find zone");
-        }
-      } else {
-        return ResultToJSON(false, "Missing parameter zoneID");
-      }
-    } else {
-      throw std::runtime_error("Unhandled function");
-    }
-  } // handleRequest
-
-
-  //=========================================== SimRequestHandler
-
-  std::string SimRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    if(_request.getMethod() == "switch") {
-      if(_request.getMethod() == "switch/pressed") {
-        int buttonNr = strToIntDef(_request.getParameter("buttonnr"), -1);
-        if(buttonNr == -1) {
-          return ResultToJSON(false, "Invalid button number");
-        }
-
-        int zoneID = strToIntDef(_request.getParameter("zoneID"), -1);
-        if(zoneID == -1) {
-          return ResultToJSON(false, "Could not parse zoneID");
-        }
-        int groupID = strToIntDef(_request.getParameter("groupID"), -1);
-        if(groupID == -1) {
-          return ResultToJSON(false, "Could not parse groupID");
-        }
-        try {
-          Zone& zone = getDSS().getApartment().getZone(zoneID);
-          Group* pGroup = zone.getGroup(groupID);
-
-          if(pGroup == NULL) {
-            return ResultToJSON(false, "Could not find group");
-          }
-
-          switch(buttonNr) {
-          case 1: // upper-left
-          case 3: // upper-right
-          case 7: // lower-left
-          case 9: // lower-right
-            break;
-          case 2: // up
-            pGroup->increaseValue();
-            break;
-          case 8: // down
-            pGroup->decreaseValue();
-            break;
-          case 4: // left
-            pGroup->previousScene();
-            break;
-          case 6: // right
-            pGroup->nextScene();
-            break;
-          case 5:
-            {
-              if(groupID == GroupIDGreen) {
-                getDSS().getApartment().getGroup(0).callScene(SceneBell);
-              } else if(groupID == GroupIDRed){
-                getDSS().getApartment().getGroup(0).callScene(SceneAlarm);
-              } else {
-                const int lastScene = pGroup->getLastCalledScene();
-                if(lastScene == SceneOff || lastScene == SceneDeepOff ||
-                  lastScene == SceneStandBy || lastScene == ScenePanic)
-                {
-                  pGroup->callScene(Scene1);
-                } else {
-                  pGroup->callScene(SceneOff);
-                }
-              }
-            }
-            break;
-          default:
-            return ResultToJSON(false, "Invalid button nr (range is 1..9)");
-          }
-        } catch(std::runtime_error&) {
-          return ResultToJSON(false, "Could not find zone");
-        }
-      }
-    } else if(_request.getMethod() == "addDevice") {
-      //std::string type = _parameter["type"];
-      //std::string dsidStr = _parameter["dsid"];
-      // TODO: not finished yet ;)
-      return "";
-    }
-    throw std::runtime_error("Unhandled function");
-  } // handleRequest
-
-
-  //=========================================== DebugRequestHandler
-
-  std::string DebugRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    if(_request.getMethod() == "sendFrame") {
-      int destination = strToIntDef(_request.getParameter("destination"),0) & 0x3F;
-      bool broadcast = _request.getParameter("broadcast") == "true";
-      int counter = strToIntDef(_request.getParameter("counter"), 0x00) & 0x03;
-      int command = strToIntDef(_request.getParameter("command"), 0x09 /* request */) & 0x00FF;
-      int length = strToIntDef(_request.getParameter("length"), 0x00) & 0x0F;
-
-      std::cout
-          << "sending frame: "
-          << "\ndest:    " << destination
-          << "\nbcst:    " << broadcast
-          << "\ncntr:    " << counter
-          << "\ncmd :    " << command
-          << "\nlen :    " << length << std::endl;
-
-      DS485CommandFrame* frame = new DS485CommandFrame();
-      frame->getHeader().setBroadcast(broadcast);
-      frame->getHeader().setDestination(destination);
-      frame->getHeader().setCounter(counter);
-      frame->setCommand(command);
-      for(int iByte = 0; iByte < length; iByte++) {
-        uint8_t byte = strToIntDef(_request.getParameter(std::string("payload_") + intToString(iByte+1)), 0xFF);
-        std::cout << "b" << std::dec << iByte << ": " << std::hex << (int)byte << "\n";
-        frame->getPayload().add<uint8_t>(byte);
-      }
-      std::cout << std::dec << "done" << std::endl;
-      DS485Interface* intf = &DSS::getInstance()->getDS485Interface();
-      DS485Proxy* proxy = dynamic_cast<DS485Proxy*>(intf);
-      if(proxy != NULL) {
-        proxy->sendFrame(*frame);
-      } else {
-        delete frame;
-      }
-      return ResultToJSON(true);
-    } else if(_request.getMethod() == "dSLinkSend") {
-      std::string deviceDSIDString =_request.getParameter("dsid");
-      Device* pDevice = NULL;
-      if(!deviceDSIDString.empty()) {
-        dsid_t deviceDSID = dsid_t::fromString(deviceDSIDString);
-        if(!(deviceDSID == NullDSID)) {
-          try {
-            Device& device = getDSS().getApartment().getDeviceByDSID(deviceDSID);
-            pDevice = &device;
-          } catch(std::runtime_error& e) {
-            return ResultToJSON(false ,"Could not find device with dsid '" + deviceDSIDString + "'");
-          }
-        } else {
-          return ResultToJSON(false, "Could not parse dsid '" + deviceDSIDString + "'");
-        }
-      } else {
-        return ResultToJSON(false, "Missing parameter 'dsid'");
-      }
+  boost::shared_ptr<JSONObject> WebServerRequestHandlerJSON::success(const std::string& _message) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    result->addProperty("ok", true);
+    result->addProperty("message", _message);
+    return result;
+  }
 
-      int iValue = strToIntDef(_request.getParameter("value"), -1);
-      if(iValue == -1) {
-        return ResultToJSON(false, "Missing parameter 'value'");
-      }
-      if(iValue < 0 || iValue > 0x00ff) {
-        return ResultToJSON(false, "Parameter 'value' is out of range (0-0xff)");
-      }
-      bool writeOnly = false;
-      bool lastValue = false;
-      if(_request.getParameter("writeOnly") == "true") {
-        writeOnly = true;
-      }
-      if(_request.getParameter("lastValue") == "true") {
-        lastValue = true;
-      }
-      uint8_t result;
-      try {
-        result = pDevice->dsLinkSend(iValue, lastValue, writeOnly);
-      } catch(std::runtime_error& e) {
-        return ResultToJSON(false, std::string("Error: ") + e.what());
-      }
-      if(writeOnly) {
-        return ResultToJSON(true);
-      } else {
-        std::ostringstream sstream;
-        sstream << "{" << ToJSONValue("value") << ":" << ToJSONValue(result) << "}";
-        return JSONOk(sstream.str());
-      }
-    } else if(_request.getMethod() == "pingDevice") {
-      std::string deviceDSIDString = _request.getParameter("dsid");
-      if(deviceDSIDString.empty()) {
-        return ResultToJSON(false, "Missing parameter 'dsid'");
-      }
-      try {
-        dsid_t deviceDSID = dsid_t::fromString(deviceDSIDString);
-        Device& device = getDSS().getApartment().getDeviceByDSID(deviceDSID);
-        DS485CommandFrame* frame = new DS485CommandFrame();
-        frame->getHeader().setBroadcast(true);
-        frame->getHeader().setDestination(device.getDSMeterID());
-        frame->setCommand(CommandRequest);
-        frame->getPayload().add<uint8_t>(FunctionDeviceGetTransmissionQuality);
-        frame->getPayload().add<uint16_t>(device.getShortAddress());
-        DS485Interface* intf = &DSS::getInstance()->getDS485Interface();
-        DS485Proxy* proxy = dynamic_cast<DS485Proxy*>(intf);
-        if(proxy != NULL) {
-          boost::shared_ptr<FrameBucketCollector> bucket = proxy->sendFrameAndInstallBucket(*frame, FunctionDeviceGetTransmissionQuality);
-          bucket->waitForFrame(2000);
-
-          boost::shared_ptr<DS485CommandFrame> recFrame = bucket->popFrame();
-          if(recFrame == NULL) {
-            return ResultToJSON(false, "No result received");
-          }
-          PayloadDissector pd(recFrame->getPayload());
-          pd.get<uint8_t>();
-          int errC = int(pd.get<uint16_t>());
-          if(errC < 0) {
-            return ResultToJSON(false, "dSM reported error-code: " + intToString(errC));
-          }
-          pd.get<uint16_t>(); // device address
-          int qualityHK = pd.get<uint16_t>();
-          int qualityRK = pd.get<uint16_t>();
-          std::ostringstream sstream;
-          sstream << "{" << ToJSONValue("qualityHK") << ":" << ToJSONValue(qualityHK) << ",";
-          sstream << ToJSONValue("qualityRK") << ":" << ToJSONValue(qualityRK) << "}";
-          return JSONOk(sstream.str());
-        } else {
-          delete frame;
-          return ResultToJSON(false, "Proxy has a wrong type or is null");
-        }
-      } catch(ItemNotFoundException&) {
-        return ResultToJSON(false ,"Could not find device with dsid '" + deviceDSIDString + "'");
-      } catch(std::invalid_argument&) {
-        return ResultToJSON(false, "Could not parse dsid '" + deviceDSIDString + "'");
-      }
-    } else if(_request.getMethod() == "resetZone") {
-      std::string zoneIDStr = _request.getParameter("zoneID");
-      int zoneID;
-      try {
-        zoneID = strToInt(zoneIDStr);
-      } catch(std::runtime_error&) {
-        return ResultToJSON(false, "Could not parse Zone ID");
-      }
-      DS485CommandFrame* frame = new DS485CommandFrame();
-      frame->getHeader().setBroadcast(true);
-      frame->getHeader().setDestination(0);
-      frame->setCommand(CommandRequest);
-      frame->getPayload().add<uint8_t>(FunctionZoneRemoveAllDevicesFromZone);
-      frame->getPayload().add<uint8_t>(zoneID);
-      DS485Interface* intf = &DSS::getInstance()->getDS485Interface();
-      DS485Proxy* proxy = dynamic_cast<DS485Proxy*>(intf);
-      if(proxy != NULL) {
-        proxy->sendFrame(*frame);
-        return ResultToJSON(true, "Please restart your dSMs");
-      } else {
-        delete frame;
-        return ResultToJSON(false, "Proxy has a wrong type or is null");
-      }
+  boost::shared_ptr<JSONObject> WebServerRequestHandlerJSON::success(boost::shared_ptr<JSONElement> _innerResult) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    result->addProperty("ok", true);
+    if(_innerResult != NULL) {
+      result->addElement("result", _innerResult);
     }
-    throw std::runtime_error("Unhandled function");
-  } // handleRequest
-
+    return result;
+  }
 
-  //=========================================== MeteringRequestHandler
-
-  std::string MeteringRequestHandler::handleRequest(const RestfulRequest& _request, Session* _session) {
-    if(_request.getMethod() == "getResolutions") {
-      std::vector<boost::shared_ptr<MeteringConfigChain> > meteringConfig = getDSS().getMetering().getConfig();
-      std::ostringstream sstream;
-      sstream << "{" << ToJSONValue("resolutions") << ":" << "[";
-      for(unsigned int iConfig = 0; iConfig < meteringConfig.size(); iConfig++) {
-        boost::shared_ptr<MeteringConfigChain> cConfig = meteringConfig[iConfig];
-        for(int jConfig = 0; jConfig < cConfig->size(); jConfig++) {
-          sstream << "{" << ToJSONValue("type") << ":" << (cConfig->isEnergy() ? ToJSONValue("energy") : ToJSONValue("consumption") ) << ","
-                  << ToJSONValue("unit") << ":" << ToJSONValue(cConfig->getUnit()) << ","
-                  << ToJSONValue("resolution") << ":" << ToJSONValue(cConfig->getResolution(jConfig)) << "}";
-          if(jConfig < cConfig->size() && iConfig < meteringConfig.size()) {
-            sstream << ",";
-          }
-        }
-      }
-      sstream << "]"  << "}";
-      return JSONOk(sstream.str());
-    } else if(_request.getMethod() == "getSeries") {
-      std::ostringstream sstream;
-      sstream << "{ " << ToJSONValue("series") << ": [";
-      bool first = true;
-      vector<DSMeter*>& dsMeters = getDSS().getApartment().getDSMeters();
-      foreach(DSMeter* dsMeter, dsMeters) {
-        if(!first) {
-          sstream << ",";
-        }
-        first = false;
-        sstream << "{ " << ToJSONValue("dsid") << ": " << ToJSONValue(dsMeter->getDSID().toString());
-        sstream << ", " << ToJSONValue("type") << ": " << ToJSONValue("energy");
-        sstream << "},";
-        sstream << "{ " << ToJSONValue("dsid") << ": " << ToJSONValue(dsMeter->getDSID().toString());
-        sstream << ", " << ToJSONValue("type") << ": " << ToJSONValue("consumption");
-        sstream << "}";
-      }
-      sstream << "]}";
-      return JSONOk(sstream.str());
-    } else if(_request.getMethod() == "getValues") { //?dsid=;n=,resolution=,type=
-      std::string errorMessage;
-      std::string deviceDSIDString = _request.getParameter("dsid");
-      std::string resolutionString = _request.getParameter("resolution");
-      std::string typeString = _request.getParameter("type");
-      std::string fileSuffix;
-      std::string storageLocation;
-      std::string seriesPath;
-      int resolution;
-      bool energy;
-      if(!deviceDSIDString.empty()) {
-        dsid_t deviceDSID = dsid_t::fromString(deviceDSIDString);
-        if(!(deviceDSID == NullDSID)) {
-          try {
-            getDSS().getApartment().getDSMeterByDSID(deviceDSID);
-          } catch(std::runtime_error& e) {
-            return ResultToJSON(false, "Could not find device with dsid '" + deviceDSIDString + "'");
-          }
-        } else {
-        return ResultToJSON(false, "Could not parse dsid '" + deviceDSIDString + "'");
-        }
-      } else {
-        return ResultToJSON(false, "Could not parse dsid '" + deviceDSIDString + "'");
-      }
-      resolution = strToIntDef(resolutionString, -1);
-      if(resolution == -1) {
-        return ResultToJSON(false, "Need could not parse resolution '" + resolutionString + "'");
-      }
-      if(typeString.empty()) {
-        return ResultToJSON(false, "Need a type, 'energy' or 'consumption'");
-      } else {
-        if(typeString == "consumption") {
-          energy = false;
-        } else if(typeString == "energy") {
-          energy = true;
-        } else {
-          return ResultToJSON(false, "Invalide type '" + typeString + "'");
-        }
-      }
-      if(!resolutionString.empty()) {
-        std::vector<boost::shared_ptr<MeteringConfigChain> > meteringConfig = getDSS().getMetering().getConfig();
-        storageLocation = getDSS().getMetering().getStorageLocation();
-        for(unsigned int iConfig = 0; iConfig < meteringConfig.size(); iConfig++) {
-          boost::shared_ptr<MeteringConfigChain> cConfig = meteringConfig[iConfig];
-          for(int jConfig = 0; jConfig < cConfig->size(); jConfig++) {
-            if(cConfig->isEnergy() == energy && cConfig->getResolution(jConfig) == resolution) {
-              fileSuffix = cConfig->getFilenameSuffix(jConfig);
-            }
-          }
-        }
-        if(fileSuffix.empty()) {
-          return ResultToJSON(false, "No data for '" + typeString + "' and resolution '" + resolutionString + "'");
-        } else {
-          seriesPath = storageLocation + deviceDSIDString + "_" + fileSuffix + ".xml";
-          log("_Trying to load series from " + seriesPath);
-          if(boost::filesystem::exists(seriesPath)) {
-            SeriesReader<CurrentValue> reader;
-            boost::shared_ptr<Series<CurrentValue> > s = boost::shared_ptr<Series<CurrentValue> >(reader.readFromXML(seriesPath));
-            boost::shared_ptr<std::deque<CurrentValue> > values = s->getExpandedValues();
-            bool first = true;
-            std::ostringstream sstream;
-            sstream << "{ " ;
-            sstream << ToJSONValue("dsmid") << ":" << ToJSONValue(deviceDSIDString) << ",";
-            sstream << ToJSONValue("type") << ":" << ToJSONValue(typeString) << ",";
-            sstream << ToJSONValue("resolution") << ":" << ToJSONValue(resolutionString) << ",";
-            sstream << ToJSONValue("values") << ": [";
-            for(std::deque<CurrentValue>::iterator iValue = values->begin(), e = values->end(); iValue != e; iValue++)
-            {
-              if(!first) {
-                sstream << ",";
-              }
-              first = false;
-              sstream << "[" << iValue->getTimeStamp().secondsSinceEpoch()  << "," << iValue->getValue() << "]";
-            }
-            sstream << "]}";
-            return JSONOk(sstream.str());
-          } else {
-            return ResultToJSON(false, "No data-file for '" + typeString + "' and resolution '" + resolutionString + "'");
-          }
-        }
-      } else {
-        return ResultToJSON(false, "Could not parse resolution '" + resolutionString + "'");
-      }
-    } else if(_request.getMethod() == "getAggregatedValues") { //?set=;n=,resolution=;type=
-      // TODO: implement
+  boost::shared_ptr<JSONObject> WebServerRequestHandlerJSON::failure(const std::string& _message) {
+    boost::shared_ptr<JSONObject> result(new JSONObject());
+    result->addProperty("ok", false);
+    if(!_message.empty()) {
+      result->addProperty("message", _message);
     }
-    throw std::runtime_error("Unhandled function");
-  } // handleRequest
+    Logger::getInstance()->log("JSON call failed: '" + _message + "'");
+    return result;
+  }
 
 } // namespace dss
diff --git a/core/web/webrequests.h b/core/web/webrequests.h
index 9692a7a..8663dd4 100644
--- a/core/web/webrequests.h
+++ b/core/web/webrequests.h
@@ -26,6 +26,7 @@
 #include "core/web/restful.h"
 
 #include <string>
+#include <boost/shared_ptr.hpp>
 
 #include "core/logger.h"
 #include "core/dss.h"
@@ -33,6 +34,8 @@
 namespace dss {
 
   class IDeviceInterface;
+  class JSONObject;
+  class JSONElement;
   
   class WebServerRequestHandler : public RestfulRequestHandler {
   protected:
@@ -45,9 +48,20 @@ namespace dss {
     }
   }; // WebServerRequestHandler
 
-  class DeviceInterfaceRequestHandler : public WebServerRequestHandler {
+  class WebServerRequestHandlerJSON : public WebServerRequestHandler {
+  protected:
+    boost::shared_ptr<JSONObject> success();
+    boost::shared_ptr<JSONObject> success(boost::shared_ptr<JSONElement> _innerResult);
+    boost::shared_ptr<JSONObject> success(const std::string& _message);
+    boost::shared_ptr<JSONObject> failure(const std::string& _message = "");
+  public:
+    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session) = 0;
+  }; // WebServerRequestHandlerJSON
+
+  class DeviceInterfaceRequestHandler : public WebServerRequestHandlerJSON {
   public:
-    std::string handleDeviceInterfaceRequest(const RestfulRequest& _request, IDeviceInterface* _interface);
+    boost::shared_ptr<JSONObject> handleDeviceInterfaceRequest(const RestfulRequest& _request, IDeviceInterface* _interface);
 
   protected:
     bool isDeviceInterfaceCall(const RestfulRequest& _request);
@@ -55,64 +69,29 @@ namespace dss {
 
   class ApartmentRequestHandler : public DeviceInterfaceRequestHandler {
   public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
   };
 
   class ZoneRequestHandler : public DeviceInterfaceRequestHandler {
   public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
   }; // ZoneRequestHandler
 
   class DeviceRequestHandler : public DeviceInterfaceRequestHandler {
   public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
   }; // DeviceRequestHandler
 
-  class CircuitRequestHandler : public WebServerRequestHandler {
+  class CircuitRequestHandler : public WebServerRequestHandlerJSON {
   public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
   }; // CircuitRequestHandler
 
   class SetRequestHandler : public DeviceInterfaceRequestHandler {
   public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
+    virtual boost::shared_ptr<JSONObject> jsonHandleRequest(const RestfulRequest& _request, Session* _session);
   }; // SetRequestHandler
 
-  class PropertyRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // PropertyRequestHandler
-
-  class EventRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // EventRequestHandler
-
-  class SystemRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // SystemRequestHandler
-
-  class StructureRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // StructureRequestHandler
-
-  class SimRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // SimRequestHandler
-
-  class DebugRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // DebugRequestHandler
-
-  class MeteringRequestHandler : public WebServerRequestHandler {
-  public:
-    virtual std::string handleRequest(const RestfulRequest& _request, Session* _session);
-  }; // MeteringRequestHandler
-
 
 }
 
diff --git a/core/web/webserver.cpp b/core/web/webserver.cpp
index b1d19f1..a6364d5 100644
--- a/core/web/webserver.cpp
+++ b/core/web/webserver.cpp
@@ -33,7 +33,16 @@
 #include "core/web/webrequests.h"
 #include "core/web/webserverplugin.h"
 
+#include "core/web/handler/debugrequesthandler.h"
+#include "core/web/handler/systemrequesthandler.h"
+#include "core/web/handler/simrequesthandler.h"
+#include "core/web/handler/meteringrequesthandler.h"
+#include "core/web/handler/structurerequesthandler.h"
+#include "core/web/handler/eventrequesthandler.h"
+#include "core/web/handler/propertyrequesthandler.h"
+
 #include "webserverapi.h"
+#include "json.h"
 
 namespace dss {
   //============================================= WebServer
@@ -97,8 +106,8 @@ namespace dss {
   } // loadPlugin
 
   void WebServer::setupAPI() {
-    RestfulAPI api = WebServerAPI::createRestfulAPI();
-    RestfulAPIWriter::writeToXML(api, "doc/json_api.xml");
+    m_pAPI = WebServerAPI::createRestfulAPI();
+    RestfulAPIWriter::writeToXML(*m_pAPI, "doc/json_api.xml");
   } // setupAPI
 
   void WebServer::doStart() {
@@ -247,8 +256,16 @@ namespace dss {
 
     std::string result;
     if(self.m_Handlers[request.getClass()] != NULL) {
-      result = self.m_Handlers[request.getClass()]->handleRequest(request, session);
-      emitHTTPHeader(200, _connection, "application/json");
+      try {
+        result = self.m_Handlers[request.getClass()]->handleRequest(request, session);
+        emitHTTPHeader(200, _connection, "application/json");
+      } catch(std::runtime_error& e) {
+        emitHTTPHeader(500, _connection, "application/json");
+        JSONObject resultObj;
+        resultObj.addProperty("ok", false);
+        resultObj.addProperty("message", e.what());
+        result = resultObj.toString();
+      }
     } else {
       emitHTTPHeader(404, _connection, "application/json");
       std::ostringstream sstream;
diff --git a/core/web/webserver.h b/core/web/webserver.h
index f506bf3..84d52da 100644
--- a/core/web/webserver.h
+++ b/core/web/webserver.h
@@ -33,6 +33,7 @@
 
 #include <boost/ptr_container/ptr_map.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/shared_ptr.hpp>
 
 namespace dss {
 
@@ -40,6 +41,7 @@ namespace dss {
   class PropertyNode;
   class WebServerPlugin;
   class RestfulRequestHandler;
+  class RestfulAPI;
 
   typedef boost::ptr_map<const int, Session> SessionByID;
 
@@ -50,6 +52,7 @@ namespace dss {
     SessionByID m_Sessions;
     boost::ptr_vector<WebServerPlugin> m_Plugins;
     __gnu_cxx::hash_map<const std::string, RestfulRequestHandler*> m_Handlers;
+    boost::shared_ptr<RestfulAPI> m_pAPI;
   private:
     void setupAPI();
     void loadPlugin(PropertyNode& _node);
diff --git a/core/web/webserverapi.cpp b/core/web/webserverapi.cpp
index af7cc0d..8baf332 100644
--- a/core/web/webserverapi.cpp
+++ b/core/web/webserverapi.cpp
@@ -26,9 +26,9 @@
 
 namespace dss {
  
-  RestfulAPI WebServerAPI::createRestfulAPI() {
-    RestfulAPI api;
-    RestfulClass& clsApartment = api.addClass("apartment")
+  boost::shared_ptr<RestfulAPI> WebServerAPI::createRestfulAPI() {
+    boost::shared_ptr<RestfulAPI> api(new RestfulAPI());
+    RestfulClass& clsApartment = api->addClass("apartment")
        .withDocumentation("A wrapper for global functions as well as adressing all devices connected to the dSS");
     clsApartment.addMethod("getName")
       .withDocumentation("Returns the name of the apartment");
@@ -105,7 +105,7 @@ namespace dss {
     clsApartment.addMethod("rescan")
       .withDocumentation("Rescans all circuits of the apartment");
 
-    RestfulClass& clsZone = api.addClass("zone")
+    RestfulClass& clsZone = api->addClass("zone")
         .withInstanceParameter("id", "integer", false)
         .withInstanceParameter("name", "string", false)
         .requireOneOf("id", "name");
@@ -172,7 +172,7 @@ namespace dss {
       .withParameter("groupName", "string", false)
       .withDocumentation("Returns the consumption of all devices in the zone in mW.", "If groupID or groupName are specified, only devices contained in this group will be addressed");
 
-    RestfulClass& clsDevice = api.addClass("device")
+    RestfulClass& clsDevice = api->addClass("device")
         .withInstanceParameter("dsid", "integer", false)
         .withInstanceParameter("name", "string", false)
         .requireOneOf("dsid", "name");
@@ -230,7 +230,7 @@ namespace dss {
       .withDocumentation("Returns the consumption of the device in mW.", "Note that this works only for simulated devices at the moment.");
 
 
-    RestfulClass& clsCircuit = api.addClass("circuit")
+    RestfulClass& clsCircuit = api->addClass("circuit")
        .withInstanceParameter("id", "dsid", true);
     clsCircuit.addMethod("getName")
        .withDocumentation("Returns the name of the circuit.");
@@ -246,7 +246,7 @@ namespace dss {
     clsCircuit.addMethod("rescan")
        .withDocumentation("Rescans the circuit");
 
-    RestfulClass& clsProp = api.addClass("property")
+    RestfulClass& clsProp = api->addClass("property")
         .withInstanceParameter("path", "string", true);
     clsProp.addMethod("getString")
         .withDocumentation("Returns the std::string value of the property", "This will fail if the property is not of type 'string'.");
@@ -269,7 +269,7 @@ namespace dss {
     clsProp.addMethod("setString")
         .withDocumentation("Returns the type of the node");
 
-    RestfulClass& clsEvent = api.addClass("event");
+    RestfulClass& clsEvent = api->addClass("event");
     clsEvent.addMethod("raise")
        .withParameter("name", "string", true)
        .withParameter("context", "string", false)
@@ -277,12 +277,12 @@ namespace dss {
        .withDocumentation("Raises an event", "The context describes the source of the event. The location, if provided, defines where any action that is taken "
            "by any subscription should happen.");
 
-    RestfulClass& clsSystem = api.addClass("system");
+    RestfulClass& clsSystem = api->addClass("system");
     clsSystem.addMethod("version")
       .withDocumentation("Returns the dss version",
                          "This method returns the version std::string of the dss");
 
-    RestfulClass& clsSet = api.addClass("set")
+    RestfulClass& clsSet = api->addClass("set")
         .withInstanceParameter("self", "string", false);
     clsSet.addMethod("fromApartment")
         .withDocumentation("Creates a set that contains all devices of the apartment");
diff --git a/core/web/webserverapi.h b/core/web/webserverapi.h
index ed2e21e..9ac852b 100644
--- a/core/web/webserverapi.h
+++ b/core/web/webserverapi.h
@@ -23,13 +23,15 @@
 #ifndef WEBSERVERAPI_H
 #define WEBSERVERAPI_H
 
+#include <boost/shared_ptr.hpp>
+
 namespace dss {
 
   class RestfulAPI;
   
   class WebServerAPI {
   public:
-    static RestfulAPI createRestfulAPI();
+    static boost::shared_ptr<RestfulAPI> createRestfulAPI();
   };
 }
 #endif // WEBSERVERAPI_H
diff --git a/data/webroot/js/model.js b/data/webroot/js/model.js
index 7bfa78b..1670484 100644
--- a/data/webroot/js/model.js
+++ b/data/webroot/js/model.js
@@ -77,9 +77,9 @@ var Apartment = Class.create({
 	
 	fetch: function() {
 		var self = this;
-		var structure = self.sendSyncRequest("getStructure", {});
+		var response = self.sendSyncRequest("getStructure", {});
 		self.zones = [];
-		structure.apartment.zones.each(function(zone) {
+		response.result.apartment.zones.each(function(zone) {
 			var zoneObj = new Zone(zone.id, zone.name);
 			self.zones.push(zoneObj);
 			zone.devices.each(function(device) {
@@ -557,7 +557,7 @@ var Set = Class.create({
   getDevices: function() {
     var respObj = this.sendSyncRequest("getDevices", this.getParameterForSetCall());
     if(respObj.ok) {
-      return respObj.result.devices;
+      return respObj.result;
     }
     return undefined;
   }
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3721a49..1c4d73d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -3,7 +3,7 @@ add_library(tests basetests.cpp  datetoolstests.cpp  ds485tests.cpp
 	propertysystemtests.cpp  scriptstest.cpp  seriestests.cpp tests.cpp busrequesttests.cpp restfulapitests.cpp)
 
 add_executable( dsstests EXCLUDE_FROM_ALL testrunner.cpp ../namespaces.cpp
-	basetests.cpp  datetoolstests.cpp  ds485tests.cpp
+	basetests.cpp  datetoolstests.cpp  jsontests.cpp ds485tests.cpp
         eventtests.cpp  modeljstests.cpp  modeltests.cpp
         propertysystemtests.cpp  scriptstest.cpp busrequesttests.cpp
 	seriestests.cpp jshandlertests.cpp restfulapitests.cpp)
diff --git a/tests/jsontests.cpp b/tests/jsontests.cpp
new file mode 100644
index 0000000..aa0a93f
--- /dev/null
+++ b/tests/jsontests.cpp
@@ -0,0 +1,136 @@
+/*
+    Copyright (c) 2010 digitalSTROM.org, Zurich, Switzerland
+
+    Author: Patrick Staehlin, futureLAB AG <pstaehlin at futurelab.ch>
+
+    This file is part of digitalSTROM Server.
+
+    digitalSTROM Server 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 3 of the License, or
+    (at your option) any later version.
+
+    digitalSTROM Server 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 digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#define BOOST_TEST_NO_MAIN
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+#include "core/web/json.h"
+
+using namespace dss;
+
+BOOST_AUTO_TEST_SUITE(JSON)
+
+BOOST_AUTO_TEST_CASE(testObjectEmpty) {
+  JSONObject obj;
+  std::string value = obj.toString();
+  BOOST_CHECK_EQUAL(value, "{}");
+}
+
+BOOST_AUTO_TEST_CASE(testValueInt) {
+  JSONValue<int> i(1);
+  std::string value = i.toString();
+  BOOST_CHECK_EQUAL(value, "1");
+}
+
+BOOST_AUTO_TEST_CASE(testPropertyString) {
+  JSONValue<std::string> str("1");
+  std::string value = str.toString();
+  BOOST_CHECK_EQUAL(value, "\"1\"");
+}
+
+BOOST_AUTO_TEST_CASE(testPropertyBoolFalse) {
+  JSONValue<bool> b(false);
+  std::string value = b.toString();
+  BOOST_CHECK_EQUAL(value, "false");
+}
+
+BOOST_AUTO_TEST_CASE(testPropertyBoolTrue) {
+  JSONValue<bool> b(true);
+  std::string value = b.toString();
+  BOOST_CHECK_EQUAL(value, "true");
+}
+
+BOOST_AUTO_TEST_CASE(testPropertyDoubleTrue) {
+  JSONValue<double> d(10.5);
+  std::string value = d.toString();
+  BOOST_CHECK_EQUAL(value, "10.5");
+}
+
+BOOST_AUTO_TEST_CASE(testObjectWithProperty) {
+  JSONObject obj;
+  obj.addProperty("name", "test");
+  std::string value = obj.toString();
+  BOOST_CHECK_EQUAL(value, "{\"name\":\"test\"}");
+}
+
+BOOST_AUTO_TEST_CASE(testObjectWithProperties) {
+  JSONObject obj;
+  obj.addProperty("name", "test");
+  obj.addProperty("i", 1);
+  obj.addProperty("b", false);
+  std::string value = obj.toString();
+  BOOST_CHECK_EQUAL(value, "{\"name\":\"test\",\"i\":1,\"b\":false}");
+}
+
+BOOST_AUTO_TEST_CASE(testObjectWithSubObject) {
+  JSONObject obj;
+  obj.addProperty("name", "test");
+  boost::shared_ptr<JSONObject> obj2(new JSONObject());
+  obj2->addProperty("street", "blastreet");
+  obj.addElement("address", obj2);
+  std::string value = obj.toString();
+  BOOST_CHECK_EQUAL(value, "{\"name\":\"test\",\"address\":{\"street\":\"blastreet\"}}");
+}
+
+BOOST_AUTO_TEST_CASE(testIntArrayNoElements) {
+  JSONArray<int> array;
+  array.add(1);
+  std::string value = array.toString();
+  BOOST_CHECK_EQUAL(value, "[1]");
+}
+
+BOOST_AUTO_TEST_CASE(testIntArrayOneElement) {
+  JSONArray<int> array;
+  array.add(1);
+  std::string value = array.toString();
+  BOOST_CHECK_EQUAL(value, "[1]");
+}
+
+BOOST_AUTO_TEST_CASE(testIntArrayTwoElements) {
+  JSONArray<int> array;
+  array.add(1);
+  array.add(2);
+  std::string value = array.toString();
+  BOOST_CHECK_EQUAL(value, "[1,2]");
+}
+
+BOOST_AUTO_TEST_CASE(testStringArray) {
+  JSONArray<std::string> array;
+  array.add("1");
+  array.add("2");
+  std::string value = array.toString();
+  BOOST_CHECK_EQUAL(value, "[\"1\",\"2\"]");
+}
+
+BOOST_AUTO_TEST_CASE(testObjectWithSubArray) {
+  JSONObject obj;
+  boost::shared_ptr<JSONArray<int> > array(new JSONArray<int>());
+  obj.addElement("elements", array);
+  array->add(1);
+  array->add(2);
+  std::string value = obj.toString();
+  BOOST_CHECK_EQUAL(value, "{\"elements\":[1,2]}");
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()


hooks/post-receive
-- 
digitalSTROM Server


More information about the dss-commits mailing list