You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by js...@apache.org on 2012/05/28 18:49:38 UTC

svn commit: r1343316 [4/5] - in /tuscany/sca-cpp/trunk: ./ hosting/server/ hosting/server/htdocs/ hosting/server/htdocs/account/ hosting/server/htdocs/app/ hosting/server/htdocs/clone/ hosting/server/htdocs/create/ hosting/server/htdocs/delete/ hosting...

Modified: tuscany/sca-cpp/trunk/hosting/server/htdocs/store/index.html
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/htdocs/store/index.html?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/htdocs/store/index.html (original)
+++ tuscany/sca-cpp/trunk/hosting/server/htdocs/store/index.html Mon May 28 16:49:36 2012
@@ -17,29 +17,19 @@
  * specific language governing permissions and limitations
  * under the License.    
 -->
-<div id="bodydiv" class="bodydiv">
+<div id="bodydiv" class="body">
 
-<table style="width: 100%;">
-<tr>
-<td><h2><span id="h1"></span></h2></td>
-<td style="vertical-align: middle; text-align: right;"><span id="status" style="font-weight: bold; color: #808080;"></span></td>
-</tr>
-</table>
-
-<div id="catmenu"></div>
-
-<div id="apps"></div>
+<div id="apps" class="viewcontent"></div>
 
 <script type="text/javascript">
 
 // Set page titles
 document.title = ui.windowtitle(location.hostname) + ' - Store';
-$('h1').innerHTML = ui.hometitle(location.hostname);
 
 // Get the store category
 var category = ui.fragmentParams(location)['category'];
 if (isNil(category))
-    category = 'myapps';
+    category = 'top';
 
 /**
  * Build store menu bar
@@ -47,28 +37,21 @@ if (isNil(category))
 function catmenu() {
     function catmenuitem(name, cat, idx) {
         var c = cat == category? 'smenu' : 'amenu';
-        return '<th class="thl thr" style="width: 10px; padding-top: 4px; padding-bottom: 4px; padding-right: 6px;">'
-                + ui.ahref('/#view=store&category=' + cat + '&idx=' + idx, '_view', '<span class="' + c + '">' + name + '</span>') + '</th>';
+        return '<span>' + ui.ahref('/#view=store&category=' + cat + '&idx=' + idx, '_view', '<span class="' + c + '">' + name + '</span>') + '</span>';
     }
 
-    var m = '<table style="width: 100%; margin-bottom: 2px;"><tr>';
-    m += catmenuitem('My Apps', 'myapps', '1');
-    m += catmenuitem('New', 'new', '2');
-    m += catmenuitem('Top', 'top', '3');
-    m += catmenuitem('Featured', 'featured', '4');
-    m += catmenuitem('All', 'all', '5');
-    if (category == 'myapps') {
-        m += '<th class="thl thr" style="width: 100%; padding-top: 0px; padding-bottom: 0px; padding-right: 0px; text-align: right;">';
-        m += '<input type="button" class="graybutton" id="createApp" title="Create a new app" style="font-weight: bold; margin-top: 0px; margin-bottom: 0px; height: 24px;" Value="New App"/>';
-        m += '</th></tr></table>';
-        return m;
-    }
-    m += '<th class="thl thr" style="width: 100%;"></th></tr></table>';
+    var m = '';
+    //m += catmenuitem('Featured', 'featured', '1');
+    m += catmenuitem('Top', 'top', '2');
+    m += catmenuitem('New', 'new', '3');
+    m += catmenuitem('Search', 'all', '4');
+    m += catmenuitem('My Apps', 'myapps', '5');
+    m += '<span class="rmenu"><input type="button" class="graybutton bluebutton" id="createApp" title="Create a new app" Value="Create"/></span>';
     return m;
 }
 
 // Build store menu bar
-$('catmenu').innerHTML = catmenu();
+$('viewhead').innerHTML = catmenu();
 
 /**
  * Service references.
@@ -94,24 +77,22 @@ function viewApp(appname) {
 /**
  * Create an app.
  */
-if (category == 'myapps') {
-    $('createApp').onclick = function() {
-        return ui.navigate('/#view=create', '_view');
-    }
+$('createApp').onclick = function() {
+    return ui.navigate('/#view=create', '_view');
 }
 
 /**
  * Get and display list of apps.
  */
 function getapps(category) {
-    //log('category', category);
+    //debug('category', category);
     showStatus('Loading');
 
     function display(doc) {
 
         // Stop now if we didn't get the apps
         if (doc == null) {
-            showStatus('No data');
+            showError('App not available');
             return false;
         }
         showStatus(defaultStatus());
@@ -128,23 +109,17 @@ function getapps(category) {
                 return apps;
             var entry = car(entries);
             var title = cadr(assoc("'title", entry))
-            var name = cadr(assoc("'id", entry))
-            var author = 'joe';
-            var clone = isNil(config.clone)? 'Clone' : config.clone;
-
-            apps += '<div class="box" style="width: 150px; display: inline-block; border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse; margin: 2px; padding: 2px; vertical-align: top;">'
-            apps += '<table><tr>';
-            apps += '<td>';
-            apps += '<div>' + ui.ahref('/#view=stats&app=' + name, '_view', '<img src="' + appimg + '" width="50" height="50" style="height: 50px; width: 50px; vertical-align: top; margin: 0px; padding: 0px;"></img>') + '</div>';
-            apps += '</td>';
-            apps += '<td class="tdw">';
-            apps += '<div style="font-weight: bold">' + ui.ahref('/' + name + '/', '_blank', name) + '</div>';
-            if (category == 'myapps')
-                apps += '<div style="color: #808080;">Shared</div>';
-            else
-                apps += '<div>' + 'by&nbsp;' + '<span style="font-weight: bold;">' + author + '</span></div>';
-            apps += '</td>';
-            apps += '</tr></table>';
+            var name = cadr(assoc("'id", entry));
+            var author = cadr(assoc("'author", entry));
+            var updated = cadr(assoc("'updated", entry));
+
+            apps += '<div class="box">'
+            apps += '<span class="appicon">' + ui.ahref('/#view=stats&app=' + name, '_view', '<img src="' + appimg + '" width="50" height="50"></img>') + '</span>';
+            apps += '<span>'
+            apps += '<span class="apptitle">' + ui.ahref('/#view=stats&app=' + name, '_view', name) + '</span>';
+            if (category != 'myapps')
+                apps += '<br/><span>' + 'by&nbsp;' + author.split('@')[0] + '</span>';
+            apps += '</span>';
             apps += '</div>';
             return displayentries(cdr(entries));
         }

Modified: tuscany/sca-cpp/trunk/hosting/server/pages.py
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/pages.py?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/pages.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/pages.py Mon May 28 16:49:36 2012
@@ -16,29 +16,81 @@
 #  under the License.
 
 # App pages collection implementation
+from time import strftime
 from util import *
+from sys import debug
 
-# Convert an id to an app id
-def appid(id):
+# Convert an id to a page id
+def pageid(id):
     return ("apps", car(id), "htdocs", "app.html")
 
-# Put an app page into the apps db
-def put(id, app, cache):
-    xhtml = cdr(cadddr(car(app)))
-    cache.put(appid(id), xhtml)
-    return True
-
-# Get an app page from the apps db
-def get(id, cache):
+# Put a page into the page db
+def put(id, page, user, cache, apps):
+    debug('pages.py::put::id', id)
+    debug('pages.py::put::page', page)
+
+    # Get the requested app
+    app = apps.get(id);
+    if isNil(app) or app is None:
+        debug('pages.py::put', 'app not found', id)
+        return False
+
+    # Check app author
+    author = cadr(assoc("'author", car(app)))
+    if author != user.get(()):
+        debug('pages.py::put', 'different author', author)
+        return False
+
+    # Update the page in the page db
+    pageentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y')), assoc("'content", car(page))),)
+    debug('pages.py::put::pageentry', pageentry)
+    return cache.put(pageid(id), pageentry)
+
+# Get a page from the page db
+def get(id, user, cache, apps):
+    debug('pages.py::get::id', id)
     if isNil(id):
         return (("'feed", ("'title", "Pages"), ("'id", "pages")),)
-    xhtml = cache.get(appid(id))
-    if isNil(xhtml) or xhtml is None:
-        return (("'entry", ("'title", car(id)), ("'id", car(id))),)
-    return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'content", car(xhtml))),)
-
-# Delete an app page from the apps db
-def delete(id, cache):
-    cache.delete(appid(id))
-    return True
+
+    # Get the requested app
+    app = apps.get(id)
+    if isNil(app) or app is None:
+        debug('pages.py::get', 'app not found', id)
+
+        # Return a default new page
+        return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y'))),)
+
+    # Get the requested page
+    page = cache.get(pageid(id))
+    if isNil(page) or page is None:
+        debug('pages.py::get', 'page not found', id)
+
+        # Return a default new page
+        return (("'entry", ("'title", car(id)), ("'id", car(id)), assoc("'author", car(app)), assoc("'updated", car(app))),)
+
+    # Return the page
+    def updated(u):
+        return assoc("'updated", car(app)) if isNil(u) or u is None else u
+    pageentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), assoc("'author", car(app)), updated(assoc("'updated", car(page))), assoc("'content", car(page))),)
+    debug('pages.py::get::pageentry', pageentry)
+    return pageentry
+
+# Delete a page from the page db
+def delete(id, user, cache, apps):
+    debug('pages.py::delete::id', id)
+
+    # Get the requested app
+    app = apps.get(id);
+    if isNil(app) or app is None:
+        debug('pages.py::delete', 'app not found', id)
+        return False
+
+    # Check app author
+    author = cadr(assoc("'author", car(app)))
+    if author != user.get(()):
+        debug('pages.py::delete', 'different author', author)
+        return False
+
+    # Delete the page
+    return cache.delete(pageid(id))
 

Copied: tuscany/sca-cpp/trunk/hosting/server/server-test (from r1343140, tuscany/sca-cpp/trunk/hosting/server/user.py)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/server-test?p2=tuscany/sca-cpp/trunk/hosting/server/server-test&p1=tuscany/sca-cpp/trunk/hosting/server/user.py&r1=1343140&r2=1343316&rev=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/user.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/server-test Mon May 28 16:49:36 2012
@@ -1,3 +1,5 @@
+#!/bin/sh
+
 #  Licensed to the Apache Software Foundation (ASF) under one
 #  or more contributor license agreements.  See the NOTICE file
 #  distributed with this work for additional information
@@ -15,14 +17,12 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# User info service component
+# Run Python test cases
+here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here`
+python_prefix=`cat $here/../../modules/python/python.prefix`
+export LD_LIBRARY_PATH=$python_prefix/lib:$LD_LIBRARY_PATH
+
+$python_prefix/bin/python test.py 2>/dev/null
+rc=$?
 
-# Return the user id
-def id(user, email, nick, full, first, last, realm):
-    if email.eval() != '?':
-        return email.eval()
-    if nick.eval() != '?':
-        return nick.eval() + '@' + realm.eval()
-    if user.eval() != '?':
-        return user.eval() + '@' + realm.eval()
-    return 'joe@localhost'
+exit $rc

Propchange: tuscany/sca-cpp/trunk/hosting/server/server-test
------------------------------------------------------------------------------
    svn:executable = *

Modified: tuscany/sca-cpp/trunk/hosting/server/server.composite
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/server.composite?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/server.composite (original)
+++ tuscany/sca-cpp/trunk/hosting/server/server.composite Mon May 28 16:49:36 2012
@@ -30,6 +30,7 @@
         <property name="firstname">?</property>
         <property name="lastname">?</property>
         <property name="realm">?</property>
+        <property name="host">?</property>
         <service name="User">
             <binding.http uri="user"/>
         </service>
@@ -52,6 +53,7 @@
         <implementation.widget location="/app/index.html"/>
         <reference name="user" target="User"/>
         <reference name="pages" target="Pages"/>
+        <reference name="composites" target="Composites"/>
         <reference name="log" target="Log"/>
     </component>
     
@@ -79,7 +81,9 @@
         <service name="AppStore">
             <binding.http uri="appstore"/>
         </service>        
+        <reference name="user" target="User"/>
         <reference name="cache" target="Cache"/>
+        <reference name="apps" target="Apps"/>
     </component>
     
     <component name="Apps">
@@ -87,7 +91,9 @@
         <service name="Apps">
             <binding.http uri="apps"/>
         </service>
+        <reference name="user" target="User"/>
         <reference name="cache" target="Cache"/>
+        <reference name="dashboard" target="Dashboards"/>
         <reference name="store" target="AppStore"/>
         <reference name="composites" target="Composites"/>
         <reference name="pages" target="Pages"/>
@@ -98,7 +104,9 @@
         <service name="Composites">
             <binding.http uri="composites"/>
         </service>
+        <reference name="user" target="User"/>
         <reference name="cache" target="Doccache"/>
+        <reference name="apps" target="Apps"/>
     </component>
     
     <component name="Pages">
@@ -106,7 +114,9 @@
         <service name="Pages">
             <binding.http uri="pages"/>
         </service>
+        <reference name="user" target="User"/>
         <reference name="cache" target="Doccache"/>
+        <reference name="apps" target="Apps"/>
     </component>
     
     <component name="Palettes">

Modified: tuscany/sca-cpp/trunk/hosting/server/ssl-start
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/ssl-start?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/ssl-start (original)
+++ tuscany/sca-cpp/trunk/hosting/server/ssl-start Mon May 28 16:49:36 2012
@@ -17,7 +17,8 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# For this module to work, add the www.example.com domain to your /etc/hosts as follows:
+# For this module to work, add the www.example.com domain to your /etc/hosts as
+# follows:
 # 127.0.0.1 www.example.com
 
 here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here`
@@ -45,10 +46,8 @@ fi
 ../../modules/http/httpd-event-conf tmp
 ../../modules/http/httpd-ssl-conf tmp 8453
 
-# Configure OpenID step2 authentication
-../../modules/openid/openid-conf tmp
-../../modules/openid/openid-step2-conf tmp
-../../modules/openid/openid-memcached-conf tmp localhost 11212
+# Configure HTTP basic auth
+../../modules/http/basic-auth-conf tmp
 
 # Configure OAuth authentication
 # Configure your OAuth app keys here
@@ -63,6 +62,11 @@ fi
 ../../modules/http/passwd-auth-conf tmp jane jane
 ../../modules/http/passwd-auth-conf tmp admin admin
 
+# Configure OpenID step2 authentication
+../../modules/openid/openid-conf tmp
+../../modules/openid/openid-step2-conf tmp
+../../modules/openid/openid-memcached-conf tmp localhost 11212
+
 # Configure authorized users
 ../../modules/http/group-auth-conf tmp john
 ../../modules/http/group-auth-conf tmp jane
@@ -72,7 +76,7 @@ fi
 ../../modules/http/group-auth-conf tmp jane@example.com
 
 # Configure mod-security
-../../modules/http/mod-security-conf tmp
+#../../modules/http/mod-security-conf tmp
 
 # Configure Python component support
 ../../modules/server/server-conf tmp
@@ -93,11 +97,11 @@ CustomLog "|$here/../../components/log/s
 
 EOF
 
-#    cat >tmp/conf/mod-security-log.conf <<EOF
+    cat >tmp/conf/mod-security-log.conf <<EOF
 # Generated by: ssl-start $*
-#SecAuditLog "|$here/../../components/log/scribe-cat $host secaudit"
-#
-#EOF
+SecAuditLog "|$here/../../components/log/scribe-cat $host secaudit"
+
+EOF
 
 else
     cat >tmp/conf/log.conf <<EOF
@@ -113,13 +117,14 @@ CustomLog $here/tmp/logs/ssl_access_log 
 
 EOF
 
-#    cat >tmp/conf/mod-security-log.conf <<EOF
+    cat >tmp/conf/mod-security-log.conf <<EOF
 # Generated by: ssl-start $*
-#SecAuditLog $here/tmp/logs/secaudit_log
-#
-#EOF
+SecAuditLog $here/tmp/logs/secaudit_log
+
+EOF
 
 fi
+#../../modules/http/httpd-loglevel-conf tmp debug
 
 # Configure certificate mime type
 cat >>tmp/conf/svhost-ssl.conf <<EOF
@@ -139,6 +144,8 @@ ErrorDocument 404 /public/notfound/
 ErrorDocument 401 /public/notauth/
 ErrorDocument 403 /public/notauth/
 ErrorDocument 500 /public/oops/
+ErrorDocument 502 /public/oops/
+ErrorDocument 503 /public/oops/
 ErrorDocument 405 /public/oops/
 
 EOF
@@ -151,8 +158,6 @@ SCAContribution $here/
 SCAComposite server.composite
 
 # Configure SCA Composite for mass dynamic virtual Hosting
-#SCAVirtualContribution $here/data/apps/
-#SCAVirtualComposite app.composite
 SCAVirtualContributor Composites
 
 EOF
@@ -162,6 +167,8 @@ cat >>tmp/conf/httpd.conf <<EOF
 # Generated by: ssl-start $*
 Alias /home/home.png $here/htdocs/home/home.png
 Alias /home/home.b64 $here/htdocs/home/home.b64
+Alias /proxy/public/config.js $here/htdocs/public/config.js
+Alias /proxy/public/config-min.js $here/public/config-min.js
 
 EOF
 
@@ -182,6 +189,5 @@ AliasMatch /v/([^/]+)(.*)$ $here/htdocs/
 EOF
 
 # Start server
-#../../modules/http/httpd-loglevel-conf tmp debug
 ../../modules/http/httpd-start tmp
 

Modified: tuscany/sca-cpp/trunk/hosting/server/start
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/start?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/start (original)
+++ tuscany/sca-cpp/trunk/hosting/server/start Mon May 28 16:49:36 2012
@@ -17,8 +17,9 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# For this module to work, add the example.com domain to your /etc/hosts as follows:
-# 127.0.0.1 example.com
+# For this module to work, add the www.example.com domain to your /etc/hosts as
+# follows:
+# 127.0.0.1 www.example.com
 
 here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here`
 jsprefix=`echo "import os; print os.path.realpath('$here/../../modules/js')" | python`
@@ -37,7 +38,7 @@ fi
 ../../components/cache/memcached-start tmp 11212
 
 # Configure server
-../../modules/http/httpd-conf tmp example.com 8090 htdocs
+../../modules/http/httpd-conf tmp www.example.com 8090 htdocs
 ../../modules/http/httpd-event-conf tmp
 
 # Configure Python component support
@@ -95,6 +96,8 @@ cat >>tmp/conf/httpd.conf <<EOF
 # Generated by: start $*
 Alias /home/home.png $here/htdocs/home/home.png
 Alias /home/home.b64 $here/htdocs/home/home.b64
+Alias /proxy/public/config.js $here/htdocs/public/config.js
+Alias /proxy/public/config-min.js $here/public/config-min.js
 
 EOF
 

Modified: tuscany/sca-cpp/trunk/hosting/server/store.py
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/store.py?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/store.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/store.py Mon May 28 16:49:36 2012
@@ -15,8 +15,9 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# stores collection implementation
+# Stores collection implementation
 from util import *
+from sys import debug
 
 # Convert a particular store tag to a store id
 def storeid(tag):
@@ -24,61 +25,88 @@ def storeid(tag):
 
 # Get a store from the cache
 def getstore(id, cache):
+    debug('store.py::getstore::id', id)
     val = cache.get(id)
     if isNil(val) or val is None:
         return ()
-    return cdddr(car(val))
+    store = cdddr(car(val))
+    if not isNil(store) and isList(car(cadr(car(store)))):
+        # Expand list of entries
+        estore = tuple(map(lambda e: cons("'entry", e), cadr(car(store))))
+        debug('store.py::getstore::estore', estore)
+        return estore
+
+    debug('store.py::getstore::store', store)
+    return store
 
 # Put a store into the cache
 def putstore(id, store, cache):
+    debug('store.py::putstore::id', id)
+    debug('store.py::putstore::store', store)
     val = ((("'feed", ("'title", "App Store"), ("'id", cadr(id))) + store),)
+    return cache.put(id, val)
 
 # Put an app into a store
-def put(key, app, cache):
-    def putapp(app, store):
+def put(id, app, user, cache, apps):
+    debug('store.py::put::id', id)
+    debug('store.py::put::app', app)
+    tag = car(id)
+    appid = cdr(id)
+
+    def putapp(appid, app, store):
         if isNil(store):
             return app
-        if cadr(caddr(car(app))) == cadr(caddr(car(store))):
+        if car(appid) == cadr(assoc("'id", car(store))):
             return cons(car(app), cdr(store))
-        return cons(car(store), putapp(app, cdr(store)))
+        return cons(car(store), putapp(appid, app, cdr(store)))
+
+    appentry = (("'entry", assoc("'title", car(app)), ("'id", car(appid)), ("'author", user.get(())), assoc("'updated", car(app)), assoc("'content", car(app))),)
+    debug('store.py::put::appentry', appentry)
 
-    tag = car(key)
-    store = putapp(app, getstore(storeid(tag), cache))
-    putstore(storeid(tag), store, cache)
-    return True
+    store = putapp(appid, appentry, getstore(storeid(tag), cache))
+    return putstore(storeid(tag), store, cache)
 
 # Get apps from a store
-def get(key, cache):
-    tag = car(key)
-    id = cdr(key)
+def get(id, user, cache, apps):
+    debug('store.py::get::id', id)
+    tag = car(id)
+    appid = cdr(id)
 
-    def findapp(id, store):
+    def findapp(appid, store):
         if isNil(store):
             return None
-        if car(id) == cadr(caddr(car(store))):
+        if car(appid) == cadr(assoc("'id", car(store))):
             return (car(store),)
-        return findapp(id, cdr(store))
+        return findapp(appid, cdr(store))
 
-    if isNil(id):
-        return ((("'feed", ("'title", "App Store"), ("'id", tag)) + getstore(storeid(tag), cache)),)
-    return findapp(id, getstore(storeid(tag), cache))
+    if isNil(appid):
+        store = ((("'feed", ("'title", "App Store"), ("'id", tag)) + getstore(storeid(tag), cache)),)
+        debug('store.py::get::store', store)
+        return store
+
+    app = findapp(appid, getstore(storeid(tag), cache))
+    debug('store.py::get::app', app)
+    return app
 
 # Delete apps from a store
-def delete(key, cache):
-    tag = car(key)
-    id = cdr(key)
+def delete(id, user, cache, apps):
+    debug('store.py::delete::id', id)
+    tag = car(id)
+    appid = cdr(id)
 
-    if isNil(id):
+    if isNil(appid):
         return cache.delete(storeid(tag))
 
-    def deleteapp(id, store):
+    def deleteapp(appid, store):
         if isNil(store):
             return ()
-        if car(id) == cadr(caddr(car(store))):
+        if car(appid) == cadr(assoc("'id", car(store))):
             return cdr(store)
-        return cons(car(store), deleteapp(id, cdr(store)))
+        return cons(car(store), deleteapp(appid, cdr(store)))
 
-    store = deleteapp(id, getstore(storeid(tag), cache))
-    putstore(storeid(tag), store, cache)
-    return True
+    store = getstore(storeid(tag), cache)
+    deleted = deleteapp(appid, store)
+    if deleted == store:
+        return False
+    return putstore(storeid(tag), deleted, cache)
 

Added: tuscany/sca-cpp/trunk/hosting/server/test.py
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/test.py?rev=1343316&view=auto
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/test.py (added)
+++ tuscany/sca-cpp/trunk/hosting/server/test.py Mon May 28 16:49:36 2012
@@ -0,0 +1,296 @@
+#!/usr/bin/python
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#  
+#    http://www.apache.org/licenses/LICENSE-2.0
+#    
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+# Test the hosting server components
+
+import sys
+sys.debug = lambda *l: sys.stderr.write('python::debug ' + repr(l) + '\n')
+import time
+time.strftime = lambda f: 'Jan 01, 2012'
+
+import unittest
+from test.property import *
+from test.reference import *
+from test.cache import *
+
+import user
+import accounts
+import pages
+import composites
+import apps
+import store
+import dashboards
+
+def testUser():
+    # Return current user
+    assert user.get((), mkprop('user', lambda: 'johndoe'), mkprop('email', lambda: 'jdoe@example.com'), mkprop('nick', lambda: 'jdoe'), mkprop('full', lambda: 'john doe'), mkprop('first', lambda: 'john'), mkprop('last', lambda: 'doe'), mkprop('realm', lambda: 'example.com'), mkprop('host', lambda: 'localhost')) == 'jdoe@example.com'
+    return True
+
+def testAccounts():
+    # Get default account
+    defaccount = (("'entry", ("'title", 'jdoe@example.com'), ("'id", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012')),)
+    assert accounts.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {})) == defaccount
+
+    # Get user's account
+    jdoe = (("'entry", ("'title", 'John Doe'), ("'id", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'key", 'value'))),)
+    assert accounts.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('accounts', 'jdoe@example.com', 'user.account') : jdoe})) == jdoe
+
+    # Put and get account
+    cache1 = mkcache('cache', {})
+    assert accounts.put((), jdoe, mkref('user', lambda id: 'jdoe@example.com'), cache1) == True
+    assert accounts.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1) == jdoe
+    return True
+
+def testPages():
+    # Get default page
+    defpage = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012')),)
+    app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),)
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defpage
+    defpagefromapp = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012')),)
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: app1)) == defpagefromapp
+
+    # Get a page
+    page1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ())),)
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('apps', 'app1', 'htdocs', 'app.html') : page1}), mkref('apps', lambda id: app1)) == page1
+
+    # Put and get a page
+    cache1 = mkcache('cache', {})
+    page1updated = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ())),)
+    assert pages.put(('app1',), page1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == page1updated
+    
+    # Reject put from user other than the author
+    app1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),)
+    page1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 02, 2012')),)
+    assert pages.put(('app1',), page1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False
+    assert pages.put(('app1',), page1otherauthor, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == page1updated
+
+    # Reject delete from user other than the author
+    assert pages.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == page1updated
+
+    # Delete a page
+    assert pages.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True
+    assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == defpagefromapp
+    return True
+
+def testComposites():
+    # Get default composite
+    defcomposite = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012')),)
+    app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),)
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defcomposite
+    defcompositefromapp = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012')),)
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: app1)) == defcompositefromapp
+
+    # Get a composite
+    composite1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ())),)
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('apps', 'app1', 'app.composite') : composite1}), mkref('apps', lambda id: app1)) == composite1
+
+    # Put and get a composite
+    cache1 = mkcache('cache', {})
+    composite1updated = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ())),)
+    assert composites.put(('app1',), composite1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == composite1updated
+    
+    # Reject put from user other than the author
+    app1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),)
+    composite1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 02, 2012')),)
+    assert composites.put(('app1',), composite1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False
+    assert composites.put(('app1',), composite1otherauthor, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == composite1updated
+
+    # Reject delete from user other than the author
+    assert composites.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == composite1updated
+
+    # Delete a composite
+    assert composites.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True
+    assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == defcompositefromapp
+    return True
+
+def testApps():
+    # Get default app
+    defapp = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ("'stats", ("'description", '')))),)
+    assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == defapp
+
+    # Get an app
+    app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ("'stats", ("'description", '')))),)
+    assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('apps', 'app1', 'app.stats') : app1}), mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1
+
+    # Put and get an app
+    cache1 = mkcache('cache', {})
+    assert apps.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('dashboard', lambda id, app: True), mkref('store', lambda id, app: True), mkref('composites', lambda id, app: True), mkref('pages', lambda id, app: True)) == True
+    assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1
+    return True
+    
+    # Reject put from user other than the author
+    app1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),)
+    assert apps.put(('app1',), app1, mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id, app: True), mkref('store', lambda id, app: True), mkref('composites', lambda id, app: True), mkref('pages', lambda id, app: True)) == false
+    assert apps.get(('app1',), mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1
+
+    # Reject delete from user other than the author
+    assert apps.delete(('app1',), mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == False
+    assert apps.get(('app1',), mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1
+
+    # Delete an app
+    assert apps.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == True
+    assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == defapp
+    return True
+
+def testStore():
+    # Get default store
+    defstore = (("'feed", ("'title", 'App Store'), ("'id", 'top')),)
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defstore
+
+    # Get a store
+    store1= (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),)
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('store', 'top', 'store.apps') : store1}), mkref('apps', lambda id: None)) == store1
+    
+    store1compact = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ((("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), (("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))))),)
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('store', 'top', 'store.apps') : store1compact}), mkref('apps', lambda id: None)) == store1
+
+    # Put an app in an empty store
+    cache1 = mkcache('cache', {})
+    app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))),)
+    store1withapp1 = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1'))))),)
+    assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp1
+    assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp1
+
+    # Put a second app in the store
+    app2 = (("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))),)
+    store1withapp2 = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),)
+    assert store.put(('top', 'app2'), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp2
+    assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp2
+    assert store.put(('top', 'app2'), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp2
+
+    # Put a third app in the store
+    app3 = (("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3')))),)
+    store1withapp3 = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))), ("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3'))))),)
+    assert store.put(('top', 'app3'), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3
+    assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3
+    assert store.put(('top', 'app2'), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3
+    assert store.put(('top', 'app3'), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3
+
+    # Get an app from the store
+    assert store.get(('top','app1'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app1
+    assert store.get(('top','app2'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app2
+    assert store.get(('top','app3'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app3
+
+    # Put a third app in the store, starting from a compacted list
+    cache2 = mkcache('cache', {('store', 'top', 'store.apps') : store1compact})
+    assert store.put(('top', 'app3'), app3, mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == store1withapp3
+
+    # Delete the apps
+    assert store.delete(('top', 'app2'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.delete(('top', 'app4'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == False
+    assert store.delete(('top', 'app1'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.delete(('top', 'app3'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == defstore
+
+    # Delete a store
+    assert store.delete(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True
+    assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == defstore
+    return True
+
+def testDashboards():
+    # Get default dashboard
+    defdashboard = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com')),)
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defdashboard
+
+    # Get the user's dashboard
+    dash1= (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),)
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('dashboards', 'jdoe@example.com', 'user.apps') : dash1}), mkref('apps', lambda id: None)) == dash1
+    
+    dash1compact = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ((("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), (("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))))),)
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('dashboards', 'jdoe@example.com', 'user.apps') : dash1compact}), mkref('apps', lambda id: None)) == dash1
+
+    # Put an app in an empty dashboard
+    cache1 = mkcache('cache', {})
+    app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))),)
+    dash1withapp1 = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1'))))),)
+    assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp1
+    assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp1
+
+    # Put a second app in the dashboard
+    app2 = (("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))),)
+    dash1withapp2 = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),)
+    assert dashboards.put(('app2',), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp2
+    assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp2
+    assert dashboards.put(('app2',), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp2
+
+    # Put a third app in the dashboard
+    app3 = (("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3')))),)
+    dash1withapp3 = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))), ("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3'))))),)
+    assert dashboards.put(('app3',), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3
+    assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3
+    assert dashboards.put(('app2',), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3
+    assert dashboards.put(('app3',), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3
+
+    # Get an app from the user's dashboard
+    assert dashboards.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app1
+    assert dashboards.get(('app2',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app2
+    assert dashboards.get(('app3',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app3
+
+    # Put a third app in the dashboard, starting from a compacted list
+    cache2 = mkcache('cache', {('dashboards', 'jdoe@example.com', 'user.apps') : dash1compact})
+    assert dashboards.put(('app3',), app3, mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == dash1withapp3
+
+    # Delete the apps
+    assert dashboards.delete(('app2',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.delete(('app4',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == False
+    assert dashboards.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.delete(('app3',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == defdashboard
+
+    # Delete the dashboard
+    assert dashboards.delete((), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True
+    assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == defdashboard
+    return True
+
+if __name__ == '__main__':
+    print 'Testing...'
+    testUser()
+    testAccounts()
+    testPages()
+    testComposites()
+    testApps()
+    testStore()
+    testDashboards()
+    print 'OK'
+

Propchange: tuscany/sca-cpp/trunk/hosting/server/test.py
------------------------------------------------------------------------------
    svn:executable = *

Copied: tuscany/sca-cpp/trunk/hosting/server/test/__init__.py (from r1343140, tuscany/sca-cpp/trunk/hosting/server/user.py)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/test/__init__.py?p2=tuscany/sca-cpp/trunk/hosting/server/test/__init__.py&p1=tuscany/sca-cpp/trunk/hosting/server/user.py&r1=1343140&r2=1343316&rev=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/user.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/test/__init__.py Mon May 28 16:49:36 2012
@@ -15,14 +15,3 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# User info service component
-
-# Return the user id
-def id(user, email, nick, full, first, last, realm):
-    if email.eval() != '?':
-        return email.eval()
-    if nick.eval() != '?':
-        return nick.eval() + '@' + realm.eval()
-    if user.eval() != '?':
-        return user.eval() + '@' + realm.eval()
-    return 'joe@localhost'

Copied: tuscany/sca-cpp/trunk/hosting/server/test/cache.py (from r1343140, tuscany/sca-cpp/trunk/hosting/server/accounts.py)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/test/cache.py?p2=tuscany/sca-cpp/trunk/hosting/server/test/cache.py&p1=tuscany/sca-cpp/trunk/hosting/server/accounts.py&r1=1343140&r2=1343316&rev=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/accounts.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/test/cache.py Mon May 28 16:49:36 2012
@@ -15,21 +15,34 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# Accounts collection implementation
-from util import *
+# Mockup cache for testing
 
-# Convert a particular user id to an account id
-def accountid(user):
-    return ("accounts", user.id(), "user.account")
-
-# Get the current user's account
-def get(id, user, cache):
-    account = cache.get(accountid(user))
-    if isNil(account) or account is None:
-        return ()
-    return account
-
-# Update the user's account
-def put(id, account, user, cache):
-    return cache.put(accountid(user), account)
+class cache:
+    def __init__(self, name, values):
+        self.name = name
+        self.values = values
+
+    def get(self, id):
+        if id in self.values:
+            return self.values[id]
+        return None
+
+    def put(self, id, value):
+        self.values[id] = value
+        return True
+
+    def post(self, id):
+        return self.put(id)
+
+    def delete(self, id):
+        if id in self.values:
+            del self.values[id]
+            return True
+        return False
+
+    def __repr__(self):
+        return repr((self.name, self.values))
+
+def mkcache(name, values = {}):
+    return cache(name, values)
 

Copied: tuscany/sca-cpp/trunk/hosting/server/test/property.py (from r1343140, tuscany/sca-cpp/trunk/hosting/server/user.py)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/test/property.py?p2=tuscany/sca-cpp/trunk/hosting/server/test/property.py&p1=tuscany/sca-cpp/trunk/hosting/server/user.py&r1=1343140&r2=1343316&rev=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/user.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/test/property.py Mon May 28 16:49:36 2012
@@ -15,14 +15,24 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# User info service component
+# Mockup component properties for testing
+
+class property:
+    def __init__(self, name, l):
+        self.name = name
+        self.l = l
+
+    def __call__(self, *args):
+        return self.l(*args)
+
+    def __getattr__(self, name):
+        if name == "eval":
+            return self
+        raise AttributeError()
+
+    def __repr__(self):
+        return repr((self.name, self.l()))
+
+def mkprop(name, l):
+    return property(name, l)
 
-# Return the user id
-def id(user, email, nick, full, first, last, realm):
-    if email.eval() != '?':
-        return email.eval()
-    if nick.eval() != '?':
-        return nick.eval() + '@' + realm.eval()
-    if user.eval() != '?':
-        return user.eval() + '@' + realm.eval()
-    return 'joe@localhost'

Copied: tuscany/sca-cpp/trunk/hosting/server/test/reference.py (from r1343140, tuscany/sca-cpp/trunk/hosting/server/user.py)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/test/reference.py?p2=tuscany/sca-cpp/trunk/hosting/server/test/reference.py&p1=tuscany/sca-cpp/trunk/hosting/server/user.py&r1=1343140&r2=1343316&rev=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/user.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/test/reference.py Mon May 28 16:49:36 2012
@@ -15,14 +15,24 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-# User info service component
+# Mockup component references for testing
+
+class reference:
+    def __init__(self, name, l):
+        self.name = name
+        self.l = l
+
+    def __call__(self, *args):
+        return self.l(*args)
+
+    def __getattr__(self, name):
+        if name == "get" or name == "put":
+            return self
+        raise AttributeError()
+
+    def __repr__(self):
+        return repr((self.name, self.l))
+
+def mkref(name, l):
+    return reference(name, l)
 
-# Return the user id
-def id(user, email, nick, full, first, last, realm):
-    if email.eval() != '?':
-        return email.eval()
-    if nick.eval() != '?':
-        return nick.eval() + '@' + realm.eval()
-    if user.eval() != '?':
-        return user.eval() + '@' + realm.eval()
-    return 'joe@localhost'

Modified: tuscany/sca-cpp/trunk/hosting/server/user.py
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/hosting/server/user.py?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/hosting/server/user.py (original)
+++ tuscany/sca-cpp/trunk/hosting/server/user.py Mon May 28 16:49:36 2012
@@ -17,12 +17,13 @@
 
 # User info service component
 
-# Return the user id
-def id(user, email, nick, full, first, last, realm):
+# Return the current user id
+def get(i, user, email, nick, full, first, last, realm, host):
     if email.eval() != '?':
         return email.eval()
     if nick.eval() != '?':
         return nick.eval() + '@' + realm.eval()
     if user.eval() != '?':
         return user.eval() + '@' + realm.eval()
-    return 'joe@localhost'
+    return 'anonymous@' + host.eval();
+

Modified: tuscany/sca-cpp/trunk/modules/atom/atom-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/atom/atom-test.cpp?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/atom/atom-test.cpp (original)
+++ tuscany/sca-cpp/trunk/modules/atom/atom-test.cpp Mon May 28 16:49:36 2012
@@ -41,6 +41,10 @@ const string itemEntry(
         "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
         " <title type=\"text\">item</title>\n"
         " <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+        " <author>\n"
+        "  <email>jane@example.com</email>\n"
+        " </author>\n"
+        " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
         " <content type=\"application/xml\">\n"
         "  <item>\n"
         "   <name>Apple</name>\n"
@@ -54,6 +58,10 @@ const string itemTextEntry("<?xml versio
         "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
         " <title type=\"text\">item</title>\n"
         " <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+        " <author>\n"
+        "  <email>jane@example.com</email>\n"
+        " </author>\n"
+        " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
         " <content type=\"text\">Apple</content>\n"
         " <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
         "</entry>\n");
@@ -62,6 +70,10 @@ const string itemNoContentEntry("<?xml v
         "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
         " <title type=\"text\">item</title>\n"
         " <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+        " <author>\n"
+        "  <name>jane</name>\n"
+        " </author>\n"
+        " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
         " <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
         "</entry>\n");
 
@@ -96,6 +108,8 @@ bool testEntry() {
         const list<value> a = list<value>() + (list<value>() + element + value("entry")
                 + value(list<value>() + element + value("title") + value(string("item")))
                 + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+                + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+                + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
                 + value(list<value>() + element + value("content") + value(i)));
         ostringstream os;
         writeATOMEntry<ostream*>(writer, &os, a);
@@ -105,6 +119,8 @@ bool testEntry() {
         const list<value> a = list<value>() + (list<value>() + element + value("entry")
                 + value(list<value>() + element + value("title") + value(string("item")))
                 + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+                + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+                + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
                 + value(list<value>() + element + value("content") + value(string("Apple"))));
         ostringstream os;
         writeATOMEntry<ostream*>(writer, &os, a);
@@ -113,7 +129,9 @@ bool testEntry() {
     {
         const list<value> a = list<value>() + (list<value>() + element + value("entry")
                 + value(list<value>() + element + value("title") + value(string("item")))
-                + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))));
+                + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+                + value(list<value>() + element + value("author") + value(string("jane")))
+                + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012"))));
         ostringstream os;
         writeATOMEntry<ostream*>(writer, &os, a);
         assert(str(os) == itemNoContentEntry);
@@ -158,6 +176,10 @@ const string itemFeed("<?xml version=\"1
         " <entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
         "  <title type=\"text\">item</title>\n"
         "  <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+        "  <author>\n"
+        "   <email>jane@example.com</email>\n"
+        "  </author>\n"
+        "  <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
         "  <content type=\"application/xml\">\n"
         "   <item>\n"
         "    <name>Apple</name>\n"
@@ -169,6 +191,10 @@ const string itemFeed("<?xml version=\"1
         " <entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
         "  <title type=\"text\">item</title>\n"
         "  <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>\n"
+        "  <author>\n"
+        "   <email>jane@example.com</email>\n"
+        "  </author>\n"
+        "  <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
         "  <content type=\"application/xml\">\n"
         "   <item>\n"
         "    <name>Orange</name>\n"
@@ -183,7 +209,9 @@ bool testFeed() {
     {
         const list<value> a = list<value>() + (list<value>() + element + value("feed")
                 + value(list<value>() + element + value("title") + value(string("Feed")))
-                + value(list<value>() + element + value("id") + value(string("1234"))));
+                + value(list<value>() + element + value("id") + value(string("1234")))
+                + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+                + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012"))));
         ostringstream os;
         writeATOMFeed<ostream*>(writer, &os, a);
         assert(str(os) == emptyFeed);
@@ -207,10 +235,14 @@ bool testFeed() {
             + value(list<value>() + element + value("entry")
                 + value(list<value>() + element + value("title") + value(string("item")))
                 + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+                + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+                + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
                 + value(list<value>() + element + value("content") + value(i1)))
             + value(list<value>() + element + value("entry")
                 + value(list<value>() + element + value("title") + value(string("item")))
                 + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c")))
+                + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+                + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
                 + value(list<value>() + element + value("content") + value(i2)));
         
         const list<value> a = list<value>() + (append<value>(list<value>() + element + value("feed")

Modified: tuscany/sca-cpp/trunk/modules/atom/atom.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/atom/atom.hpp?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/atom/atom.hpp (original)
+++ tuscany/sca-cpp/trunk/modules/atom/atom.hpp Mon May 28 16:49:36 2012
@@ -46,14 +46,24 @@ const value entry("entry");
  */
 const list<value> entryElementValues(const list<value>& e) {
     const list<value> lt = filter<value>(selector(mklist<value>(element, "title")), e);
-    const value t = isNil(lt)? value(emptyString) : elementValue(car(lt));
+    const list<value> t = list<value>() + element + value("title") + (isNil(lt)? value(emptyString) : elementValue(car(lt)));
+
     const list<value> li = filter<value>(selector(mklist<value>(element, "id")), e);
-    const value i = isNil(li)? value(emptyString) : elementValue(car(li));
+    const list<value> i = list<value>() + element + value("id") + (isNil(li)? value(emptyString) : elementValue(car(li)));
+
+    const list<value> la = filter<value>(selector(mklist<value>(element, "author")), e);
+    const list<value> lan = isNil(la)? list<value>() : filter<value>(selector(mklist<value>(element, "name")), car(la));
+    const list<value> lae = isNil(la)? list<value>() : filter<value>(selector(mklist<value>(element, "email")), car(la));
+    const list<value> laa = isNil(lan)? lae : lan;
+    const list<value> a = isNil(laa)? list<value>() : mklist<value>(list<value>() + element + value("author") + elementValue(car(laa)));
+
+    const list<value> lu = filter<value>(selector(mklist<value>(element, "updated")), e);
+    const list<value> u = isNil(lu)? list<value>() : mklist<value>(list<value>() + element + value("updated") + elementValue(car(lu)));
+
     const list<value> lc = filter<value>(selector(mklist<value>(element, "content")), e);
-    return append<value>(list<value>() + element + entry 
-                + value(list<value>() + element + value("title") + t)
-                + value(list<value>() + element + value("id") + i),
-                isNil(lc)? list<value>() : mklist<value>(value(list<value>() + element + value("content") + elementValue(car(lc)))));
+    const list<value> c = isNil(lc)? list<value>() : mklist<value>(list<value>() + element + value("content") + elementValue(car(lc)));
+
+    return append<value>(append<value>(append<value>(list<value>() + element + entry + value(t) + value(i), a), u), c);
 }
 
 /**
@@ -110,22 +120,44 @@ const failable<list<value> > readATOMFee
 }
 
 /**
+ * Returns children of an ATOM content element.
+ */
+struct filterContentElementChildren {
+    const value type;
+    filterContentElementChildren() : type("type") {
+    }
+    const bool operator()(const value& v) const {
+        return !(isAttribute(v) && attributeName((list<value>)v) == type);
+    }
+};
+
+const list<value> contentElementChildren(const value& content) {
+    return filter<value>(filterContentElementChildren(), elementChildren(content));
+}
+
+/**
  * Convert a list of element values representing an ATOM entry to a list of elements.
  */
 const list<value> entryElement(const list<value>& l) {
-    const value title = elementValue(elementChild("title", l));
-    const value id = elementValue(elementChild("id", l));
+    const value title = elementChild("title", l);
+    const value id = elementChild("id", l);
+    const value author = elementChild("author", l);
+    const bool email = isNil(author)? false : contains(elementValue(author), "@");
+    const value updated = elementChild("updated", l);
     const value content = elementChild("content", l);
     const bool text = isNil(content)? false : elementHasValue(content);
     return list<value>()
         + element + entry + (list<value>() + attribute + "xmlns" + "http://www.w3.org/2005/Atom")
-        + (list<value>() + element + "title" + (list<value>() + attribute + "type" + "text") + title)
-        + (list<value>() + element + "id" + id)
+        + (list<value>() + element + "title" + (list<value>() + attribute + "type" + "text") + elementValue(title))
+        + (list<value>() + element + "id" + elementValue(id))
+        + (isNil(author)? list<value>() : (list<value>() + element + "author" +
+            (email? (list<value>() + element + "email" + elementValue(author)) : (list<value>() + element + "name" + elementValue(author)))))
+        + (isNil(updated)? list<value>() : (list<value>() + element + "updated" + elementValue(updated)))
         + (isNil(content)?
             list<value>() :
             append<value>(list<value>() + element + "content" + (list<value>() + attribute + "type" + (text? "text" : "application/xml")),
-                text? mklist<value>(elementValue(content)) : elementChildren(content)))
-        + (list<value>() + element + "link" + (list<value>() + attribute + "href" + id));
+                text? mklist<value>(elementValue(content)) : contentElementChildren(content)))
+        + (list<value>() + element + "link" + (list<value>() + attribute + "href" + elementValue(id)));
 }
 
 /**

Modified: tuscany/sca-cpp/trunk/modules/http/conf/mime.types
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/conf/mime.types?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/conf/mime.types (original)
+++ tuscany/sca-cpp/trunk/modules/http/conf/mime.types Mon May 28 16:49:36 2012
@@ -471,7 +471,7 @@ image/gif			gif
 image/ief			ief
 image/jpeg			jpeg jpg jpe
 image/naplps
-image/png			png
+image/png			png b64
 image/prs.btif
 image/prs.pti
 image/svg+xml			svg
@@ -546,7 +546,7 @@ text/directory
 text/enriched
 text/html			html htm
 text/parityfec
-text/plain			asc txt b64
+text/plain			asc txt
 text/prs.lines.tag
 text/rfc822-headers
 text/richtext			rtx

Modified: tuscany/sca-cpp/trunk/modules/http/form-auth-conf
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/form-auth-conf?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/form-auth-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/form-auth-conf Mon May 28 16:49:36 2012
@@ -57,7 +57,7 @@ AuthFormProvider file
 AuthFormLoginRequiredLocation /login
 AuthFormLogoutLocation /
 Session On
-SessionCookieName TuscanyFormAuth path=/;secure=TRUE
+SessionCookieName TuscanyFormAuth domain=.$host; path=/
 SessionCryptoPassphrase $pw
 Require valid-user
 </Location>

Modified: tuscany/sca-cpp/trunk/modules/http/httpd-conf
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/httpd-conf?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/httpd-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/httpd-conf Mon May 28 16:49:36 2012
@@ -35,8 +35,6 @@ else
     pportsuffix=":$pport"
 fi
 
-dothost=`echo $host | grep "\."`
-
 mkdir -p $4
 htdocs=`echo "import os; print os.path.realpath('$4')" | python`
 
@@ -83,12 +81,9 @@ HostNameLookups Off
 # [timestamp] [access] remote-host remote-ident remote-user "request-line"
 # status response-size "referrer" "user-agent" "user-track" local-IP
 # virtual-host response-time bytes-received bytes-sent
-LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [access] %h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{cookie}n\" %A %V %D %I %O" combined
+LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [access] %h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" combined
 Include conf/log.conf
 
-# Configure tracking
-Include conf/tracking.conf
-
 # Configure Mime types and default charsets
 TypesConfig $here/conf/mime.types
 AddDefaultCharset utf-8
@@ -116,7 +111,8 @@ Require all denied
 
 # Configure output filters to enable compression and rate limiting
 <Location />
-SetOutputFilter RATE_LIMIT;DEFLATE
+#SetOutputFilter RATE_LIMIT;DEFLATE
+SetOutputFilter DEFLATE
 
 BrowserMatch ^Mozilla/4 gzip-only-text/html
 BrowserMatch ^Mozilla/4\.0[678] no-gzip
@@ -125,7 +121,7 @@ BrowserMatch ^check_http/ check_http
 SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
 Header append Vary User-Agent env=!dont-vary
 
-SetEnv rate-limit 400 
+#SetEnv rate-limit 400 
 </Location>
 
 # Listen on HTTP port
@@ -165,26 +161,6 @@ Include conf/adminauth.conf
 
 EOF
 
-# Generate tracking configuration
-cat >$root/conf/tracking.conf <<EOF
-# Generated by: httpd-conf $*
-# Configure tracking
-CookieTracking on
-CookieName TuscanyVisitorId
-CookieStyle Cookie
-CookieExpires 31556926
-
-EOF
-
-if [ "$dothost" != "" ]; then
-    cat >>$root/conf/tracking.conf <<EOF
-# Generated by: httpd-conf $*
-CookieDomain .$dothost
-
-EOF
-
-fi
-
 # Configure logging
 cat >$root/conf/log.conf <<EOF
 # Generated by: httpd-conf $*
@@ -303,6 +279,10 @@ Require all granted
 AuthType None
 Require all granted
 </Location>
+<Location /proxy/public>
+AuthType None
+Require all granted
+</Location>
 <Location /favicon.ico>
 AuthType None
 Require all granted

Modified: tuscany/sca-cpp/trunk/modules/http/httpd-ssl-conf
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/httpd-ssl-conf?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/httpd-ssl-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/httpd-ssl-conf Mon May 28 16:49:36 2012
@@ -37,6 +37,8 @@ else
     sslpportsuffix=":$sslpport"
 fi
 
+dothost=`echo $host | grep "\."`
+
 htdocs=`echo $conf | awk '{ print $8 }'`
 mkdir -p $htdocs
 htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python`
@@ -80,6 +82,9 @@ Include conf/locauth-ssl.conf
 Include conf/pubauth-ssl.conf
 Include conf/adminauth-ssl.conf
 
+# Configure tracking
+Include conf/tracking-ssl.conf
+
 </VirtualHost>
 
 EOF
@@ -163,7 +168,7 @@ SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 1
 # SSL-cipher "request-line" status response-size "referrer" "user-agent"
 # "SSL-client-I-DN" "SSL-client-S-DN" "user-track" local-IP virtual-host
 # response-time bytes-received bytes-sent
-LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [sslaccess] %h %l %u %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{SSL_CLIENT_I_DN}x\" \"%{SSL_CLIENT_S_DN}x\" \"%{cookie}n\" %A %V %D %I %O" sslcombined
+LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [sslaccess] %h %l %u %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{SSL_CLIENT_I_DN}x\" \"%{SSL_CLIENT_S_DN}x\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" sslcombined
 Include conf/log-ssl.conf
 
 # Enable HTTPS reverse proxy
@@ -180,6 +185,26 @@ SSLProxyCheckPeerCN Off
 
 EOF
 
+# Generate tracking configuration
+cat >$root/conf/tracking-ssl.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+# Configure tracking
+CookieTracking on
+CookieName TuscanyVisitorId
+CookieStyle Cookie
+CookieExpires 31556926
+
+EOF
+
+if [ "$dothost" != "" ]; then
+    cat >>$root/conf/tracking-ssl.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+CookieDomain .$dothost
+
+EOF
+
+fi
+
 # Configure logging
 cat >$root/conf/log-ssl.conf <<EOF
 # Generated by: httpd-ssl-conf $*

Modified: tuscany/sca-cpp/trunk/modules/http/proxy-base-conf
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/proxy-base-conf?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/proxy-base-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/proxy-base-conf Mon May 28 16:49:36 2012
@@ -24,10 +24,11 @@ root=`echo "import os; print os.path.rea
 
 cat >>$root/conf/vhost.conf <<EOF
 # Generated by: proxy-base-conf $*
-# Enable load balancing
+# Do not proxy admin pages
 ProxyPass /balancer-manager !
 ProxyPass /server-status !
 ProxyPass /server-info !
+ProxyPass /proxy !
 
 # Enable balancer manager
 <Location /balancer-manager>
@@ -38,7 +39,7 @@ HostnameLookups on
 EOF
 
 cat >>$root/conf/adminauth.conf <<EOF
-# Generated by: proxy-conf $*
+# Generated by: proxy-base-conf $*
 # Allow the server admin to manage the load balancer
 <Location /balancer-manager>
 Require user admin

Modified: tuscany/sca-cpp/trunk/modules/http/proxy-conf
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/proxy-conf?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/proxy-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/proxy-conf Mon May 28 16:49:36 2012
@@ -24,12 +24,14 @@ root=`echo "import os; print os.path.rea
 
 cat >>$root/conf/vhost.conf <<EOF
 # Generated by: proxy-conf $*
-# Enable load balancing
+# Do not proxy admin pages
 ProxyPass /balancer-manager !
 ProxyPass /server-status !
 ProxyPass /server-info !
-ProxyPass / balancer://cluster/
+ProxyPass /proxy !
 
+# Enable load balancing
+ProxyPass / balancer://cluster/
 <Proxy balancer://cluster>
 Require all granted
 ProxySet lbmethod=byrequests

Modified: tuscany/sca-cpp/trunk/modules/http/proxy-ssl-conf
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/proxy-ssl-conf?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/proxy-ssl-conf (original)
+++ tuscany/sca-cpp/trunk/modules/http/proxy-ssl-conf Mon May 28 16:49:36 2012
@@ -24,12 +24,14 @@ root=`echo "import os; print os.path.rea
 
 cat >>$root/conf/vhost-ssl.conf <<EOF
 # Generated by: proxy-ssl-conf $*
-# Enable load balancing
+# Do not proxy admin pages
 ProxyPass /balancer-manager !
 ProxyPass /server-status !
 ProxyPass /server-info !
-ProxyPass / balancer://sslcluster/
+ProxyPass /proxy !
 
+# Enable load balancing
+ProxyPass / balancer://sslcluster/
 <Proxy balancer://sslcluster>
 Require all granted
 ProxySet lbmethod=byrequests

Modified: tuscany/sca-cpp/trunk/modules/js/htdocs/atomutil.js
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/js/htdocs/atomutil.js?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/js/htdocs/atomutil.js (original)
+++ tuscany/sca-cpp/trunk/modules/js/htdocs/atomutil.js Mon May 28 16:49:36 2012
@@ -27,12 +27,24 @@ var atom = {};
  */
 atom.entryElementValues = function(e) {
     var lt = filter(selector(mklist(element, "'title")), e);
-    var t = isNil(lt)? '' : elementValue(car(lt));
+    var t = mklist(element, "'title", isNil(lt)? '' : elementValue(car(lt)));
+
     var li = filter(selector(mklist(element, "'id")), e);
-    var i = isNil(li)? '' : elementValue(car(li));
+    var i = mklist(element, "'id", isNil(li)? '' : elementValue(car(li)));
+
+    var la = filter(selector(mklist(element, "'author")), e);
+    var lan = isNil(la)? mklist() : filter(selector(mklist(element, "'name")), car(la));
+    var lae = isNil(la)? mklist() : filter(selector(mklist(element, "'email")), car(la));
+    var laa = isNil(lan)? lae : lan;
+    var a = isNil(laa)? mklist() : mklist(mklist(element, "'author", elementValue(car(laa))));
+
+    var lu = filter(selector(mklist(element, "'updated")), e);
+    var u = isNil(lu)? mklist() : mklist(mklist(element, "'updated", elementValue(car(lu))));
+
     var lc = filter(selector(mklist(element, "'content")), e);
-    return append(mklist(element, "'entry", mklist(element, "'title", t), mklist(element, "'id", i)),
-            isNil(lc)? mklist() : mklist(mklist(element, "'content", elementValue(car(lc)))))
+    var c = isNil(lc)? mklist() : mklist(mklist(element, "'content", elementValue(car(lc))));
+
+    return append(append(append(mklist(element, "'entry", t, i), a), u), c);
 };
 
 /**
@@ -107,14 +119,20 @@ atom.readATOMFeed = function(l) {
 atom.entryElement = function(l) {
     var title = elementValue(namedElementChild("'title", l));
     var id = elementValue(namedElementChild("'id", l));
+    var author = namedElementChild("'author", l);
+    var email = isNil(author)? false : (elementValue(author).indexOf('@') != -1);
+    var updated = namedElementChild("'updated", l);
     var content = namedElementChild("'content", l);
     var text = isNil(content)? false : elementHasValue(content);
-    return append(append(
+    return append(append(append(append(
             mklist(element, "'entry", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
                 mklist(element, "'title", mklist(attribute, "'type", "text"), title), mklist(element, "'id", id)),
+                isNil(author)? mklist() : mklist(element, "'author",
+                    (email? mklist(element, "'email", elementValue(author)) : mklist(element, "'name", elementValue(author))))),
+                isNil(updated)? mklist() : mklist(element, "'updated", elementValue(updated))),
                 isNil(content)? mklist() :
-                mklist(append(mklist(element, "'content", mklist(attribute, "'type", text? "text" : "application/xml")),
-                                text? mklist(elementValue(content)) : elementChildren(content)))),
+                    mklist(append(mklist(element, "'content", mklist(attribute, "'type", text? "text" : "application/xml")),
+                        text? mklist(elementValue(content)) : elementChildren(content)))),
                 mklist(mklist(element, "'link", mklist(attribute, "'href", id))));
 };
 

Modified: tuscany/sca-cpp/trunk/modules/js/htdocs/component.js
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/js/htdocs/component.js?rev=1343316&r1=1343315&r2=1343316&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/js/htdocs/component.js (original)
+++ tuscany/sca-cpp/trunk/modules/js/htdocs/component.js Mon May 28 16:49:36 2012
@@ -191,6 +191,7 @@ HTTPBindingClient.prototype.jsonApply = 
     var http = HTTPBindingClient.getHTTPRequest();
     var hascb = req.cb? true : false;
     http.open("POST", this.uri, hascb);
+    http.setRequestHeader("Accept", "*/*");
     http.setRequestHeader("Content-Type", "application/json-rpc");
 
     // Construct call back if we have one
@@ -238,7 +239,9 @@ HTTPBindingClient.prototype.get = functi
     var hascb = cb? true : false;
 
     // Get from local storage first
-    var item = localStorage.getItem(u);
+    var ls = window.lstorage || localStorage;
+    var item = null;
+    try { item = ls.getItem(u); } catch(e) {}
     //log('localStorage.getItem', u, item);
     if (item != null && item != '') {
         if (!hascb)
@@ -253,6 +256,7 @@ HTTPBindingClient.prototype.get = functi
     // Connect to the service
     var http = HTTPBindingClient.getHTTPRequest();
     http.open("GET", u, hascb);
+    http.setRequestHeader("Accept", "*/*");
 
     // Construct call back if we have one
     if (hascb) {
@@ -282,7 +286,7 @@ HTTPBindingClient.prototype.get = functi
                             // Store retrieved entry in local storage
                             if (http.responseText != null) {
                                 //log('localStorage.setItem', u, http.responseText);
-                                localStorage.setItem(u, http.responseText);
+                                try { ls.setItem(u, http.responseText); } catch(e) {}
                             }
                             try {
                                 return cb(http.responseText);
@@ -337,6 +341,7 @@ HTTPBindingClient.prototype.getnocache =
     // Connect to the service
     var http = HTTPBindingClient.getHTTPRequest();
     http.open("GET", u, hascb);
+    http.setRequestHeader("Accept", "*/*");
 
     // Construct call back if we have one
     if (hascb) {
@@ -407,6 +412,7 @@ HTTPBindingClient.prototype.post = funct
     var http = HTTPBindingClient.getHTTPRequest();
     var hascb = cb? true : false;
     http.open("POST", this.uri, hascb);
+    http.setRequestHeader("Accept", "*/*");
     http.setRequestHeader("Content-Type", "application/atom+xml");
 
     // Construct call back if we have one
@@ -445,13 +451,15 @@ HTTPBindingClient.prototype.put = functi
     var u = this.uri + '/' + id;
 
     // Update local storage
-    localStorage.setItem(u, entry);
+    var ls = window.lstorage || localStorage;
+    try { ls.setItem(u, entry); } catch(e) {}
     //log('localStorage.setItem', u, entry);
 
     // Connect to the service
     var http = HTTPBindingClient.getHTTPRequest();
     var hascb = cb? true : false;
     http.open("PUT", u, hascb);
+    http.setRequestHeader("Accept", "*/*");
     http.setRequestHeader("Content-Type", "application/atom+xml");
 
     // Construct call back if we have one
@@ -489,13 +497,15 @@ HTTPBindingClient.prototype.del = functi
     var u = this.uri + '/' + id;
 
     // Update local storage
-    localStorage.removeItem(u);
+    var ls = window.lstorage || localStorage;
+    try { ls.removeItem(u); } catch(e) {}
     //log('localStorage.removeItem', u);
 
     // Connect to the service
     var http = HTTPBindingClient.getHTTPRequest();
     var hascb = cb? true : false;
     http.open("DELETE", u, hascb);        
+    http.setRequestHeader("Accept", "*/*");
 
     // Construct call back if we have one
     if (cb) {