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

git version control dss-commits at forum.digitalstrom.org
Mon Jan 11 16:59:34 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  e150a5e3f8a2a3032e85849649c3a3a83db55b31 (commit)
       via  75869d7b9496a7a46a1e6db118133ce1f35664ab (commit)
       via  013edbb6a82f7d81f20db0c4d47c0685e4b8835a (commit)
       via  6efc4d7afe6e7671d0bec7b434c3ca7059641315 (commit)
      from  55f7a79cb023b6f54634c1f51c6ce41ea72ae310 (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 e150a5e3f8a2a3032e85849649c3a3a83db55b31
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Mon Jan 11 16:57:54 2010 +0100

    Compiling but not yet working jssocket

commit 75869d7b9496a7a46a1e6db118133ce1f35664ab
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Mon Jan 11 10:44:21 2010 +0100

    Getting/Setting flags on property nodes
    
    New calls added to the global js-context:
    * @setFlag(propPath, flagName, value)@
    * @getFlag(propPath, flagName)@
    
    Where @flagName@ is one of @ARCHIVE@, @READABLE@ or @WRITEABLE@

commit 013edbb6a82f7d81f20db0c4d47c0685e4b8835a
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Mon Jan 11 10:16:22 2010 +0100

    Corrected check for parameter count

commit 6efc4d7afe6e7671d0bec7b434c3ca7059641315
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Mon Jan 11 09:58:20 2010 +0100

    Moved PropertyScriptExtension to own file

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

Changes:
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 56c82a5..120697e 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -5,7 +5,8 @@ ENDIF(WITH_GCOV)
 
 file(GLOB files *.cpp)
 
-add_library(core ${files} scripting/modeljs.cpp sim/dssim.cpp sim/dsidsim.cpp
+add_library(core ${files} scripting/modeljs.cpp scripting/propertyscriptextension.cpp 
+scripting/jssocket.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
diff --git a/core/eventinterpreterplugins.cpp b/core/eventinterpreterplugins.cpp
index 5265303..555b010 100644
--- a/core/eventinterpreterplugins.cpp
+++ b/core/eventinterpreterplugins.cpp
@@ -31,7 +31,8 @@
 #include "DS485Interface.h"
 #include "setbuilder.h"
 #include "dss.h"
-#include "scripting/modeljs.h"
+#include "core/scripting/modeljs.h"
+#include "core/scripting/propertyscriptextension.h"
 #include "core/foreach.h"
 #include "core/model/set.h"
 #include "core/model/zone.h"
diff --git a/core/scripting/jssocket.cpp b/core/scripting/jssocket.cpp
new file mode 100644
index 0000000..214de53
--- /dev/null
+++ b/core/scripting/jssocket.cpp
@@ -0,0 +1,232 @@
+/*
+    Copyright (c) 2009 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 "jssocket.h"
+
+#include "core/thread.h"
+
+#include <boost/noncopyable.hpp>
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+
+using boost::asio::ip::tcp;
+
+namespace dss {
+
+
+  //================================================== BoostIORunner
+
+  class BoostIORunner : private boost::noncopyable,
+                        public Thread {
+  public:
+    virtual void execute() {
+      m_IOService.run();
+    }
+
+    boost::asio::io_service& getIOService() {
+      return m_IOService;
+    }
+
+    static BoostIORunner& getInstance() {
+      if(m_pInstance == NULL) {
+        m_pInstance = new BoostIORunner();
+      }
+      return *m_pInstance;
+    }
+  private:
+    static BoostIORunner* m_pInstance;
+    boost::asio::io_service m_IOService;
+    BoostIORunner() : Thread("BoostIORunner") {}
+  };
+
+  BoostIORunner* BoostIORunner::m_pInstance = NULL;
+
+  //================================================== SocketHelper
+
+  class SocketHelper {
+  }; // SocketHelper
+
+  class SocketHelperSendOneShot {
+  public:
+    SocketHelperSendOneShot(const std::string& _host, int _port, const std::string& _data)
+    : m_Socket(BoostIORunner::getInstance().getIOService()),
+      m_IOService(BoostIORunner::getInstance().getIOService()),
+      m_Data(_data)
+    {
+      tcp::resolver resolver(m_IOService);
+      tcp::resolver::query query(_host, _port);
+      tcp::resolver::iterator iterator = resolver.resolve(query);
+
+      tcp::endpoint endpoint = *iterator;
+      m_Socket.async_connect(endpoint,
+          boost::bind(&SocketHelperSendOneShot::handle_connect, this,
+            boost::asio::placeholders::error, ++iterator));
+    }
+
+    void write()
+    {
+      boost::asio::async_write(m_Socket,
+          boost::asio::buffer(m_Data.c_str(),
+            m_Data.size()),
+          boost::bind(&SocketHelperSendOneShot::handle_write, this,
+            boost::asio::placeholders::error));
+    }
+
+  private:
+    void handle_connect(const boost::system::error_code& error,
+        tcp::resolver::iterator endpoint_iterator)
+    {
+      if (!error) {
+        m_IOService.post(boost::bind(&SocketHelperSendOneShot::write, this));
+      } else if (endpoint_iterator != tcp::resolver::iterator()) {
+        m_Socket.close();
+        tcp::endpoint endpoint = *endpoint_iterator;
+        m_Socket.async_connect(endpoint,
+            boost::bind(&SocketHelperSendOneShot::handle_connect, this,
+              boost::asio::placeholders::error, ++endpoint_iterator));
+      }
+    }
+
+    void handle_write(const boost::system::error_code& error) {
+      if(!error) {
+        // call js callback(true)
+      } else {
+        // call js callback(false)
+      }
+      // terminate, remove from helper-list of extension
+      do_close();
+    }
+
+    void do_close() {
+      m_Socket.close();
+    }
+  private:
+    tcp::socket m_Socket;
+    boost::asio::io_service& m_IOService;
+    const std::string& m_Data;
+  }; // SocketHelperOneShot
+
+  //================================================== SocketScriptContextExtension
+
+  const std::string SocketScriptExtensionName = "propertyextension";
+
+  SocketScriptContextExtension::SocketScriptContextExtension()
+  : ScriptExtension(SocketScriptExtensionName)
+  { }
+
+  void tcpSocket_finalize(JSContext *cx, JSObject *obj) {
+  } // tcpSocket_finalize
+
+  JSBool tcpSocket_construct(JSContext *cx, JSObject *obj, uintN argc,
+                             jsval *argv, jsval *rval) {
+      return JS_TRUE;
+  } // tcpSocket_construct
+
+  static JSClass tcpSocket_class = {
+    "TcpSocket", JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+    JS_EnumerateStandardClasses,
+    JS_ResolveStub,
+    JS_ConvertStub,  tcpSocket_finalize, JSCLASS_NO_OPTIONAL_MEMBERS
+  }; // tcpSocket_class
+
+  JSFunctionSpec tcpSocket_methods[] = {
+  //  {"send", tcpSocket_send, 2, 0, 0},
+  //  {"connect", tcpSocket_connect, 3, 0, 0},
+  //  {"receive", tcpSocket_receive, 2, 0, 0},
+  //  {"bind", tcpSocket_bind, 2, 0, 0},
+  //  {"accept", tcpSocket_send, 1, 0, 0},
+  //  {"close", tcpSocket_close, 0, 0, 0},
+    {NULL, NULL, 0, 0, 0},
+  }; // tcpSockets_methods
+
+  JSBool tcpSocket_sendTo(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+ //   SocketScriptContextExtension* ext =
+//        dynamic_cast<SocketScriptContextExtension*>(ctx->getEnvironment().getExtension(SocketScriptExtensionName));
+
+    if(argc >= 3) {
+      try {
+        std::string host = ctx->convertTo<std::string>(argv[0]);
+        int port = ctx->convertTo<int>(argv[2]);
+        std::string data = ctx->convertTo<std::string>(argv[2]);
+
+        tcp::resolver resolver(BoostIORunner::getInstance().getIOService());
+        tcp::resolver::query query(host, port);
+        tcp::resolver::iterator iterator = resolver.resolve(query);
+
+        if(!BoostIORunner::getInstance().isRunning()) {
+          BoostIORunner::getInstance().run();
+        }
+
+
+        *rval = JSVAL_TRUE;
+        return JS_TRUE;
+      } catch(const ScriptException&) {
+      }
+    }
+    return JS_FALSE;
+  } // tcpSocket_sendTo
+
+  JSFunctionSpec tcpSocket_static_methods[] = {
+    {"sendTo", tcpSocket_sendTo, 4, 0, 0},
+    {NULL, NULL, 0, 0, 0},
+  }; // tcpSocket_static_methods
+
+  JSBool tcpSocket_JSGet(JSContext *cx, JSObject *obj, jsval id, jsval *rval) {
+    int opt = JSVAL_TO_INT(id);
+    switch(opt) {
+      case 0:
+        *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "TcpSocket"));
+        return JS_TRUE;
+    }
+    return JS_FALSE;
+  } // tcpSocket_JSGet
+
+
+  static JSPropertySpec tcpSocket_properties[] = {
+    {"className", 0, 0, tcpSocket_JSGet},
+    {NULL}
+  }; // tcpSocket_properties
+
+  void SocketScriptContextExtension::extendContext(ScriptContext& _context) {
+    JS_InitClass(_context.getJSContext(), _context.getRootObject().getJSObject(), NULL, &tcpSocket_class,
+                 tcpSocket_construct, 0, tcpSocket_properties, tcpSocket_methods, NULL, tcpSocket_static_methods);
+  } // extendContext
+
+  void SocketScriptContextExtension::removeSocketHelper(SocketHelper& _helper) {
+    m_SocketHelperMutex.lock();
+//    SocketHelperVector::iterator it = std::find(m_SocketHelper.begin(), m_SocketHelper.end(), _helper);
+//    if(it != m_SocketHelper.end()) {
+//      m_SocketHelper.erase(it);
+//    }
+    m_SocketHelperMutex.unlock();
+  } // removeSocketHelper
+
+  void SocketScriptContextExtension::addSocketHelper(SocketHelper& _helper) {
+    m_SocketHelperMutex.lock();
+    m_SocketHelper.push_back(&_helper);
+    m_SocketHelperMutex.unlock();
+  } // addSocketHelper
+
+
+} // namespace dss
diff --git a/core/scripting/jssocket.h b/core/scripting/jssocket.h
new file mode 100644
index 0000000..b5fe0e3
--- /dev/null
+++ b/core/scripting/jssocket.h
@@ -0,0 +1,49 @@
+/*
+    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 JSSOCKET_H_
+#define JSSOCKET_H_
+
+#include "core/jshandler.h"
+
+namespace dss {
+
+  class SocketHelper;
+
+  class SocketScriptContextExtension : public ScriptExtension {
+  public:
+    SocketScriptContextExtension();
+
+    virtual void extendContext(ScriptContext& _context);
+    void removeSocketHelper(SocketHelper& _helper);
+    void addSocketHelper(SocketHelper& _helper);
+
+//    JSObject* createJSSocket(ScriptContext& _ctx);
+  private:
+    Mutex m_SocketHelperMutex;
+    typedef boost::ptr_vector<SocketHelper> SocketHelperVector;
+    SocketHelperVector m_SocketHelper;
+  }; // SocketScriptExtension
+
+} // namespace dss
+
+#endif /* JSSOCKET_H_ */
diff --git a/core/scripting/modeljs.cpp b/core/scripting/modeljs.cpp
index 9dffe91..f72930b 100644
--- a/core/scripting/modeljs.cpp
+++ b/core/scripting/modeljs.cpp
@@ -1021,212 +1021,5 @@ namespace dss {
     return result;
   }
 
-  //================================================== PropertyScriptExtension
-
-  const std::string PropertyScriptExtensionName = "propertyextension";
-
-  PropertyScriptExtension::PropertyScriptExtension(PropertySystem& _propertySystem) 
-  : ScriptExtension(PropertyScriptExtensionName),
-    m_PropertySystem(_propertySystem),
-    m_NextListenerID(1)
-  { } // ctor
-    
-  JSBool global_prop_setProperty(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
-    if(argc > 2) {
-      Logger::getInstance()->log("JS: global_prop_setProperty: need two arguments: property-path & value", lsError);
-    } else {
-      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
-
-      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
-      std::string propName = ctx->convertTo<std::string>(argv[0]);
-      
-      PropertyNodePtr node = ext->getPropertySystem().createProperty(propName);
-      if(node != NULL) {
-        try {
-          if(JSVAL_IS_STRING(argv[1])) {
-            node->setStringValue(ctx->convertTo<std::string>(argv[1]));
-          } else if(JSVAL_IS_BOOLEAN(argv[1])) {
-            node->setBooleanValue(ctx->convertTo<bool>(argv[1]));
-          } else if(JSVAL_IS_INT(argv[1])) {
-            node->setIntegerValue(ctx->convertTo<int>(argv[1]));
-          } else {
-            Logger::getInstance()->log("JS: global_prop_setProperty: unknown type of argument 2", lsError);
-          }
-          *rval = JSVAL_TRUE;
-          return JS_TRUE;
-        } catch(PropertyTypeMismatch&) {
-          Logger::getInstance()->log("Error setting value of " + propName, lsFatal);
-        }
-      } else {
-        Logger::getInstance()->log("Coule not create property " + propName, lsFatal);
-        *rval = JSVAL_FALSE;
-        return JS_TRUE;
-      }
-    }
-    return JS_FALSE;
-  } // global_prop_setProperty
-
-  JSBool global_prop_getProperty(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
-    if(argc > 1) {
-      Logger::getInstance()->log("JS: global_prop_getProperty: need one argument: property-path", lsError);
-    } else {
-      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
-
-      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
-      std::string propName = ctx->convertTo<std::string>(argv[0]);
-      
-      PropertyNodePtr node = ext->getPropertySystem().getProperty(propName);
-      if(node == NULL) {
-        *rval = JSVAL_NULL;
-      } else {
-        switch(node->getValueType()) {
-        case vTypeInteger:
-          *rval = INT_TO_JSVAL(node->getIntegerValue());
-          break;
-        case vTypeString: {
-            std::string val = node->getStringValue();
-            *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, val.c_str()));
-          }
-          break;
-        case vTypeBoolean:
-          *rval = BOOLEAN_TO_JSVAL(node->getBoolValue());
-          break;
-        case vTypeNone:
-          *rval = JSVAL_VOID;
-        default:
-          *rval = JSVAL_NULL;
-        }
-      }
-      return JS_TRUE;
-    }
-    return JS_FALSE;
-  } // global_prop_getProperty
-
-  JSBool global_prop_setListener(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
-    if(argc > 2) {
-      Logger::getInstance()->log("JS: global_prop_setListener: need two arguments: property-path &  callback", lsError);
-    } else {
-      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
-
-      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
-      std::string propName = ctx->convertTo<std::string>(argv[0]);
-
-      PropertyNodePtr node = ext->getPropertySystem().getProperty(propName);
-      if(node == NULL) {
-        *rval = JSVAL_NULL;
-      } else {
-        std::string ident = ext->produceListenerID();
-        PropertyScriptListener* listener =
-            new PropertyScriptListener(ext, ctx, obj, argv[1], ident);
-        ext->addListener(listener);
-        node->addListener(listener);
-        ctx->attachObject(listener);
-
-        JSString* str = JS_NewStringCopyZ(cx, ident.c_str());
-        *rval = STRING_TO_JSVAL(str);
-      }
-      return JS_TRUE;
-    }
-    return JS_FALSE;
-  } // global_prop_setListener
-
-  JSBool global_prop_removeListener(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
-    if(argc > 2) {
-      Logger::getInstance()->log("JS: global_prop_removeListener: need two arguments: listener-id", lsError);
-    } else {
-      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
-
-      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
-      std::string listenerIdent = ctx->convertTo<std::string>(argv[0]);
-      ext->removeListener(listenerIdent);
-
-      *rval = JSVAL_TRUE;
-      return JS_TRUE;
-    }
-    return JS_FALSE;
-  } // global_prop_setListener
-
-  JSFunctionSpec prop_global_methods[] = {
-    {"setProperty", global_prop_setProperty, 2, 0, 0},
-    {"getProperty", global_prop_getProperty, 1, 0, 0},
-    {"setListener", global_prop_setListener, 2, 0, 0},
-    {"removeListener", global_prop_removeListener, 1, 0, 0},
-    {NULL},
-  };
-
-  void PropertyScriptExtension::extendContext(ScriptContext& _context) {
-    JS_DefineFunctions(_context.getJSContext(), JS_GetGlobalObject(_context.getJSContext()), prop_global_methods);
-  } // extendContext
-
-  JSObject* PropertyScriptExtension::createJSProperty(ScriptContext& _ctx, boost::shared_ptr<PropertyNode> _node) {
-    return NULL;
-  } // createJSProperty
-
-  std::string PropertyScriptExtension::produceListenerID() {
-    return "listener_" + intToString(long(this), true) + "_" + intToString(m_NextListenerID++);
-  } // produceListenerID
-
-  void PropertyScriptExtension::addListener(PropertyScriptListener* _pListener) {
-    m_Listeners.push_back(_pListener);
-  } // addListener
-
-  void PropertyScriptExtension::removeListener(const std::string& _identifier) {
-    for(std::vector<PropertyScriptListener*>::iterator it = m_Listeners.begin(), e = m_Listeners.end();
-        it != e; ++it) {
-      if((*it)->getIdentifier() == _identifier) {
-        (*it)->unsubscribe();
-        m_Listeners.erase(it);
-        return;
-      }
-    }
-  } // removeListener
-
-
-  //================================================== PropertyScriptListener
-  
-  PropertyScriptListener::PropertyScriptListener(PropertyScriptExtension* _pExtension,
-                                                 ScriptContext* _pContext, 
-                                                 JSObject* _functionObj, 
-                                                 jsval _function, 
-                                                 const std::string& _identifier)
-  : m_pExtension(_pExtension),
-    m_pContext(_pContext),
-    m_pFunctionObject(_functionObj),
-    m_Function(_function),
-    m_Identifier(_identifier)
-  { } // ctor
-
-  PropertyScriptListener::~PropertyScriptListener() {
-    m_pExtension->removeListener(m_Identifier);
-  } // dtor
-
-  void PropertyScriptListener::createScriptObject() {
-    if(m_pScriptObject == NULL) {
-      m_pScriptObject.reset(new ScriptObject(m_pFunctionObject, *m_pContext));
-    }
-    assert(m_pScriptObject != NULL);
-  } // createScriptObject
-
-  void PropertyScriptListener::propertyChanged(PropertyNodePtr _changedNode) {
-    doOnChange(_changedNode);
-  } // propertyChanged
-  
-  void PropertyScriptListener::propertyRemoved(PropertyNodePtr _parent, PropertyNodePtr _child) {
-  } // propertyRemoved
-  
-  void PropertyScriptListener::propertyAdded(PropertyNodePtr _parent, PropertyNodePtr _child) {
-  } // propertyAdded
-
-  void PropertyScriptListener::doOnChange(PropertyNodePtr _changedNode) {
-    AssertLocked locked(m_pContext);
-    createScriptObject();
-    ScriptFunctionParameterList list(*m_pContext);
-    list.add(_changedNode->getDisplayName());
-    try {
-      m_pScriptObject->callFunctionByReference<void>(m_Function, list);
-    } catch(ScriptException& e) {
-      Logger::getInstance()->log("PropertyScriptListener::doOnChange: Caught exception while calling handler: " + std::string(e.what()), lsFatal);
-    }
-  } // doOnChange
 
 } // namespace
diff --git a/core/scripting/modeljs.h b/core/scripting/modeljs.h
index 5d4ac3b..acdc99b 100644
--- a/core/scripting/modeljs.h
+++ b/core/scripting/modeljs.h
@@ -91,52 +91,6 @@ namespace dss {
     JSObject* createJSSubscription(ScriptContext& _ctx, boost::shared_ptr<EventSubscription> _subscription);
   }; // EventScriptExtension
   
-  class PropertySystem;
-  class PropertyNode;
-  class PropertyScriptExtension;
-  
-  class PropertyScriptListener : public PropertyListener,
-                                 public ScriptContextAttachedObject {
-  public:
-    PropertyScriptListener(PropertyScriptExtension* _pExtension, ScriptContext* _pContext, JSObject* _functionObj, jsval _function, const std::string& _identifier);
-    virtual ~PropertyScriptListener();
-
-    virtual void propertyChanged(PropertyNodePtr _changedNode);
-    virtual void propertyRemoved(PropertyNodePtr _parent, PropertyNodePtr _child);
-    virtual void propertyAdded(PropertyNodePtr _parent, PropertyNodePtr _child);
-
-    const std::string& getIdentifier() const { return m_Identifier; }
-  private:
-    void doOnChange(PropertyNodePtr _changedNode);
-    void createScriptObject();
-  private:
-    PropertyScriptExtension* m_pExtension;
-    ScriptContext* m_pContext;
-    JSObject* m_pFunctionObject;
-    jsval m_Function;
-    std::string m_Identifier;
-    boost::scoped_ptr<ScriptObject> m_pScriptObject;
-  }; // PropertyScriptListener
-  
-  class PropertyScriptExtension : public ScriptExtension {
-  public:
-    PropertyScriptExtension(PropertySystem& _propertySystem);
-    virtual ~PropertyScriptExtension() {}
-    
-    virtual void extendContext(ScriptContext& _context);
-    
-    PropertySystem& getPropertySystem() { return m_PropertySystem; }
-    
-    JSObject* createJSProperty(ScriptContext& _ctx, boost::shared_ptr<PropertyNode> _node);
-    std::string produceListenerID();
-    void addListener(PropertyScriptListener* _pListener);
-    void removeListener(const std::string& _identifier);
-  private:
-    PropertySystem& m_PropertySystem;
-    std::vector<PropertyScriptListener*> m_Listeners;
-    int m_NextListenerID;
-  }; // PropertyScriptExtension
-
 }
 
 #endif
diff --git a/core/scripting/propertyscriptextension.cpp b/core/scripting/propertyscriptextension.cpp
new file mode 100644
index 0000000..dfead6c
--- /dev/null
+++ b/core/scripting/propertyscriptextension.cpp
@@ -0,0 +1,303 @@
+/*
+    Copyright (c) 2009 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 "propertyscriptextension.h"
+
+#include "core/propertysystem.h"
+
+namespace dss {
+
+  //================================================== PropertyScriptExtension
+
+  const std::string PropertyScriptExtensionName = "propertyextension";
+
+  PropertyScriptExtension::PropertyScriptExtension(PropertySystem& _propertySystem)
+  : ScriptExtension(PropertyScriptExtensionName),
+    m_PropertySystem(_propertySystem),
+    m_NextListenerID(1)
+  { } // ctor
+
+  JSBool global_prop_setProperty(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    if(argc < 2) {
+      Logger::getInstance()->log("JS: global_prop_setProperty: need two arguments: property-path & value", lsError);
+    } else {
+      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+
+      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
+      std::string propName = ctx->convertTo<std::string>(argv[0]);
+
+      PropertyNodePtr node = ext->getPropertySystem().createProperty(propName);
+      if(node != NULL) {
+        try {
+          if(JSVAL_IS_STRING(argv[1])) {
+            node->setStringValue(ctx->convertTo<std::string>(argv[1]));
+          } else if(JSVAL_IS_BOOLEAN(argv[1])) {
+            node->setBooleanValue(ctx->convertTo<bool>(argv[1]));
+          } else if(JSVAL_IS_INT(argv[1])) {
+            node->setIntegerValue(ctx->convertTo<int>(argv[1]));
+          } else {
+            Logger::getInstance()->log("JS: global_prop_setProperty: unknown type of argument 2", lsError);
+          }
+          *rval = JSVAL_TRUE;
+          return JS_TRUE;
+        } catch(PropertyTypeMismatch&) {
+          Logger::getInstance()->log("Error setting value of " + propName, lsFatal);
+        }
+      } else {
+        Logger::getInstance()->log("Coule not create property " + propName, lsFatal);
+        *rval = JSVAL_FALSE;
+        return JS_TRUE;
+      }
+    }
+    return JS_FALSE;
+  } // global_prop_setProperty
+
+  JSBool global_prop_getProperty(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    if(argc < 1) {
+      Logger::getInstance()->log("JS: global_prop_getProperty: need one argument: property-path", lsError);
+    } else {
+      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+
+      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
+      std::string propName = ctx->convertTo<std::string>(argv[0]);
+
+      PropertyNodePtr node = ext->getPropertySystem().getProperty(propName);
+      if(node == NULL) {
+        *rval = JSVAL_NULL;
+      } else {
+        switch(node->getValueType()) {
+        case vTypeInteger:
+          *rval = INT_TO_JSVAL(node->getIntegerValue());
+          break;
+        case vTypeString: {
+            std::string val = node->getStringValue();
+            *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, val.c_str()));
+          }
+          break;
+        case vTypeBoolean:
+          *rval = BOOLEAN_TO_JSVAL(node->getBoolValue());
+          break;
+        case vTypeNone:
+          *rval = JSVAL_VOID;
+        default:
+          *rval = JSVAL_NULL;
+        }
+      }
+      return JS_TRUE;
+    }
+    return JS_FALSE;
+  } // global_prop_getProperty
+
+  JSBool global_prop_setListener(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    if(argc < 2) {
+      Logger::getInstance()->log("JS: global_prop_setListener: need two arguments: property-path &  callback", lsError);
+    } else {
+      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+
+      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
+      std::string propName = ctx->convertTo<std::string>(argv[0]);
+
+      PropertyNodePtr node = ext->getPropertySystem().getProperty(propName);
+      if(node == NULL) {
+        *rval = JSVAL_NULL;
+      } else {
+        std::string ident = ext->produceListenerID();
+        PropertyScriptListener* listener =
+            new PropertyScriptListener(ext, ctx, obj, argv[1], ident);
+        ext->addListener(listener);
+        node->addListener(listener);
+        ctx->attachObject(listener);
+
+        JSString* str = JS_NewStringCopyZ(cx, ident.c_str());
+        *rval = STRING_TO_JSVAL(str);
+      }
+      return JS_TRUE;
+    }
+    return JS_FALSE;
+  } // global_prop_setListener
+
+  JSBool global_prop_removeListener(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    if(argc < 1) {
+      Logger::getInstance()->log("JS: global_prop_removeListener: need one argument: listener-id", lsError);
+    } else {
+      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+
+      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
+      std::string listenerIdent = ctx->convertTo<std::string>(argv[0]);
+      ext->removeListener(listenerIdent);
+
+      *rval = JSVAL_TRUE;
+      return JS_TRUE;
+    }
+    return JS_FALSE;
+  } // global_prop_removeListener
+
+  JSBool global_prop_setFlag(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    if(argc < 3) {
+      Logger::getInstance()->log("JS: global_prop_setFlag: need three arguments: prop-path, flag, value", lsError);
+    } else {
+      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+
+      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
+      std::string propName = ctx->convertTo<std::string>(argv[0]);
+      PropertyNodePtr node = ext->getPropertySystem().getProperty(propName);
+      std::string flagName = ctx->convertTo<std::string>(argv[1]);
+      bool value = ctx->convertTo<bool>(argv[2]);
+      PropertyNode::Flag flag;
+      if(flagName == "ARCHIVE") {
+        flag = PropertyNode::Archive;
+      } else if(flagName == "WRITEABLE") {
+        flag = PropertyNode::Writeable;
+      } else if(flagName == "READABLE") {
+        flag = PropertyNode::Readable;
+      } else {
+        Logger::getInstance()->log("JS: global_prop_setFlag: Invalid value for flag: " + flagName, lsError);
+        *rval = JSVAL_TRUE;
+        return JS_TRUE;
+      }
+
+      node->setFlag(flag, value);
+      *rval = JSVAL_TRUE;
+      return JS_TRUE;
+    }
+    return JS_FALSE;
+  } // global_prop_setFlag
+
+  JSBool global_prop_hasFlag(JSContext* cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+    if(argc < 2) {
+      Logger::getInstance()->log("JS: global_prop_hasFlag: need three arguments: prop-path, flag", lsError);
+    } else {
+      ScriptContext* ctx = static_cast<ScriptContext*>(JS_GetContextPrivate(cx));
+
+      PropertyScriptExtension* ext = dynamic_cast<PropertyScriptExtension*>(ctx->getEnvironment().getExtension(PropertyScriptExtensionName));
+      std::string propName = ctx->convertTo<std::string>(argv[0]);
+      PropertyNodePtr node = ext->getPropertySystem().getProperty(propName);
+      std::string flagName = ctx->convertTo<std::string>(argv[1]);
+      PropertyNode::Flag flag;
+      if(flagName == "ARCHIVE") {
+        flag = PropertyNode::Archive;
+      } else if(flagName == "WRITEABLE") {
+        flag = PropertyNode::Writeable;
+      } else if(flagName == "READABLE") {
+        flag = PropertyNode::Readable;
+      } else {
+        Logger::getInstance()->log("JS: global_prop_hasFlag: Invalid value for flag: " + flagName, lsError);
+        *rval = JSVAL_NULL;
+        return JS_TRUE;
+      }
+
+      if(node->hasFlag(flag)) {
+        *rval = JSVAL_TRUE;
+      } else {
+        *rval = JSVAL_FALSE;
+      }
+      return JS_TRUE;
+    }
+    return JS_FALSE;
+  } // global_prop_setFlag
+
+  JSFunctionSpec prop_global_methods[] = {
+    {"setProperty", global_prop_setProperty, 2, 0, 0},
+    {"getProperty", global_prop_getProperty, 1, 0, 0},
+    {"setListener", global_prop_setListener, 2, 0, 0},
+    {"removeListener", global_prop_removeListener, 1, 0, 0},
+    {"setFlag", global_prop_setFlag, 3, 0, 0},
+    {"hasFlag", global_prop_hasFlag, 2, 0, 0},
+    {NULL, NULL, 0, 0, 0},
+  };
+
+  void PropertyScriptExtension::extendContext(ScriptContext& _context) {
+    JS_DefineFunctions(_context.getJSContext(), JS_GetGlobalObject(_context.getJSContext()), prop_global_methods);
+  } // extendContext
+
+  JSObject* PropertyScriptExtension::createJSProperty(ScriptContext& _ctx, boost::shared_ptr<PropertyNode> _node) {
+    return NULL;
+  } // createJSProperty
+
+  std::string PropertyScriptExtension::produceListenerID() {
+    return "listener_" + intToString(long(this), true) + "_" + intToString(m_NextListenerID++);
+  } // produceListenerID
+
+  void PropertyScriptExtension::addListener(PropertyScriptListener* _pListener) {
+    m_Listeners.push_back(_pListener);
+  } // addListener
+
+  void PropertyScriptExtension::removeListener(const std::string& _identifier) {
+    for(std::vector<PropertyScriptListener*>::iterator it = m_Listeners.begin(), e = m_Listeners.end();
+        it != e; ++it) {
+      if((*it)->getIdentifier() == _identifier) {
+        (*it)->unsubscribe();
+        m_Listeners.erase(it);
+        return;
+      }
+    }
+  } // removeListener
+
+
+  //================================================== PropertyScriptListener
+
+  PropertyScriptListener::PropertyScriptListener(PropertyScriptExtension* _pExtension,
+                                                 ScriptContext* _pContext,
+                                                 JSObject* _functionObj,
+                                                 jsval _function,
+                                                 const std::string& _identifier)
+  : m_pExtension(_pExtension),
+    m_pContext(_pContext),
+    m_pFunctionObject(_functionObj),
+    m_Function(_function),
+    m_Identifier(_identifier)
+  { } // ctor
+
+  PropertyScriptListener::~PropertyScriptListener() {
+    m_pExtension->removeListener(m_Identifier);
+  } // dtor
+
+  void PropertyScriptListener::createScriptObject() {
+    if(m_pScriptObject == NULL) {
+      m_pScriptObject.reset(new ScriptObject(m_pFunctionObject, *m_pContext));
+    }
+    assert(m_pScriptObject != NULL);
+  } // createScriptObject
+
+  void PropertyScriptListener::propertyChanged(PropertyNodePtr _changedNode) {
+    doOnChange(_changedNode);
+  } // propertyChanged
+
+  void PropertyScriptListener::propertyRemoved(PropertyNodePtr _parent, PropertyNodePtr _child) {
+  } // propertyRemoved
+
+  void PropertyScriptListener::propertyAdded(PropertyNodePtr _parent, PropertyNodePtr _child) {
+  } // propertyAdded
+
+  void PropertyScriptListener::doOnChange(PropertyNodePtr _changedNode) {
+    AssertLocked locked(m_pContext);
+    createScriptObject();
+    ScriptFunctionParameterList list(*m_pContext);
+    list.add(_changedNode->getDisplayName());
+    try {
+      m_pScriptObject->callFunctionByReference<void>(m_Function, list);
+    } catch(ScriptException& e) {
+      Logger::getInstance()->log("PropertyScriptListener::doOnChange: Caught exception while calling handler: " + std::string(e.what()), lsFatal);
+    }
+  } // doOnChange
+
+}
diff --git a/core/scripting/propertyscriptextension.h b/core/scripting/propertyscriptextension.h
new file mode 100644
index 0000000..55a8c4a
--- /dev/null
+++ b/core/scripting/propertyscriptextension.h
@@ -0,0 +1,77 @@
+/*
+    Copyright (c) 2009 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 PROPERTYSCRIPTEXTENSION_H_
+#define PROPERTYSCRIPTEXTENSION_H_
+
+#include "core/jshandler.h"
+#include "core/propertysystem.h"
+
+namespace dss {
+
+  class PropertyScriptExtension;
+
+  class PropertyScriptListener : public PropertyListener,
+                                 public ScriptContextAttachedObject {
+  public:
+    PropertyScriptListener(PropertyScriptExtension* _pExtension, ScriptContext* _pContext, JSObject* _functionObj, jsval _function, const std::string& _identifier);
+    virtual ~PropertyScriptListener();
+
+    virtual void propertyChanged(PropertyNodePtr _changedNode);
+    virtual void propertyRemoved(PropertyNodePtr _parent, PropertyNodePtr _child);
+    virtual void propertyAdded(PropertyNodePtr _parent, PropertyNodePtr _child);
+
+    const std::string& getIdentifier() const { return m_Identifier; }
+  private:
+    void doOnChange(PropertyNodePtr _changedNode);
+    void createScriptObject();
+  private:
+    PropertyScriptExtension* m_pExtension;
+    ScriptContext* m_pContext;
+    JSObject* m_pFunctionObject;
+    jsval m_Function;
+    std::string m_Identifier;
+    boost::scoped_ptr<ScriptObject> m_pScriptObject;
+  }; // PropertyScriptListener
+
+  class PropertyScriptExtension : public ScriptExtension {
+  public:
+    PropertyScriptExtension(PropertySystem& _propertySystem);
+    virtual ~PropertyScriptExtension() {}
+
+    virtual void extendContext(ScriptContext& _context);
+
+    PropertySystem& getPropertySystem() { return m_PropertySystem; }
+
+    JSObject* createJSProperty(ScriptContext& _ctx, boost::shared_ptr<PropertyNode> _node);
+    std::string produceListenerID();
+    void addListener(PropertyScriptListener* _pListener);
+    void removeListener(const std::string& _identifier);
+  private:
+    PropertySystem& m_PropertySystem;
+    std::vector<PropertyScriptListener*> m_Listeners;
+    int m_NextListenerID;
+  }; // PropertyScriptExtension
+
+} // namespace dss
+
+#endif /* PROPERTYSCRIPTEXTENSION_H_ */
diff --git a/core/sim/dsid_js.cpp b/core/sim/dsid_js.cpp
index c68eee7..36b7a12 100644
--- a/core/sim/dsid_js.cpp
+++ b/core/sim/dsid_js.cpp
@@ -23,6 +23,7 @@
 #include "dsid_js.h"
 #include "core/jshandler.h"
 #include "core/scripting/modeljs.h"
+#include "core/scripting/propertyscriptextension.h"
 #include "core/dss.h"
 #include "core/thread.h"
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3556b54..ca7b7eb 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,12 +1,13 @@
 add_library(tests basetests.cpp  datetoolstests.cpp  ds485tests.cpp
 	eventtests.cpp  modeljstests.cpp  modeltests.cpp devicetests.cpp
-	propertysystemtests.cpp  scriptstest.cpp  seriestests.cpp tests.cpp busrequesttests.cpp restfulapitests.cpp)
+	propertysystemtests.cpp  scriptstest.cpp  seriestests.cpp tests.cpp
+	busrequesttests.cpp restfulapitests.cpp jssockettests.cpp)
 
 add_executable( dsstests EXCLUDE_FROM_ALL testrunner.cpp ../namespaces.cpp
 	basetests.cpp  datetoolstests.cpp  jsontests.cpp ds485tests.cpp
-        eventtests.cpp  modeljstests.cpp  modeltests.cpp devicetests.cpp
-        propertysystemtests.cpp  scriptstest.cpp busrequesttests.cpp
-	seriestests.cpp jshandlertests.cpp restfulapitests.cpp)
+	eventtests.cpp  modeljstests.cpp  modeltests.cpp devicetests.cpp
+	propertysystemtests.cpp  scriptstest.cpp busrequesttests.cpp
+	seriestests.cpp jshandlertests.cpp restfulapitests.cpp jssockettests.cpp)
 
 target_link_libraries(dsstests ${BOOST_TEST_LIB} core ds485 unix webservices model
 	pthread mongoose ${REQUIRED_LIBS})
diff --git a/tests/jssockettests.cpp b/tests/jssockettests.cpp
new file mode 100644
index 0000000..8483408
--- /dev/null
+++ b/tests/jssockettests.cpp
@@ -0,0 +1,45 @@
+/*
+    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/scripting/jssocket.h"
+
+#include <boost/scoped_ptr.hpp>
+
+using namespace std;
+using namespace dss;
+
+BOOST_AUTO_TEST_SUITE(SocketJS)
+
+BOOST_AUTO_TEST_CASE(testBasics) {
+  boost::scoped_ptr<ScriptEnvironment> env(new ScriptEnvironment());
+  env->initialize();
+  ScriptExtension* ext = new SocketScriptContextExtension();
+  env->addExtension(ext);
+
+//  boost::scoped_ptr<ScriptContext> ctx(env->getContext());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/modeljstests.cpp b/tests/modeljstests.cpp
index 3d3711d..f22da2b 100644
--- a/tests/modeljstests.cpp
+++ b/tests/modeljstests.cpp
@@ -25,6 +25,7 @@
 #include <boost/test/unit_test.hpp>
 
 #include "core/scripting/modeljs.h"
+#include "core/scripting/propertyscriptextension.h"
 #include "core/event.h"
 #include "core/eventinterpreterplugins.h"
 #include "core/propertysystem.h"
@@ -391,4 +392,30 @@ BOOST_AUTO_TEST_CASE(testThreading) {
   ctx->evaluate<void>("removeListener(l1); removeListener(l2);");
 } // testThreading
 
+BOOST_AUTO_TEST_CASE(testPropertyFlags) {
+  PropertySystem propSys;
+  boost::scoped_ptr<ScriptEnvironment> env(new ScriptEnvironment());
+  env->initialize();
+  ScriptExtension* ext = new PropertyScriptExtension(propSys);
+  env->addExtension(ext);
+
+  boost::scoped_ptr<ScriptContext> ctx(env->getContext());
+  PropertyNodePtr node1 = propSys.createProperty("/testing");
+
+  ctx->evaluate<void>("setFlag('/testing', 'ARCHIVE', true);");
+  BOOST_CHECK_EQUAL(node1->hasFlag(PropertyNode::Archive), true);
+  bool res = ctx->evaluate<bool>("hasFlag('/testing', 'ARCHIVE')");
+  BOOST_CHECK_EQUAL(res, true);
+
+  ctx->evaluate<void>("setFlag('/testing', 'READABLE', false);");
+  BOOST_CHECK_EQUAL(node1->hasFlag(PropertyNode::Readable), false);
+  res = ctx->evaluate<bool>("hasFlag('/testing', 'READABLE')");
+  BOOST_CHECK_EQUAL(res, false);
+
+  ctx->evaluate<void>("setFlag('/testing', 'WRITEABLE', false);");
+  BOOST_CHECK_EQUAL(node1->hasFlag(PropertyNode::Writeable), false);
+  res = ctx->evaluate<bool>("hasFlag('/testing', 'WRITEABLE')");
+  BOOST_CHECK_EQUAL(res, false);
+} // testPropertyFlags
+
 BOOST_AUTO_TEST_SUITE_END()


hooks/post-receive
-- 
digitalSTROM Server


More information about the dss-commits mailing list