summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/cpp
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-12-25 01:49:19 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-12-25 01:49:19 +0000
commitdc15dc32bb3348c760ba3643c083af7e0c8e43fe (patch)
tree2823b9165d5c3a8a1bc96b3d071f86101bb995b4 /sandbox/sebastien/cpp
parent088b2e47386078c79781a448e0b6e458ddaae23c (diff)
Create a sandbox branch to experiment with latest APR.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1052740 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sandbox/sebastien/cpp')
-rw-r--r--sandbox/sebastien/cpp/apr-2/AUTHORS5
-rw-r--r--sandbox/sebastien/cpp/apr-2/COPYING203
-rw-r--r--sandbox/sebastien/cpp/apr-2/ChangeLog12
-rw-r--r--sandbox/sebastien/cpp/apr-2/INSTALL216
-rw-r--r--sandbox/sebastien/cpp/apr-2/LICENSE342
-rw-r--r--sandbox/sebastien/cpp/apr-2/Makefile.am38
-rw-r--r--sandbox/sebastien/cpp/apr-2/NEWS13
-rw-r--r--sandbox/sebastien/cpp/apr-2/NOTICE48
-rw-r--r--sandbox/sebastien/cpp/apr-2/README115
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/bootstrap31
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/Makefile.am19
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am53
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/cache.composite68
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp156
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType30
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp125
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp123
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp191
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test54
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-start38
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-stop39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-test34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp77
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/server-test51
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am68
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp150
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType30
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp164
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat.composite52
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp111
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/echo-test31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/server-test39
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java79
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/vysper-start25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/vysper-stop25
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp103
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp320
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am44
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp130
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp94
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/filedb/filedb-test31
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp124
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp225
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/filedb/server-test40
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/Makefile.am76
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp107
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/client-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift112
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/log.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/log.composite57
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/log.cpp94
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/logger.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/logger.cpp92
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp77
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop42
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribe-test43
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp147
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf73
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-central-start27
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop28
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf67
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-client-start27
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop28
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/server-test65
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am49
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp130
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite33
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp123
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/nosqldb/server-test40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb24
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp460
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am57
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp99
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp97
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp260
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/qpidd-start24
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop26
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp158
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp72
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue.composite56
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/send-test31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/server-test43
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am55
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp130
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup41
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf105
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf122
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp88
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop27
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp262
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/server-test44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test32
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp124
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/standby-test39
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am71
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp85
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf64
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp138
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp151
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp71
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp194
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml148
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp94
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/webservice/echo-test37
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/module.xml25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/webservice/server-test49
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm21
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/services.xml25
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp65
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp86
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite48
-rw-r--r--sandbox/sebastien/cpp/apr-2/configure.ac928
-rw-r--r--sandbox/sebastien/cpp/apr-2/doc/Doxyfile.in1541
-rw-r--r--sandbox/sebastien/cpp/apr-2/doc/Makefile.am30
-rw-r--r--sandbox/sebastien/cpp/apr-2/etc/Makefile.am21
-rw-r--r--sandbox/sebastien/cpp/apr-2/etc/git-exclude115
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/etc/httpd-ipcrm23
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/etc/memgrind23
-rw-r--r--sandbox/sebastien/cpp/apr-2/etc/svn-config136
-rw-r--r--sandbox/sebastien/cpp/apr-2/etc/svn-ignore58
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/Makefile.am50
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/config.hpp76
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/dynlib-test.cpp48
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/dynlib.hpp91
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/element.hpp304
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/fstream.hpp254
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/function.hpp238
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/gc.hpp286
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/hash-test.cpp135
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/hash.hpp207
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/kernel-test.cpp603
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/lambda-test.cpp102
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/list.hpp587
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/mem-test.cpp162
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/monad.hpp493
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/parallel-test.cpp166
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/parallel.hpp319
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/perf.hpp68
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/sstream.hpp259
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/stream.hpp201
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/string-test.cpp196
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/string.hpp305
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/tree.hpp125
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/value.hpp624
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/xml-test.cpp180
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/xml.hpp378
-rw-r--r--sandbox/sebastien/cpp/apr-2/kernel/xsd-test.cpp107
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/Makefile.am19
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/atom/Makefile.am25
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/atom/atom-test.cpp212
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/atom/atom.hpp203
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/Makefile.am65
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/basic-auth-conf41
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/cert-auth-conf52
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/conf/mime.types607
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/curl-connect.cpp98
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/curl-get.cpp53
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/curl-test.cpp91
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/form-auth-conf54
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/group-auth-conf44
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/htdocs/index.html21
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/htdocs/login/index.html40
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/htdocs/logout/index.html33
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/http-test32
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/http.hpp663
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-addr54
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-conf255
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-event-conf35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-restart25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-ssl-conf163
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-start25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-stop25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-test40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/httpd-worker-conf35
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/httpd.hpp689
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/mod-openauth.cpp325
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/mod-ssltunnel.cpp361
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/open-auth-conf55
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/http/openauth.hpp98
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/passwd-auth-conf31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/proxy-conf41
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/proxy-member-conf35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-conf72
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-member-conf43
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/proxy-test37
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/ssl-ca-conf96
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-conf76
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-find26
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/tunnel-ssl-conf55
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/vhost-conf65
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/http/vhost-ssl-conf53
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/Makefile.am69
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/client-test.cpp39
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/domain-test.composite42
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/driver.hpp61
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/eval.hpp562
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/java/java-conf31
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/java-shell.cpp40
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/java-test.cpp138
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/jni-test.cpp80
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/mod-java.cpp80
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/mod-java.hpp77
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/ClassLoader.java76
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/InvocationHandler.java59
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/IterableUtil.java368
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/Service.java53
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/UUIDUtil.java32
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/java/server-test41
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/Adder.java26
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/AdderImpl.java28
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/CalcImpl.java52
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/Client.java34
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/ClientImpl.java44
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/Server.java34
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/java/test/ServerImpl.java51
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/java/wiring-test80
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am29
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp308
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js169
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js561
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js231
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js638
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js163
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css121
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js233
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js208
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js197
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp52
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/json/Makefile.am25
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/json/json-test.cpp165
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/json/json.hpp194
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am42
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html58
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html116
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html211
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html33
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html27
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp580
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp432
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf59
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf32
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test67
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/start-test54
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/stop-test24
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm36
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/Makefile.am32
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/index.html46
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/login/index.html129
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/logout/index.html33
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/public/index.html27
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/openid/openid-conf67
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/openid/openid-memcached-conf32
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/openid/openid-step2-conf78
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/openid.composite40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/openid/start-test46
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/openid/stop-test24
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/openid/user-info.scm28
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/Makefile.am56
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/client-test.cpp39
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/client-test.py40
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/domain-test.composite42
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/driver.hpp63
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/eval.hpp351
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/mod-python.cpp66
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/mod-python.hpp80
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/python/python-conf30
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/python-shell.cpp40
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/python-test.cpp109
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/python/server-test39
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/python/server-test.py42
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/python/wiring-test78
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/rss/Makefile.am25
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/rss/rss-test.cpp214
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/rss/rss.hpp201
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scdl/Makefile.am27
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scdl/scdl-test.cpp124
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scdl/scdl.hpp190
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scdl/test.composite64
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/scdl/validate-test23
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/Makefile.am44
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/driver.hpp76
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/element-value.cpp46
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/environment.hpp179
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/eval-shell.cpp36
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/eval-test.cpp231
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/eval.hpp290
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/io.hpp222
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/json-value.cpp53
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/primitive.hpp279
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/value-element.cpp46
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/value-json.cpp52
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/value-xml.cpp51
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/scheme/xml-value.cpp47
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/Makefile.am55
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/client-test.cpp39
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/client-test.hpp350
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/client-test.scm38
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/server/cpp-conf30
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/domain-test.composite49
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/htdocs/index.html21
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/entry.xml2
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/feed.xml2
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-request.txt1
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-result.txt1
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/htdocs/wiring/ref.js574
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/server/httpd-test78
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/impl-test.cpp76
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/mod-cpp.hpp104
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.cpp62
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.hpp896
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/mod-scheme.hpp91
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/mod-wiring.cpp472
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/server/scheme-conf30
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/server/server-conf103
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/server/server-test39
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/server/server-test.scm44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/server/wiring-test78
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/Makefile.am58
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/app.yaml50
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/atom-test.py168
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/atomutil.py120
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.cpp40
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.py40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/composite.py251
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/domain-test.composite42
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/elemutil.py168
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/gae-start29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/gae-stop29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/gae-test30
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/index.html1
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/entry.xml2
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/feed.xml2
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-request.txt1
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-result.txt1
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/http-test39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/http-test.py32
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/httputil.py93
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/json-test.py59
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/jsonutil.py152
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/rss-test.py170
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/rssutil.py117
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py272
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/server-test30
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test.py44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/stream-test.py47
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/util-test43
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/util.py145
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/wiring-test75
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-start28
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-stop28
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-test71
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/wsgi/xml-test.py74
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/xmlutil.py122
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/Makefile.am22
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/README3
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/loan-python/Makefile.am28
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/loan-python/htdocs/index.html156
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/loan-python/loan-approval.py77
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.composite46
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.py45
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/loan-python/server-test58
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/loan-python/start31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/loan-python/stop21
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/loan-python/util.py145
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/Makefile.am25
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/index.html31
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/test/index.html21
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/html.py22
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/json.py24
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/relay.composite75
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/rss.py25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/relay-python/start30
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/relay-python/stop20
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/relay-python/xml.py24
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/Makefile.am36
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/currency-converter.py29
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/fruits-catalog.py30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/shopping-cart.py76
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.composite64
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.py40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/currency-converter.py29
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/fruits-catalog.py30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/shopping-cart.py76
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.composite64
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.py40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/login/index.html194
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/logout/index.html33
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/login/index.html194
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/logout/index.html33
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/index.html34
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/login/index.html194
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/logout/index.html33
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-conf35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-ssl-conf40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/server-conf45
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/server-ssl-conf63
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/server-test61
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cluster/shared/shared.composite62
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-master-conf47
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-standby-conf40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-start121
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-stop44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/start79
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/stop42
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cluster/tunnel-ssl-conf32
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/Makefile.am40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/currency-converter.cpp67
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/fruits-catalog.cpp76
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-request.txt1
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-result.txt1
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/shopping-cart-entry.xml1
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cpp/server-test58
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/shopping-cart.cpp135
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cpp/ssl-start36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cpp/start31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-cpp/stop21
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-cpp/store.composite70
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/Makefile.am44
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/app.yaml54
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/currency-converter.py29
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-backend.composite32
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-frontend.composite66
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-single.composite71
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/domain.composite71
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/fruits-catalog.py30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/gmemcache.py45
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/index.html169
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/test/items-result.txt1
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/htpasswd.py21
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-gae/server-test59
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/shopping-cart.py82
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-gae/start21
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-gae/stop21
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-gae/store.py40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/Makefile.am34
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/htdocs/index.html150
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-java/server-test58
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-java/ssl-start38
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-java/start33
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-java/stop23
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/store.composite70
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverter.java28
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverterImpl.java45
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/store/FruitsCatalogImpl.java51
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-java/store/ShoppingCartImpl.java112
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/Makefile.am25
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/currency-converter.scm27
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/fruits-catalog.scm30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/htdocs/index.html150
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-nosql/server-test58
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/shopping-cart.scm82
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-nosql/ssl-start36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-nosql/start31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-nosql/stop20
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.composite70
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.scm47
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/Makefile.am28
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/currency-converter.py29
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/fruits-catalog.py30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/login/index.html40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/logout/index.html33
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/test/items-result.txt1
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-python/server-test58
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/shopping-cart.py75
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-python/ssl-start36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-python/start31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-python/stop21
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/store.composite70
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-python/store.py40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-python/uec2-start46
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/Makefile.am30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/currency-converter.scm27
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/fruits-catalog.scm30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/htdocs/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.cpp96
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.scm140
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-scheme/server-test58
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/shopping-cart.scm82
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-scheme/ssl-start36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-scheme/start31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-scheme/stop21
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.composite70
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.scm47
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/Makefile.am28
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/currency-converter.scm27
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/fruits-catalog.scm30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/htdocs/index.html150
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-sql/server-test58
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/shopping-cart.scm82
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-sql/ssl-start39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-sql/start34
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-sql/stop22
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/store.composite90
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-sql/store.scm47
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/Makefile.am28
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/currency-converter.py29
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/fruits-catalog.py30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/shopping-cart.py75
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.composite62
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.py40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/currency-converter.py29
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/fruits-catalog.py30
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/shopping-cart.py75
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.composite62
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.py40
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/jane/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/joe/index.html150
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/index.html34
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-vhost/server-test61
-rw-r--r--sandbox/sebastien/cpp/apr-2/samples/store-vhost/shared/shared.composite33
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-vhost/ssl-start46
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-vhost/start36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-vhost/stop21
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/samples/store-vhost/uec2-start50
-rw-r--r--sandbox/sebastien/cpp/apr-2/ubuntu/Makefile.am22
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect-all31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-bin-all-image95
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-dev-all-image41
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-install-all340
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-bin-all-image23
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-conf39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-dev-all-image23
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-setenv34
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-ssh21
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-start38
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-status23
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/ubuntu/uec2-stop24
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/XMLSchema.dtd402
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/datatypes.dtd204
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-secext-1.0.xsd195
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-utility-1.0.xsd108
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/ws-addr.xsd137
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/ws-policy.xsd141
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/wsdl20-instance.xsd35
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/xml.xsd117
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/external/xmldsig-core-schema.xsd318
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-1.1-cd05.xsd24
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-binding-sca-1.1-cd05.xsd20
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-binding-ws-1.1-cd04.xsd35
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-core-1.1-cd05.xsd478
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-definitions-1.1-cd05.xsd30
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-composite-1.1-cd05.xsd26
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-cpp-1.1-cd04.xsd63
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-java-1.1-cd02.xsd26
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-interface-cpp-1.1-cd04.xsd51
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-interface-java-1.1-cd04.xsd28
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-interface-wsdl-1.1-cd05.xsd28
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/sca-policy-1.1-cd03.xsd119
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-atom.xsd43
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-http.xsd41
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-jsonrpc.xsd41
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rest.xsd97
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rss.xsd43
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-python.xsd43
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-scheme.xsd43
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-widget.xsd43
-rw-r--r--sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1.xsd34
590 files changed, 55306 insertions, 0 deletions
diff --git a/sandbox/sebastien/cpp/apr-2/AUTHORS b/sandbox/sebastien/cpp/apr-2/AUTHORS
new file mode 100644
index 0000000000..b06da1bf3a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/AUTHORS
@@ -0,0 +1,5 @@
+Apache Tuscany SCA Runtime
+==========================
+
+The Apache Software Foundation (http://www.apache.org/)
+
diff --git a/sandbox/sebastien/cpp/apr-2/COPYING b/sandbox/sebastien/cpp/apr-2/COPYING
new file mode 100644
index 0000000000..6b0b1270ff
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/COPYING
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
diff --git a/sandbox/sebastien/cpp/apr-2/ChangeLog b/sandbox/sebastien/cpp/apr-2/ChangeLog
new file mode 100644
index 0000000000..a4151dc22a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ChangeLog
@@ -0,0 +1,12 @@
+Apache Tuscany SCA Runtime
+==========================
+
+For a log of all changes see the Tuscany commits mailing list:
+commits@tuscany.apache.org
+
+Archives:
+http://www.mail-archive.com/commits@tuscany.apache.org
+
+To subscribe send an email to:
+commits-subscribe@tuscany.apache.org
+
diff --git a/sandbox/sebastien/cpp/apr-2/INSTALL b/sandbox/sebastien/cpp/apr-2/INSTALL
new file mode 100644
index 0000000000..c9e7597a08
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/INSTALL
@@ -0,0 +1,216 @@
+Apache Tuscany SCA Runtime
+==========================
+
+Automated installation on Ubuntu 10.10 64-bit
+=============================================
+
+Tuscany provides two automated install scripts for Ubuntu. You can start with
+a fresh Ubuntu Server 10.10 64-bit system and these scripts will take care of
+all the download, build and installation steps for you.
+
+ubuntu/ubuntu-install-all:
+Complete build and installation with most dependencies built from source.
+
+System dependencies are downloaded and installed using sudo apt-get. Source
+dependencies are downloaded and built in the current directory.
+
+To run the automated installation:
+mkdir tuscany
+cd tuscany
+wget http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-install-all
+chmod +x ./ubuntu-install-all
+./ubuntu-install-all
+
+The installation script will display each command as it's executed.
+
+That's all you need to do to build and install the Tuscany SCA runtime on
+Ubuntu 10.10 64-bit.
+
+For manual build and install steps on other systems or if you need to customize
+your installation, read on...
+
+
+Building
+========
+
+The Tuscany SCA Linux build uses the GNU Autotools tool chain.
+
+First install the following development tools:
+autoconf-2.67
+automake-1.11
+libtool-2.2.6
+doxygen-1.7.1
+gcc-g++-4.4.5
+
+Then install the following development dependencies:
+
+Apache HTTP server and APR:
+httpd-2.3.8 (http://httpd.apache.org/)
+with included libapr and libaprutil
+built with OpenSSL libssl-0.9.8, libpcre3-8.02,
+and expat 2.0.1
+
+Memcached:
+memcached-1.4.5 (http://memcached.org/)
+built with libevent-1.4.13
+
+XML:
+libxml2-2.7.7 (http://xmlsoft.org/)
+
+CURL:
+curl-7-19-5
+libcurl4-openssl-7.19.5
+
+JSON:
+Mozilla TraceMonkey libmozjs (https://wiki.mozilla.org/JavaScript:TraceMonkey)
+also included in xulrunner-1.9.2
+
+Key/value store:
+tinycdb-0.77 (http://www.corpit.ru/mjt/tinycdb.html)
+
+Optional dependencies:
+
+Web Services:
+Apache Axis2/C 1.6.0 (http://ws.apache.org/axis2/c/)
+
+Queueing:
+Apache Qpid/C++ 0.6 (http://qpid.apache.org/)
+built with libuuid-2.17.2, libboost-1.42.0, libboost-program-options-1.42.0 and
+libboost-filesystem-1.42.0
+
+Python:
+Python 2.6.6 (http://www.python.org/)
+Google AppEngine 1.4.0 (http://code.google.com/appengine/)
+
+Java:
+a Java 5+ JDK (http://openjdk.java.net/, http://harmony.apache.org/)
+
+OpenID authentication:
+Mod_auth_openid (http://trac.butterfat.net/public/mod_auth_openid)
+build it from source at http://github.com/jsdelfino/mod_auth_openid
+requires Libopkele (http://kin.klever.net/libopkele/ or
+http://github.com/jsdelfino/libopkele)
+and HTML Tidy (http://tidy.sourceforge.net/)
+
+OAuth authorization:
+Liboauth 0.9.1 (http://liboauth.sourceforge.net/)
+
+XMPP Chat:
+Apache Vysper 0.5 (http://mina.apache.org/)
+
+Libstrophe (http://code.stanziq.com/strophe/)
+build it from source at git://github.com/jsdelfino/libstrophe.git
+
+SQL Database:
+postgresql-9.0.1 (http://www.postgresql.org/)
+
+Logging:
+Facebook Scribe 2.2 (http://github.com/facebook/scribe/downloads)
+requires Apache Thrift 0.2.0 (http://incubator.apache.org/thrift/)
+
+Cloud deployment:
+Apache Libcloud 0.3.1 (http://incubator.apache.org/libcloud/)
+
+
+To configure the Tuscany SCA build do this:
+./bootstrap
+./configure --prefix=<install dir>
+
+To enable debugging and strict warning compile options, add:
+--enable-maintainer-mode
+
+To enable gprof profiling, add:
+--enable-profiling
+
+To enable multi-threading (required by the Queue and Chat components and
+for running with the HTTPD worker or event multi-threaded MPMs):
+--enable-threads
+
+To enable support for Python component implementations:
+--enable-python
+
+To enable support for Java component implementations:
+--enable-java
+
+To build the Queue utility component (requires Apache Qpid/C++):
+--enable-queue
+
+To build the Chat utility component (requires Libstrophe and optionally Apache
+Vysper if you want to run the tests with a local Vysper XMPP server):
+--enable-chat
+
+To build the Log utility component (requires Facebook Scribe and Apache Thrift):
+--enable-log
+
+To build the SQL Database utility component (requires PostgreSQL):
+--enable-sqldb
+
+To build the Web service utility component (requires Apache Axis2/C):
+--enable-webservice
+
+To build the support for OAuth authorization:
+--enable-oauth
+
+To build the support for OpenID authentication:
+--enable-openid
+
+To generate doxygen documentation, add:
+--enable-doxygen
+
+To configure where to find dependencies, see the --with-* options described
+in the configure help:
+./configure --help
+
+
+Here's an example configuration tested on Ubuntu 10.10 64-bit, with the system
+dependencies installed in the standard system directories and some of the
+dependencies installed under $HOME:
+
+./configure --prefix=$HOME/tuscany-sca-cpp-bin \
+--with-apr=$HOME/httpd-2.3.8-bin --with-httpd=$HOME/httpd-2.3.8-bin \
+--with-memcached=$HOME/memcached-1.4.5-bin \
+--with-tinycdb=$HOME/tinycdb-0.77-bin \
+--with-curl=$HOME/curl-7.19.5-bin --with-libxml2=/usr \
+--with-js-include=/usr/include/xulrunner-1.9.2 \
+--with-js-lib=/usr/lib/xulrunner-1.9.2 \
+--enable-libcloud \
+--with-libcloud=$HOME/libcloud-0.3.1-bin \
+--enable-threads \
+--enable-python --with-python=/usr \
+--enable-gae --with-gae=$HOME/google_appengine \
+--enable-java --with-java=/usr/lib/jvm/default-java \
+--enable-webservice --with-axis2c=$HOME/axis2c-1.6.0-bin \
+--with-libxml2=$HOME/libxml2-2.7.7-bin \
+--enable-queue --with-qpidc=$HOME/qpidc-0.6-bin \
+--enable-chat --with-libstrophe=$HOME/libstrophe-bin \
+--with-vysper=$HOME/vysper-0.5 \
+--enable-sqldb --with-pgsql=$HOME/postgresql-9.0.1-bin \
+--enable-log --with-thrift=$HOME/thrift-0.2.0-bin \
+--with-scribe=$HOME/scribe-2.2-bin \
+--enable-openid --with-mod-auth-openid=$HOME/mod-auth-openid-bin \
+--enable-oauth --with-liboauth=$HOME/liboauth-0.9.1-bin \
+--enable-maintainer-mode
+
+
+To build the Tuscany SCA runtime, do this:
+make
+
+To run the tests, do this:
+make check
+
+To build ctags for the source, do this:
+make ctags
+
+To build a source distribution, do this:
+make dist
+
+To build a binary distribution, do this:
+make bindist
+
+
+Installing
+==========
+
+To install the Tuscany SCA binaries, do this:
+make install
+
diff --git a/sandbox/sebastien/cpp/apr-2/LICENSE b/sandbox/sebastien/cpp/apr-2/LICENSE
new file mode 100644
index 0000000000..ff3e0653d1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/LICENSE
@@ -0,0 +1,342 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
+================================================================================
+
+Apache Tuscany SCA C++ Subcomponents:
+
+The Tuscany SCA C++ release includes a number of subcomponents with separate
+copyright notices and license terms. Your use of the source code for these
+subcomponents is subject to the terms and conditions of the following licenses.
+
+================================================================================
+
+The xsd component includes XML files under the following license:
+
+Copyright OASIS 2005, 2009. All Rights Reserved.
+All capitalized terms in the following text have the meanings assigned to them in the OASIS Intellectual
+Property Rights Policy (the "OASIS IPR Policy"). The full Policy may be found at the OASIS website.
+This document and translations of it may be copied and furnished to others, and derivative works that
+comment on or otherwise explain it or assist in its implementation may be prepared, copied, published,
+and distributed, in whole or in part, without restriction of any kind, provided that the above copyright
+notice and this section are included on all such copies and derivative works. However, this document
+itself may not be modified in any way, including by removing the copyright notice or references to OASIS,
+except as needed for the purpose of developing any document or deliverable produced by an OASIS
+Technical Committee (in which case the rules applicable to copyrights, as set forth in the OASIS IPR
+Policy, must be followed) or as required to translate it into languages other than English.
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors
+or assigns.
+This document and the information contained herein is provided on an "AS IS" basis and OASIS
+DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
+WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP
+RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+PURPOSE.
+OASIS requests that any OASIS Party or any other party that believes it has patent claims that would
+necessarily be infringed by implementations of this OASIS Committee Specification or OASIS Standard,
+to notify OASIS TC Administrator and provide an indication of its willingness to grant patent licenses to
+such patent claims in a manner consistent with the IPR Mode of the OASIS Technical Committee that
+produced this specification.
+OASIS invites any party to contact the OASIS TC Administrator if it is aware of a claim of ownership of
+any patent claims that would necessarily be infringed by implementations of this specification by a patent
+holder that is not willing to provide a license to such patent claims in a manner consistent with the IPR
+Mode of the OASIS Technical Committee that produced this specification. OASIS may include such
+claims on its website, but disclaims any obligation to do so.
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that
+might be claimed to pertain to the implementation or use of the technology described in this document or
+the extent to which any license under such rights might or might not be available; neither does it represent
+that it has made any effort to identify any such rights. Information on OASIS' procedures with respect to
+rights in any document or deliverable produced by an OASIS Technical Committee can be found on the
+OASIS website. Copies of claims of rights made available for publication and any assurances of licenses
+to be made available, or the result of an attempt made to obtain a general license or permission for the use
+of such proprietary rights by implementers or users of this OASIS Committee Specification or OASIS
+Standard, can be obtained from the OASIS TC Administrator. OASIS makes no representation that any
+information or list of intellectual property rights will at any time be complete, or that any claims in such list
+are, in fact, Essential Claims.
+The names "OASIS", are trademarks of OASIS, the owner and developer of this specification, and should
+be used only to refer to the organization and its official outputs. OASIS welcomes reference to, and
+implementation and use of, specifications, while reserving the right to enforce its marks against misleading
+uses. Please see http://www.oasis-open.org/who/trademark.php for above guidance.
+
+================================================================================
+
+The xsd component includes XML files under the following license:
+
+http://www.w3.org/Consortium/Legal/copyright-software-19980720
+
+W3C® SOFTWARE NOTICE AND LICENSE
+Copyright (c) 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche
+en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/
+
+This W3C work (including software, documents, or other related items) is being provided by the copyright holders under
+the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood,
+and will comply with the following terms and conditions:
+
+Permission to use, copy, modify, and distribute this software and its documentation, with or without modification,
+for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies
+of the software and documentation or portions thereof, including modifications, that you make:
+
+ 1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
+ 2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short
+notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed
+or derivative code: "Copyright (c) [$date-of-software] World Wide Web Consortium, (Massachusetts Institute of Technology,
+Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/"
+ 3. Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs
+to the location from which the code is derived.)
+
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE
+OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE
+OF THE SOFTWARE OR DOCUMENTATION.
+
+The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software
+without specific, written prior permission. Title to copyright in this software and any associated documentation will
+at all times remain with copyright holders.
+
+================================================================================
+
+The components/chat component includes the Libstrophe library under the
+following MIT license:
+
+Copyright (c) 2005-2009 Collecta, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+================================================================================
+
+The components/log component includes the Scribe library under the following
+Apache license:
+
+Copyright (c) 2007-2008 Facebook
+
+Licensed 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.
+
+================================================================================
+
diff --git a/sandbox/sebastien/cpp/apr-2/Makefile.am b/sandbox/sebastien/cpp/apr-2/Makefile.am
new file mode 100644
index 0000000000..d41536ac0b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/Makefile.am
@@ -0,0 +1,38 @@
+# 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.
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = etc kernel modules components samples doc ubuntu
+
+datadir=$(prefix)
+dist_data_DATA = AUTHORS README LICENSE COPYING NOTICE NEWS
+nobase_dist_data_DATA = xsd/*.xsd xsd/external/*.xsd xsd/external/*.dtd
+EXTRA_DIST = INSTALL bootstrap
+
+dist-hook:
+ rm -rf `find $(distdir)/ -type d -name .svn`
+ rm -rf `find $(distdir)/ -type d -name .deps`
+ rm -rf $(distdir)/.git
+
+bindist: install
+ rm -rf ${PACKAGE}-${PACKAGE_VERSION}-bin
+ mkdir ${PACKAGE}-${PACKAGE_VERSION}-bin
+ cp -r $(prefix)/* ${PACKAGE}-${PACKAGE_VERSION}-bin
+ tar -cf - ${PACKAGE}-${PACKAGE_VERSION}-bin | gzip -c > ${PACKAGE}-${PACKAGE_VERSION}-bin.tar.gz
+ rm -rf ${PACKAGE}-${PACKAGE_VERSION}-bin
+
diff --git a/sandbox/sebastien/cpp/apr-2/NEWS b/sandbox/sebastien/cpp/apr-2/NEWS
new file mode 100644
index 0000000000..dea502fcae
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/NEWS
@@ -0,0 +1,13 @@
+Apache Tuscany SCA Runtime
+==========================
+
+For any news see the Tuscany development mailing list:
+dev@tuscany.apache.org
+
+Archives:
+http://www.mail-archive.com/dev@tuscany.apache.org
+http://marc.info/?l=tuscany-dev
+
+To subscribe send an email to:
+dev-subscribe@tuscany.apache.org
+
diff --git a/sandbox/sebastien/cpp/apr-2/NOTICE b/sandbox/sebastien/cpp/apr-2/NOTICE
new file mode 100644
index 0000000000..615f6b1f87
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/NOTICE
@@ -0,0 +1,48 @@
+Apache Tuscany
+Copyright (c) 2005-2010 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/)
+
+This product includes software under the OASIS Specification License
+with the following copyright:
+
+Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+OASIS trademark, IPR and other policies apply.
+
+This product includes software under the W3C(c) Software License
+with the following copyright:
+
+Copyright (c) 2008 World Wide Web Consortium, (Massachusetts Institute of Technology,
+European Research Consortium for Informatics and Mathematics, Keio University).
+All Rights Reserved. This work is distributed under the W3C(c) Software License [1] 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.
+
+[1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+This product includes software under the W3C(c) Software License
+with the following copyright:
+
+Copyright 2001 The Internet Society and W3C (Massachusetts Institute
+of Technology, Institut National de Recherche en Informatique et en
+Automatique, Keio University). All Rights Reserved.
+http://www.w3.org/Consortium/Legal/
+
+This document is governed by the W3C Software License [1] as described
+in the FAQ [2].
+
+[1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
+[2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
+
+This product includes software under the MIT license
+with the following copyright:
+
+Copyright (c) 2005-2009 Collecta, Inc.
+
+This product includes software under the Apache 2.0 license
+with the following copyright:
+
+Copyright (c) 2007-2008 Facebook
+
+
diff --git a/sandbox/sebastien/cpp/apr-2/README b/sandbox/sebastien/cpp/apr-2/README
new file mode 100644
index 0000000000..aa55d25f34
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/README
@@ -0,0 +1,115 @@
+Apache Tuscany SCA Runtime
+==========================
+
+Tuscany SCA Native is an SCA (Service Component Architecture) runtime written
+in C++ and integrated with the Apache HTTPD server.
+
+It supports SCA components written in C++ and Python. Experimental support
+for other programming languages is under construction. SCA bindings are
+available for the JSON-RPC, ATOMPub and RSS protocols. User signin is
+implemented using OpenID and OAuth.
+
+Several useful SCA components are provided on top of the SCA runtime, which
+can be used to help assemble distributed SCA composite applications:
+
+Cache: Key/value memory cache, using Memcached;
+Chat: XMPP chat, using Apache Vysper and Libstrophe;
+Log: distributed logger, using Facebook Scribe.
+Nosqldb: Key/value 'NoSQL' persistent store, using TinyCDB;
+Queue: AMQP queuing, using Apache Qpid/C;
+Sqldb: SQL database, using PostgreSQL;
+Webservice: Web service gateway, using Apache Axis2/C;
+
+These components present a simple ATOMPub REST interface, allowing you to send
+a message to a queue, a chat connection, or add an entry to a cache or a
+database for example, using a simple HTTP POST.
+
+
+Getting the source code
+=======================
+
+To checkout the source code, do this:
+git clone git://git.apache.org/tuscany-sca-cpp
+or
+svn checkout http://svn.apache.org/repos/asf/tuscany/sca-cpp tuscany-sca-cpp
+
+To checkout the source code with commit access, do this:
+git clone git://git.apache.org/tuscany-sca-cpp
+cd tuscany-sca-cpp
+wget -P .git http://git.apache.org/authors.txt
+git config svn.authorsfile .git/authors.txt
+git config user.email <you>@apache.org
+git config svn.rmdir true
+git svn init --prefix=origin/ -s https://svn.apache.org/repos/asf/tuscany/sca-cpp
+git svn rebase
+
+
+Layout
+======
+
+Here's a rough guide to the Tuscany SCA source tree:
+
+ /
+ |-- trunk Master development branch
+ | |
+ | |-- kernel SCA runtime kernel
+ | |
+ | |-- modules Modules that plug into the runtime
+ | | |-- atom AtomPub encoding
+ | | |-- http HTTP protocol
+ | | |-- java Support for Java components
+ | | |-- json JSON-RPC encoding
+ | | |-- oauth User signin using OAuth
+ | | |-- openid User signin using OpenID
+ | | |-- python Support for Python components
+ | | |-- scheme Support for Scheme components
+ | | |-- server Apache HTTPD server integration
+ | | |-- wsgi Python WSGI server integration
+ | |
+ | |-- components Useful SCA components
+ | | |-- cache Memcached key/value cache
+ | | |-- chat XMPP chat
+ | | |-- log Scribe logger
+ | | |-- nosqldb TinyCDB NoSQL database
+ | | |-- queue AMQP message queue
+ | | |-- sqldb PostgreSQL database
+ | | |-- webservice Axis2 Web service gateway
+ | |
+ | |-- samples Sample Applications
+ | | |-- store-cluster Online store on a proxy + server + db cluster
+ | | |-- store-cpp Online store written in C++
+ | | |-- store-gae Online store written in Python, working on GAE
+ | | |-- store-java Online store written in Java
+ | | |-- store-nosql Online store using a NoSQL database
+ | | |-- store-python Online store written in Python
+ | | |-- store-scheme Online store written in Scheme
+ | | |-- store-sql Online store using an SQL database
+ | | |-- store-vhost Online store on virtual hosts
+ | |
+ | |-- ubuntu Automated install on Ubuntu 10.10 64-bit
+ |
+ |-- branches Topic and release branches
+ |
+ |-- tags Release tags
+
+
+Building
+========
+
+See the INSTALL file at the root of the source tree.
+
+
+Contributing to the project
+===========================
+
+To contribute to the project or report issues see the Tuscany development
+mailing list:
+dev@tuscany.apache.org
+
+Archives:
+http://www.mail-archive.com/dev@tuscany.apache.org
+http://marc.info/?l=tuscany-dev
+
+To subscribe send an email to:
+dev-subscribe@tuscany.apache.org
+
diff --git a/sandbox/sebastien/cpp/apr-2/bootstrap b/sandbox/sebastien/cpp/apr-2/bootstrap
new file mode 100755
index 0000000000..af38864985
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/bootstrap
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# 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.
+
+for i in "libtoolize --force" aclocal autoconf autoheader
+do
+ echo -n "Running $i..."
+ $i || exit 1
+ echo 'done.'
+done
+
+echo -n 'Running automake...'
+automake --add-missing
+echo 'done.'
+exit 0
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/Makefile.am
new file mode 100644
index 0000000000..55f14a4ea8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/Makefile.am
@@ -0,0 +1,19 @@
+# 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.
+
+SUBDIRS = cache chat log nosqldb filedb queue sqldb webservice
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am
new file mode 100644
index 0000000000..2f162bf8f5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am
@@ -0,0 +1,53 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/cache
+
+dist_comp_SCRIPTS = memcached-start memcached-stop
+compdir=$(prefix)/components/cache
+
+comp_DATA = memcached.prefix
+memcached.prefix: $(top_builddir)/config.status
+ echo ${MEMCACHED_PREFIX} >memcached.prefix
+
+EXTRA_DIST = cache.composite memcache.componentType datacache.componentType memocache.componentType *.scm
+
+comp_LTLIBRARIES = libmemcache.la libdatacache.la libmemocache.la
+noinst_DATA = libmemcache.so libdatacache.so libmemocache.so
+
+libmemcache_la_SOURCES = memcache.cpp
+libmemcache.so:
+ ln -s .libs/libmemcache.so
+
+libdatacache_la_SOURCES = datacache.cpp
+libdatacache.so:
+ ln -s .libs/libdatacache.so
+
+libmemocache_la_SOURCES = memocache.cpp
+libmemocache.so:
+ ln -s .libs/libmemocache.so
+
+memcache_test_SOURCES = memcache-test.cpp
+memcache_test_LDFLAGS = -lxml2
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = memcached-test memcached-ssl-test server-test
+noinst_PROGRAMS = memcache-test client-test
+TESTS = memcached-test memcached-ssl-test server-test
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm b/sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm
new file mode 100644
index 0000000000..ccd5bc555f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Logger test case
+
+(define (add a b) (+ a b))
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/cache.composite b/sandbox/sebastien/cpp/apr-2/components/cache/cache.composite
new file mode 100644
index 0000000000..1f3302614d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/cache.composite
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="memcache">
+
+ <component name="memcache">
+ <implementation.cpp path="." library="libmemcache"/>
+ <service name="memcache">
+ <t:binding.http uri="memcache"/>
+ </service>
+ <property name="servers">localhost,localhost:11212,localhost:11213</property>
+ </component>
+
+ <component name="l2cache">
+ <implementation.cpp path="." library="libmemcache"/>
+ <service name="l2cache">
+ <t:binding.http uri="l2cache"/>
+ </service>
+ <property name="servers">localhost:11411,localhost:11412,localhost:11413</property>
+ </component>
+
+ <component name="datacache">
+ <implementation.cpp path="." library="libdatacache"/>
+ <service name="datacache">
+ <t:binding.http uri="datacache"/>
+ </service>
+ <reference name="l1reader" target="memcache"/>
+ <reference name="l1writer" target="memcache"/>
+ <reference name="l2reader" target="l2cache"/>
+ <reference name="l2writer" target="l2cache"/>
+ </component>
+
+ <component name="memocache">
+ <implementation.cpp path="." library="libmemocache"/>
+ <service name="memocache">
+ <t:binding.http uri="memocache"/>
+ </service>
+ <reference name="relay" target="adder"/>
+ <reference name="cache" target="memcache"/>
+ </component>
+
+ <component name="adder">
+ <implementation.scheme script="adder-test.scm"/>
+ <service name="adder">
+ <t:binding.http uri="adder"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp
new file mode 100644
index 0000000000..fce911a302
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test cache component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace cache {
+
+const string memcacheuri("http://localhost:8090/memcache");
+const string datacacheuri("http://localhost:8090/datacache");
+const string memocacheuri("http://localhost:8090/memocache");
+
+bool testCache(const string& uri) {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+bool testMemcache() {
+ return testCache(memcacheuri);
+}
+
+bool testDatacache() {
+ return testCache(datacacheuri);
+}
+
+bool testMemocache() {
+ http::CURLSession cs("", "", "");
+
+ const failable<value> res = http::evalExpr(mklist<value>(string("add"), 33, 22), memocacheuri, cs);
+ assert(hasContent(res));
+ assert((int)content(res) == 55);
+
+ const failable<value> res2 = http::evalExpr(mklist<value>(string("add"), 33, 22), memocacheuri, cs);
+ assert(hasContent(res2));
+ assert((int)content(res2) == 55);
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(memcacheuri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, memcacheuri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "Cache get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::cache::testMemcache();
+ tuscany::cache::testDatacache();
+ tuscany::cache::testMemocache();
+ tuscany::cache::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType
new file mode 100644
index 0000000000..ca6284c661
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="datacache"/>
+ <reference name="l1reader"/>
+ <reference name="l1writer"/>
+ <reference name="l2reader"/>
+ <reference name="l2writer"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp
new file mode 100644
index 0000000000..e1cfdbfa57
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * A data cache component implementation which coordinates access to two
+ * levels of backend read/write caches or stores. Each cache or store is
+ * accessed through two references: a writer reference and a reader reference.
+ *
+ * This is useful if your level2 store is made of a master and slave
+ * replicated databases, you can then wire the writer reference to the master
+ * database and the reader reference to one your slave databases (assuming
+ * that the updates eventually get replicated to the slave database, in the
+ * meantime the updates will be retrieved from the level1 cache).
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace datacache {
+
+/**
+ * Get an item from the cache.
+ */
+const failable<value> get(const value& key, const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, const lambda<value(const list<value>&)> rcache2, unused const lambda<value(const list<value>&)> wcache2) {
+
+ // Lookup level1 cache
+ const value val1 = rcache1(mklist<value>("get", key));
+ if (!isNil(val1))
+ return val1;
+
+ // Lookup level2 cache
+ const value val2 = rcache2(mklist<value>("get", key));
+ if (isNil(val2))
+ return mkfailure<value>("Couldn't get cache entry");
+
+ // Update level1 cache
+ wcache1(mklist<value>("put", key, val2));
+
+ return val2;
+}
+
+/**
+ * Post an item to the cache.
+ */
+const failable<value> post(const value& key, const value& val, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
+ const value id = append<value>(key, mklist(mkuuid()));
+
+ // Update level1 cache
+ wcache1(mklist<value>("put", id, val));
+
+ // Update level2 cache
+ wcache2(mklist<value>("put", id, val));
+
+ return id;
+}
+
+/**
+ * Put an item into the cache.
+ */
+const failable<value> put(const value& key, const value& val, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
+
+ // Update level1 cache
+ wcache1(mklist<value>("put", key, val));
+
+ // Update level2 cache
+ wcache2(mklist<value>("put", key, val));
+
+ return value(true);
+}
+
+/**
+ * Delete an item from the cache.
+ */
+const failable<value> del(const value& key, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
+
+ // Delete from level1 cache
+ wcache1(mklist<value>("delete", key));
+
+ // Delete from level2 cache
+ wcache2(mklist<value>("delete", key));
+
+ return value(true);
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "get")
+ return tuscany::datacache::get(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params));
+ if (func == "post")
+ return tuscany::datacache::post(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params));
+ if (func == "put")
+ return tuscany::datacache::put(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params));
+ if (func == "delete")
+ return tuscany::datacache::del(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp
new file mode 100644
index 0000000000..49848dd2a7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Memcached access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "memcache.hpp"
+
+namespace tuscany {
+namespace memcache {
+
+bool testMemCached() {
+ MemCached ch(mklist<string>("localhost:11211", "localhost:11212", "localhost:11213"));
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), ch)));
+ assert(get(k, ch) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), ch)));
+ assert(get(k, ch) == value(string("aaa")));
+ assert(hasContent(del(k, ch)));
+ assert(!hasContent(get(k, ch)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ MemCached& ch;
+ getLoop(const value& k, MemCached& ch) : k(k), ch(ch) {
+ }
+ const bool operator()() const {
+ assert(get(k, ch) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ MemCached ch(mklist<string>("localhost:11211", "localhost:11212", "localhost:11213"));
+ assert(hasContent(post(k, string("CCC"), ch)));
+
+ const lambda<bool()> gl = getLoop(k, ch);
+ cout << "Memcached get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::memcache::testMemCached();
+ tuscany::memcache::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType
new file mode 100644
index 0000000000..2ae66d1c43
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="memcache"/>
+ <property name="servers" type="xsd:string">localhost</property>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp
new file mode 100644
index 0000000000..4b62ce2e4c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Memcached-based cache component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "memcache.hpp"
+
+namespace tuscany {
+namespace cache {
+
+/**
+ * Get an item from the cache.
+ */
+const failable<value> get(const list<value>& params, memcache::MemCached& ch) {
+ return memcache::get(car(params), ch);
+}
+
+/**
+ * Post an item to the cache.
+ */
+const failable<value> post(const list<value>& params, memcache::MemCached& ch) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = memcache::post(id, cadr(params), ch);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the cache.
+ */
+const failable<value> put(const list<value>& params, memcache::MemCached& ch) {
+ const failable<bool> val = memcache::put(car(params), cadr(params), ch);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the cache.
+ */
+const failable<value> del(const list<value>& params, memcache::MemCached& ch) {
+ const failable<bool> val = memcache::del(car(params), ch);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyCache {
+public:
+ applyCache(memcache::MemCached& ch) : ch(ch) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), ch);
+ if (func == "post")
+ return post(cdr(params), ch);
+ if (func == "put")
+ return put(cdr(params), ch);
+ if (func == "delete")
+ return del(cdr(params), ch);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ memcache::MemCached& ch;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to memcached
+ const value servers = ((lambda<value(list<value>)>)car(params))(list<value>());
+ memcache::MemCached& ch = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(tokenize(",", servers)));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyCache(ch)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::cache::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp
new file mode 100644
index 0000000000..a76af6b662
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_memcache_hpp
+#define tuscany_memcache_hpp
+
+/**
+ * Memcached access functions.
+ */
+
+#include "apr.h"
+#include "apu.h"
+#include "apr_general.h"
+#include "apr_strings.h"
+#include "apr_hash.h"
+#include "apr_memcache.h"
+#include "apr_network_io.h"
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace memcache {
+
+/**
+ * Represents a memcached context.
+ */
+class MemCached {
+public:
+ MemCached() : owner(false) {
+ }
+
+ MemCached(const string host, const int port) : owner(true) {
+ apr_pool_create(&pool, NULL);
+ apr_memcache_create(pool, 1, 0, &mc);
+ addServer(host, port);
+ }
+
+ MemCached(const list<string>& servers) : owner(true) {
+ apr_pool_create(&pool, NULL);
+ apr_memcache_create(pool, 1, 0, &mc);
+ addServers(servers);
+ }
+
+ MemCached(const MemCached& c) : owner(false), pool(c.pool), mc(c.mc) {
+ }
+
+ ~MemCached() {
+ if (!owner)
+ return;
+ apr_pool_destroy(pool);
+ }
+
+private:
+ bool owner;
+ apr_pool_t* pool;
+ apr_memcache_t* mc;
+
+ friend const failable<bool> post(const value& key, const value& val, const MemCached& cache);
+ friend const failable<bool> put(const value& key, const value& val, const MemCached& cache);
+ friend const failable<value> get(const value& key, const MemCached& cache);
+ friend const failable<bool> del(const value& key, const MemCached& cache);
+
+ /**
+ * Add servers to the memcached context.
+ */
+ const failable<bool> addServer(const string& host, const int port) {
+ apr_memcache_server_t *server;
+ const apr_status_t sc = apr_memcache_server_create(pool, c_str(host), (apr_port_t)port, 1, 1, 1, 600, &server);
+ if (sc != APR_SUCCESS)
+ return mkfailure<bool>("Could not create memcached server");
+ const apr_status_t as = apr_memcache_add_server(mc, server);
+ if (as != APR_SUCCESS)
+ return mkfailure<bool>("Could not add memcached server");
+ return true;
+ }
+
+ const failable<bool> addServers(const list<string>& servers) {
+ if (isNil(servers))
+ return true;
+ const list<string> toks = tokenize(":", car(servers));
+ const failable<bool> r = addServer(car(toks), isNil(cdr(toks))? 11211 : atoi(c_str(cadr(toks))));
+ if (!hasContent(r))
+ return r;
+ return addServers(cdr(servers));
+ }
+};
+
+/**
+ * Replace spaces by tabs (as spaces are not allowed in memcached keys).
+ */
+const char* nospaces(const char* s) {
+ char* c = const_cast<char*>(s);
+ for (; *c; c++)
+ if (*c == ' ')
+ *c = '\t';
+ return s;
+}
+
+/**
+ * Post a new item to the cache.
+ */
+const failable<bool> post(const value& key, const value& val, const MemCached& cache) {
+ debug(key, "memcache::post::key");
+ debug(val, "memcache::post::value");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const apr_status_t rc = apr_memcache_add(cache.mc, nospaces(c_str(ks)), const_cast<char*>(c_str(vs)), length(vs), 0, 27);
+ if (rc != APR_SUCCESS)
+ return mkfailure<bool>("Could not add memcached entry");
+
+ debug(true, "memcache::post::result");
+ return true;
+}
+
+/**
+ * Update an item in the cache. If the item doesn't exist it is added.
+ */
+const failable<bool> put(const value& key, const value& val, const MemCached& cache) {
+ debug(key, "memcache::put::key");
+ debug(val, "memcache::put::value");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const apr_status_t rc = apr_memcache_set(cache.mc, nospaces(c_str(ks)), const_cast<char*>(c_str(vs)), length(vs), 0, 27);
+ if (rc != APR_SUCCESS)
+ return mkfailure<bool>("Could not set memcached entry");
+
+ debug(true, "memcache::put::result");
+ return true;
+}
+
+/**
+ * Get an item from the cache.
+ */
+const failable<value> get(const value& key, const MemCached& cache) {
+ debug(key, "memcache::get::key");
+
+ const string ks(scheme::writeValue(key));
+ char *data;
+ apr_size_t size;
+ const apr_status_t rc = apr_memcache_getp(cache.mc, cache.pool, nospaces(c_str(ks)), &data, &size, NULL);
+ if (rc != APR_SUCCESS)
+ return mkfailure<value>("Could not get memcached entry");
+ const value val(scheme::readValue(string(data, size)));
+
+ debug(val, "memcache::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the cache
+ */
+const failable<bool> del(const value& key, const MemCached& cache) {
+ debug(key, "memcache::delete::key");
+
+ const string ks(scheme::writeValue(key));
+ const apr_status_t rc = apr_memcache_delete(cache.mc, nospaces(c_str(ks)), 0);
+ if (rc != APR_SUCCESS)
+ return mkfailure<bool>("Could not delete memcached entry");
+
+ debug(true, "memcache::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_memcache_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test
new file mode 100755
index 0000000000..88143490f8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test
@@ -0,0 +1,54 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/ssl-ca-conf tmp/ssl localhost
+../../modules/http/ssl-cert-conf tmp/ssl localhost server
+../../modules/http/ssl-cert-conf tmp/ssl localhost tunnel
+
+./memcached-start 11411
+./memcached-start 11412
+./memcached-start 11413
+
+../../modules/http/httpd-conf tmp/tunnel localhost 8089 htdocs
+../../modules/http/httpd-event-conf tmp/tunnel
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/tunnel -x
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11211 localhost 8453 11411
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11212 localhost 8453 11412
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11213 localhost 8453 11413
+../../modules/http/httpd-start tmp/tunnel
+
+../../modules/http/httpd-conf tmp/server localhost 8090 htdocs
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/server -x
+../../modules/http/httpd-ssl-conf tmp/server 8453
+../../modules/http/cert-auth-conf tmp/server
+../../modules/http/httpd-start tmp/server
+sleep 1
+
+# Test
+./memcache-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp/tunnel
+../../modules/http/httpd-stop tmp/server
+./memcached-stop 11411
+./memcached-stop 11412
+./memcached-stop 11413
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-start b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-start
new file mode 100755
index 0000000000..75524d0dec
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-start
@@ -0,0 +1,38 @@
+#!/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
+# 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.
+
+# Start memcached
+here=`readlink -f $0`; here=`dirname $here`
+
+addr=$1
+if [ "$addr" = "" ]; then
+ ip=""
+ port="11211"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+memcached_prefix=`cat $here/memcached.prefix`
+if [ "$ip" = "" ]; then
+ $memcached_prefix/bin/memcached -d -m 4 -p $port
+else
+ $memcached_prefix/bin/memcached -d -l $ip -m 4 -p $port
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-stop b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-stop
new file mode 100755
index 0000000000..c414616752
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-stop
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+# Stop memcached
+here=`readlink -f $0`; here=`dirname $here`
+
+addr=$1
+if [ "$addr" = "" ]; then
+ ip=""
+ port="11211"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+memcached_prefix=`cat $here/memcached.prefix`
+if [ "$ip" = "" ]; then
+ mc="$memcached_prefix/bin/memcached -d -m 4 -p $port"
+else
+ mc="$memcached_prefix/bin/memcached -d -l $ip -m 4 -p $port"
+fi
+
+kill `ps -ef | grep -v grep | grep "${mc}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-test b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-test
new file mode 100755
index 0000000000..993d63ba1b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-test
@@ -0,0 +1,34 @@
+#!/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
+# 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.
+
+# Setup
+./memcached-start 11211
+./memcached-start 11212
+./memcached-start 11213
+sleep 1
+
+# Test
+./memcache-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./memcached-stop 11211
+./memcached-stop 11212
+./memcached-stop 11213
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType
new file mode 100644
index 0000000000..f32677544f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="memocache"/>
+ <reference name="relay"/>
+ <reference name="cache"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp
new file mode 100644
index 0000000000..2482c2202b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * A cache component implementation which memoizes the value of function
+ * applications, keyed by the function arguments, in a key/value cache passed
+ * as a reference.
+ *
+ * This is useful if your functions are idempotent and applied many times to
+ * the same arguments. The results can then be retrieved quickly from the
+ * cache without actually applying the function.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace memocache {
+
+/**
+ * Memoize the value of a function application in a cache.
+ */
+const failable<value> memoize(const list<value>& params, const lambda<value(const list<value>&)> relay, const lambda<value(const list<value>&)> cache) {
+ debug(params, "memocache::memoize::params");
+
+ // Lookup memoized value from cache
+ const value val = cache(mklist<value>("get", params));
+ if (!isNil(val)) {
+ debug(val, "memocache::memoize::cached");
+ return val;
+ }
+
+ // Apply the given function
+ const value res = relay(params);
+ debug(res, "memocache::memoize::res");
+
+ // Store the result value in the cache
+ cache(mklist<value>("put", params, res));
+
+ return res;
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start" || func == "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ const tuscany::list<tuscany::value> rev = tuscany::reverse(params);
+ return tuscany::memocache::memoize(tuscany::reverse(tuscany::cddr(rev)), tuscany::cadr(rev), tuscany::car(rev));
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/server-test b/sandbox/sebastien/cpp/apr-2/components/cache/server-test
new file mode 100755
index 0000000000..6d14f789f5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/server-test
@@ -0,0 +1,51 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite cache.composite
+EOF
+
+./memcached-start 11211
+./memcached-start 11212
+./memcached-start 11213
+./memcached-start 11411
+./memcached-start 11412
+./memcached-start 11413
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+./memcached-stop 11211
+./memcached-stop 11212
+./memcached-stop 11213
+./memcached-stop 11411
+./memcached-stop 11412
+./memcached-stop 11413
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am
new file mode 100644
index 0000000000..35fb57daf3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am
@@ -0,0 +1,68 @@
+# 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.
+
+JAVAROOT = $(top_builddir)/components/chat
+
+if WANT_CHAT
+
+INCLUDES = -I${LIBSTROPHE_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/chat
+
+dist_comp_SCRIPTS = vysper-start vysper-stop vysper-classpath
+compdir=$(prefix)/components/chat
+
+comp_DATA = vysper.prefix
+vysper.prefix: $(top_builddir)/config.status
+ echo ${VYSPER_PREFIX} >vysper.prefix
+
+EXTRA_DIST = chat.composite chat-sendreceiver.componentType chat-sender.componentType *.scm
+
+comp_LTLIBRARIES = libchat-sendreceiver.la libchat-sender.la
+noinst_DATA = libchat-sendreceiver.so libchat-sender.so
+
+libchat_sendreceiver_la_SOURCES = chat-sendreceiver.cpp
+libchat_sendreceiver_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+libchat-sendreceiver.so:
+ ln -s .libs/libchat-sendreceiver.so
+
+libchat_sender_la_SOURCES = chat-sender.cpp
+libchat_sender_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+libchat-sender.so:
+ ln -s .libs/libchat-sender.so
+
+xmpp_test_SOURCES = xmpp-test.cpp
+xmpp_test_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+
+noinst_PROGRAMS = xmpp-test client-test
+dist_noinst_SCRIPTS = server-test
+
+if WANT_VYSPER
+
+AM_JAVACFLAGS = -cp `${top_builddir}/components/chat/vysper-classpath ${VYSPER_PREFIX}`${JAVAROOT}
+dist_noinst_JAVA = test/*.java
+CLEANFILES = test/*.class
+
+dist_noinst_SCRIPTS += echo-test
+TESTS = echo-test
+endif
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType
new file mode 100644
index 0000000000..01838f0260
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="send"/>
+ <property name="jid" type="xsd:string"/>
+ <property name="password" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp
new file mode 100644
index 0000000000..d3726a4e1c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * XMPP chat sender component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+namespace sender {
+
+/**
+ * Post an item to an XMPP JID.
+ */
+const failable<value> post(const list<value>& params, XMPPClient& xc) {
+ const value to = car<value>(car(params));
+ const value val = cadr(params);
+ debug(to, "chat::post::jid");
+ debug(val, "chat::post::value");
+ const failable<bool> r = post(to, val, xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+ return value(mklist<value>(to));
+}
+
+/**
+ * Subscribe and listen to an XMPP session.
+ */
+class noop {
+public:
+ noop() {
+ }
+
+ const failable<bool> operator()(unused const value& jid, unused const value& val, unused XMPPClient& xc) const {
+ return true;
+ }
+};
+
+class subscribe {
+public:
+ subscribe(XMPPClient& xc) : xc(xc) {
+ }
+
+ const failable<bool> operator()() const {
+ gc_pool pool;
+ debug("chat::subscribe::listen");
+ const failable<bool> r = listen(noop(), const_cast<XMPPClient&>(xc));
+ debug("chat::subscribe::stopped");
+ return r;
+ }
+
+private:
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l;
+ XMPPClient xc;
+};
+
+/**
+ * Chatter component lambda function
+ */
+class chatSender {
+public:
+ chatSender(XMPPClient& xc, worker& w) : xc(xc), w(w) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return post(cdr(params), const_cast<XMPPClient&>(xc));
+
+ // Stop the chat sender component
+ if (func != "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ debug("chat::sender::stop");
+
+ // Disconnect and shutdown the worker thread
+ disconnect(const_cast<XMPPClient&>(xc));
+ cancel(const_cast<worker&>(w));
+ debug("chat::sender::stopped");
+
+ return failable<value>(value(lambda<value(const list<value>&)>()));
+ }
+
+private:
+ const XMPPClient xc;
+ worker w;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Extract the the XMPP JID and password
+ const list<value> props = params;
+ const value jid = ((lambda<value(list<value>)>)car(props))(list<value>());
+ const value pass = ((lambda<value(list<value>)>)cadr(props))(list<value>());
+
+ // Create an XMPP client session
+ XMPPClient xc(jid, pass, false);
+ const failable<bool> r = connect(xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+
+ // Listen and relay messages in a worker thread
+ worker w(3);
+ submit<failable<bool> >(w, lambda<failable<bool>()>(subscribe(xc)));
+
+ // Return the chat sender component lambda function
+ return value(lambda<value(const list<value>&)>(chatSender(xc, w)));
+}
+
+}
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::chat::sender::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType
new file mode 100644
index 0000000000..0367c38f55
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="send"/>
+ <reference name="relay"/>
+ <property name="jid" type="xsd:string"/>
+ <property name="password" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp
new file mode 100644
index 0000000000..610f3cc9cc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * XMPP chat sender/receiver component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+namespace sendreceiver {
+
+/**
+ * Post an item to an XMPP JID.
+ */
+const failable<value> post(const list<value>& params, XMPPClient& xc) {
+ const value to = car<value>(car(params));
+ const value val = cadr(params);
+ debug(to, "chat::post::jid");
+ debug(val, "chat::post::value");
+ const failable<bool> r = post(to, val, xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+ return value(mklist<value>(to));
+}
+
+/**
+ * A relay function that posts the XMPP messages it receives to a relay component reference.
+ */
+class relay {
+public:
+ relay(const lambda<value(const list<value>&)>& rel) : rel(rel) {
+ }
+
+ const failable<bool> operator()(const value& jid, const value& val, unused XMPPClient& xc) const {
+ if (isNil(rel))
+ return true;
+ debug(jid, "chat::relay::jid");
+ debug(val, "chat::relay::value");
+ const value res = rel(mklist<value>("post", mklist<value>(jid), val));
+ return true;
+ }
+
+private:
+ const lambda<value(const list<value>&)> rel;
+};
+
+/**
+ * Subscribe and listen to an XMPP session.
+ */
+class subscribe {
+public:
+ subscribe(const lambda<failable<bool>(const value&, const value&, XMPPClient&)>& l, XMPPClient& xc) : l(l), xc(xc) {
+ }
+
+ const failable<bool> operator()() const {
+ gc_pool pool;
+ debug("chat::subscribe::listen");
+ const failable<bool> r = listen(l, const_cast<XMPPClient&>(xc));
+ debug("chat::subscribe::stopped");
+ return r;
+ }
+
+private:
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l;
+ XMPPClient xc;
+};
+
+/**
+ * Chat sender/receiver component lambda function
+ */
+class chatSenderReceiver {
+public:
+ chatSenderReceiver(XMPPClient& xc, worker& w) : xc(xc), w(w) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return post(cdr(params), const_cast<XMPPClient&>(xc));
+
+ // Stop the chat sender/receiver component
+ if (func != "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ debug("chat::sendreceiver::stop");
+
+ // Disconnect and shutdown the worker thread
+ disconnect(const_cast<XMPPClient&>(xc));
+ cancel(const_cast<worker&>(w));
+ debug("chat::sendreceiver::stopped");
+
+ return failable<value>(value(lambda<value(const list<value>&)>()));
+ }
+
+private:
+ const XMPPClient xc;
+ worker w;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Extract the relay reference and the XMPP JID and password
+ const bool hasRelay = !isNil(cddr(params));
+ const value rel = hasRelay? car(params) : value(lambda<value(const list<value>&)>());
+ const list<value> props = hasRelay? cdr(params) : params;
+ const value jid = ((lambda<value(list<value>)>)car(props))(list<value>());
+ const value pass = ((lambda<value(list<value>)>)cadr(props))(list<value>());
+
+ // Create an XMPP client session
+ XMPPClient xc(jid, pass, false);
+ const failable<bool> r = connect(xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+
+ // Listen and relay messages in a worker thread
+ worker w(3);
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> rl = relay(rel);
+ submit<failable<bool> >(w, lambda<failable<bool>()>(subscribe(rl, xc)));
+
+ // Return the chat sender/receiver component lambda function
+ return value(lambda<value(const list<value>&)>(chatSenderReceiver(xc, w)));
+}
+
+}
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::chat::sendreceiver::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat.composite b/sandbox/sebastien/cpp/apr-2/components/chat/chat.composite
new file mode 100644
index 0000000000..9eada5c372
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat.composite
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="chat">
+
+ <component name="print-sender">
+ <implementation.cpp path="." library="libchat-sender"/>
+ <property name="jid">sca1@localhost</property>
+ <property name="password">sca1</property>
+ <service name="print-sender">
+ <t:binding.http uri="print-sender"/>
+ </service>
+ </component>
+
+ <component name="print-chatter">
+ <implementation.cpp path="." library="libchat-sendreceiver"/>
+ <property name="jid">sca2@localhost</property>
+ <property name="password">sca2</property>
+ <service name="print-chatter">
+ <t:binding.http uri="print-chatter"/>
+ </service>
+ <reference name="relay" target="print"/>
+ </component>
+
+ <component name="print">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="print">
+ <t:binding.http uri="print"/>
+ </service>
+ <reference name="report" target="print-chatter"/>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp
new file mode 100644
index 0000000000..2c91fda1f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test chat component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "parallel.hpp"
+#include "../../modules/http/http.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+
+const value jid1("sca1@localhost");
+const value pass1("sca1");
+const value jid2("sca2@localhost");
+const value pass2("sca2");
+const value jid3("sca3@localhost");
+const value pass3("sca3");
+
+const list<value> item = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+const list<value> entry = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), item);
+
+worker w(2);
+bool received;
+
+const failable<bool> listener(const value& from, const value& val, unused XMPPClient& xc) {
+ assert(contains(from, "sca2@localhost"));
+ assert(val == entry);
+ received = true;
+ return false;
+}
+
+struct subscribe {
+ XMPPClient& xc;
+ subscribe(XMPPClient& xc) : xc(xc) {
+ }
+ const failable<bool> operator()() const {
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l(listener);
+ listen(l, xc);
+ return true;
+ }
+};
+
+bool testListen() {
+ received = false;
+ XMPPClient& xc = *(new (gc_new<XMPPClient>()) XMPPClient(jid3, pass3));
+ const failable<bool> c = connect(xc);
+ assert(hasContent(c));
+ const lambda<failable<bool>()> subs = subscribe(xc);
+ submit(w, subs);
+ return true;
+}
+
+bool testPost() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const failable<value> id = http::post(entry, "http://localhost:8090/print-sender/sca2@localhost", ch);
+ assert(hasContent(id));
+ return true;
+}
+
+bool testReceived() {
+ shutdown(w);
+ assert(received == true);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::chat::testListen();
+ tuscany::chat::testPost();
+ tuscany::chat::testReceived();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/echo-test b/sandbox/sebastien/cpp/apr-2/components/chat/echo-test
new file mode 100755
index 0000000000..271d40d122
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/echo-test
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+# Setup
+./vysper-start
+sleep 3
+
+# Test
+./xmpp-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./vysper-stop
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/server-test b/sandbox/sebastien/cpp/apr-2/components/chat/server-test
new file mode 100755
index 0000000000..dd1dc6faa7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/server-test
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite chat.composite
+EOF
+
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm b/sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm
new file mode 100644
index 0000000000..a6023708e1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Chat test case
+
+(define (post key val report) (report "post" '("sca3@localhost") val))
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java b/sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java
new file mode 100644
index 0000000000..3d2b7d7c3e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package test;
+
+/**
+ * A test XMPP server, using Apache Vysper.
+ */
+import static java.lang.System.*;
+
+import java.io.File;
+
+import org.apache.vysper.mina.TCPEndpoint;
+import org.apache.vysper.stanzasession.StanzaSessionFactory;
+import org.apache.vysper.storage.StorageProviderRegistry;
+import org.apache.vysper.storage.inmemory.MemoryStorageProviderRegistry;
+import org.apache.vysper.xmpp.authorization.AccountManagement;
+import org.apache.vysper.xmpp.modules.extension.xep0049_privatedata.PrivateDataModule;
+import org.apache.vysper.xmpp.modules.extension.xep0054_vcardtemp.VcardTempModule;
+import org.apache.vysper.xmpp.modules.extension.xep0092_software_version.SoftwareVersionModule;
+import org.apache.vysper.xmpp.modules.extension.xep0119_xmppping.XmppPingModule;
+import org.apache.vysper.xmpp.modules.extension.xep0202_entity_time.EntityTimeModule;
+import org.apache.vysper.xmpp.server.XMPPServer;
+
+class TestVysperServer {
+ public static void main(final String args[]) throws Exception {
+ out.println("Starting test Vysper server...");
+
+ // Add the XMPP users used by the xmpp-test and server-test test cases
+ // If you're using your own XMPP server you need to add these users manually
+ final StorageProviderRegistry providerRegistry = new MemoryStorageProviderRegistry();
+ final AccountManagement accountManagement = (AccountManagement)providerRegistry.retrieve(AccountManagement.class);
+ accountManagement.addUser("sca1@localhost", "sca1");
+ accountManagement.addUser("sca2@localhost", "sca2");
+ accountManagement.addUser("sca3@localhost", "sca3");
+
+ // Create and start XMPP server for domain: localhost
+ final XMPPServer server = new org.apache.vysper.xmpp.server.XMPPServer("localhost");
+ server.addEndpoint(new TCPEndpoint());
+ server.addEndpoint(new StanzaSessionFactory());
+ server.setStorageProviderRegistry(providerRegistry);
+ final File cert = new File(TestVysperServer.class.getClassLoader().getResource("bogus_mina_tls.cert").getPath());
+ server.setTLSCertificateInfo(cert, "boguspw");
+ server.start();
+ server.addModule(new SoftwareVersionModule());
+ server.addModule(new EntityTimeModule());
+ server.addModule(new VcardTempModule());
+ server.addModule(new XmppPingModule());
+ server.addModule(new PrivateDataModule());
+ out.println("Test Vysper server started...");
+
+ // Wait forever
+ final Object lock = new Object();
+ synchronized(lock) {
+ lock.wait();
+ }
+
+ System.out.println("Stopping test Vysper server...");
+ server.stop();
+ out.println("Test Vysper server stopped.");
+ System.exit(0);
+ }
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath
new file mode 100755
index 0000000000..7cf16a5ae8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath
@@ -0,0 +1,29 @@
+#!/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
+# 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.
+
+# Compute a classpath for running a Vysper server
+here=`readlink -f $0`; here=`dirname $here`
+
+if [ "$1" = "" ]; then
+ vysper_prefix=`cat $here/vysper.prefix`
+else
+ vysper_prefix=$1
+fi
+jars=`find $vysper_prefix/lib -name "*.jar" | awk '{ printf "%s:", $1 }'`
+echo "$vysper_prefix/config:$jars"
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/vysper-start b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-start
new file mode 100755
index 0000000000..af95ecadf4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-start
@@ -0,0 +1,25 @@
+#!/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
+# 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.
+
+# Start Vysper test XMPP server
+here=`readlink -f $0`; here=`dirname $here`
+
+java_prefix=`cat $here/../../modules/java/java.prefix`
+mkdir -p $here/tmp/logs
+${java_prefix}/jre/bin/java -cp `$here/vysper-classpath`$here test.TestVysperServer 2>&1 1>>$here/tmp/logs/vysper.log &
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/vysper-stop b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-stop
new file mode 100755
index 0000000000..3c4be4efa9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-stop
@@ -0,0 +1,25 @@
+#!/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
+# 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.
+
+# Stop Vysper test XMPP server
+here=`readlink -f $0`; here=`dirname $here`
+
+java_prefix=`cat $here/../../modules/java/java.prefix`
+kill `ps -ef | grep -v grep | grep "${java_prefix}/jre/bin/java" | grep "vysper" | awk '{ print $2 }'`
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp
new file mode 100644
index 0000000000..6b7fa3439f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test XMPP support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "parallel.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+
+const value jid1("sca1@localhost");
+const value pass1("sca1");
+const value jid2("sca2@localhost");
+const value pass2("sca2");
+
+worker w(2);
+bool received;
+
+const failable<bool> listener(const value& from, const value& val, unused XMPPClient& xc) {
+ assert(contains(from, "sca1@localhost"));
+ assert(val == "hey");
+ received = true;
+ return false;
+}
+
+struct subscribe {
+ XMPPClient& xc;
+ subscribe(XMPPClient& xc) : xc(xc) {
+ }
+ const failable<bool> operator()() const {
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l(listener);
+ listen(l, xc);
+ return true;
+ }
+};
+
+bool testListen() {
+ received = false;
+ XMPPClient& xc = *(new (gc_new<XMPPClient>()) XMPPClient(jid2, pass2));
+ const failable<bool> c = connect(xc);
+ assert(hasContent(c));
+ const lambda<failable<bool>()> subs = subscribe(xc);
+ submit(w, subs);
+ return true;
+}
+
+bool testPost() {
+ XMPPClient xc(jid1, pass1);
+ const failable<bool> c = connect(xc);
+ assert(hasContent(c));
+ const failable<bool> p = post(jid2, "hey", xc);
+ assert(hasContent(p));
+ return true;
+}
+
+bool testReceived() {
+ shutdown(w);
+ assert(received == true);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::chat::testListen();
+ tuscany::chat::testPost();
+ tuscany::chat::testReceived();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp
new file mode 100644
index 0000000000..3a6aa86c5c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_queue_hpp
+#define tuscany_queue_hpp
+
+/**
+ * XMPP support functions.
+ */
+
+#include "strophe.h"
+extern "C" {
+#include "common.h"
+}
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace chat {
+
+/**
+ * XMPP runtime, one per process.
+ */
+class XMPPRuntime {
+public:
+ XMPPRuntime() {
+ xmpp_initialize();
+ log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
+ }
+
+ ~XMPPRuntime() {
+ xmpp_shutdown();
+ }
+
+private:
+ friend class XMPPClient;
+ xmpp_log_t* log;
+
+} xmppRuntime;
+
+/**
+ * Represents an XMPP client.
+ */
+class XMPPClient {
+public:
+ XMPPClient(const string& jid, const string& pass, bool owner = true) : owner(owner), ctx(xmpp_ctx_new(NULL, xmppRuntime.log)), conn(xmpp_conn_new(ctx)), connecting(false), connected(false), disconnecting(false) {
+ xmpp_conn_set_jid(conn, c_str(jid + "/" + mkuuid()));
+ xmpp_conn_set_pass(conn, c_str(pass));
+ }
+
+ XMPPClient(const XMPPClient& xc) : owner(false), ctx(xc.ctx), conn(xc.conn), listener(xc.listener), connecting(xc.connecting), connected(xc.connected), disconnecting(xc.disconnecting) {
+ }
+
+ ~XMPPClient() {
+ extern const failable<bool> disconnect(XMPPClient& xc);
+ if (!owner)
+ return;
+ if (!disconnecting)
+ disconnect(*this);
+ xmpp_conn_release(conn);
+ xmpp_ctx_free(ctx);
+ }
+
+private:
+ friend int versionHandler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata);
+ friend void connHandler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int err, xmpp_stream_error_t* const errstream, void *const udata);
+ friend int messageHandler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata);
+ friend const failable<bool> connect(XMPPClient& xc);
+ friend const failable<size_t> send(const char* data, const size_t len, XMPPClient& xc);
+ friend const failable<size_t> send(xmpp_stanza_t* const stanza, XMPPClient& xc);
+ friend const failable<bool> post(const value& to, const value& val, XMPPClient& xc);
+ friend const failable<bool> disconnect(XMPPClient& xc);
+ friend const failable<bool> listen(const lambda<failable<bool>(const value&, const value&, XMPPClient&)>& listener, XMPPClient& xc);
+
+ const bool owner;
+ xmpp_ctx_t* ctx;
+ xmpp_conn_t* conn;
+ lambda<failable<bool>(const value&, const value&, XMPPClient&)> listener;
+ bool connecting;
+ bool connected;
+ bool disconnecting;
+};
+
+/**
+ * Make a text stanza.
+ */
+xmpp_stanza_t* textStanza(const char* text, xmpp_ctx_t* ctx) {
+ xmpp_stanza_t* stanza = xmpp_stanza_new(ctx);
+ xmpp_stanza_set_text(stanza, text);
+ return stanza;
+}
+
+/**
+ * Make a named stanza.
+ */
+xmpp_stanza_t* namedStanza(const char* ns, const char* name, xmpp_ctx_t* ctx) {
+ xmpp_stanza_t* stanza = xmpp_stanza_new(ctx);
+ xmpp_stanza_set_name(stanza, name);
+ if (ns != NULL)
+ xmpp_stanza_set_ns(stanza, ns);
+ return stanza;
+}
+
+/**
+ * Make a named stanza using a qualified name.
+ */
+xmpp_stanza_t* namedStanza(const char* name, xmpp_ctx_t* ctx) {
+ xmpp_stanza_t* stanza = xmpp_stanza_new(ctx);
+ xmpp_stanza_set_name(stanza, name);
+ return stanza;
+}
+
+/**
+ * XMPP version handler.
+ */
+int versionHandler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata) {
+ XMPPClient& xc = *(XMPPClient*)udata;
+
+ // Build version reply stanza
+ xmpp_stanza_t* reply = namedStanza("iq", xc.ctx);
+ xmpp_stanza_set_type(reply, "result");
+ xmpp_stanza_set_id(reply, xmpp_stanza_get_id(stanza));
+ xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
+ xmpp_stanza_t* query = namedStanza(xmpp_stanza_get_ns(xmpp_stanza_get_children(stanza)), "query", xc.ctx);
+ xmpp_stanza_add_child(reply, query);
+ xmpp_stanza_t* name = namedStanza("name", xc.ctx);
+ xmpp_stanza_add_child(query, name);
+ xmpp_stanza_add_child(name, textStanza("Apache Tuscany", xc.ctx));
+ xmpp_stanza_t* version = namedStanza("version", xc.ctx);
+ xmpp_stanza_add_child(query, version);
+ xmpp_stanza_add_child(version, textStanza("1.0", xc.ctx));
+
+ // Send it
+ xmpp_send(conn, reply);
+ xmpp_stanza_release(reply);
+ return 1;
+}
+
+/**
+ * XMPP message handler
+ */
+int messageHandler(unused xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata) {
+ // Ignore noise
+ if(xmpp_stanza_get_child_by_name(stanza, "body") == NULL)
+ return 1;
+ if(!strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error"))
+ return 1;
+
+ // Call the client listener function
+ XMPPClient& xc = *(XMPPClient*)udata;
+ const char* from = xmpp_stanza_get_attribute(stanza, "from");
+ const char* text = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
+ if (isNil(xc.listener))
+ return 1;
+ const value val(scheme::readValue(text));
+ debug(from, "chat::messageHandler::from");
+ debug(val, "chat::messageHandler::body");
+ const failable<bool> r = xc.listener(value(string(from)), val, xc);
+ if (!hasContent(r) || !content(r)) {
+ // Stop listening
+ xc.listener = lambda<failable<bool>(const value&, const value&, XMPPClient&)>();
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * XMPP connection handler.
+ */
+void connHandler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, unused const int err, unused xmpp_stream_error_t* const errstream, void *const udata) {
+ XMPPClient& xc = *(XMPPClient*)udata;
+ xc.connecting = false;
+
+ if (status == XMPP_CONN_CONNECT) {
+ debug("chat::connHandler::connected");
+ xmpp_handler_add(conn, versionHandler, "jabber:iq:version", "iq", NULL, &xc);
+
+ // Send a <presence/> stanza so that we appear online to contacts
+ xmpp_stanza_t* pres = xmpp_stanza_new(xc.ctx);
+ xmpp_stanza_set_name(pres, "presence");
+ xmpp_send(conn, pres);
+ xmpp_stanza_release(pres);
+ xc.connected = true;
+ return;
+ }
+
+ debug("chat::connHandler::disconnected");
+ xc.connected = false;
+ if (xc.ctx->loop_status == XMPP_LOOP_RUNNING)
+ xc.ctx->loop_status = XMPP_LOOP_QUIT;
+}
+
+/**
+ * Connect to an XMPP server.
+ */
+const failable<bool> connect(XMPPClient& xc) {
+ xc.connecting = true;
+ xmpp_connect_client(xc.conn, NULL, 0, connHandler, &xc);
+ while(xc.connecting)
+ xmpp_run_once(xc.ctx, 20L);
+ if (!xc.connected)
+ return mkfailure<bool>("Couldn't connect to XMPP server");
+ return true;
+}
+
+/**
+ * Send a buffer on an XMPP session.
+ */
+const failable<size_t> send(const char* data, const size_t len, XMPPClient& xc) {
+ if (len == 0)
+ return 0;
+ const size_t written = xc.conn->tls? tls_write(xc.conn->tls, data, len) : sock_write(xc.conn->sock, data, len);
+ if (written == (size_t)-1) {
+ xc.conn->error = xc.conn->tls? tls_error(xc.conn->tls) : sock_error();
+ return mkfailure<size_t>("Couldn't send stanza to XMPP server");
+ }
+ return send(data + written, len - written, xc);
+}
+
+/**
+ * Send a string on an XMPP session.
+ */
+const failable<size_t> send(const string& data, XMPPClient& xc) {
+ return send(c_str(data), length(data), xc);
+}
+
+/**
+ * Send a stanza on an XMPP session.
+ */
+const failable<size_t> send(xmpp_stanza_t* const stanza, XMPPClient& xc) {
+ char *buf;
+ size_t len;
+ const int rc = xmpp_stanza_to_text(stanza, &buf, &len);
+ if (rc != 0)
+ return mkfailure<size_t>("Couldn't convert stanza to text");
+ const failable<size_t> r = send(buf, len, xc);
+ if (!hasContent(r)) {
+ xmpp_free(xc.conn->ctx, buf);
+ return r;
+ }
+ xmpp_debug(xc.conn->ctx, "conn", "SENT: %s", buf);
+ xmpp_free(xc.conn->ctx, buf);
+ return content(r);
+}
+
+/**
+ * Post a message to an XMPP jid.
+ */
+const failable<bool> post(const value& to, const value& val, XMPPClient& xc) {
+ debug(to, "chat::post::to");
+ debug(val, "chat::post::body");
+
+ // Convert the value to a string
+ const string vs(scheme::writeValue(val));
+
+ // Build message stanza
+ xmpp_stanza_t* stanza = namedStanza("message", xc.ctx);
+ xmpp_stanza_set_type(stanza, "chat");
+ xmpp_stanza_set_attribute(stanza, "to", c_str(string(to)));
+ xmpp_stanza_t* body = namedStanza("body", xc.ctx);
+ xmpp_stanza_add_child(stanza, body);
+ xmpp_stanza_add_child(body, textStanza(c_str(vs), xc.ctx));
+
+ // Send it
+ const failable<size_t> r = send(stanza, xc);
+ xmpp_stanza_release(stanza);
+ if (!hasContent(r))
+ return mkfailure<bool>(reason(r));
+ return true;
+}
+
+/**
+ * Disconnect an XMPP session.
+ */
+const failable<bool> disconnect(XMPPClient& xc) {
+ xc.disconnecting = true;
+ const failable<size_t> r = send("</stream:stream>", xc);
+ if (!hasContent(r))
+ return mkfailure<bool>(reason(r));
+ return true;
+}
+
+/**
+ * Listen to messages received by an XMPP client.
+ */
+const failable<bool> listen(const lambda<failable<bool>(const value&, const value&, XMPPClient&)>& listener, XMPPClient& xc) {
+ debug("chat::listen");
+ xc.listener = listener;
+ xmpp_handler_add(xc.conn, messageHandler, NULL, "message", NULL, &xc);
+ xc.ctx->loop_status = XMPP_LOOP_RUNNING;
+ while(xc.connected && !isNil(xc.listener) && xc.ctx->loop_status == XMPP_LOOP_RUNNING)
+ xmpp_run_once(xc.ctx, 1000L);
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_xmpp_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am
new file mode 100644
index 0000000000..90c8b4207d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am
@@ -0,0 +1,44 @@
+# 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.
+
+INCLUDES = -I${TINYCDB_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/filedb
+
+compdir=$(prefix)/components/filedb
+
+EXTRA_DIST = filedb.composite filedb.componentType
+
+comp_LTLIBRARIES = libfiledb.la
+noinst_DATA = libfiledb.so
+
+libfiledb_la_SOURCES = filedb.cpp
+libfiledb_la_LDFLAGS = -lxml2 -lmozjs
+libfiledb.so:
+ ln -s .libs/libfiledb.so
+
+file_test_SOURCES = file-test.cpp
+file_test_LDFLAGS = -lxml2 -lmozjs
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = filedb-test server-test
+noinst_PROGRAMS = file-test client-test
+TESTS = filedb-test server-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp
new file mode 100644
index 0000000000..a65ec45341
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test file database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+const string uri("http://localhost:8090/filedb");
+
+bool testFileDB() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(uri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "FileDB get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::filedb::testFileDB();
+ tuscany::filedb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp b/sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp
new file mode 100644
index 0000000000..ff57bd79ce
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test FileDB access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "filedb.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+bool testFileDB(const string& dbname, const string& format) {
+ FileDB db(dbname, format);
+ const value k = mklist<value>("a", "b");
+
+ const list<value> a = mklist<value>(list<value>() + "ns1:a" + (list<value>() + "@xmlns:ns1" + string("http://aaa")) + (list<value>() + "text" + string("Hey!")));
+ const list<value> b = mklist<value>(list<value>() + "ns1:b" + (list<value>() + "@xmlns:ns1" + string("http://bbb")) + (list<value>() + "text" + string("Hey!")));
+
+ assert(hasContent(post(k, a, db)));
+ assert((get(k, db)) == value(a));
+ assert(hasContent(put(k, b, db)));
+ assert((get(k, db)) == value(b));
+ assert(hasContent(del(k, db)));
+ assert(!hasContent(get(k, db)));
+ assert(hasContent(post(k, a, db)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ FileDB& db;
+ const list<value> c;
+ getLoop(const value& k, FileDB& db) : k(k), db(db),
+ c(mklist<value>(list<value>() + "ns1:c" + (list<value>() + "@xmlns:ns1" + string("http://ccc")) + (list<value>() + "text" + string("Hey!")))) {
+ }
+ const bool operator()() const {
+ assert((get(k, db)) == value(c));
+ return true;
+ }
+};
+
+bool testGetPerf(const string& dbname, const string& format) {
+ FileDB db(dbname, format);
+
+ const value k = mklist<value>("c");
+ const list<value> c = mklist<value>(list<value>() + "ns1:c" + (list<value>() + "@xmlns:ns1" + string("http://ccc")) + (list<value>() + "text" + string("Hey!")));
+ assert(hasContent(post(k, c, db)));
+
+ const lambda<bool()> gl = getLoop(k, db);
+ cout << "FileDB get test " << time(gl, 5, 5000) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::filedb::testFileDB("tmp/schemedb", "scheme");
+ tuscany::filedb::testGetPerf("tmp/schemedb", "scheme");
+ tuscany::filedb::testFileDB("tmp/xmldb", "xml");
+ tuscany::filedb::testGetPerf("tmp/xmldb", "xml");
+ tuscany::filedb::testFileDB("tmp/jsondb", "json");
+ tuscany::filedb::testGetPerf("tmp/jsondb", "json");
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb-test b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb-test
new file mode 100755
index 0000000000..083bd1b96c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb-test
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+# Setup
+mkdir -p tmp
+mkdir -p tmp/schemedb
+mkdir -p tmp/xmldb
+mkdir -p tmp/jsondb
+
+# Test
+./file-test 2>/dev/null
+rc=$?
+
+# Cleanup
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType
new file mode 100644
index 0000000000..31f996ef3e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="filedb"/>
+ <property name="dbname" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite
new file mode 100644
index 0000000000..05a2d50847
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="filedb">
+
+ <component name="filedb">
+ <implementation.cpp path="." library="libfiledb"/>
+ <property name="dbname">tmp/testdb</property>
+ <property name="format">scheme</property>
+ <service name="filedb">
+ <t:binding.http uri="filedb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp
new file mode 100644
index 0000000000..473dfea281
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * File based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "filedb.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, filedb::FileDB& db) {
+ return filedb::get(car(params), db);
+}
+
+/**
+ * Post an item to the database.
+ */
+const failable<value> post(const list<value>& params, filedb::FileDB& db) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = filedb::post(id, cadr(params), db);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, filedb::FileDB& db) {
+ const failable<bool> val = filedb::put(car(params), cadr(params), db);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, filedb::FileDB& db) {
+ const failable<bool> val = filedb::del(car(params), db);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyfiledb {
+public:
+ applyfiledb(filedb::FileDB& db) : db(db) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), db);
+ if (func == "post")
+ return post(cdr(params), db);
+ if (func == "put")
+ return put(cdr(params), db);
+ if (func == "delete")
+ return del(cdr(params), db);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ filedb::FileDB& db;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Connect to the configured database and table
+ const value dbname = ((lambda<value(list<value>)>)car(params))(list<value>());
+ const value format = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ filedb::FileDB& db = *(new (gc_new<filedb::FileDB>()) filedb::FileDB(dbname, format));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyfiledb(db)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::filedb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp
new file mode 100644
index 0000000000..89ff3b8157
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_filedb_hpp
+#define tuscany_filedb_hpp
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "fstream.hpp"
+#include "element.hpp"
+#include "xml.hpp"
+#include "../../modules/scheme/eval.hpp"
+#include "../../modules/json/json.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+/**
+ * Represents a FileDB connection.
+ */
+class FileDB {
+public:
+ FileDB() : owner(false), jscx(*jscontext("")) {
+ }
+
+ FileDB(const string& name, const string& format) : owner(true), name(name), format(format), jscx(*jscontext(format)) {
+ }
+
+ FileDB(const FileDB& c) : owner(false), name(c.name), format(c.format), jscx(c.jscx) {
+ }
+
+ ~FileDB() {
+ }
+
+private:
+ bool owner;
+ string name;
+ string format;
+ js::JSContext& jscx;
+
+ js::JSContext* jscontext(const string& format) {
+ if (format != "json")
+ return NULL;
+ return new (gc_new<js::JSContext>()) js::JSContext();
+ }
+
+ friend const failable<bool> write(const value& v, ostream& os, const string& format, FileDB& db);
+ friend const failable<value> read(istream& is, const string& format, FileDB& db);
+ friend const failable<bool> post(const value& key, const value& val, FileDB& db);
+ friend const failable<bool> put(const value& key, const value& val, FileDB& db);
+ friend const failable<value> get(const value& key, FileDB& db);
+ friend const failable<bool> del(const value& key, FileDB& db);
+};
+
+/**
+ * Convert a key to a file name.
+ */
+const string filename(const list<value>& path, const string& root) {
+ if (isNil(path))
+ return root;
+ string name = root + "/" + scheme::writeValue(car(path));
+ return filename(cdr(path), name);
+}
+
+const string filename(const value& key, const string& root) {
+ if (!isList(key))
+ return filename(mklist(key), root);
+ return filename((list<value>)key, root);
+}
+
+/**
+ * Make the parent directories of a keyed file.
+ */
+const failable<bool> mkdirs(const list<value>& path, const string& root) {
+ if (isNil(cdr(path)))
+ return true;
+ string dir = root + "/" + scheme::writeValue(car(path));
+ mkdir(c_str(dir), S_IRWXU);
+ return mkdirs(cdr(path), dir);
+}
+
+/**
+ * Write a value to a database file.
+ */
+const failable<bool> write(const value& v, ostream& os, const string& format, FileDB& db) {
+ if (format == "scheme") {
+ const string vs(scheme::writeValue(v));
+ os << vs;
+ return true;
+ }
+ if (format == "xml") {
+ failable<list<string> > s = writeXML(valuesToElements(v));
+ if (!hasContent(s))
+ return mkfailure<bool>(reason(s));
+ write(content(s), os);
+ return true;
+ }
+ if (format == "json") {
+ failable<list<string> > s = json::writeJSON(valuesToElements(v), db.jscx);
+ if (!hasContent(s))
+ return mkfailure<bool>(reason(s));
+ write(content(s), os);
+ return true;
+ }
+ return mkfailure<bool>(string("Unsupported database format: ") + format);
+}
+
+/**
+ * Read a value from a database file.
+ */
+const failable<value> read(istream& is, const string& format, FileDB& db) {
+ if (format == "scheme") {
+ return scheme::readValue(is);
+ }
+ if (format == "xml") {
+ const value v = elementsToValues(readXML(streamList(is)));
+ return v;
+ }
+ if (format == "json") {
+ const failable<list<value> > fv = json::readJSON(streamList(is), db.jscx);
+ if (!hasContent(fv))
+ return mkfailure<value>(reason(fv));
+ const value v = elementsToValues(content(fv));
+ return v;
+ }
+ return mkfailure<value>(string("Unsupported database format: ") + format);
+}
+
+/**
+ * Post a new item to the database.
+ */
+const failable<bool> post(const value& key, const value& val, FileDB& db) {
+ debug(key, "filedb::post::key");
+ debug(val, "filedb::post::value");
+ debug(db.name, "filedb::post::dbname");
+
+ if (isList(key))
+ mkdirs(key, db.name);
+ ofstream os(filename(key, db.name));
+ if (os.fail())
+ return mkfailure<bool>("Couldn't post file database entry.");
+ const failable<bool> r = write(val, os, db.format, db);
+
+ debug(r, "filedb::post::result");
+ return r;
+}
+
+/**
+ * Update an item in the database. If the item doesn't exist it is added.
+ */
+const failable<bool> put(const value& key, const value& val, FileDB& db) {
+ debug(key, "filedb::put::key");
+ debug(val, "filedb::put::value");
+ debug(db.name, "filedb::put::dbname");
+
+ if (isList(key))
+ mkdirs(key, db.name);
+ ofstream os(filename(key, db.name));
+ if (os.fail())
+ return mkfailure<bool>("Couldn't put file database entry.");
+ const failable<bool> r = write(val, os, db.format, db);
+
+ debug(r, "filedb::put::result");
+ return r;
+}
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const value& key, FileDB& db) {
+ debug(key, "filedb::get::key");
+ debug(db.name, "filedb::get::dbname");
+
+ ifstream is(filename(key, db.name));
+ if (is.fail())
+ return mkfailure<value>("Couldn't get file database entry.");
+ const failable<value> val = read(is, db.format, db);
+
+ debug(val, "filedb::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the database
+ */
+const failable<bool> del(const value& key, FileDB& db) {
+ debug(key, "filedb::delete::key");
+ debug(db.name, "filedb::delete::dbname");
+
+ const int rc = unlink(c_str(filename(key, db.name)));
+ if (rc == -1)
+ return mkfailure<bool>("Couldn't delete file database entry.");
+
+ debug(true, "filedb::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_filedb_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/server-test b/sandbox/sebastien/cpp/apr-2/components/filedb/server-test
new file mode 100755
index 0000000000..ace8dd59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/server-test
@@ -0,0 +1,40 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite filedb.composite
+EOF
+
+mkdir -p tmp/testdb
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/log/Makefile.am
new file mode 100644
index 0000000000..c53230b23f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/Makefile.am
@@ -0,0 +1,76 @@
+# 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.
+
+if WANT_LOG
+
+INCLUDES = -I${THRIFT_INCLUDE} -I${FB303_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/log
+
+dist_comp_SCRIPTS = scribed-central-conf scribed-client-conf scribed-central-start scribed-central-stop scribed-client-start scribed-client-stop scribe-tail-start scribe-tail-stop
+compdir=$(prefix)/components/log
+
+comp_DATA = scribe.prefix thrift.prefix
+scribe.prefix: $(top_builddir)/config.status
+ echo ${SCRIBE_PREFIX} >scribe.prefix
+
+thrift.prefix: $(top_builddir)/config.status
+ echo ${THRIFT_PREFIX} >thrift.prefix
+
+EXTRA_DIST = log.composite log.componentType logger.componentType *.scm *.thrift
+
+BUILT_SOURCES=gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h: scribe.thrift
+ ${THRIFT_PREFIX}/bin/thrift -r --gen cpp scribe.thrift
+
+CLEANFILES = gen-cpp/*
+
+comp_LTLIBRARIES = liblog.la liblogger.la
+noinst_DATA = liblog.so liblogger.so
+
+CXXFLAGS = ${DEFAULT_CXXFLAGS} -Wno-unused-parameter -Wno-conversion
+
+nodist_liblog_la_SOURCES = gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+liblog_la_CXXFLAGS = -Wno-unused-parameter -Wno-conversion
+liblog_la_SOURCES = log.cpp
+liblog_la_LDFLAGS = -L${THRIFT_LIB} -R${THRIFT_LIB} -lthrift -L${FB303_LIB} -R${FB303_LIB} -lfb303 -L${SCRIBE_LIB} -R${SCRIBE_LIB} -lscribe
+liblog.so:
+ ln -s .libs/liblog.so
+
+nodist_liblogger_la_SOURCES = gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+liblogger_la_CXXFLAGS = -Wno-unused-parameter -Wno-conversion
+liblogger_la_SOURCES = logger.cpp
+liblogger_la_LDFLAGS = -L${THRIFT_LIB} -R${THRIFT_LIB} -lthrift -L${FB303_LIB} -R${FB303_LIB} -lfb303 -L${SCRIBE_LIB} -R${SCRIBE_LIB} -lscribe
+liblogger.so:
+ ln -s .libs/liblogger.so
+
+comp_PROGRAMS = scribe-cat
+
+nodist_scribe_cat_SOURCES = gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+scribe_cat_CXXFLAGS = -Wno-unused-parameter -Wno-conversion
+scribe_cat_SOURCES = scribe-cat.cpp
+scribe_cat_LDFLAGS = -L${THRIFT_LIB} -R${THRIFT_LIB} -lthrift -L${FB303_LIB} -R${FB303_LIB} -lfb303 -L${SCRIBE_LIB} -R${SCRIBE_LIB} -lscribe
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = scribe-test server-test
+noinst_PROGRAMS = client-test
+TESTS = scribe-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm b/sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm
new file mode 100644
index 0000000000..ccd5bc555f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Logger test case
+
+(define (add a b) (+ a b))
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp
new file mode 100644
index 0000000000..5f13f64ac1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test log component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace log {
+
+const string uri("http://localhost:8090/log");
+
+bool testLog() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ return true;
+}
+
+struct logLoop {
+ const value a;
+ const string uri;
+ http::CURLSession cs;
+ logLoop(const value& a, const string& uri, http::CURLSession cs) : a(a), uri(uri), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ return true;
+ }
+};
+
+bool testLogPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const lambda<bool()> ll = logLoop(a, uri, cs);
+ cout << "Log test " << time(ll, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+bool testLogger() {
+ http::CURLSession cs("", "", "");
+
+ const failable<value> res = http::evalExpr(mklist<value>(string("sum"), 33, 22), string("http://localhost:8090/client"), cs);
+ assert(hasContent(res));
+ assert((int)content(res) == 55);
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::log::testLog();
+ tuscany::log::testLogPerf();
+ tuscany::log::testLogger();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/client-test.scm b/sandbox/sebastien/cpp/apr-2/components/log/client-test.scm
new file mode 100644
index 0000000000..1da6ca3564
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/client-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Logger test case
+
+(define (sum a b adder) (adder "add" a b))
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift b/sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift
new file mode 100644
index 0000000000..66c8315274
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/**
+ * fb303.thrift
+ */
+
+namespace java com.facebook.fb303
+namespace cpp facebook.fb303
+namespace perl Facebook.FB303
+
+/**
+ * Common status reporting mechanism across all services
+ */
+enum fb_status {
+ DEAD = 0,
+ STARTING = 1,
+ ALIVE = 2,
+ STOPPING = 3,
+ STOPPED = 4,
+ WARNING = 5,
+}
+
+/**
+ * Standard base service
+ */
+service FacebookService {
+
+ /**
+ * Returns a descriptive name of the service
+ */
+ string getName(),
+
+ /**
+ * Returns the version of the service
+ */
+ string getVersion(),
+
+ /**
+ * Gets the status of this service
+ */
+ fb_status getStatus(),
+
+ /**
+ * User friendly description of status, such as why the service is in
+ * the dead or warning state, or what is being started or stopped.
+ */
+ string getStatusDetails(),
+
+ /**
+ * Gets the counters for this service
+ */
+ map<string, i64> getCounters(),
+
+ /**
+ * Gets the value of a single counter
+ */
+ i64 getCounter(1: string key),
+
+ /**
+ * Sets an option
+ */
+ void setOption(1: string key, 2: string value),
+
+ /**
+ * Gets an option
+ */
+ string getOption(1: string key),
+
+ /**
+ * Gets all options
+ */
+ map<string, string> getOptions(),
+
+ /**
+ * Returns a CPU profile over the given time interval (client and server
+ * must agree on the profile format).
+ */
+ string getCpuProfile(1: i32 profileDurationInSec),
+
+ /**
+ * Returns the unix time that the server has been running since
+ */
+ i64 aliveSince(),
+
+ /**
+ * Tell the server to reload its configuration, reopen log files, etc
+ */
+ oneway void reinitialize(),
+
+ /**
+ * Suggest a shutdown to the server
+ */
+ oneway void shutdown(),
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/log.componentType b/sandbox/sebastien/cpp/apr-2/components/log/log.componentType
new file mode 100644
index 0000000000..e661f568f1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/log.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="log"/>
+ <property name="category" type="xsd:string">default</property>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/log.composite b/sandbox/sebastien/cpp/apr-2/components/log/log.composite
new file mode 100644
index 0000000000..3e13c410fa
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/log.composite
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="log">
+
+ <component name="log">
+ <implementation.cpp path="." library="liblog"/>
+ <property name="category">default</property>
+ <service name="log">
+ <t:binding.http uri="log"/>
+ </service>
+ </component>
+
+ <component name="client">
+ <implementation.scheme script="client-test.scm"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="adder" target="logger"/>
+ </component>
+
+ <component name="logger">
+ <implementation.cpp path="." library="liblogger"/>
+ <property name="category">default</property>
+ <service name="logger">
+ <t:binding.http uri="logger"/>
+ </service>
+ <reference name="relay" target="adder"/>
+ </component>
+
+ <component name="adder">
+ <implementation.scheme script="adder-test.scm"/>
+ <service name="adder">
+ <t:binding.http uri="adder"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/log.cpp b/sandbox/sebastien/cpp/apr-2/components/log/log.cpp
new file mode 100644
index 0000000000..24a5844c45
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/log.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Scribe-based log component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "scribe.hpp"
+
+namespace tuscany {
+namespace log {
+
+/**
+ * Post an item to the Scribe log.
+ */
+const failable<value> post(const list<value>& params, const value& category, scribe::Scribe& sc) {
+ debug(cadr(params), "log::post::value");
+ const failable<bool> val = scribe::log(cadr(params), category, sc);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(mklist<value>(true));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyLog {
+public:
+ applyLog(const value& category, scribe::Scribe& sc) : category(category), sc(sc) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "post")
+ return post(cdr(params), category, sc);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ const value category;
+ scribe::Scribe& sc;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to Scribe
+ scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe("localhost", 1464));
+
+ // Extract the configured category
+ const value category = ((lambda<value(list<value>)>)car(params))(list<value>());
+ debug(category, "log::start::category");
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyLog(category, sc)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::log::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/logger.componentType b/sandbox/sebastien/cpp/apr-2/components/log/logger.componentType
new file mode 100644
index 0000000000..1c9546e685
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/logger.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="logger"/>
+ <reference name="relay"/>
+ <property name="category" type="xsd:string">default</property>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/logger.cpp b/sandbox/sebastien/cpp/apr-2/components/log/logger.cpp
new file mode 100644
index 0000000000..e1f4712d61
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/logger.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Scribe-based logger component implementation, used to intercept
+ * and log service invocations.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "scribe.hpp"
+
+namespace tuscany {
+namespace logger {
+
+/**
+ * Component implementation lambda function.
+ */
+class applyLog {
+public:
+ applyLog(const lambda<value(const list<value>&)>& relay, const value& category, scribe::Scribe& sc) : relay(relay), category(category), sc(sc) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ // Log the function params
+ debug(params, "logger::apply::params");
+ scribe::log(params, category, sc);
+
+ // Relay the function
+ const failable<value> res = relay(params);
+
+ // Log the result
+ scribe::log(res, category, sc);
+ return res;
+ }
+
+private:
+ const lambda<value(const list<value>&)> relay;
+ const value category;
+ scribe::Scribe& sc;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to Scribe
+ scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe("localhost", 1464));
+
+ // Extract the configured relay service and category
+ const value rel = car(params);
+ const value category = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ debug(category, "logger::start::category");
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyLog(rel, category, sc)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::logger::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp b/sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp
new file mode 100644
index 0000000000..f3c5e898cd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * A utility that logs stdin into a scribe log.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+#undef debug
+#define debug(...)
+#include "scribe.hpp"
+
+namespace tuscany {
+namespace scribecat {
+
+int cat(const string& category, const string& type) {
+ // Connect to Scribe
+ scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe("localhost", 1464));
+
+ // Read lines from stdin and log them
+ char buf[8192];
+ for (;;) {
+ const char* s = fgets(buf, 8192, stdin);
+ if (s == NULL)
+ return 0;
+ const int l = strlen(s);
+ if (l < 2)
+ return 0;
+ buf[l - 1] = '\0';
+
+ // Log each line as is
+ if (length(type) == 0) {
+ const failable<bool> val = scribe::log(buf, category, sc);
+ if (!hasContent(val))
+ return 1;
+ continue;
+ }
+
+ // Log each line prefixed with time and a type tag
+ ostringstream os;
+ os << "[" << logTime() << "] [" << type << "] " << buf;
+ const failable<bool> val = scribe::log(c_str(str(os)), category, sc);
+ if (!hasContent(val))
+ return 1;
+ }
+}
+
+}
+}
+
+int main(const int argc, const char** argv) {
+ return tuscany::scribecat::cat(argc < 2? "default" : argv[1], argc < 3? "" : argv[2]);
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start
new file mode 100755
index 0000000000..0044f1620d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start
@@ -0,0 +1,44 @@
+#!/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
+# 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.
+
+# Tail a file and pipe into scribe-cat
+here=`readlink -f $0`; here=`dirname $here`
+
+category=""
+type=""
+file=""
+if [ "$3" != "" ]; then
+ category=$1
+ type=$2
+ file=$3
+else
+ if [ "$2" != "" ]; then
+ category=$1
+ file=$2
+ else
+ file=$1
+ fi
+fi
+
+mkdir -p `dirname $file`
+touch $file
+file=`readlink -f $file`
+
+tail -f -n 0 $file | $here/scribe-cat $category $type &
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop
new file mode 100755
index 0000000000..e1b74fc0c6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop
@@ -0,0 +1,42 @@
+#!/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
+# 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.
+
+# Stop tailing a file
+here=`readlink -f $0`; here=`dirname $here`
+
+category=""
+type=""
+file=""
+if [ "$3" != "" ]; then
+ category=$1
+ type=$2
+ file=$3
+else
+ if [ "$2" != "" ]; then
+ category=$1
+ file=$2
+ else
+ file=$1
+ fi
+fi
+file=`readlink -f $file`
+
+cmd="tail -f -n 0 $file"
+kill `ps -ef | grep -v grep | grep "${cmd}" | awk '{ print $2 }'`
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-test b/sandbox/sebastien/cpp/apr-2/components/log/scribe-test
new file mode 100755
index 0000000000..a355026dd0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-test
@@ -0,0 +1,43 @@
+#!/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
+# 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.
+
+echo "Testing..."
+
+# Setup
+rm -rf tmp
+./scribed-central-conf tmp
+./scribed-client-conf tmp localhost
+./scribed-central-start tmp
+./scribed-client-start tmp
+sleep 1
+
+# Test logging a message
+echo test | ./scribe-cat >/dev/null
+sleep 4
+grep test tmp/scribe/logs/central/default/default_current >/dev/null
+rc=$?
+
+# Cleanup
+./scribed-client-stop tmp
+./scribed-central-stop tmp
+sleep 1
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp b/sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp
new file mode 100644
index 0000000000..5237bd0183
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scribe_hpp
+#define tuscany_scribe_hpp
+
+/**
+ * Scribe logging functions.
+ */
+
+// Work around redundant defines in Scribe headers
+#undef PACKAGE
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef VERSION
+
+// Ignore integer conversion issues in Thrift and Scribe headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#endif
+
+#include <protocol/TBinaryProtocol.h>
+#include <transport/TSocket.h>
+#include <transport/TTransportUtils.h>
+
+#include "gen-cpp/scribe.h"
+
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wconversion"
+#endif
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace scribe {
+
+/**
+ * Represents a Scribe connection.
+ */
+class Scribe {
+public:
+ Scribe() : owner(false) {
+ }
+
+ Scribe(const string host, const int port) : owner(true) {
+ init(host, port);
+ }
+
+ Scribe(const Scribe& c) : owner(false) {
+ client = c.client;
+ transport = c.transport;
+ }
+
+ ~Scribe() {
+ if (!owner)
+ return;
+ try {
+ transport->close();
+ delete client;
+ } catch (const std::exception& e) {
+ mkfailure<bool>(e.what());
+ }
+ }
+
+private:
+ bool owner;
+ ::scribe::thrift::scribeClient* client;
+ boost::shared_ptr<apache::thrift::transport::TTransport> transport;
+
+ friend const failable<bool> log(const value& val, const value& category, const Scribe& sc);
+
+ /**
+ * Initialize the Scribe connection.
+ */
+ const failable<bool> init(const string& host, const int port) {
+ try {
+ boost::shared_ptr<apache::thrift::transport::TTransport> sock(new apache::thrift::transport::TSocket(c_str(host), port));
+ boost::shared_ptr<apache::thrift::transport::TFramedTransport> framedSock(new apache::thrift::transport::TFramedTransport(sock));
+ transport = framedSock;
+ boost::shared_ptr<apache::thrift::protocol::TProtocol> proto(new apache::thrift::protocol::TBinaryProtocol(transport));
+ client = new ::scribe::thrift::scribeClient(proto);
+ transport->open();
+ return true;
+ } catch (const std::exception& e) {
+ return mkfailure<bool>(e.what());
+ }
+ }
+};
+
+/**
+ * Log an item.
+ */
+const failable<bool> log(const value& val, const value& category, const Scribe& sc) {
+ debug(val, "scribe::log::value");
+ debug(category, "scribe::log::category");
+
+ const value cat = isString(category)? value(c_str(category)):category;
+ const string cs(scheme::writeValue(cat));
+ const string vs(scheme::writeValue(val));
+
+ try {
+ ::scribe::thrift::LogEntry entry;
+ entry.category = c_str(cs);
+ entry.message = c_str(vs);
+ std::vector< ::scribe::thrift::LogEntry> msgs;
+ msgs.push_back(entry);
+
+ int result = sc.client->Log(msgs);
+ if (result != ::scribe::thrift::OK)
+ return mkfailure<bool>("Could not log value, retry later");
+ } catch (const std::exception& e) {
+ return mkfailure<bool>(e.what());
+ }
+
+ debug(true, "scribe::log::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_scribe_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift b/sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift
new file mode 100644
index 0000000000..592e8b630e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift
@@ -0,0 +1,39 @@
+#!/usr/local/bin/thrift --cpp --php
+
+## Copyright (c) 2007-2008 Facebook
+##
+## Licensed 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.
+##
+## See accompanying file LICENSE or visit the Scribe site at:
+## http://developers.facebook.com/scribe/
+
+include "fb303.thrift"
+
+namespace cpp scribe.thrift
+
+enum ResultCode
+{
+ OK,
+ TRY_LATER
+}
+
+struct LogEntry
+{
+ 1: string category,
+ 2: string message
+}
+
+service scribe extends fb303.FacebookService
+{
+ ResultCode Log(1: list<LogEntry> messages);
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf
new file mode 100755
index 0000000000..b23646c24f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf
@@ -0,0 +1,73 @@
+#!/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
+# 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.
+
+# Generate a Scribe central conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+port=$2
+if [ "$port" = "" ]; then
+ port="1463"
+fi
+
+mkdir -p $root/scribe/conf
+mkdir -p $root/scribe/logs/central
+mkdir -p $root/scribe/logs/central-secondary
+
+cat >$root/scribe/conf/scribe-central.conf <<EOF
+# Generated by: scribed-central-conf $*
+# Scribe central configuration
+port=$port
+max_msg_per_second=2000000
+check_interval=3
+
+# Log store configuration
+<store>
+category=default
+type=buffer
+
+target_write_size=20480
+max_write_interval=1
+buffer_send_rate=2
+retry_interval=30
+retry_interval_range=10
+
+<primary>
+type=file
+fs_type=std
+file_path=$root/scribe/logs/central
+base_filename=central
+max_size=1000000
+add_newlines=1
+rotate_period=daily
+rotate_hour=0
+rotate_minute=10
+</primary>
+
+<secondary>
+type=file
+fs_type=std
+file_path=$root/scribe/logs/central-secondary
+base_filename=central
+max_size=3000000
+</secondary>
+
+</store>
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-start b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-start
new file mode 100755
index 0000000000..c2035037de
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-start
@@ -0,0 +1,27 @@
+#!/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
+# 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.
+
+# Start central scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${thrift_prefix}/lib:${thrift_prefix}/contrib/fb303/lib:${scribe_prefix}/lib
+$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-central.conf 1>$root/scribe/logs/central.log 2>&1 &
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop
new file mode 100755
index 0000000000..95a976813f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop
@@ -0,0 +1,28 @@
+#!/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
+# 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.
+
+# Stop central scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+scribed="$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-central.conf"
+
+kill `ps -ef | grep -v grep | grep "${scribed}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf
new file mode 100755
index 0000000000..87c8749c2e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf
@@ -0,0 +1,67 @@
+#!/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
+# 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.
+
+# Generate a Scribe client conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+central=$2
+cport=$3
+if [ "$cport" = "" ]; then
+ cport="1463"
+fi
+
+mkdir -p $root/scribe/conf
+mkdir -p $root/scribe/logs/client-secondary
+
+cat >$root/scribe/conf/scribe-client.conf <<EOF
+# Generated by: scribed-client-conf $*
+# Scribe client configuration
+port=1464
+max_msg_per_second=2000000
+check_interval=3
+
+# Forward all messages to central Scribe on port 1463
+# Save them locally as well
+<store>
+category=default
+type=buffer
+
+target_write_size=20480
+max_write_interval=1
+buffer_send_rate=1
+retry_interval=30
+retry_interval_range=10
+
+<primary>
+type=network
+remote_host=$central
+remote_port=$cport
+</primary>
+
+<secondary>
+type=file
+fs_type=std
+file_path=$root/scribe/logs/client-secondary
+base_filename=client
+max_size=3000000
+</secondary>
+</store>
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-start b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-start
new file mode 100755
index 0000000000..ed8636d7f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-start
@@ -0,0 +1,27 @@
+#!/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
+# 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.
+
+# Start client scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${thrift_prefix}/lib:${thrift_prefix}/contrib/fb303/lib:${scribe_prefix}/lib
+$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-client.conf 1>$root/scribe/logs/client.log 2>&1 &
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop
new file mode 100755
index 0000000000..2e8959fbfc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop
@@ -0,0 +1,28 @@
+#!/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
+# 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.
+
+# Stop client scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+scribed="$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-client.conf"
+
+kill `ps -ef | grep -v grep | grep "${scribed}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/server-test b/sandbox/sebastien/cpp/apr-2/components/log/server-test
new file mode 100755
index 0000000000..631487c77a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/server-test
@@ -0,0 +1,65 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite log.composite
+EOF
+
+rm -rf tmp/scribe
+./scribed-central-conf tmp
+./scribed-client-conf tmp localhost
+./scribed-central-start tmp
+./scribed-client-start tmp
+sleep 1
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+if [ "$rc" = "0" ]; then
+ echo "Testing..."
+ sleep 4
+ grep "Apple" tmp/scribe/logs/central/default/default_current >/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ grep "(add 33 22)" tmp/scribe/logs/central/default/default_current >/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ grep "55" tmp/scribe/logs/central/default/default_current >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 1
+./scribed-client-stop tmp
+./scribed-central-stop tmp
+sleep 1
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am
new file mode 100644
index 0000000000..6cf829fa7a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am
@@ -0,0 +1,49 @@
+# 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.
+
+INCLUDES = -I${TINYCDB_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/nosqldb
+
+dist_comp_SCRIPTS = tinycdb
+compdir=$(prefix)/components/nosqldb
+
+comp_DATA = tinycdb.prefix
+tinycdb.prefix: $(top_builddir)/config.status
+ echo ${TINYCDB_PREFIX} >tinycdb.prefix
+
+EXTRA_DIST = nosqldb.composite nosqldb.componentType
+
+comp_LTLIBRARIES = libnosqldb.la
+noinst_DATA = libnosqldb.so
+
+libnosqldb_la_SOURCES = nosqldb.cpp
+libnosqldb_la_LDFLAGS = -L${TINYCDB_LIB} -R${TINYCDB_LIB} -lcdb
+libnosqldb.so:
+ ln -s .libs/libnosqldb.so
+
+tinycdb_test_SOURCES = tinycdb-test.cpp
+tinycdb_test_LDFLAGS = -L${TINYCDB_LIB} -R${TINYCDB_LIB} -lcdb
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = nosqldb-test server-test
+noinst_PROGRAMS = tinycdb-test client-test
+TESTS = nosqldb-test server-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp
new file mode 100644
index 0000000000..8eed7ce8cd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test NoSQL database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace nosqldb {
+
+const string uri("http://localhost:8090/nosqldb");
+
+bool testNoSqlDb() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(uri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "NoSqldb get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::nosqldb::testNoSqlDb();
+ tuscany::nosqldb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test
new file mode 100755
index 0000000000..30c9f89bc9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test
@@ -0,0 +1,29 @@
+#!/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
+# 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.
+
+# Setup
+mkdir -p tmp
+./tinycdb -c -m tmp/test.cdb </dev/null
+
+# Test
+./tinycdb-test 2>/dev/null
+rc=$?
+
+# Cleanup
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType
new file mode 100644
index 0000000000..bb79882b5d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="nosqldb"/>
+ <property name="dbname" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite
new file mode 100644
index 0000000000..af2d3a18d7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="nosqldb">
+
+ <component name="nosqldb">
+ <implementation.cpp path="." library="libnosqldb"/>
+ <property name="dbname">tmp/test.cdb</property>
+ <service name="nosqldb">
+ <t:binding.http uri="nosqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp
new file mode 100644
index 0000000000..cda3ca44a9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * TinyCDB-based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "tinycdb.hpp"
+
+namespace tuscany {
+namespace nosqldb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ return tinycdb::get(car(params), cdb);
+}
+
+/**
+ * Post an item to the database.
+ */
+const failable<value> post(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = tinycdb::post(id, cadr(params), cdb);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ const failable<bool> val = tinycdb::put(car(params), cadr(params), cdb);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ const failable<bool> val = tinycdb::del(car(params), cdb);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyNoSqldb {
+public:
+ applyNoSqldb(tinycdb::TinyCDB& cdb) : cdb(cdb) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), cdb);
+ if (func == "post")
+ return post(cdr(params), cdb);
+ if (func == "put")
+ return put(cdr(params), cdb);
+ if (func == "delete")
+ return del(cdr(params), cdb);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ tinycdb::TinyCDB& cdb;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to the configured database and table
+ const value dbname = ((lambda<value(list<value>)>)car(params))(list<value>());
+ tinycdb::TinyCDB& cdb = *(new (gc_new<tinycdb::TinyCDB>()) tinycdb::TinyCDB(dbname));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyNoSqldb(cdb)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::nosqldb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/server-test b/sandbox/sebastien/cpp/apr-2/components/nosqldb/server-test
new file mode 100755
index 0000000000..5a5d792a32
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/server-test
@@ -0,0 +1,40 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite nosqldb.composite
+EOF
+
+./tinycdb -c -m tmp/test.cdb </dev/null
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb
new file mode 100755
index 0000000000..68459d7622
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+tinycdb_prefix=`cat $here/tinycdb.prefix`
+
+$tinycdb_prefix/bin/cdb $*
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp
new file mode 100644
index 0000000000..b3b4ea7fd7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test TinyCDB access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "tinycdb.hpp"
+
+namespace tuscany {
+namespace tinycdb {
+
+bool testTinyCDB() {
+ TinyCDB cdb("tmp/test.cdb");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), cdb)));
+ assert((get(k, cdb)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), cdb)));
+ assert((get(k, cdb)) == value(string("aaa")));
+ assert(hasContent(del(k, cdb)));
+ assert(!hasContent(get(k, cdb)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ TinyCDB& cdb;
+ getLoop(const value& k, TinyCDB& cdb) : k(k), cdb(cdb) {
+ }
+ const bool operator()() const {
+ assert((get(k, cdb)) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ TinyCDB cdb("tmp/test.cdb");
+ assert(hasContent(post(k, string("CCC"), cdb)));
+
+ const lambda<bool()> gl = getLoop(k, cdb);
+ cout << "TinyCDB get test " << time(gl, 5, 100000) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::tinycdb::testTinyCDB();
+ tuscany::tinycdb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp
new file mode 100644
index 0000000000..0fab1a9854
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp
@@ -0,0 +1,460 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_tinycdb_hpp
+#define tuscany_tinycdb_hpp
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <cdb.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace tinycdb {
+
+/**
+ * A reallocatable buffer.
+ */
+class buffer {
+public:
+ operator void*() const throw() {
+ return buf;
+ }
+
+ operator unsigned char*() const throw() {
+ return (unsigned char*)buf;
+ }
+
+ operator char*() const throw() {
+ return (char*)buf;
+ }
+
+private:
+ buffer(const unsigned int size, void* buf) : size(size), buf(buf) {
+ }
+
+ unsigned int size;
+ void* buf;
+
+ friend const buffer mkbuffer(const unsigned int sz);
+ friend const buffer mkbuffer(const buffer& b, const unsigned int newsz);
+ friend const bool free(const buffer& b);
+};
+
+/**
+ * Make a new buffer.
+ */
+const buffer mkbuffer(const unsigned int sz) {
+ return buffer(sz, malloc(sz));
+}
+
+/**
+ * Make a new buffer by reallocating an existing one.
+ */
+const buffer mkbuffer(const buffer& b, const unsigned int sz) {
+ if (sz <= b.size)
+ return b;
+ return buffer(sz, realloc(b.buf, sz));
+}
+
+/**
+ * Free a buffer.
+ */
+const bool free(const buffer&b) {
+ ::free(b.buf);
+ return true;
+}
+
+/**
+ * Represents a TinyCDB connection.
+ */
+class TinyCDB {
+public:
+ TinyCDB() : owner(false), fd(-1) {
+ st.st_ino = 0;
+ }
+
+ TinyCDB(const string& name) : owner(true), name(name), fd(-1) {
+ st.st_ino = 0;
+ }
+
+ TinyCDB(const TinyCDB& c) : owner(false), name(c.name), fd(c.fd) {
+ st.st_ino = c.st.st_ino;
+ }
+
+ ~TinyCDB() {
+ if (!owner)
+ return;
+ if (fd == -1)
+ return;
+ close(fd);
+ }
+
+private:
+ bool owner;
+ string name;
+ int fd;
+ struct stat st;
+
+ friend const string dbname(const TinyCDB& cdb);
+ friend const failable<int> cdbopen(TinyCDB& cdb);
+ friend const failable<bool> cdbclose(TinyCDB& cdb);
+};
+
+/**
+ * Return the name of the database.
+ */
+const string dbname(const TinyCDB& cdb) {
+ return cdb.name;
+}
+
+/**
+ * Open a database.
+ */
+const failable<int> cdbopen(TinyCDB& cdb) {
+
+ // Get database file serial number
+ struct stat st;
+ const int s = stat(c_str(cdb.name), &st);
+ if (s == -1)
+ return mkfailure<int>(string("Couldn't tinycdb read database stat ") + cdb.name);
+
+ // Open database for the first time
+ if (cdb.fd == -1) {
+ cdb.fd = open(c_str(cdb.name), O_RDONLY);
+ if (cdb.fd == -1)
+ return mkfailure<int>(string("Couldn't open tinycdb database file ") + cdb.name);
+ debug(cdb.fd, "tinycdb::open::fd");
+ cdb.st = st;
+ return cdb.fd;
+ }
+
+ // Close and reopen database after a change
+ if (st.st_ino != cdb.st.st_ino) {
+
+ // Close current fd
+ close(cdb.fd);
+
+ // Reopen database
+ const int newfd = open(c_str(cdb.name), O_RDONLY);
+ if (newfd == -1)
+ return mkfailure<int>(string("Couldn't open tinycdb database file ") + cdb.name);
+ if (newfd == cdb.fd) {
+ debug(cdb.fd, "tinycdb::open::fd");
+ cdb.st = st;
+ return cdb.fd;
+ }
+
+ // We got a different fd, dup it to the current fd then close it
+ if (fcntl(newfd, F_DUPFD, cdb.fd) == -1)
+ return mkfailure<int>(string("Couldn't dup tinycdb database file handle ") + cdb.name);
+ close(newfd);
+
+ debug(cdb.fd, "tinycdb::open::fd");
+ cdb.st = st;
+ return cdb.fd;
+ }
+
+ // No change, just return the current fd
+ return cdb.fd;
+}
+
+/**
+ * Close a database.
+ */
+const failable<bool> cdbclose(TinyCDB& cdb) {
+ close(cdb.fd);
+ cdb.fd = -1;
+ return true;
+}
+
+/**
+ * Rewrite a database. The given update function is passed each entry, and
+ * can return true to let the entry added to the new db, false to skip the
+ * entry, or a failure.
+ */
+const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)>& update, const lambda<failable<bool>(struct cdb_make&)>& finish, buffer& buf, const int tmpfd, TinyCDB& cdb) {
+
+ // Initialize new db structure
+ struct cdb_make cdbm;
+ cdb_make_start(&cdbm, tmpfd);
+
+ // Open existing db
+ failable<int> ffd = cdbopen(cdb);
+ if (!hasContent(ffd))
+ return mkfailure<bool>(reason(ffd));
+ const int fd = content(ffd);
+
+ // Read the db header
+ unsigned int pos = 0;
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ return mkfailure<bool>("Could not seek to tinycdb database start");
+ if (::read(fd, buf, 2048) != 2048)
+ return mkfailure<bool>("Could not read tinycdb database header");
+ pos += 2048;
+ unsigned int eod = cdb_unpack(buf);
+ debug(pos, "tinycdb::rewrite::eod");
+
+ // Read and add the existing entries
+ while(pos < eod) {
+ if (eod - pos < 8)
+ return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry header");
+ if (::read(fd, buf, 8) != 8)
+ return mkfailure<bool>("Couldn't read tinycdb entry header");
+ pos += 8;
+ unsigned int klen = cdb_unpack(buf);
+ unsigned int vlen = cdb_unpack(((unsigned char*)buf) + 4);
+ unsigned int elen = klen + vlen;
+
+ // Read existing entry
+ buf = mkbuffer(buf, elen);
+ if (eod - pos < elen)
+ return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry");
+ if ((unsigned int)::read(fd, buf, elen) != elen)
+ return mkfailure<bool>("Couldn't read tinycdb entry");
+ pos += elen;
+
+ // Apply the update function to the entry
+ debug(string((char*)buf, klen), "tinycdb::rewrite::existing key");
+ debug(string(((char*)buf) + klen, vlen), "tinycdb::rewrite::existing value");
+ const failable<bool> u = update(buf, klen, vlen);
+ if (!hasContent(u))
+ return u;
+
+ // Skip the entry if the update function returned false
+ if (u == false)
+ continue;
+
+ // Add the entry to the new db
+ if (cdb_make_add(&cdbm, buf, klen, ((unsigned char*)buf)+klen, vlen) == -1)
+ return mkfailure<bool>("Could not add tinycdb entry");
+ }
+ if (pos != eod)
+ return mkfailure<bool>("Invalid tinycdb database format");
+
+ // Call the finish function
+ const failable<bool> f = finish(cdbm);
+ if (!hasContent(f))
+ return f;
+
+ // Save the new db
+ if (cdb_make_finish(&cdbm) == -1)
+ return mkfailure<bool>("Could not save tinycdb database");
+
+ return true;
+}
+
+const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)>& update, const lambda<failable<bool>(struct cdb_make&)>& finish, TinyCDB& cdb) {
+
+ // Create a new temporary db file
+ string tmpname = dbname(cdb) + ".XXXXXX";
+ int tmpfd = mkstemp(const_cast<char*>(c_str(tmpname)));
+ if (tmpfd == -1)
+ return mkfailure<bool>("Could not create temporary tinycdb database");
+
+ // Rewrite the db, apply the update function to each entry
+ buffer buf = mkbuffer(2048);
+ const failable<bool> r = rewrite(update, finish, buf, tmpfd, cdb);
+ if (!hasContent(r)) {
+ close(tmpfd);
+ free(buf);
+ return r;
+ }
+
+ // Atomically replace the db and reopen it in read mode
+ if (rename(c_str(tmpname), c_str(dbname(cdb))) == -1)
+ return mkfailure<bool>("Could not rename temporary tinycdb database");
+ cdbclose(cdb);
+ failable<int> ffd = cdbopen(cdb);
+ if (!hasContent(ffd))
+ return mkfailure<bool>(reason(ffd));
+
+ return true;
+}
+
+/**
+ * Post a new item to the database.
+ */
+struct postUpdate {
+ const string ks;
+ postUpdate(const string& ks) : ks(ks) {
+ }
+ const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
+ if (ks == string((char*)buf, klen))
+ return mkfailure<bool>("Key already exists in tinycdb database");
+ return true;
+ }
+};
+
+struct postFinish {
+ const string ks;
+ const string vs;
+ postFinish(const string& ks, const string& vs) : ks(ks), vs(vs) {
+ }
+ const failable<bool> operator()(struct cdb_make& cdbm) const {
+ if (cdb_make_add(&cdbm, c_str(ks), (unsigned int)length(ks), c_str(vs), (unsigned int)length(vs)) == -1)
+ return mkfailure<bool>("Could not add tinycdb entry");
+ return true;
+ }
+};
+
+const failable<bool> post(const value& key, const value& val, TinyCDB& cdb) {
+ debug(key, "tinycdb::post::key");
+ debug(val, "tinycdb::post::value");
+ debug(dbname(cdb), "tinycdb::post::dbname");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+
+ // Process each entry and detect existing key
+ const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)> update = postUpdate(ks);
+
+ // Add the new entry to the db
+ const lambda<failable<bool>(struct cdb_make& cdbm)> finish = postFinish(ks, vs);
+
+ // Rewrite the db
+ const failable<bool> r = rewrite(update, finish, cdb);
+ debug(r, "tinycdb::post::result");
+ return r;
+}
+
+/**
+ * Update an item in the database. If the item doesn't exist it is added.
+ */
+struct putUpdate {
+ const string ks;
+ putUpdate(const string& ks) : ks(ks) {
+ }
+ const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
+ if (ks == string((char*)buf, klen))
+ return false;
+ return true;
+ }
+};
+
+struct putFinish {
+ const string ks;
+ const string vs;
+ putFinish(const string& ks, const string& vs) : ks(ks), vs(vs) {
+ }
+ const failable<bool> operator()(struct cdb_make& cdbm) const {
+ if (cdb_make_add(&cdbm, c_str(ks), (unsigned int)length(ks), c_str(vs), (unsigned int)length(vs)) == -1)
+ return mkfailure<bool>("Could not add tinycdb entry");
+ return true;
+ }
+};
+
+const failable<bool> put(const value& key, const value& val, TinyCDB& cdb) {
+ debug(key, "tinycdb::put::key");
+ debug(val, "tinycdb::put::value");
+ debug(dbname(cdb), "tinycdb::put::dbname");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+
+ // Process each entry and skip existing key
+ const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)> update = putUpdate(ks);
+
+ // Add the new entry to the db
+ const lambda<failable<bool>(struct cdb_make& cdbm)> finish = putFinish(ks, vs);
+
+ // Rewrite the db
+ const failable<bool> r = rewrite(update, finish, cdb);
+ debug(r, "tinycdb::put::result");
+ return r;
+}
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const value& key, TinyCDB& cdb) {
+ debug(key, "tinycdb::get::key");
+ debug(dbname(cdb), "tinycdb::get::dbname");
+
+ const failable<int> ffd = cdbopen(cdb);
+ if (!hasContent(ffd))
+ return mkfailure<value>(reason(ffd));
+ const int fd = content(ffd);
+
+ const string ks(scheme::writeValue(key));
+
+ cdbi_t vlen;
+ if (cdb_seek(fd, c_str(ks), (unsigned int)length(ks), &vlen) <= 0)
+ return mkfailure<value>("Could not get tinycdb entry");
+ char* data = gc_cnew(vlen + 1);
+ cdb_bread(fd, data, vlen);
+ data[vlen] = '\0';
+ const value val(scheme::readValue(string(data)));
+
+ debug(val, "tinycdb::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the database
+ */
+struct delUpdate {
+ const string ks;
+ delUpdate(const string& ks) : ks(ks) {
+ }
+ const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
+ if (ks == string((char*)buf, klen))
+ return false;
+ return true;
+ }
+};
+
+struct delFinish {
+ delFinish() {
+ }
+ const failable<bool> operator()(unused struct cdb_make& cdbm) const {
+ return true;
+ }
+};
+
+const failable<bool> del(const value& key, TinyCDB& cdb) {
+ debug(key, "tinycdb::delete::key");
+ debug(dbname(cdb), "tinycdb::delete::dbname");
+
+ const string ks(scheme::writeValue(key));
+
+ // Process each entry and skip existing key
+ const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)> update = delUpdate(ks);
+
+ // Nothing to do to finish
+ const lambda<failable<bool>(struct cdb_make& cdbm)> finish = delFinish();
+
+ // Rewrite the db
+ const failable<bool> r = rewrite(update, finish, cdb);
+ debug(r, "tinycdb::delete::result");
+ return r;
+}
+
+}
+}
+
+#endif /* tuscany_tinycdb_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am
new file mode 100644
index 0000000000..f527488a3b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am
@@ -0,0 +1,57 @@
+# 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.
+
+if WANT_QUEUE
+
+INCLUDES = -I${QPIDC_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/queue
+
+dist_comp_SCRIPTS = qpidd-start qpidd-stop
+compdir=$(prefix)/components/queue
+
+comp_DATA = qpidc.prefix
+qpidc.prefix: $(top_builddir)/config.status
+ echo ${QPIDC_PREFIX} >qpidc.prefix
+
+EXTRA_DIST = queue.composite queue-sender.componentType queue-listener.componentType *.scm
+
+comp_LTLIBRARIES = libqueue-sender.la libqueue-listener.la
+noinst_DATA = libqueue-sender.so libqueue-listener.so
+
+libqueue_sender_la_SOURCES = queue-sender.cpp
+libqueue_sender_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+libqueue-sender.so:
+ ln -s .libs/libqueue-sender.so
+
+libqueue_listener_la_SOURCES = queue-listener.cpp
+libqueue_listener_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+libqueue-listener.so:
+ ln -s .libs/libqueue-listener.so
+
+qpid_test_SOURCES = qpid-test.cpp
+qpid_test_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+
+dist_noinst_SCRIPTS = send-test server-test
+noinst_PROGRAMS = qpid-test client-test
+TESTS = send-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp
new file mode 100644
index 0000000000..286faa2930
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test queue component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+const value key(mklist<value>(string("report")));
+const string qname("reportq");
+
+const list<value> item = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+const list<value> entry = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), item);
+
+bool testDeclareQueue() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ const failable<bool> r = declareQueue(key, qname, qs);
+ assert(hasContent(r));
+ return true;
+}
+
+const bool listener(const value& k, const value& v) {
+ cerr << "k " << k << " v " << v << endl;
+ assert(k == key);
+ assert(v == entry);
+ return false;
+}
+
+bool testListen() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ QpidSubscription qsub(qs);
+ const lambda<bool(const value&, const value&)> l(listener);
+ listen(qname, l, qsub);
+ return true;
+}
+
+bool testPost() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const failable<value> id = http::post(entry, "http://localhost:8090/print-sender", ch);
+ assert(hasContent(id));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::queue::testDeclareQueue();
+ tuscany::queue::testPost();
+ tuscany::queue::testListen();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp
new file mode 100644
index 0000000000..1a650157b2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Qpid support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+const value key(mklist<value>("test"));
+const string qname("testq");
+
+bool testDeclareQueue() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ const failable<bool> r = declareQueue(key, qname, qs);
+ assert(hasContent(r));
+ return true;
+}
+
+const list<value> item = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+const list<value> entry = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), item);
+
+bool testPost() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ const failable<bool> r = post(key, entry, qs);
+ assert(hasContent(r));
+ return true;
+}
+
+const bool listener(const value& k, const value& v) {
+ assert(k == key);
+ assert(v == entry);
+ return false;
+}
+
+bool testListen() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ QpidSubscription qsub(qs);
+ const lambda<bool(const value&, const value&)> l(listener);
+ listen(qname, l, qsub);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::queue::testDeclareQueue();
+ tuscany::queue::testPost();
+ tuscany::queue::testListen();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp b/sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp
new file mode 100644
index 0000000000..2651e3a433
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_qpid_hpp
+#define tuscany_qpid_hpp
+
+/**
+ * AMQP queue access functions.
+ */
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace queue {
+
+/**
+ * Represents a Qpid connection.
+ */
+class QpidConnection {
+public:
+ QpidConnection() : owner(true) {
+ c.open("localhost", 5672);
+ }
+
+ QpidConnection(const bool owner) : owner(owner) {
+ c.open("localhost", 5672);
+ }
+
+ QpidConnection(const QpidConnection& qc) : owner(false), c(qc.c) {
+ }
+
+ ~QpidConnection() {
+ if (!owner)
+ return;
+ c.close();
+ }
+
+private:
+ friend const failable<bool> close(QpidConnection& qc);
+ friend class QpidSession;
+
+ const bool owner;
+ qpid::client::Connection c;
+
+};
+
+/**
+ * Close a Qpid connection.
+ */
+const failable<bool> close(QpidConnection& qc) {
+ qc.c.close();
+ return true;
+}
+
+/**
+ * Represents a Qpid session.
+ */
+class QpidSession {
+public:
+ QpidSession(QpidConnection& qc) : owner(true), s(qc.c.newSession()) {
+ }
+
+ QpidSession(QpidConnection& qc, const bool owner) : owner(owner), s(qc.c.newSession()) {
+ }
+
+ QpidSession(const QpidSession& qs) : owner(false), s(qs.s) {
+ }
+
+ ~QpidSession() {
+ if (!owner)
+ return;
+ s.close();
+ }
+
+private:
+ friend const failable<bool> close(QpidSession& qs);
+ friend const failable<bool> declareQueue(const value& key, const string& name, QpidSession& qs);
+ friend const failable<bool> post(const value& key, const value& val, QpidSession& qs);
+ friend class QpidSubscription;
+
+ const bool owner;
+ qpid::client::Session s;
+};
+
+/**
+ * Close a Qpid session.
+ */
+const failable<bool> close(QpidSession& qs) {
+ try {
+ qs.s.close();
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ return true;
+}
+
+/**
+ * Declare a key / AMQP queue pair.
+ */
+const failable<bool> declareQueue(const value& key, const string& name, QpidSession& qs) {
+ const string ks(scheme::writeValue(key));
+ try {
+ qs.s.queueDeclare(qpid::client::arg::queue=c_str(name));
+ qs.s.exchangeBind(qpid::client::arg::exchange="amq.direct", qpid::client::arg::queue=c_str(name), qpid::client::arg::bindingKey=c_str(ks));
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ return true;
+}
+
+/**
+ * Post a key / value pair message to an AMQP broker.
+ */
+const failable<bool> post(const value& key, const value& val, QpidSession& qs) {
+
+ // Send in a message with the given key.
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ try {
+ qpid::client::Message message;
+ message.getDeliveryProperties().setRoutingKey(c_str(ks));
+ message.setData(c_str(vs));
+ qs.s.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="amq.direct");
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ return true;
+}
+
+/**
+ * Represents a Qpid subscription.
+ */
+class QpidSubscription {
+public:
+ QpidSubscription(QpidSession& qs) : owner(true), subs(qs.s) {
+ }
+
+ QpidSubscription(QpidSession& qs, const bool owner) : owner(owner), subs(qs.s) {
+ }
+
+ QpidSubscription(const QpidSubscription& qsub) : owner(false), subs(qsub.subs) {
+ }
+
+ ~QpidSubscription() {
+ if (!owner)
+ return;
+ try {
+ subs.stop();
+ } catch (const qpid::Exception& e) {
+ mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ }
+
+private:
+ friend const failable<bool> listen(const string& name, const lambda<bool(const value&, const value&)>& l, QpidSubscription& qsub);
+ friend const failable<bool> stop(QpidSubscription& qsub);
+
+ const bool owner;
+ qpid::client::SubscriptionManager subs;
+};
+
+/**
+ * Register a listener function with an AMQP queue.
+ */
+class Listener : public qpid::client::MessageListener {
+public:
+ Listener(const lambda<bool(const value&, const value&)> l, qpid::client::SubscriptionManager& subs) : l(l), subs(subs) {
+ }
+
+ virtual void received(qpid::client::Message& msg) {
+
+ // Call the listener function
+ const value k(scheme::readValue(msg.getDeliveryProperties().getRoutingKey().c_str()));
+ const value v(scheme::readValue(msg.getData().c_str()));
+ const bool r = l(k, v);
+ if (!r) {
+ try {
+ subs.cancel(msg.getDestination());
+ } catch (const qpid::Exception& e) {
+ mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ }
+ }
+
+private:
+ const lambda<bool(const value&, const value&)> l;
+ qpid::client::SubscriptionManager& subs;
+};
+
+
+const failable<bool> listen(const string& name, const lambda<bool(const value&, const value&)>& l, QpidSubscription& qsub) {
+ debug("queue::listen");
+ Listener listener(l, qsub.subs);
+ try {
+ qsub.subs.subscribe(listener, c_str(name));
+ qsub.subs.run();
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ debug("queue::listen::stopped");
+ return true;
+}
+
+/**
+ * Stop an AMQP subscription.
+ */
+const failable<bool> stop(QpidSubscription& qsub) {
+ debug("queue::stop");
+ try {
+ qsub.subs.stop();
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ debug("queue::stopped");
+ return true;
+}
+
+}
+}
+
+// Re-enable conversion and redundant declarations warnings
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wconversion"
+#pragma GCC diagnostic warning "-Wredundant-decls"
+#endif
+
+#endif /* tuscany_qpid_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-start b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-start
new file mode 100755
index 0000000000..02e048c41e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-start
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+# Start qpidd
+here=`readlink -f $0`; here=`dirname $here`
+
+qpid_prefix=`cat $here/qpidc.prefix`
+$qpid_prefix/sbin/qpidd &
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop
new file mode 100755
index 0000000000..3baf2fee27
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop
@@ -0,0 +1,26 @@
+#!/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
+# 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.
+
+# Stop qpidd
+here=`readlink -f $0`; here=`dirname $here`
+
+qpid_prefix=`cat $here/qpidc.prefix`
+qpidd="$qpid_prefix/sbin/qpidd"
+
+kill `ps -ef | grep -v grep | grep "${qpidd}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType
new file mode 100644
index 0000000000..1e94f9a2df
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <reference name="relay"/>
+ <property name="key" type="xsd:string"/>
+ <property name="queue" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp
new file mode 100644
index 0000000000..d714101583
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * AMQP queue listener component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+/**
+ * A relay function that posts the AMQP messages it receives to a relay component reference.
+ */
+class relay {
+public:
+ relay(const lambda<value(const list<value>&)>& rel) : rel(rel) {
+ }
+
+ const bool operator()(const value& k, const value& v) const {
+ debug(k, "queue::relay::key");
+ debug(v, "queue::relay::value");
+ const value res = rel(mklist<value>("post", isList(k)? (list<value>)k : mklist<value>(k), v));
+ return true;
+ }
+
+private:
+ const lambda<value(const list<value>&)> rel;
+};
+
+/**
+ * Subscribe and listen to an AMQP queue.
+ */
+class subscribe {
+public:
+ subscribe(const string& qname, const lambda<bool(const value&, const value&)>& l, const QpidSubscription& qsub) : qname(qname), l(l), qsub(qsub) {
+ }
+
+ const failable<bool> operator()() const {
+ gc_pool pool;
+ debug(qname, "queue::subscribe::listen");
+ const failable<bool> r = listen(qname, l, const_cast<QpidSubscription&>(qsub));
+ debug(qname, "queue::subscribe::stopped");
+ return r;
+ }
+
+private:
+ const string qname;
+ const lambda<bool(const value&, const value&)> l;
+ const QpidSubscription qsub;
+};
+
+/**
+ * Listener lambda function, responsible for starting an AMQP subscription in a worker thread, and
+ * apply any function calls to the listener component. The only supported function is stop(),
+ * called to stop the listener component and shutdown the worker thread.
+ */
+class listener {
+public:
+ listener(QpidConnection& qc, QpidSession& qs, QpidSubscription& qsub, worker& w) : qc(qc), qs(qs), qsub(qsub), w(w) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const tuscany::value func(car(params));
+
+ // Stop the component
+ if (func != "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ debug("queue::listener::stop");
+
+ // TODO check why stop() and close() hang in child processes
+ stop(const_cast<QpidSubscription&>(qsub));
+ close(const_cast<QpidSession&>(qs));
+ close(const_cast<QpidConnection&>(qc));
+ cancel(const_cast<worker&>(w));
+
+ debug("queue::listener::stopped");
+ return failable<value>(value(lambda<value(const list<value>&)>()));
+ }
+
+private:
+ QpidConnection qc;
+ QpidSession qs;
+ QpidSubscription qsub;
+ worker w;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Extract the relay reference and the AMQP key and queue name
+ const value rel = car(params);
+ const value pk = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ const value key = isList(pk)? (list<value>)pk : mklist<value>(pk);
+ const value qname = ((lambda<value(list<value>)>)caddr(params))(list<value>());
+
+ // Create an AMQP session
+ QpidConnection qc(false);
+ QpidSession qs(qc, false);
+
+ // Declare the configured AMQP key / queue pair
+ declareQueue(key, qname, qs);
+
+ // Listen and relay messages in a worker thread
+ QpidSubscription qsub(qs, false);
+ worker w(3);
+ const lambda<bool(const value&, const value&)> rl = relay(rel);
+ submit<failable<bool> >(w, lambda<failable<bool>()>(subscribe(qname, rl, qsub)));
+
+ // Return the listener component lambda function
+ return value(lambda<value(const list<value>&)>(listener(qc, qs, qsub, w)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::queue::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType
new file mode 100644
index 0000000000..fc06bf2dcf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="sender"/>
+ <property name="key" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp
new file mode 100644
index 0000000000..07f8491f54
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * AMQP queue sender component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+/**
+ * Post an item to a queue.
+ */
+const failable<value> post(const list<value>& params) {
+ QpidConnection qc;
+ QpidSession qs(qc);
+
+ // Post the item
+ const value pk = ((lambda<value(list<value>)>)caddr(params))(list<value>());
+ const value key = isList(pk)? append<value>(pk, (list<value>)car(params)) : cons<value>(pk, (list<value>)car(params));
+ debug(key, "queue::post::key");
+ debug(cadr(params), "queue::post::value");
+ const failable<bool> r = post(key, cadr(params), qs);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+ return key;
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return tuscany::queue::post(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue.composite b/sandbox/sebastien/cpp/apr-2/components/queue/queue.composite
new file mode 100644
index 0000000000..e8fb1b1049
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue.composite
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="queue">
+
+ <component name="print-sender">
+ <implementation.cpp path="." library="libqueue-sender"/>
+ <property name="key">print</property>
+ <service name="print-sender">
+ <t:binding.http uri="print-sender"/>
+ </service>
+ </component>
+
+ <component name="print-listener">
+ <implementation.cpp path="." library="libqueue-listener"/>
+ <property name="key">print</property>
+ <property name="queue">printq</property>
+ <reference name="relay" target="print"/>
+ </component>
+
+ <component name="print">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="print">
+ <t:binding.http uri="print"/>
+ </service>
+ <reference name="report" target="report-sender"/>
+ </component>
+
+ <component name="report-sender">
+ <implementation.cpp path="." library="libqueue-sender"/>
+ <property name="key">report</property>
+ <service name="report-sender">
+ <t:binding.http uri="report-sender"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/send-test b/sandbox/sebastien/cpp/apr-2/components/queue/send-test
new file mode 100755
index 0000000000..ec6d9d9083
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/send-test
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+# Setup
+./qpidd-start
+sleep 1
+
+# Test
+./qpid-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./qpidd-stop
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/server-test b/sandbox/sebastien/cpp/apr-2/components/queue/server-test
new file mode 100755
index 0000000000..571b09082c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/server-test
@@ -0,0 +1,43 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite queue.composite
+EOF
+
+./qpidd-start
+sleep 1
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 1
+./qpidd-stop
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm b/sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm
new file mode 100644
index 0000000000..1a89ce8b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Queue test case
+
+(define (post key val report) (report "post" '() val))
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am
new file mode 100644
index 0000000000..4cd27e967c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am
@@ -0,0 +1,55 @@
+# 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.
+
+if WANT_SQLDB
+
+INCLUDES = -I${PGSQL_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/sqldb
+
+dist_comp_SCRIPTS = pgsql-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf pgsql-backup
+compdir=$(prefix)/components/sqldb
+
+comp_DATA = pgsql.prefix
+pgsql.prefix: $(top_builddir)/config.status
+ echo ${PGSQL_PREFIX} >pgsql.prefix
+
+EXTRA_DIST = sqldb.composite sqldb.componentType
+
+comp_LTLIBRARIES = libsqldb.la
+noinst_DATA = libsqldb.so
+
+libsqldb_la_SOURCES = sqldb.cpp
+libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+libsqldb.so:
+ ln -s .libs/libsqldb.so
+
+pgsql_test_SOURCES = pgsql-test.cpp
+pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+
+pgsql_standby_test_SOURCES = pgsql-standby-test.cpp
+pgsql_standby_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = sqldb-test standby-test server-test
+noinst_PROGRAMS = pgsql-test pgsql-standby-test client-test
+TESTS = sqldb-test standby-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp
new file mode 100644
index 0000000000..4e5c067633
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test SQL database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace sqldb {
+
+const string uri("http://localhost:8090/sqldb");
+
+bool testSqlDb() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(uri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "Sqldb get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::sqldb::testSqlDb();
+ tuscany::sqldb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql
new file mode 100755
index 0000000000..dab30e642b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql
@@ -0,0 +1,35 @@
+#!/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
+# 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.
+
+# Run SQL command
+here=`readlink -f $0`; here=`dirname $here`
+pgsql_prefix=`cat $here/pgsql.prefix`
+
+if [ "$2" = "" ]; then
+ host="localhost"
+ port="5432"
+ cmd="$1"
+else
+ host="$1"
+ port="$2"
+ cmd="$3"
+fi
+
+$pgsql_prefix/bin/psql -h $host -p $port -c "$cmd" db
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup
new file mode 100755
index 0000000000..fad59236bf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup
@@ -0,0 +1,41 @@
+#!/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
+# 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.
+
+# Backup postgresql data directory
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+if [ "$2" = "" ]; then
+ host="localhost"
+ port="5432"
+else
+ host="$2"
+ port="$3"
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('backup', true)" db 1>>$root/logs/postgresql 2>&1
+
+echo "Content-type: application/x-compressed"
+echo
+
+tar -C $root/sqldb -cz data
+
+$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_stop_backup()" db 1>>$root/logs/postgresql 2>&1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf
new file mode 100755
index 0000000000..f5cc2d23e3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf
@@ -0,0 +1,105 @@
+#!/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
+# 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.
+
+# Configure a postgresql master server
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+addr=$2
+if [ "$addr" = "" ]; then
+ ip="*"
+ port="5432"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ if [ "$ip" = "" ]; then
+ ip="*"
+ fi
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb/data
+chmod 700 $root/sqldb/data
+mkdir -p $root/sqldb/archive
+mkdir -p $root/logs
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ $pgsql_prefix/bin/pg_ctl init -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+ cp $root/sqldb/data/postgresql.conf $root/sqldb/data/postgresql-init.conf
+ cp $root/sqldb/data/pg_hba.conf $root/sqldb/data/pg_hba-init.conf
+fi
+
+# Generate server configuration
+cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf
+cat >>$root/sqldb/data/postgresql.conf <<EOF
+
+# Generated by: pgsql-conf $*
+
+# Listen
+listen_addresses = '$ip'
+port = $port
+
+# Setup archival
+archive_mode = on
+archive_command = 'cp %p $root/sqldb/archive/%f'
+
+# Setup hot standby with streaming replication
+wal_level = hot_standby
+max_wal_senders = 5
+wal_keep_segments = 32
+
+EOF
+
+# Generate client auth configuration
+cp $root/sqldb/data/pg_hba-init.conf $root/sqldb/data/pg_hba.conf
+cat >>$root/sqldb/data/pg_hba.conf <<EOF
+
+# Generated by: pgsql-conf $*
+# TYPE DATABASE USER CIDR-ADDRESS METHOD
+host all all samenet trust
+host replication all samenet trust
+
+EOF
+
+# Create the db
+$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1
+$pgsql_prefix/bin/createdb -h localhost -p $port db 1>>$root/logs/postgresql 2>&1
+$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+
+# Generate database backup script
+mkdir -p $root/sqldb/scripts
+cat >$root/sqldb/scripts/backup <<EOF
+#!/bin/sh
+$here/pgsql-backup $root localhost $port
+EOF
+chmod 700 $root/sqldb/scripts/backup
+
+# Configure HTTPD to serve backup and archive files
+if [ -f "$root/conf/httpd.conf" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Generated by: pgsql-conf $*
+
+# Serve PostgreSQL backup and WAL archive files
+ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup"
+Alias /pgsql-archive "$root/sqldb/archive"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf
new file mode 100755
index 0000000000..cbfd90b48c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf
@@ -0,0 +1,122 @@
+#!/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
+# 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.
+
+# Configure a postgresql hot standby server
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+# Server address
+addr=$2
+if [ "$addr" = "" ]; then
+ ip="*"
+ port="5432"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ if [ "$ip" = "" ]; then
+ ip="*"
+ fi
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+# Master server address
+if [ "$3" = "" ]; then
+ mhost="localhost"
+ mport="5432"
+ mhttpport="80"
+else
+ mhost="$3"
+ mport="$4"
+ mhttpport="$5"
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb/data
+chmod 700 $root/sqldb/data
+mkdir -p $root/sqldb/archive
+mkdir -p $root/logs
+
+# Initialize from a backup of the master
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ (wget http://$mhost:$mhttpport/pgsql-backup -O - | tar -C $root/sqldb -xz) 1>>$root/logs/postgresql 2>&1
+ rm -rf $root/sqldb/data/postmaster.pid $root/sqldb/data/pg_xlog
+ mkdir -p $root/sqldb/data/pg_xlog/archive_status
+ chmod 700 $root/sqldb/data/pg_xlog/archive_status
+fi
+
+# Generate server configuration
+cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf
+cat >>$root/sqldb/data/postgresql.conf <<EOF
+
+# Generated by: standby-conf $*
+
+# Listen
+listen_addresses = '$ip'
+port = $port
+
+# Setup archival
+archive_mode = on
+archive_command = 'cp %p $root/sqldb/archive/%f'
+
+# Setup hot standby with streaming replication
+wal_level = hot_standby
+max_wal_senders = 5
+wal_keep_segments = 32
+
+# Enable hot standby
+hot_standby = on
+
+EOF
+
+# Generate recovery configuration
+cat >$root/sqldb/data/recovery.conf << EOF
+# Generated by: pgsql-slave-conf $*
+
+# Start in standby mode
+standby_mode = 'on'
+primary_conninfo = 'host=$mhost port=$mport'
+
+# Failover
+trigger_file = '$root/sqldb/failover'
+
+restore_command = 'wget http://$mhost:$mhttpport/pgsql-archive/%f -O "%p"'
+
+EOF
+
+# Generate database backup script
+mkdir -p $root/sqldb/scripts
+cat >$root/sqldb/scripts/backup <<EOF
+#!/bin/sh
+$here/pgsql-backup $root localhost $port
+EOF
+chmod 700 $root/sqldb/scripts/backup
+
+# Configure HTTPD to serve backup and archive files
+if [ -f "$root/conf/httpd.conf" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Generated by: pgsql-conf $*
+
+# Serve PostgreSQL backup and WAL archive files
+ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup"
+Alias /pgsql-archive "$root/sqldb/archive"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp
new file mode 100644
index 0000000000..44f0a4a9e6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test PostgreSQL hot standby support.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+bool testPGSql() {
+ PGSql wpg("host=localhost port=5432 dbname=db", "test");
+ PGSql rpg("host=localhost port=5433 dbname=db", "test");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), wpg)));
+ sleep(1);
+ assert((get(k, rpg)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), wpg)));
+ sleep(1);
+ assert((get(k, rpg)) == value(string("aaa")));
+ assert(hasContent(del(k, wpg)));
+ sleep(1);
+ assert(!hasContent(get(k, rpg)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ PGSql& pg;
+ getLoop(const value& k, PGSql& pg) : k(k), pg(pg) {
+ }
+ const bool operator()() const {
+ assert((get(k, pg)) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ PGSql wpg("host=localhost port=5432 dbname=db", "test");
+ PGSql rpg("host=localhost port=5433 dbname=db", "test");
+ assert(hasContent(post(k, string("CCC"), wpg)));
+ sleep(1);
+
+ const lambda<bool()> gl = getLoop(k, rpg);
+ cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::pgsql::testPGSql();
+ tuscany::pgsql::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start
new file mode 100755
index 0000000000..3f03d0b4dc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start
@@ -0,0 +1,29 @@
+#!/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
+# 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.
+
+# Start postgresql
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb
+mkdir -p $root/logs
+$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1
+sleep 1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop
new file mode 100755
index 0000000000..eefade47d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop
@@ -0,0 +1,27 @@
+#!/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
+# 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.
+
+# Stop postgresql
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/logs
+$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp
new file mode 100644
index 0000000000..1019667285
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test PostgreSQL access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+bool testPGSql() {
+ PGSql pg("host=localhost port=5432 dbname=db", "test");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), pg)));
+ assert((get(k, pg)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), pg)));
+ assert((get(k, pg)) == value(string("aaa")));
+ assert(hasContent(del(k, pg)));
+ assert(!hasContent(get(k, pg)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ PGSql& pg;
+ getLoop(const value& k, PGSql& pg) : k(k), pg(pg) {
+ }
+ const bool operator()() const {
+ assert((get(k, pg)) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ PGSql pg("host=localhost port=5432 dbname=db", "test");
+ assert(hasContent(post(k, string("CCC"), pg)));
+
+ const lambda<bool()> gl = getLoop(k, pg);
+ cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::pgsql::testPGSql();
+ tuscany::pgsql::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp
new file mode 100644
index 0000000000..f4da8db220
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_pgsql_hpp
+#define tuscany_pgsql_hpp
+
+/**
+ * PostgreSQL access functions.
+ */
+
+#include <libpq-fe.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+/**
+ * Return and clear a Postgres result failure.
+ */
+const string pgfailure(PGresult* r, PGconn* conn) {
+ const string re = PQresultErrorMessage(r);
+ PQclear(r);
+ if (length(re) != 0)
+ return re;
+ const string ce = PQerrorMessage(conn);
+ return ce;
+}
+
+/**
+ * Represents a PGSql connection.
+ */
+class PGSql {
+public:
+ PGSql() : owner(false) {
+ }
+
+ PGSql(const string& conninfo, const string& table) : owner(true), conn(NULL), conninfo(conninfo), table(table) {
+ conn = PQconnectdb(c_str(conninfo));
+ if (PQstatus(conn) != CONNECTION_OK) {
+ mkfailure<bool>(string("Could not connect to postgresql database: ") + PQerrorMessage(conn));
+ return;
+ }
+ setup(true);
+ }
+
+ PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) {
+ }
+
+ ~PGSql() {
+ if (!owner)
+ return;
+ if (conn == NULL)
+ return;
+ PQfinish(conn);
+ }
+
+private:
+ bool owner;
+ PGconn *conn;
+ string conninfo;
+ string table;
+
+ friend const failable<bool> setup(const PGSql& pgsql);
+ friend const failable<bool> post(const value& key, const value& val, const PGSql& pgsql);
+ friend const failable<bool> put(const value& key, const value& val, const PGSql& pgsql);
+ friend const failable<value> get(const value& key, const PGSql& pgsql);
+ friend const failable<bool> del(const value& key, const PGSql& pgsql);
+
+ /**
+ * Setup the database connection.
+ */
+ const failable<bool> setup(const bool init) const {
+
+ // Check the status of the connection and reconnect if necessary
+ if (!init) {
+ if (PQstatus(conn) == CONNECTION_OK)
+ return true;
+ debug("pgsql::setup::reset");
+ PQreset(conn);
+ if (PQstatus(conn) != CONNECTION_OK)
+ return mkfailure<bool>(string("Could not reconnect to postgresql database: ") + PQerrorMessage(conn));
+ }
+ debug("pgsql::setup::init");
+
+ // Find the name of the first column in the target table
+ // Assume that's the key we need to use
+ string ks = string("select a.attname from pg_attribute a, pg_class c where a.attrelid = c.relfilenode and c.relname = '") + table + string("' and a.attnum in (1, 2) order by a.attnum;");
+ PGresult* kr = PQexec(conn, c_str(ks));
+ if (PQresultStatus(kr) != PGRES_TUPLES_OK)
+ return mkfailure<bool>(string("Could not execute postgresql column select statement: ") + pgfailure(kr, conn));
+ if (PQntuples(kr) != 2) {
+ PQclear(kr);
+ return mkfailure<bool>(string("Could not find postgresql table key and value column names"));
+ }
+ const string kname = PQgetvalue(kr, 0, 0);
+ const string vname = PQgetvalue(kr, 1, 0);
+ PQclear(kr);
+
+ // Prepare the post, put, get and delete statements
+ {
+ PGresult* r = PQprepare(conn, "post", c_str(string("insert into ") + table + string(" values($1, $2);")), 2, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare post postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ {
+ PGresult* r = PQprepare(conn, "put", c_str(string("update ") + table + string(" set ") + vname + string(" = $2 where ") + kname + string(" = $1;")), 2, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare put postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ {
+ PGresult* r = PQprepare(conn, "get", c_str(string("select * from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare get postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ {
+ PGresult* r = PQprepare(conn, "delete", c_str(string("delete from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare delete postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ return true;
+ }
+};
+
+/**
+ * Setup the database connection if necessary.
+ */
+const failable<bool> setup(const PGSql& pgsql) {
+ return pgsql.setup(false);
+}
+
+/**
+ * Post a new item to the database.
+ */
+const failable<bool> post(const value& key, const value& val, const PGSql& pgsql) {
+ debug(key, "pgsql::post::key");
+ debug(val, "pgsql::post::value");
+ debug(pgsql.conninfo, "pgsql::post::conninfo");
+ debug(pgsql.table, "pgsql::post::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const char* params[2] = { c_str(ks), c_str(vs) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ PQclear(r);
+
+ debug(true, "pgsql::post::result");
+ return true;
+}
+
+/**
+ * Update an item in the database. If the item doesn't exist it is added.
+ */
+const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) {
+ debug(key, "pgsql::put::key");
+ debug(val, "pgsql::put::value");
+ debug(pgsql.conninfo, "pgsql::put::conninfo");
+ debug(pgsql.table, "pgsql::put::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const char* params[2] = { c_str(ks), c_str(vs) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "put", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute update postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ const string t = PQcmdTuples(r);
+ if (t != "0") {
+ PQclear(r);
+ debug(true, "pgsql::put::result");
+ return true;
+ }
+ PQclear(r);
+
+ PGresult* pr = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(pr) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(pr, pgsql.conn));
+ PQclear(pr);
+
+ debug(true, "pgsql::put::result");
+ return true;
+}
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const value& key, const PGSql& pgsql) {
+ debug(key, "pgsql::get::key");
+ debug(pgsql.conninfo, "pgsql::get::conninfo");
+ debug(pgsql.table, "pgsql::get::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const char* params[1] = { c_str(ks) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "get", 1, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_TUPLES_OK)
+ return mkfailure<value>(string("Could not execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ if (PQntuples(r) < 1) {
+ PQclear(r);
+ return mkfailure<value>(string("Could not get postgresql entry: ") + PQerrorMessage(pgsql.conn));
+ }
+ const char* data = PQgetvalue(r, 0, 1);
+ const value val(scheme::readValue(string(data)));
+ PQclear(r);
+
+ debug(val, "pgsql::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the database
+ */
+const failable<bool> del(const value& key, const PGSql& pgsql) {
+ debug(key, "pgsql::delete::key");
+ debug(pgsql.conninfo, "pgsql::delete::conninfo");
+ debug(pgsql.table, "pgsql::delete::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const char* params[1] = { c_str(ks) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "delete", 1, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute delete postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ PQclear(r);
+
+ debug(true, "pgsql::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_pgsql_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test
new file mode 100755
index 0000000000..c07d3b0510
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test
@@ -0,0 +1,44 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+./pgsql-conf tmp
+./pgsql-start tmp
+./pgsql "drop table test;" 1>/dev/null 2>&1
+./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite sqldb.composite
+EOF
+
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+./pgsql-stop tmp
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test
new file mode 100755
index 0000000000..e910ae0059
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test
@@ -0,0 +1,32 @@
+#!/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
+# 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.
+
+# Setup
+./pgsql-conf tmp
+./pgsql-start tmp
+./pgsql "drop table test;" 1>/dev/null 2>&1
+./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1
+
+# Test
+./pgsql-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./pgsql-stop tmp
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType
new file mode 100644
index 0000000000..5aa6d8e30f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="sqldb"/>
+ <property name="conninfo" type="xsd:string">host=localhost port=5432 dbname=db</property>
+ <property name="table" type=xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite
new file mode 100644
index 0000000000..1511e66024
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="sqldb">
+
+ <component name="sqldb">
+ <implementation.cpp path="." library="libsqldb"/>
+ <property name="conninfo">host=localhost port=5432 dbname=db</property>
+ <property name="table">test</property>
+ <service name="sqldb">
+ <t:binding.http uri="sqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp
new file mode 100644
index 0000000000..0524b00bd2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * PostgreSQL-based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace sqldb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, pgsql::PGSql& pg) {
+ return pgsql::get(car(params), pg);
+}
+
+/**
+ * Post an item to the database.
+ */
+const failable<value> post(const list<value>& params, pgsql::PGSql& pg) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = pgsql::post(id, cadr(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, pgsql::PGSql& pg) {
+ const failable<bool> val = pgsql::put(car(params), cadr(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, pgsql::PGSql& pg) {
+ const failable<bool> val = pgsql::del(car(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applySqldb {
+public:
+ applySqldb(pgsql::PGSql& pg) : pg(pg) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), pg);
+ if (func == "post")
+ return post(cdr(params), pg);
+ if (func == "put")
+ return put(cdr(params), pg);
+ if (func == "delete")
+ return del(cdr(params), pg);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ pgsql::PGSql& pg;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to the configured database and table
+ const value conninfo = ((lambda<value(list<value>)>)car(params))(list<value>());
+ const value table = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ pgsql::PGSql& pg = *(new (gc_new<pgsql::PGSql>()) pgsql::PGSql(conninfo, table));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applySqldb(pg)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::sqldb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test
new file mode 100755
index 0000000000..9e56bfc039
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp/master localhost 8090 tmp/master/htdocs
+./pgsql-conf tmp/master 5432
+./pgsql-start tmp/master
+./pgsql localhost 5432 "drop table test;" 1>/dev/null 2>&1
+./pgsql localhost 5432 "create table test(key text, value text);" 1>/dev/null 2>&1
+../../modules/http/httpd-start tmp/master
+sleep 2
+./pgsql-standby-conf tmp/standby 5433 localhost 5432 8090
+./pgsql-start tmp/standby
+
+# Test
+./pgsql-standby-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp/master
+./pgsql-stop tmp/standby
+./pgsql-stop tmp/master
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am
new file mode 100644
index 0000000000..19156e3fdd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am
@@ -0,0 +1,71 @@
+# 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.
+
+if WANT_WEBSERVICE
+
+INCLUDES = -I${AXIS2C_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/webservice
+
+dist_comp_SCRIPTS = axis2-conf
+compdir=$(prefix)/components/webservice
+
+comp_DATA = axis2c.prefix axis2.xml services.xml module.xml
+
+EXTRA_DIST = webservice.composite webservice-client.componentType webservice-listener.componentType axis2.xml services.xml module.xml *.scm
+
+axis2c.prefix: $(top_builddir)/config.status
+ echo ${AXIS2C_PREFIX} >axis2c.prefix
+
+comp_LTLIBRARIES = libwebservice-client.la libwebservice-listener.la libaxis2-dispatcher.la libaxis2-service.la
+noinst_DATA = libwebservice-client.so libwebservice-listener.so libaxis2-dispatcher.so libaxis2-service.so
+
+libwebservice_client_la_SOURCES = webservice-client.cpp
+libwebservice_client_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libwebservice-client.so:
+ ln -s .libs/libwebservice-client.so
+
+libwebservice_listener_la_SOURCES = webservice-listener.cpp
+libwebservice_listener_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libwebservice-listener.so:
+ ln -s .libs/libwebservice-listener.so
+
+libaxis2_dispatcher_la_SOURCES = axis2-dispatcher.cpp
+libaxis2_dispatcher_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libaxis2-dispatcher.so:
+ ln -s .libs/libaxis2-dispatcher.so
+
+libaxis2_service_la_SOURCES = axis2-service.cpp
+libaxis2_service_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libaxis2-service.so:
+ ln -s .libs/libaxis2-service.so
+
+axiom_test_SOURCES = axiom-test.cpp
+axiom_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+
+axis2_test_SOURCES = axis2-test.cpp
+axis2_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+
+dist_noinst_SCRIPTS = echo-test server-test
+noinst_PROGRAMS = axiom-test axis2-test client-test
+TESTS = axiom-test echo-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp
new file mode 100644
index 0000000000..a3ab8e7e8f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Web service Axiom support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+const string customerElement =
+"<customer>"
+"<name>jdoe</name>"
+"<address><city>san francisco</city><state>ca</state></address>"
+"<account><id>1234</id><balance>1000</balance></account>"
+"<account><id>6789</id><balance>2000</balance></account>"
+"<account><id>4567</id><balance>3000</balance></account>"
+"</customer>";
+
+bool testAxiom() {
+ const Axis2Context ax;
+ {
+ const failable<axiom_node_t*> n = stringToAxiomNode(customerElement, ax);
+ assert(hasContent(n));
+ const failable<const string> c = axiomNodeToString(content(n), ax);
+ assert(hasContent(c));
+ assert(content(c) == customerElement);
+ }
+ {
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+ const failable<axiom_node_t*> n = valuesToAxiomNode(arg, ax);
+ assert(hasContent(n));
+ const failable<const string> x = axiomNodeToString(content(n), ax);
+ assert(hasContent(x));
+ assert(content(x) == "<ns1:echoString xmlns:ns1=\"http://ws.apache.org/axis2/services/echo\"><text>Hello World!</text></ns1:echoString>");
+ const failable<const list<value> > l = axiomNodeToValues(content(n), ax);
+ assert(hasContent(l));
+ assert(l == arg);
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::webservice::testAxiom();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf
new file mode 100755
index 0000000000..af5d189b24
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf
@@ -0,0 +1,64 @@
+#!/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
+# 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.
+
+# Generate an Axis2 server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+axis2_prefix=`cat axis2c.prefix`
+
+# Create an Axis2 home directory
+mkdir -p $root/axis2c
+ln -f -s $axis2_prefix/lib $root/axis2c/lib
+mkdir -p $root/axis2c/logs
+mkdir -p $root/axis2c/modules
+ln -f -s $axis2_prefix/modules/addressing $root/axis2c/modules/addressing
+ln -f -s $axis2_prefix/modules/logging $root/axis2c/modules/logging
+mkdir -p $root/axis2c/services
+
+# Install Tuscany Axis2 module and service
+mkdir -p $root/axis2c/modules/tuscany
+ln -f -s $here/libaxis2-dispatcher.so $root/axis2c/modules/tuscany/libaxis2-dispatcher.so
+ln -f -s $here/module.xml $root/axis2c/modules/tuscany/module.xml
+mkdir -p $root/axis2c/services/tuscany
+ln -f -s $here/libaxis2-service.so $root/axis2c/services/tuscany/libaxis2-service.so
+ln -f -s $here/services.xml $root/axis2c/services/tuscany/services.xml
+cp $here/axis2.xml $root/axis2c/axis2.xml
+
+# Configure HTTPD Axis2 module
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: axis2-conf $*
+# Support for Web Services
+LoadModule axis2_module $root/axis2c/lib/libmod_axis2.so
+
+EOF
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: axis2-conf $*
+# Support for Web Services
+SCASetEnv AXIS2C_HOME $root/axis2c
+Axis2RepoPath $root/axis2c
+Axis2LogFile $root/axis2c/logs/mod_axis2.log
+Axis2LogLevel debug
+<Location /axis2>
+ SetHandler axis2_module
+</Location>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp
new file mode 100644
index 0000000000..3f753e0e35
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Axis2/C module that dispatches all server requests to the Tuscany Axis/2C service.
+ */
+
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Determine the service and operation to dispatch a request to.
+ */
+axis2_svc_t* AXIS2_CALL dispatchFindService(axis2_msg_ctx_t* msg_ctx, const axutil_env_t* env) {
+ const axis2_conf_ctx_t* conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);
+ const axis2_conf_t* conf = axis2_conf_ctx_get_conf(conf_ctx, env);
+ axis2_svc_t* svc = axis2_conf_get_svc(conf, env, "TuscanyService");
+ return svc;
+}
+
+axis2_op_t *AXIS2_CALL dispatchFindOp(unused axis2_msg_ctx_t* msg_ctx, const axutil_env_t* env, axis2_svc_t* svc) {
+ axutil_qname_t* op_qname = axutil_qname_create(env, "execute", NULL, NULL);
+ axis2_op_t *op = axis2_svc_get_op_with_name(svc, env, axutil_qname_get_localpart(op_qname, env));
+ axutil_qname_free(op_qname, env);
+ return op;
+}
+
+/**
+ * Dispatcher invoke function, called by Axis2/C.
+ */
+axis2_status_t AXIS2_CALL dispatchInvoke( struct axis2_handler* handler, const axutil_env_t* env, axis2_msg_ctx_t* msg_ctx) {
+ if (!(axis2_msg_ctx_get_server_side(msg_ctx, env)))
+ return AXIS2_SUCCESS;
+ axis2_msg_ctx_set_find_svc(msg_ctx, env, dispatchFindService);
+ axis2_msg_ctx_set_find_op(msg_ctx, env, dispatchFindOp);
+ return axis2_disp_find_svc_and_op(handler, env, msg_ctx);
+}
+
+/**
+ * Create a dispatch handler.
+ */
+AXIS2_EXPORT axis2_handler_t* AXIS2_CALL dispatchHandler(const axutil_env_t* env, unused axutil_string_t* name) {
+ axis2_handler_t *handler = axis2_handler_create(env);
+ if (handler == NULL)
+ return NULL;
+ axis2_handler_set_invoke(handler, env, dispatchInvoke);
+ return handler;
+}
+
+/**
+ * Initialize dispatch module.
+ */
+axis2_status_t AXIS2_CALL dispatchInit(unused axis2_module_t * module, unused const axutil_env_t * env, unused axis2_conf_ctx_t * conf_ctx, unused axis2_module_desc_t * module_desc) {
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Initialize dispatch module function map.
+ */
+axis2_status_t AXIS2_CALL dispatchFuncMap(axis2_module_t * module, const axutil_env_t * env) {
+ module->handler_create_func_map = axutil_hash_make(env);
+ axutil_hash_set(module->handler_create_func_map, "TuscanyDispatcher", AXIS2_HASH_KEY_STRING, (const void *)dispatchHandler);
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Shutdown dispatch module.
+ */
+axis2_status_t AXIS2_CALL dispatchShutdown(axis2_module_t* module, const axutil_env_t* env) {
+ if (module->handler_create_func_map != NULL) {
+ axutil_hash_free(module->handler_create_func_map, env);
+ module->handler_create_func_map = NULL;
+ }
+ AXIS2_FREE(env->allocator, module);
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Return a new dispatch module.
+ */
+const axis2_module_ops_t dispatchOps = {
+ dispatchInit,
+ dispatchShutdown,
+ dispatchFuncMap
+};
+
+axis2_module_t * dispatchModule(const axutil_env_t* env) {
+ axis2_module_t *module = (axis2_module_t*)AXIS2_MALLOC(env->allocator, sizeof(axis2_module_t));
+ if (module == NULL)
+ return NULL;
+ module->ops = &dispatchOps;
+ module->handler_create_func_map = NULL;
+ return module;
+}
+
+}
+}
+
+extern "C"
+{
+
+/**
+ * Axis2/C module entry point functions.
+ */
+AXIS2_EXPORT int axis2_get_instance(axis2_module_t** inst, const axutil_env_t* env) {
+ *inst = tuscany::webservice::dispatchModule(env);
+ if(*inst == NULL)
+ return AXIS2_FAILURE;
+ return AXIS2_SUCCESS;
+}
+
+AXIS2_EXPORT int axis2_remove_instance(axis2_module_t* inst, const axutil_env_t* env) {
+ if (inst != NULL)
+ return tuscany::webservice::dispatchShutdown(inst, env);
+ return AXIS2_FAILURE;
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp
new file mode 100644
index 0000000000..4c0ce22722
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Axis2/C service implementation that dispatches requests to SCA Web service components.
+ */
+
+#include "value.hpp"
+#include "string.hpp"
+#include "../../modules/http/httpd.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Initialize the service.
+ */
+int AXIS2_CALL serviceInit(unused axis2_svc_skeleton_t* svc_skeleton, unused const axutil_env_t* env) {
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Free the service.
+ */
+int AXIS2_CALL serviceFree(axis2_svc_skeleton_t* svc_skeleton, const axutil_env_t* env) {
+ if (svc_skeleton)
+ AXIS2_FREE(env->allocator, svc_skeleton);
+ return AXIS2_SUCCESS;
+}
+
+typedef struct axis2_apache2_out_transport_info {
+ axis2_http_out_transport_info_t out_transport_info;
+ request_rec *request;
+ axis2_char_t *encoding;
+} axis2_apache2_out_transport_info_t;
+
+extern "C" {
+ extern module axis2_module;
+}
+
+/**
+ * Service invoke function, called by Axis2/C.
+ */
+axiom_node_t *AXIS2_CALL serviceInvoke(unused axis2_svc_skeleton_t* svc_skeleton, const axutil_env_t* env, axiom_node_t* node, axis2_msg_ctx_t* msg_ctx) {
+
+ // Check that we have an input node
+ if (node == NULL || axiom_node_get_node_type(node, env) != AXIOM_ELEMENT)
+ return NULL;
+ axiom_element_t *e = (axiom_element_t *) axiom_node_get_data_element(node, env);
+ if (e == NULL)
+ return NULL;
+
+ // Get the function name
+ const char* func = axiom_element_get_localname(e, env);
+ if (func == NULL)
+ return NULL;
+
+ // Get the target endpoint address
+ const axis2_endpoint_ref_t* epr = axis2_msg_ctx_get_from(msg_ctx, env);
+ if (epr == NULL)
+ return NULL;
+ string address = axis2_endpoint_ref_get_address(epr, env);
+
+ // Get the underlying HTTPD request
+ axis2_out_transport_info_t* tinfo = axis2_msg_ctx_get_out_transport_info(msg_ctx, env);
+ axis2_apache2_out_transport_info_t* httpinfo = (axis2_apache2_out_transport_info_t*)tinfo;
+ request_rec* r = httpinfo->request;
+ httpdDebugRequest(r, "webservice::serviceInvoke");
+
+ // Parse the request Axiom node and construct request expression
+ Axis2Context ax(env);
+ const failable<const list<value> > lv = axiomNodeToValues(node, ax);
+ if (!hasContent(lv))
+ return NULL;
+ const value expr = mklist<value>(func, content(lv));
+ debug(expr, "webservice::serviceInvoke::expr");
+
+ // Retrieve the target lambda function from the HTTPD request and invoke it
+ const value* rv = const_cast<const value*>((value*)ap_get_module_config(r->request_config, &axis2_module));
+ cout << "relay: " << rv << endl;
+ const lambda<value(const list<value>&)> relay = *rv;
+ const value res = relay(expr);
+ debug(res, "webservice::serviceInvoke::result");
+
+ // Construct response Axiom node
+ const failable<axiom_node_t*> rnode = valuesToAxiomNode(res, ax);
+ if (!hasContent(rnode))
+ return NULL;
+ return content(rnode);
+}
+
+/**
+ * Return a new service skeleton.
+ */
+const axis2_svc_skeleton_ops_t serviceOps = {
+ serviceInit,
+ serviceInvoke,
+ NULL,
+ serviceFree,
+ NULL
+};
+
+AXIS2_EXTERN axis2_svc_skeleton_t *AXIS2_CALL serviceSkeleton(const axutil_env_t* env) {
+ axis2_svc_skeleton_t* svc_skeleton = (axis2_svc_skeleton_t*)AXIS2_MALLOC(env->allocator, sizeof(axis2_svc_skeleton_t));
+ svc_skeleton->ops = &serviceOps;
+ svc_skeleton->func_array = NULL;
+ return svc_skeleton;
+}
+
+}
+}
+
+extern "C"
+{
+
+/**
+ * Axis2/C service entry point functions.
+ */
+AXIS2_EXPORT int axis2_get_instance(struct axis2_svc_skeleton** inst, const axutil_env_t* env) {
+ *inst = tuscany::webservice::serviceSkeleton(env);
+ if (inst == NULL)
+ return AXIS2_FAILURE;
+ return AXIS2_SUCCESS;
+}
+
+AXIS2_EXPORT int axis2_remove_instance(axis2_svc_skeleton_t* inst, const axutil_env_t* env) {
+ if (inst != NULL)
+ return AXIS2_SVC_SKELETON_FREE(inst, env);
+ return AXIS2_FAILURE;
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp
new file mode 100644
index 0000000000..d7c2f3b671
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test WebService Axis2 client support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+bool testEval() {
+ const Axis2Context ax;
+
+ const value func = "http://ws.apache.org/axis2/c/samples/echoString";
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+
+ const failable<value> rval = evalExpr(mklist<value>(func, arg, string("http://localhost:9090/axis2/services/echo")), ax);
+ assert(hasContent(rval));
+
+ const list<value> r = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples"))
+ + (list<value>() + "text" + string("Hello World!")));
+ assert(content(rval) == r);
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::webservice::testEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp
new file mode 100644
index 0000000000..c2886edb71
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_webservice_hpp
+#define tuscany_webservice_hpp
+
+/**
+ * Web service invocation functions using Axis2.
+ */
+#include "config.hpp"
+
+// Ignore redundant declarations in Axiom headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+#include <axiom.h>
+#include <axis2_client.h>
+#include <axis2_module.h>
+#include <axis2_addr_mod.h>
+#include <axis2_conf_ctx.h>
+#include <axis2_disp.h>
+#include <axis2_http_out_transport_info.h>
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wredundant-decls"
+#endif
+
+#include "string.hpp"
+#include "sstream.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "xml.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Represents an Axis2 runtime context.
+ */
+class Axis2Context {
+public:
+ Axis2Context() : env(axutil_env_create_all("axis2.log", AXIS2_LOG_LEVEL_WARNING)), owner(true) {
+ }
+
+ Axis2Context(const Axis2Context& ax) : env(ax.env), owner(false) {
+ }
+
+ Axis2Context(const axutil_env_t* env) : env(const_cast<axutil_env_t*>(env)), owner(false) {
+ }
+
+ ~Axis2Context() {
+ if (!owner || env == NULL)
+ return;
+ axutil_env_free(env);
+ }
+
+private:
+ axutil_env_t* env;
+ bool owner;
+
+ friend const axutil_env_t* env(const Axis2Context& ax);
+};
+
+const axutil_env_t* env(const Axis2Context& ax) {
+ return ax.env;
+}
+
+/**
+ * Return the latest Axis2 error in an Axis2 context.
+ */
+const string axis2Error(const Axis2Context& ax) {
+ ostringstream os;
+ os << env(ax)->error->error_number << " : " << AXIS2_ERROR_GET_MESSAGE(env(ax)->error);
+ return str(os);
+}
+
+/**
+ * Convert a string to an Axiom node.
+ */
+const failable<axiom_node_t*> stringToAxiomNode(const string& s, const Axis2Context& ax) {
+ axiom_node_t* node = axiom_node_create_from_buffer(env(ax), const_cast<axis2_char_t*>(c_str(s)));
+ if (node == NULL)
+ return mkfailure<axiom_node_t*>(string("Couldn't convert XML to Axiom node: ") + axis2Error(ax));
+ return node;
+}
+
+/**
+ * Convert a list of values representing XML elements to an Axiom node.
+ */
+const failable<axiom_node_t*> valuesToAxiomNode(const list<value>& l, const Axis2Context& ax) {
+ const failable<list<string> > xml = writeXML(valuesToElements(l), false);
+ if (!hasContent(xml))
+ return mkfailure<axiom_node_t*>(reason(xml));
+ ostringstream os;
+ write(content(xml), os);
+ return stringToAxiomNode(str(os), ax);
+}
+
+/**
+ * Convert an axiom node to a string.
+ */
+const failable<const string> axiomNodeToString(axiom_node_t* node, const Axis2Context& ax) {
+ const char* c = axiom_node_to_string(node, env(ax));
+ if (c == NULL)
+ return mkfailure<const string>(string("Couldn't convert Axiom node to XML: ") + axis2Error(ax));
+ const string s(c);
+ AXIS2_FREE(env(ax)->allocator, const_cast<char*>(c));
+ return s;
+}
+
+/**
+ * Convert an axiom node to a list of values representing XML elements.
+ */
+const failable<const list<value> > axiomNodeToValues(axiom_node_t* node, const Axis2Context& ax) {
+ const failable<const string> s = axiomNodeToString(node, ax);
+ if (!hasContent(s))
+ return mkfailure<const list<value> >(reason(s));
+ istringstream is(content(s));
+ const failable<const list<value> > l = readXML(streamList(is));
+ if (!hasContent(l))
+ return l;
+ return elementsToValues(content(l));
+}
+
+/**
+ * Evaluate an expression in the form (soap-action-string, document, uri). Send the
+ * SOAP action and document to the Web Service at the given URI using Axis2.
+ */
+const failable<value> evalExpr(const value& expr, const Axis2Context& ax) {
+ debug(expr, "webservice::evalExpr::input");
+
+ // Extract func name and single argument
+ const value func(car<value>(expr));
+ const list<value> param(cadr<value>(expr));
+ const value uri(caddr<value>(expr));
+
+ // Create Axis2 client
+ axis2_svc_client_t *client = axis2_svc_client_create(env(ax), getenv("AXIS2C_HOME"));
+ if (client == NULL)
+ return mkfailure<value>("Couldn't create Axis2 client: " + axis2Error(ax));
+ axis2_endpoint_ref_t *epr = axis2_endpoint_ref_create(env(ax), c_str(uri));
+ axis2_options_t *opt = axis2_options_create(env(ax));
+ axis2_options_set_to(opt, env(ax), epr);
+ axis2_options_set_action(opt, env(ax), (const axis2_char_t*)c_str(func));
+ axis2_svc_client_set_options(client, env(ax), opt);
+ axis2_svc_client_engage_module(client, env(ax), AXIS2_MODULE_ADDRESSING);
+
+ // Construct request Axiom node
+ const failable<axiom_node_t*> req = valuesToAxiomNode(param, ax);
+ if (!hasContent(req))
+ return mkfailure<value>(reason(req));
+
+ // Call the Web service
+ axiom_node_t* res = axis2_svc_client_send_receive(client, env(ax), content(req));
+ if (res == NULL) {
+ axis2_svc_client_free(client, env(ax));
+ return mkfailure<value>("Couldn't invoke Axis2 service: " + axis2Error(ax));
+ }
+
+ // Parse result Axiom node
+ const failable<const list<value> > lval = axiomNodeToValues(res, ax);
+ if (!hasContent(lval))
+ return mkfailure<value>(reason(lval));
+ const value rval = content(lval);
+ debug(rval, "webservice::evalExpr::result");
+
+ // Cleanup
+ axis2_svc_client_free(client, env(ax));
+
+ return rval;
+}
+
+}
+}
+
+#endif /* tuscany_webservice_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml
new file mode 100644
index 0000000000..ea9b6d2194
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml
@@ -0,0 +1,148 @@
+<!--
+ 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.
+-->
+<axisconfig name="Axis2/C">
+ <!-- ================================================= -->
+ <!-- Parameters -->
+ <!-- ================================================= -->
+ <!-- Uncomment following to enable MTOM support globally -->
+ <!--parameter name="enableMTOM" locked="false">true</parameter-->
+
+ <!-- Set the suitable size for optimum memory usage when sending large attachments -->
+ <!--parameter name="MTOMBufferSize" locked="false">10</parameter-->
+ <!--parameter name="MTOMMaxBuffers" locked="false">1000</parameter-->
+ <!--parameter name="EnableMTOMServiceCallback" locked="false">true</parameter-->
+ <!--parameter name="attachmentDIR" locked="false">/path/to/the/attachment/caching/dir/</parameter-->
+ <!--parameter name="MTOMCachingCallback" locked="false">/path/to/the/caching_callback</parameter-->
+ <!--parameter name="MTOMSendingCallback" locked="false">/path/to/the/sending_callback</parameter-->
+
+ <!-- Enable REST -->
+ <parameter name="enableREST" locked="false">true</parameter>
+
+ <!-- Uncomment following to persist op_ctx, useful with RM -->
+ <!--parameter name="persistOperationContext" locked="false">true</parameter-->
+
+ <!--if you want to extract the service archive file and work with that please uncomment this-->
+ <!--else , it wont extract archive file or does not take into consideration if someone drop-->
+ <!--exploded directory into /service directory-->
+ <!--<parameter name="extractServiceArchive" locked="false">true</parameter>-->
+
+
+ <!-- ================================================= -->
+ <!-- Message Receivers -->
+ <!-- ================================================= -->
+ <!-- This is the Deafult Message Receiver for the Request Response style Operations -->
+ <!--messageReceiver mep="INOUT" class="axis2_receivers"/-->
+
+
+ <!-- ================================================= -->
+ <!-- Transport Ins -->
+ <!-- ================================================= -->
+
+ <transportReceiver name="http" class="axis2_http_receiver">
+ <parameter name="port" locked="false">6060</parameter>
+ <parameter name="exposeHeaders" locked="true">false</parameter>
+ </transportReceiver>
+
+ <!--transportReceiver name="https" class="axis2_http_receiver">
+ <parameter name="port" locked="false">6060</parameter>
+ <parameter name="exposeHeaders" locked="true">false</parameter>
+ </transportReceiver-->
+
+ <!--transportReceiver name="tcp" class="axis2_tcp_receiver">
+ <parameter name="port" locked="false">6060</parameter>
+ </transportReceiver-->
+
+
+ <!-- ================================================= -->
+ <!-- Transport Outs -->
+ <!-- ================================================= -->
+
+ <transportSender name="http" class="axis2_http_sender">
+ <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>
+ <parameter name="xml-declaration" insert="false"/>
+ <!--parameter name="Transfer-Encoding">chunked</parameter-->
+ <!--parameter name="HTTP-Authentication" username="" password="" locked="true"/-->
+ <!--parameter name="PROXY" proxy_host="127.0.0.1" proxy_port="8080" proxy_username="" proxy_password="" locked="true"/-->
+ </transportSender>
+
+ <!-- Uncomment the following with appropriate parameters to enable the SSL transport sender.
+ Also make sure that the appropriate transport receiver is enabled above.-->
+ <!--transportSender name="https" class="axis2_http_sender">
+ <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>
+ <parameter name="xml-declaration" insert="false"/>
+ </transportSender>
+ <parameter name="SERVER_CERT">/path/to/ca/certificate</parameter>
+ <parameter name="KEY_FILE">/path/to/client/certificate/chain/file</parameter>
+ <parameter name="SSL_PASSPHRASE">passphrase</parameter>
+ -->
+
+ <!-- Uncomment this one with the appropriate papameters to enable the TCP transport Sender-->
+ <!--transportSender name="tcp" class="axis2_tcp_sender">
+ <parameter name="PROTOCOL" locked="false">TCP</parameter>
+ <parameter name="xml-declaration" insert="false"/>
+ </transportSender-->
+
+
+ <!-- ================================================= -->
+ <!-- Global Modules -->
+ <!-- ================================================= -->
+ <!-- Comment this to disable Addressing -->
+ <module ref="addressing"/>
+
+ <!-- Tuscany dispatcher module -->
+ <module ref="tuscany"/>
+
+ <!--Configuring module , providing paramters for modules whether they refer or not-->
+ <!--<moduleConfig name="addressing">-->
+ <!--<parameter name="addressingPara" locked="false">N/A</parameter>-->
+ <!--</moduleConfig>-->
+
+ <!-- ================================================= -->
+ <!-- Phases -->
+ <!-- ================================================= -->
+ <phaseOrder type="inflow">
+ <!-- System pre defined phases -->
+ <phase name="Transport"/>
+ <phase name="PreDispatch"/>
+ <phase name="Dispatch"/>
+ <phase name="PostDispatch"/>
+ <!--phase name="Security"/-->
+ <!-- End system pre defined phases -->
+ <!-- After PostDispatch phase, module or service author can add any phase as required -->
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ </phaseOrder>
+ <phaseOrder type="outflow">
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ <!--system predefined phase-->
+ <phase name="MessageOut"/>
+ <!--phase name="Security"/-->
+ </phaseOrder>
+ <phaseOrder type="INfaultflow">
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ </phaseOrder>
+ <phaseOrder type="Outfaultflow">
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ <phase name="MessageOut"/>
+ </phaseOrder>
+</axisconfig>
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp
new file mode 100644
index 0000000000..658c87e2fc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Web service component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+
+bool testModAxis2() {
+ const Axis2Context ax;
+
+ const value func = "http://ws.apache.org/axis2/c/samples/echoString";
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+
+ const failable<value> rval = evalExpr(mklist<value>(func, arg, string("http://localhost:8090/echo-listener")), ax);
+ assert(hasContent(rval));
+
+ const list<value> r = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+ assert(content(rval) == r);
+
+ return true;
+}
+
+bool testEval() {
+ http::CURLSession cs("", "", "");
+
+ const value func = "http://ws.apache.org/axis2/c/samples/echoString";
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+
+ const failable<value> rval = http::evalExpr(mklist<value>(func, arg), "http://localhost:8090/echo-client", cs);
+ assert(hasContent(rval));
+
+ const list<value> r = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples"))
+ + (list<value>() + "text" + string("Hello World!")));
+ assert(content(rval) == r);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::webservice::testModAxis2();
+ tuscany::webservice::testEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/echo-test b/sandbox/sebastien/cpp/apr-2/components/webservice/echo-test
new file mode 100755
index 0000000000..e5cd1d9a9d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/echo-test
@@ -0,0 +1,37 @@
+#!/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
+# 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.
+
+# Setup
+axis2_prefix=`cat axis2c.prefix`
+export AXIS2C_HOME=$axis2_prefix
+axis2="$axis2_prefix/bin/axis2_http_server"
+pwd=`pwd`
+cd "$axis2_prefix/bin"
+$axis2 &
+cd $pwd
+sleep 1
+
+# Test
+./axis2-test 2>/dev/null
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "$axis2" | awk '{ print $2 }'`
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/module.xml b/sandbox/sebastien/cpp/apr-2/components/webservice/module.xml
new file mode 100644
index 0000000000..8f6ba5018f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/module.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<module name="tuscany" class="axis2-dispatcher">
+ <inflow>
+ <handler name="TuscanyDispatcher" class="axis2-dispatcher">
+ <order phase="Dispatch"/>
+ </handler>
+ </inflow>
+</module>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/server-test b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test
new file mode 100755
index 0000000000..34fdb7266a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test
@@ -0,0 +1,49 @@
+#!/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
+# 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.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+./axis2-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite webservice.composite
+EOF
+
+../../modules/http/httpd-start tmp
+
+axis2_prefix=`cat axis2c.prefix`
+export AXIS2C_HOME=$axis2_prefix
+axis2="$axis2_prefix/bin/axis2_http_server"
+pwd=`pwd`
+cd "$axis2_prefix/bin"
+$axis2 &
+cd $pwd
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "${axis2}" | awk '{ print $2 }'`
+../../modules/http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm
new file mode 100644
index 0000000000..44e4eee92a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm
@@ -0,0 +1,21 @@
+; 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.
+
+; Web service test case
+
+(define (echoString x) x)
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/services.xml b/sandbox/sebastien/cpp/apr-2/components/webservice/services.xml
new file mode 100644
index 0000000000..0adf136f4f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/services.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+<serviceGroup>
+<service name="TuscanyService">
+ <parameter name="ServiceClass" locked="xsd:false">axis2-service</parameter>
+ <operation name="execute"/>
+</service>
+</serviceGroup>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType
new file mode 100644
index 0000000000..043087fe98
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="client"/>
+ <property name="uri" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp
new file mode 100644
index 0000000000..06db6c01b8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Web service client component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Apply a function provided by a remote Web service using Axis2.
+ */
+const failable<value> apply(const value& func, const list<value>& params) {
+ const Axis2Context ax;
+
+ // Extract parameters
+ const value doc = car<value>(params);
+ const lambda<value(const list<value>&)> l = cadr<value>(params);
+
+ // Call the URI property lambda function to get the configured URI
+ const value uri = l(list<value>());
+
+ // Evaluate using Axis2
+ return evalExpr(mklist<value>(func, doc, uri), ax);
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::mkfailure<tuscany::value>();
+ return tuscany::webservice::apply(func, cdr(params));
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType
new file mode 100644
index 0000000000..ecd46b3c90
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="service"/>
+ <reference name="relay"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp
new file mode 100644
index 0000000000..2127ecf0df
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Web service listener component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/http/httpd.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Redirect an HTTP request to the Axis2/C HTTPD module. The given relay lambda function
+ * is stored in the HTTPD request, for later retrieval by the Axis2 service to relay the request
+ * to a target component.
+ */
+extern "C" {
+ extern module axis2_module;
+}
+
+const value redirectToAxis2(const string& uri, request_rec* r, const value& relay) {
+ const failable<request_rec*, int> nr = httpd::internalRedirectRequest(uri, r);
+ if (!hasContent(nr))
+ return value(reason(nr));
+ ap_set_module_config(content(nr)->request_config, &axis2_module, const_cast<void*>((const void*)&relay));
+ return value(httpd::internalRedirect(content(nr)));
+}
+
+/**
+ * Handle an HTTP request.
+ */
+const failable<value> handle(const list<value>& params) {
+
+ // Extract HTTPD request from the params
+ request_rec* r = httpd::request(car(params));
+ httpdDebugRequest(r, "webservice::handle");
+
+ // Extract the relay lambda from the params and store it in the HTTPD request,
+ // for later retrieval by our Axis2 service
+ const value relay = cadr(params);
+ cout << "relay: " << &relay << endl;
+
+ // Redirect HTTPD request to Mod-axis2
+ if (r->args == NULL)
+ return redirectToAxis2(httpd::redirectURI("/axis2", string(r->uri)), r, relay);
+ return redirectToAxis2(httpd::redirectURI("/axis2", string(r->uri), string(r->args)), r, relay);
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "handle")
+ return tuscany::webservice::handle(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite
new file mode 100644
index 0000000000..0169f5eb3a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="webservice">
+
+ <component name="webservice-client">
+ <implementation.cpp path="." library="libwebservice-client"/>
+ <property name="uri">http://localhost:9090/axis2/services/echo</property>
+ <service name="webservice-client">
+ <t:binding.jsonrpc uri="echo-client"/>
+ </service>
+ </component>
+
+ <component name="webservice-listener">
+ <implementation.cpp path="." library="libwebservice-listener"/>
+ <service name="webservice-listener">
+ <t:binding.http uri="echo-listener"/>
+ </service>
+ <reference name="relay" target="echo"/>
+ </component>
+
+ <component name="echo">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="echo">
+ <t:binding.jsonrpc uri="echo"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/configure.ac b/sandbox/sebastien/cpp/apr-2/configure.ac
new file mode 100644
index 0000000000..1d53d1dacd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/configure.ac
@@ -0,0 +1,928 @@
+# 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.
+
+dnl run autogen.sh to generate the configure script.
+
+AC_PREREQ(2.59)
+AC_INIT(tuscany-sca, 1.0, dev@tuscany.apache.org)
+AC_CONFIG_MACRO_DIR([m4])
+AC_CANONICAL_SYSTEM
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE([tar-ustar])
+AC_PREFIX_DEFAULT(/usr/local/tuscany/sca)
+
+# Check for required programs.
+AC_MSG_NOTICE([checking for programs])
+AC_MSG_CHECKING([for gcc-4.5])
+if test -x "/usr/bin/g++-4.5"; then
+ # Use GCC 4.5 if available
+ CXX=/usr/bin/g++-4.5
+ CPP=/usr/bin/cpp-4.5
+ CC=/usr/bin/gcc-4.5
+ AC_MSG_RESULT(/usr/bin/gcc-4.5)
+ AM_CONDITIONAL([WANT_GCC45], true)
+ AC_DEFINE([WANT_GCC45], 1, [compile with gcc-4.5])
+else
+ AM_CONDITIONAL([WANT_GCC45], false)
+fi
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_LIBTOOL
+
+# Initialize default GCC C++ and LD options.
+cxxflags=""
+ldflags="${LDFLAGS}"
+defaultlibs="${LIBS}"
+
+# Configure TUSCANY_SCACPP path variable.
+TUSCANY_SCACPP=`echo "${TUSCANY_SCACPP}"`
+if test "${TUSCANY_SCACPP}" = ""; then
+ pwd=`pwd`
+ AC_SUBST([TUSCANY_SCACPP], ["${pwd}"])
+fi
+
+# Check for required header files.
+AC_MSG_NOTICE([checking for header files])
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS([string.h sys/time.h])
+
+# Check for typedefs, structures, and compiler characteristics.
+AC_MSG_NOTICE([checking for typedefs, structures, and compiler characteristics])
+AC_HEADER_STDBOOL
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+
+# Check for required library functions.
+AC_MSG_NOTICE([checking for library functions])
+AC_CHECK_FUNCS([gettimeofday select])
+
+# Check for running on Darwin.
+AC_MSG_CHECKING([if running on Darwin])
+UNAME=`uname -s`
+if test "${UNAME}" = "Darwin"; then
+ AC_DEFINE([IS_DARWIN], 1, [running on Darwin])
+ AC_MSG_RESULT(yes)
+ AC_SUBST([libsuffix],[".dylib"])
+ AM_CONDITIONAL([DARWIN], true)
+else
+ AC_MSG_RESULT(no)
+ AC_SUBST([libsuffix],[".so"])
+ AM_CONDITIONAL([DARWIN], false)
+fi
+
+# Enable debugging and compile-time warnings.
+AC_MSG_CHECKING([whether to compile with debugging and compile-time warnings])
+AC_ARG_ENABLE(maintainer-mode, [AS_HELP_STRING([--enable-maintainer-mode], [compile with debugging and compile-time warnings [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_maintainer_mode=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_maintainer_mode}" = "true"; then
+ cxxflags="${cxxflags} -D_DEBUG -O0 -ggdb -g3 -Werror -Wall -Wextra -Wno-ignored-qualifiers -Winit-self -Wmissing-include-dirs -Wcast-qual -Wcast-align -Wwrite-strings -Wpointer-arith -Wconversion -Waddress -Wlogical-op -Wredundant-decls -std=c++0x -fmessage-length=0"
+ ldflags="${ldflags} -pg"
+ AM_CONDITIONAL([WANT_MAINTAINER_MODE], true)
+ AC_DEFINE([WANT_MAINTAINER_MODE], 1, [compile with debugging and compile-time warnings])
+else
+ cxxflags="${cxxflags} -O3 -std=c++0x -fmessage-length=0"
+ AM_CONDITIONAL([WANT_MAINTAINER_MODE], false)
+fi
+
+# Enable profiling with gprof.
+AC_MSG_CHECKING([whether to compile with profiling])
+AC_ARG_ENABLE(profiling, [AS_HELP_STRING([--enable-profiling], [compile with profiling [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_profiling=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_profiling}" = "true"; then
+ cxxflags="${cxxflags} -pg"
+ ldflags="${ldflags} -pg"
+ AM_CONDITIONAL([WANT_PROFILING], true)
+ AC_DEFINE([WANT_PROFILING], 1, [compile with profiling])
+else
+ AM_CONDITIONAL([WANT_PROFILING], false)
+fi
+
+# Enable multi-threading support.
+AC_MSG_CHECKING([whether to compile for multi-threaded execution])
+AC_ARG_ENABLE(threads, [AS_HELP_STRING([--enable-threads], [compile for multi-threaded execution [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_threads=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_threads}" = "true"; then
+ AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR([couldn't find a suitable libpthread])])
+ LIBS="${defaultlibs}"
+ cxxflags="${cxxflags} -D_REENTRANT"
+ ldflags="${ldflags} -lpthread"
+ AM_CONDITIONAL([WANT_THREADS], true)
+ AC_DEFINE([WANT_THREADS], 1, [compile for multi-threaded execution])
+else
+ AM_CONDITIONAL([WANT_THREADS], false)
+fi
+
+# Configure exuberant ctags.
+TAGSFILE="`pwd`/tags"
+AC_SUBST([CTAGSFLAGS], ["${CTAGSFLAGS} --c++-kinds=+p --fields=+iaS --extra=+q --append --tag-relative=yes -f ${TAGSFILE}"])
+
+# Enable Doxygen documentation.
+AC_MSG_CHECKING([whether to build Doxygen documentation])
+AC_ARG_ENABLE(doxygen, [AS_HELP_STRING([--enable-doxygen], [build Doxygen documentation [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_doxygen=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_doxygen}" = "true"; then
+ AC_PATH_PROG(DOXYGEN, doxygen, , ${PATH})
+ if test "${DOXYGEN}" = ""; then
+ AC_MSG_ERROR([could not find doxygen])
+ fi
+ AM_CONDITIONAL([WANT_DOXYGEN], true)
+ AC_DEFINE([WANT_DOXYGEN], 1, [build Doxygen documentation])
+else
+ AM_CONDITIONAL([WANT_DOXYGEN], false)
+fi
+
+# Configure path to CURL.
+AC_MSG_CHECKING([for curl])
+AC_ARG_WITH([curl], [AC_HELP_STRING([--with-curl=PATH], [path to installed curl [default=/usr]])], [
+ CURL_PREFIX="${withval}"
+ LIBCURL_INCLUDE="${withval}/include"
+ LIBCURL_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+], [
+ CURL_PREFIX="/usr"
+ LIBCURL_INCLUDE="/usr/include"
+ LIBCURL_LIB="/usr/lib"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(CURL_PREFIX)
+AC_SUBST(LIBCURL_INCLUDE)
+AC_SUBST(LIBCURL_LIB)
+LIBS="-L${LIBCURL_LIB} ${defaultlibs}"
+AC_CHECK_LIB([curl], [curl_global_init], [], [AC_MSG_ERROR([couldn't find a suitable libcurl, use --with-libcurl=PATH])])
+
+# Configure path to libxml2 includes and lib.
+AC_MSG_CHECKING([for libxml2])
+AC_ARG_WITH([libxml2], [AC_HELP_STRING([--with-libxml2=PATH], [path to installed libxml2 [default=/usr]])], [
+ LIBXML2_INCLUDE="${withval}/include/libxml2"
+ LIBXML2_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+], [
+ LIBXML2_INCLUDE="/usr/include/libxml2"
+ LIBXML2_LIB="/usr/lib"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(LIBXML2_INCLUDE)
+AC_SUBST(LIBXML2_LIB)
+LIBS="-L${LIBXML2_LIB} ${defaultlibs}"
+AC_CHECK_LIB([xml2], [xmlInitParser], [], [AC_MSG_ERROR([couldn't find a suitable libxml2, use --with-libxml2=PATH])])
+
+# Configure path to libmozjs includes and lib.
+AC_MSG_CHECKING([for js-include])
+xulrunner=`ls /usr/include | grep "xulrunner" | tail -1`
+if test "$xulrunner" = ""; then
+ xulrunner="xulrunner-1.9.1.8"
+fi
+xulunstable=`ls /usr/include/$xulrunner | grep "unstable"`
+if test "$xulunstable" = ""; then
+ xulinclude="$xulrunner"
+else
+ xulinclude="$xulrunner/unstable"
+fi
+AC_ARG_WITH([js-include], [AC_HELP_STRING([--with-js-include=PATH], [path to installed SpiderMonkey include dir
+ [default=/usr/include/$xulinclude]])], [
+ JS_INCLUDE="${withval}"
+ AC_MSG_RESULT("${withval}")
+], [
+ JS_INCLUDE="/usr/include/$xulinclude"
+ AC_MSG_RESULT(/usr/include/$xulinclude)
+])
+AC_MSG_CHECKING([for js-lib])
+AC_ARG_WITH([js-lib], [AC_HELP_STRING([--with-js-lib=PATH], [path to installed SpiderMonkey lib dir [default=/usr/lib/$xulrunner]])], [
+ JS_LIB="${withval}"
+ AC_MSG_RESULT("${withval}")
+], [
+ JS_LIB="/usr/lib/$xulrunner"
+ AC_MSG_RESULT(/usr/lib/$xulrunner)
+])
+AC_SUBST(JS_INCLUDE)
+AC_SUBST(JS_LIB)
+LIBS="-L${JS_LIB} ${defaultlibs}"
+AC_CHECK_LIB([mozjs], [JS_NewContext], [], [AC_MSG_ERROR([couldn't find a suitable libmozjs, use --with-js-lib=PATH])])
+
+# Configure path to Apache APR and HTTPD includes and libs.
+AC_MSG_CHECKING([for apr])
+AC_ARG_WITH([apr], [AC_HELP_STRING([--with-apr=PATH], [path to installed Apache APR [default=/usr]])], [
+ APR_INCLUDE="${withval}/include"
+ APR_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+], [
+ APR_INCLUDE="/usr/include/apr-1.0"
+ APR_LIB="/usr/lib"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(APR_INCLUDE)
+AC_SUBST(APR_LIB)
+LIBS="-L${APR_LIB} ${defaultlibs}"
+AC_CHECK_LIB([apr-1], [apr_pool_initialize], [], [AC_MSG_ERROR([couldn't find a suitable libapr-1, use --with-apr=PATH])])
+
+AC_MSG_CHECKING([for httpd])
+AC_ARG_WITH([httpd], [AC_HELP_STRING([--with-httpd=PATH], [path to installed Apache HTTPD [default=/usr]])], [
+ HTTPD_PREFIX="${withval}"
+ HTTPD_APACHECTL_PREFIX="${withval}/bin/apachectl"
+ HTTPD_MODULES_PREFIX="${withval}"
+ HTTPD_INCLUDE="${withval}/include"
+ AC_MSG_RESULT("${withval}")
+], [
+ HTTPD_PREFIX="/usr"
+ HTTPD_APACHECTL_PREFIX="/usr/sbin/apache2ctl"
+ HTTPD_MODULES_PREFIX="/usr/lib/apache2"
+ HTTPD_INCLUDE="/usr/include/apache2"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(HTTPD_PREFIX)
+AC_SUBST(HTTPD_APACHECTL_PREFIX)
+AC_SUBST(HTTPD_MODULES_PREFIX)
+AC_SUBST(HTTPD_INCLUDE)
+AC_MSG_CHECKING([for ${APACHECTL_PREFIX}])
+if test -x "${HTTPD_APACHECTL_PREFIX}"; then
+ AC_MSG_RESULT(found)
+else
+ AC_MSG_ERROR([couldn't find apachectl, use --with-httpd=PATH])
+fi
+AC_MSG_CHECKING([for ${HTTPD_PREFIX}/bin/htpasswd])
+if test -x "${HTTPD_PREFIX}/bin/htpasswd"; then
+ AC_MSG_RESULT(found)
+else
+ AC_MSG_ERROR([couldn't find htpasswd, use --with-httpd=PATH])
+fi
+
+# Configure path to memcached.
+AC_MSG_CHECKING([for memcached])
+AC_ARG_WITH([memcached], [AC_HELP_STRING([--with-memcached=PATH], [path to installed memcached [default=/usr]])], [
+ MEMCACHED_PREFIX="${withval}"
+ AC_MSG_RESULT("${withval}")
+], [
+ MEMCACHED_PREFIX="/usr"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(MEMCACHED_PREFIX)
+AC_MSG_CHECKING([for ${MEMCACHED_PREFIX}/bin/memcached])
+if test -x "${MEMCACHED_PREFIX}/bin/memcached"; then
+ AC_MSG_RESULT(found)
+else
+ AC_MSG_ERROR([couldn't find memcached, use --with-memcached=PATH])
+fi
+
+# Configure path to tinycdb.
+AC_MSG_CHECKING([for tinycdb])
+AC_ARG_WITH([tinycdb], [AC_HELP_STRING([--with-tinycdb=PATH], [path to installed tinycdb [default=/usr]])], [
+ TINYCDB_PREFIX="${withval}"
+ TINYCDB_INCLUDE="${withval}/include"
+ TINYCDB_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+], [
+ TINYCDB_PREFIX="/usr"
+ TINYCDB_INCLUDE="/usr/include"
+ TINYCDB_LIB="/usr/lib"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(TINYCDB_PREFIX)
+AC_SUBST(TINYCDB_INCLUDE)
+AC_SUBST(TINYCDB_LIB)
+LIBS="-L${TINYCDB_LIB} ${defaultlibs}"
+AC_CHECK_LIB([cdb], [cdb_make_start], [], [AC_MSG_ERROR([couldn't find a suitable libcdb, use --with-tinycdb=PATH])])
+
+# Configure default includes and ldflags
+cxxflags="${cxxflags} ${INCLUDES} -I. -I${TUSCANY_SCACPP}/kernel -I${APR_INCLUDE} -I${HTTPD_INCLUDE} -I${LIBXML2_INCLUDE} -I${JS_INCLUDE} -I${LIBCURL_INCLUDE}"
+ldflags="${ldflags} -ldl -L${APR_LIB} -R${APR_LIB} -lapr-1 -laprutil-1"
+ldflags="${ldflags} -L${LIBCURL_LIB} -R${LIBCURL_LIB} -L${JS_LIB} -R${JS_LIB} -L${LIBXML2_LIB} -R${LIBXML2_LIB}"
+
+# Enable Python 2.6 support.
+AC_MSG_CHECKING([whether to enable Python support])
+AC_ARG_ENABLE(python, [AS_HELP_STRING([--enable-python], [enable Python support [default=yes]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_python=true
+ ;;
+ esac ],
+[
+ AC_MSG_RESULT(yes)
+ want_python=true
+])
+if test "${want_python}" = "true"; then
+
+ # Configure path to Python 2.6 includes and lib.
+ AC_MSG_CHECKING([for python])
+ AC_ARG_WITH([python], [AC_HELP_STRING([--with-python=PATH], [path to installed Python 2.6 [default=/usr]])], [
+ PYTHON_PREFIX="${withval}"
+ PYTHON_INCLUDE="${withval}/include"
+ PYTHON_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ PYTHON_PREFIX="/usr"
+ PYTHON_INCLUDE="/usr/include"
+ PYTHON_LIB="/usr/lib"
+ AC_MSG_RESULT(/usr)
+ ])
+ AC_SUBST(PYTHON_PREFIX)
+ AC_SUBST(PYTHON_INCLUDE)
+ AC_SUBST(PYTHON_LIB)
+ LIBS="-L${PYTHON_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([python2.6], [Py_Initialize], [], [AC_MSG_ERROR([couldn't find a suitable libpython2.6, use --with-python=PATH])])
+
+ AM_CONDITIONAL([WANT_PYTHON], true)
+ AC_DEFINE([WANT_PYTHON], 1, [enable Python support])
+
+else
+ AM_CONDITIONAL([WANT_PYTHON], false)
+fi
+
+# Enable Java support.
+AC_MSG_CHECKING([whether to enable Java support])
+AC_ARG_ENABLE(java, [AS_HELP_STRING([--enable-java], [enable Java support [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_java=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_java}" = "true"; then
+
+ # Configure path to Java includes and lib.
+ AC_MSG_CHECKING([for java])
+ AC_ARG_WITH([java], [AC_HELP_STRING([--with-java=PATH], [path to installed Java [default=/usr/lib/jvm/default-java]])], [
+ JAVA_PREFIX="${withval}"
+ JAVA_INCLUDE="${withval}/include"
+ JAVAC="${withval}/bin/javac"
+ JAR="${withval}/bin/jar"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ JAVA_PREFIX="/usr/lib/jvm/default-java"
+ JAVA_INCLUDE="/usr/lib/jvm/default-java/include"
+ JAVAC="/usr/lib/jvm/default-java/bin/javac"
+ JAR="/usr/lib/jvm/default-java/bin/jar"
+ AC_MSG_RESULT(/usr/lib/jvm/default-java)
+ ])
+ AC_SUBST(JAVA_PREFIX)
+ AC_SUBST(JAVA_INCLUDE)
+ AC_SUBST(JAVAC)
+ AC_SUBST(JAR)
+
+ # Detect most common Java VMs
+ JAVA_LIBJAVA_SO=`find ${JAVA_PREFIX}/jre/lib -name libjava.so`
+ if test "${JAVA_LIBJAVA_SO}" != ""; then
+ JAVA_LIBJAVA=`dirname "${JAVA_LIBJAVA_SO}"`
+ JAVA_LIBJVM_SO=`find ${JAVA_PREFIX}/jre/lib -name libjvm.so`
+ JAVA_J9_VM=`echo "${JAVA_LIBJVM}" | grep "j9vm"`
+ if test "${JAVA_J9_VM}" != ""; then
+ # IBM J9 VM
+ AC_MSG_NOTICE([checking for J9 Java VM])
+ JAVA_LIBJVM=`dirname "${JAVA_LIBJVM_SO}"`
+ JAVA_CHECK_LIB="-L${JAVA_LIBJAVA} -R${JAVA_LIBJAVA} -L${JAVA_LIBJVM} -R${JAVA_LIBJVM}"
+ LIBS="${JAVA_CHECK_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([java], [JNI_CreateJavaVM], [JAVA_LDFLAGS="${JAVA_CHECK_LIB} -ljava -ljvm -ljsig"], [], [-ljvm -ljsig])
+ if test "${JAVA_LDFLAGS}" != ""; then
+ AC_DEFINE([JAVA_J9_VM], 1, [J9 Java VM])
+ fi
+ else
+ # SUN JDK or OpenJDK VM
+ AC_MSG_NOTICE([checking for OpenJDK Java VM])
+ JAVA_LIBJVM_SO=`find ${JAVA_PREFIX}/jre/lib -name libjvm.so | grep server`
+ JAVA_LIBJVM=`dirname "${JAVA_LIBJVM_SO}"`
+ AC_MSG_NOTICE([libjava ${JAVA_LIBJAVA} libjvm ${LIBJVM}])
+ JAVA_CHECK_LIB="-L${JAVA_LIBJAVA} -R${JAVA_LIBJAVA} -L${JAVA_LIBJVM} -R${JAVA_LIBJVM}"
+ LIBS="${JAVA_CHECK_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([java], [JNI_CreateJavaVM], [JAVA_LDFLAGS="${JAVA_CHECK_LIB} -ljava -ljvm -lverify"], [], [-ljvm -lverify])
+ if test "${JAVA_LDFLAGS}" != ""; then
+ AC_DEFINE([JAVA_OPENJDK_VM], 1, [OpenJDK Java VM])
+ fi
+ fi
+ else
+ JAVA_LIBHARMONYVM_SO=`find ${JAVA_PREFIX}/jre/bin -name libharmonyvm.so`
+ if test "${JAVA_LIBHARMONYVM_SO}" != ""; then
+ # Apache Harmony VM
+ JAVA_LIBHARMONYVM=`dirname "${JAVA_LIBHARMONYVM_SO}"`
+ JAVA_LIBJAVA=`dirname "${JAVA_LIBHARMONYVM}"`
+ AC_MSG_NOTICE([checking for Apache Harmony Java VM])
+ JAVA_CHECK_LIB="-L${JAVA_LIBJAVA} -R${JAVA_LIBJAVA} -L${JAVA_LIBHARMONYVM} -R${JAVA_LIBHARMONYVM}"
+ LIBS="${JAVA_CHECK_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([harmonyvm], [JNI_CreateJavaVM], [JAVA_LDFLAGS="${JAVA_CHECK_LIB} -lharmonyvm -lhythr -licuuc -lch ${JAVA_LIBHARMONYVM}/libicudata.so.34"], [], [-lhythr -licuuc -lch ${JAVA_LIBHARMONYVM}/libicudata.so.34])
+ if test "${JAVA_LDFLAGS}" != ""; then
+ AC_DEFINE([JAVA_HARMONY_VM], 1, [Apache Harmony Java VM])
+ fi
+ fi
+ fi
+ if test "${JAVA_LDFLAGS}" = ""; then
+ AC_MSG_ERROR([couldn't find a suitable Java JNI library, use --with-java=PATH])
+ fi
+ AC_MSG_CHECKING([for javac])
+ if test -x "${JAVAC}"; then
+ AC_MSG_RESULT("${JAVAC}")
+ else
+ AC_MSG_ERROR([couldn't find a suitable javac tool, use --with-java=PATH])
+ fi
+ AC_MSG_CHECKING([for jar])
+ if test -x "${JAR}"; then
+ AC_MSG_RESULT("${JAR}")
+ else
+ AC_MSG_ERROR([couldn't find a suitable jar tool, use --with-java=PATH])
+ fi
+ AM_CONDITIONAL([WANT_JAVA], true)
+ AC_DEFINE([WANT_JAVA], 1, [enable Java support])
+else
+ AM_CONDITIONAL([WANT_JAVA], false)
+ JAVA_LDFLAGS=""
+fi
+AC_SUBST(JAVA_LDFLAGS)
+
+# Enable support for OpenID.
+AC_MSG_CHECKING([whether to enable OpenID support])
+AC_ARG_ENABLE(openid, [AS_HELP_STRING([--enable-openid], [enable OpenID support [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_openid=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_openid}" = "true"; then
+
+ # Configure path to mod-auth-openid
+ AC_MSG_CHECKING([for mod-auth-openid])
+ AC_ARG_WITH([mod-auth-openid], [AC_HELP_STRING([--with-mod-auth-openid=PATH], [path to installed mod-auth-openid [default=/usr]])], [
+ MODAUTHOPENID_PREFIX="${withval}"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ MODAUTHOPENID_PREFIX="/usr/local/"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(MODAUTHOPENID_PREFIX)
+
+ AM_CONDITIONAL([WANT_OPENID], true)
+ AC_DEFINE([WANT_OPENID], 1, [enable OpenID support])
+
+else
+ AM_CONDITIONAL([WANT_OPENID], false)
+fi
+
+# Enable support for OAuth.
+AC_MSG_CHECKING([whether to enable OAuth support])
+AC_ARG_ENABLE(oauth, [AS_HELP_STRING([--enable-oauth], [enable OAuth support [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_oauth=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_oauth}" = "true"; then
+
+ # Configure path to Liboauth includes and lib.
+ AC_MSG_CHECKING([for liboauth])
+ AC_ARG_WITH([liboauth], [AC_HELP_STRING([--with-liboauth=PATH], [path to liboauth [default=/usr/local]])], [
+ LIBOAUTH_INCLUDE="${withval}/include"
+ LIBOAUTH_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ LIBOAUTH_INCLUDE="/usr/local/include"
+ LIBOAUTH_LIB="/usr/local/lib"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(LIBOAUTH_INCLUDE)
+ AC_SUBST(LIBOAUTH_LIB)
+ LIBS="-L${LIBOAUTH_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([oauth], [oauth_sign_url2], [], [AC_MSG_ERROR([couldn't find a suitable liboauth, use --with-liboauth=PATH])], [-lssl])
+
+ AM_CONDITIONAL([WANT_OAUTH], true)
+ AC_DEFINE([WANT_OAUTH], 1, [enable OAuth support])
+
+else
+ AM_CONDITIONAL([WANT_OAUTH], false)
+fi
+
+# Enable support for Google AppEngine.
+AC_MSG_CHECKING([whether to enable Google AppEngine support])
+AC_ARG_ENABLE(gae, [AS_HELP_STRING([--enable-gae], [enable Google AppEngine support [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_gae=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_gae}" = "true"; then
+
+ # Configure path to Google AppEngine SDK.
+ AC_MSG_CHECKING([for gae])
+ AC_ARG_WITH([gae], [AC_HELP_STRING([--with-gae=PATH], [path to installed Google AppEngine 1.3.2 [default=${HOME}/google_appengine]])], [
+ GAE_PREFIX="${withval}"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ GAE_PREFIX="${HOME}/google_appengine"
+ AC_MSG_RESULT(${HOME}/google_appengine)
+ ])
+ AC_SUBST(GAE_PREFIX)
+
+ AM_CONDITIONAL([WANT_GAE], true)
+ AC_DEFINE([WANT_GAE], 1, [enable Google AppEngine support])
+else
+ AM_CONDITIONAL([WANT_GAE], false)
+fi
+
+# Enable support for Libcloud.
+AC_MSG_CHECKING([whether to enable libcloud support])
+AC_ARG_ENABLE(libcloud, [AS_HELP_STRING([--enable-libcloud], [enable libcloud support [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_libcloud=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_libcloud}" = "true"; then
+
+ # Configure path to Apache Libcloud.
+ AC_MSG_CHECKING([for libcloud])
+ AC_ARG_WITH([libcloud], [AC_HELP_STRING([--with-libcloud=PATH], [path to installed Apache libcloud [default=/usr/local]])], [
+ LIBCLOUD_LIB="${withval}/lib/python"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ LIBCLOUD_LIB="/usr/local/lib/python2.6/site-packages"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(LIBCLOUD_LIB)
+
+ AM_CONDITIONAL([WANT_LIBCLOUD], true)
+ AC_DEFINE([WANT_LIBCLOUD], 1, [enable libcloud support])
+else
+ AM_CONDITIONAL([WANT_LIBCLOUD], false)
+fi
+
+# Enable Web service component.
+AC_MSG_CHECKING([whether to enable the Web service component])
+AC_ARG_ENABLE(webservice, [AS_HELP_STRING([--enable-webservice], [enable Web service component [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_webservice=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_webservice}" = "true"; then
+
+ # Configure path to Apache Axis2C includes and lib.
+ AC_MSG_CHECKING([for axis2c])
+ AC_ARG_WITH([axis2c], [AC_HELP_STRING([--with-axis2c=PATH], [path to installed Apache Axis2C [default=/usr/local/axis2c]])], [
+ AXIS2C_PREFIX="${withval}"
+ AXIS2C_INCLUDE="${withval}/include/axis2-1.6.0"
+ AXIS2C_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ AXIS2C_PREFIX="/usr/local/axis2c"
+ AXIS2C_INCLUDE="/usr/local/axis2c/include/axis2-1.6.0"
+ AXIS2C_LIB="/usr/local/axis2c/lib"
+ AC_MSG_RESULT(/usr/local/axis2c)
+ ])
+ AC_SUBST(AXIS2C_PREFIX)
+ AC_SUBST(AXIS2C_INCLUDE)
+ AC_SUBST(AXIS2C_LIB)
+ LIBS="-L${AXIS2C_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([axis2_engine], [axis2_svc_client_create], [], [AC_MSG_ERROR([couldn't find a suitable libaxis2_engine, use --with-axis2c=PATH])])
+
+ AM_CONDITIONAL([WANT_WEBSERVICE], true)
+ AC_DEFINE([WANT_WEBSERVICE], 1, [enable Web service component])
+
+else
+ AM_CONDITIONAL([WANT_WEBSERVICE], false)
+fi
+
+# Enable SQL Database component.
+AC_MSG_CHECKING([whether to enable the SQL Database component])
+AC_ARG_ENABLE(sqldb, [AS_HELP_STRING([--enable-sqldb], [enable SQL Database component [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_sqldb=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_sqldb}" = "true"; then
+
+ # Configure path to PostgreSQL.
+ AC_MSG_CHECKING([for pgsql])
+ AC_ARG_WITH([pgsql], [AC_HELP_STRING([--with-pgsql=PATH], [path to installed PostgreSQL [default=/usr/local/pgsql]])], [
+ PGSQL_PREFIX="${withval}"
+ PGSQL_INCLUDE="${withval}/include"
+ PGSQL_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ PGSQL_PREFIX="/usr/local/pgsql"
+ PGSQL_INCLUDE="/usr/local/pgsql/include"
+ PGSQL_LIB="/usr/local/pgsql/lib"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(PGSQL_PREFIX)
+ AC_SUBST(PGSQL_INCLUDE)
+ AC_SUBST(PGSQL_LIB)
+
+ AM_CONDITIONAL([WANT_SQLDB], true)
+ AC_DEFINE([WANT_SQLDB], 1, [enable SQL Database component])
+else
+ AM_CONDITIONAL([WANT_SQLDB], false)
+fi
+
+# Enable Queue component.
+AC_MSG_CHECKING([whether to enable the Queue component])
+AC_ARG_ENABLE(queue, [AS_HELP_STRING([--enable-queue], [enable Queue component [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_queue=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_queue}" = "true"; then
+
+ # Configure path to Apache Qpid/C++.
+ AC_MSG_CHECKING([for qpidc])
+ AC_ARG_WITH([qpidc], [AC_HELP_STRING([--with-qpidc=PATH], [path to installed Apache Qpid/C++ [default=/usr/local]])], [
+ QPIDC_PREFIX="${withval}"
+ QPIDC_INCLUDE="${withval}/include"
+ QPIDC_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ QPIDC_PREFIX="/usr/local"
+ QPIDC_INCLUDE="/usr/local/include"
+ QPIDC_LIB="/usr/local/lib"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(QPIDC_PREFIX)
+ AC_SUBST(QPIDC_INCLUDE)
+ AC_SUBST(QPIDC_LIB)
+
+ if test "${want_threads}" != "true"; then
+ AC_MSG_ERROR([--enable-queue requires multi-threading, use --enable-threads])
+ fi
+ LIBS="-L${QPIDC_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([qpidclient], [_init], [], [AC_MSG_ERROR([couldn't find a suitable libqpidclient, use --with-qpidc=PATH])])
+
+ AM_CONDITIONAL([WANT_QUEUE], true)
+ AC_DEFINE([WANT_QUEUE], 1, [enable Queue component])
+else
+ AM_CONDITIONAL([WANT_QUEUE], false)
+fi
+
+# Enable Chat component.
+AC_MSG_CHECKING([whether to enable the Chat component])
+AC_ARG_ENABLE(chat, [AS_HELP_STRING([--enable-chat], [enable Chat component [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_chat=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_chat}" = "true"; then
+
+ # Configure path to Libstrophe includes and lib.
+ AC_MSG_CHECKING([for libstrophe])
+ AC_ARG_WITH([libstrophe], [AC_HELP_STRING([--with-libstrophe=PATH], [path to libstrophe [default=/usr/local]])], [
+ LIBSTROPHE_INCLUDE="${withval}/include"
+ LIBSTROPHE_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ LIBSTROPHE_INCLUDE="/usr/local/include"
+ LIBSTROPHE_LIB="/usr/local/lib"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(LIBSTROPHE_INCLUDE)
+ AC_SUBST(LIBSTROPHE_LIB)
+ if test "${want_threads}" != "true"; then
+ AC_MSG_ERROR([--enable-chat requires multi-threading, use --enable-threads])
+ fi
+ LIBS="-L${LIBSTROPHE_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([strophe], [xmpp_initialize], [], [AC_MSG_ERROR([couldn't find a suitable libstrophe, use --with-libstrophe=PATH])], [-lssl -lresolv])
+
+ # Configure path to Vysper
+ AC_MSG_CHECKING([for vysper])
+ AC_ARG_WITH([vysper], [AC_HELP_STRING([--with-vysper=PATH], [path to Apache Vysper [default=${HOME}/vysper-1.0.0]])], [
+ VYSPER_PREFIX="${withval}"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ VYSPER_PREFIX="${HOME}/vysper-1.0.0"
+ AC_MSG_RESULT(${HOME}/vysper-1.0.0)
+ ])
+ AC_SUBST(VYSPER_PREFIX)
+ AC_CHECK_FILE([${VYSPER_PREFIX}/lib/vysper-core-0.5.jar], [want_vysper=true], [])
+ if test "${want_vysper}" = "true"; then
+ AM_CONDITIONAL([WANT_VYSPER], true)
+ else
+ AM_CONDITIONAL([WANT_VYSPER], false)
+ fi
+
+ AM_CONDITIONAL([WANT_CHAT], true)
+ AC_DEFINE([WANT_CHAT], 1, [enable Chat component])
+
+else
+ AM_CONDITIONAL([WANT_CHAT], false)
+ AM_CONDITIONAL([WANT_VYSPER], false)
+fi
+
+# Enable Log component.
+AC_MSG_CHECKING([whether to enable the Log component])
+AC_ARG_ENABLE(log, [AS_HELP_STRING([--enable-log], [enable Log component [default=no]])],
+[ case "${enableval}" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ want_log=true
+ ;;
+ esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_log}" = "true"; then
+
+ # Configure path to Apache Thrift (and Facebook fb303).
+ AC_MSG_CHECKING([for thrift])
+ AC_ARG_WITH([thrift], [AC_HELP_STRING([--with-thrift=PATH], [path to installed Apache Thrift [default=/usr/local]])], [
+ THRIFT_PREFIX="${withval}"
+ THRIFT_INCLUDE="${withval}/include/thrift"
+ THRIFT_LIB="${withval}/lib"
+ FB303_PREFIX="${withval}/contrib/fb303"
+ FB303_INCLUDE="${withval}/contrib/fb303/include/thrift"
+ FB303_LIB="${withval}/contrib/fb303/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ THRIFT_PREFIX="/usr/local"
+ THRIFT_INCLUDE="/usr/local/include"
+ THRIFT_LIB="/usr/local/lib"
+ FB303_PREFIX="/usr/local"
+ FB303_INCLUDE="/usr/local/include"
+ FB303_LIB="/usr/local/lib"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(THRIFT_PREFIX)
+ AC_SUBST(THRIFT_INCLUDE)
+ AC_SUBST(THRIFT_LIB)
+ AC_SUBST(FB303_PREFIX)
+ AC_SUBST(FB303_INCLUDE)
+ AC_SUBST(FB303_LIB)
+
+ # Configure path to Facebook Scribe.
+ AC_MSG_CHECKING([for scribe])
+ AC_ARG_WITH([scribe], [AC_HELP_STRING([--with-scribe=PATH], [path to installed Facebook Scribe [default=/usr/local]])], [
+ SCRIBE_PREFIX="${withval}"
+ SCRIBE_INCLUDE="${withval}/include"
+ SCRIBE_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+ ], [
+ SCRIBE_PREFIX="/usr/local"
+ SCRIBE_INCLUDE="/usr/local/include"
+ SCRIBE_LIB="/usr/local/lib"
+ AC_MSG_RESULT(/usr/local)
+ ])
+ AC_SUBST(SCRIBE_PREFIX)
+ AC_SUBST(SCRIBE_INCLUDE)
+ AC_SUBST(SCRIBE_LIB)
+
+ LIBS="-L${THRIFT_LIB} -L${FB303_LIB} -L${SCRIBE_LIB} ${defaultlibs}"
+ AC_CHECK_LIB([thrift], [_init], [], [AC_MSG_ERROR([couldn't find a suitable libthrift, use --with-thrift=PATH])])
+ AC_CHECK_LIB([fb303], [_init], [], [AC_MSG_ERROR([couldn't find a suitable libfb303, use --with-thrift=PATH])])
+ AC_CHECK_LIB([scribe], [_init], [], [AC_MSG_ERROR([couldn't find a suitable libscribe, use --with-scribe=PATH])])
+
+ AM_CONDITIONAL([WANT_LOG], true)
+ AC_DEFINE([WANT_LOG], 1, [enable Log component])
+else
+ AM_CONDITIONAL([WANT_LOG], false)
+fi
+
+# Configure GCC C++ and LD options.
+AC_SUBST([DEFAULT_CXXFLAGS], ["${cxxflags}"])
+AC_SUBST([CXXFLAGS], ["${cxxflags}"])
+AC_SUBST([LDFLAGS], ["${ldflags}"])
+AC_SUBST([DEFAULT_LDFLAGS], ["${ldflags}"])
+LIBS="${defaultlibs}"
+
+AC_CONFIG_FILES([Makefile
+ etc/Makefile
+ kernel/Makefile
+ modules/Makefile
+ modules/scheme/Makefile
+ modules/atom/Makefile
+ modules/rss/Makefile
+ modules/js/Makefile
+ modules/json/Makefile
+ modules/scdl/Makefile
+ modules/http/Makefile
+ modules/server/Makefile
+ modules/python/Makefile
+ modules/java/Makefile
+ modules/openid/Makefile
+ modules/oauth/Makefile
+ modules/wsgi/Makefile
+ components/Makefile
+ components/cache/Makefile
+ components/log/Makefile
+ components/chat/Makefile
+ components/nosqldb/Makefile
+ components/filedb/Makefile
+ components/queue/Makefile
+ components/sqldb/Makefile
+ components/webservice/Makefile
+ samples/Makefile
+ samples/store-scheme/Makefile
+ samples/store-cpp/Makefile
+ samples/store-python/Makefile
+ samples/store-java/Makefile
+ samples/store-gae/Makefile
+ samples/store-sql/Makefile
+ samples/store-nosql/Makefile
+ samples/store-vhost/Makefile
+ samples/store-cluster/Makefile
+ samples/relay-python/Makefile
+ doc/Makefile
+ doc/Doxyfile
+ ubuntu/Makefile
+ ])
+AC_OUTPUT
+
diff --git a/sandbox/sebastien/cpp/apr-2/doc/Doxyfile.in b/sandbox/sebastien/cpp/apr-2/doc/Doxyfile.in
new file mode 100644
index 0000000000..ba02d58a2a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/doc/Doxyfile.in
@@ -0,0 +1,1541 @@
+# 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.
+
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = tuscany-sca
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 1.0-M3
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../kernel \
+ ../modules
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = doxygen
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/sandbox/sebastien/cpp/apr-2/doc/Makefile.am b/sandbox/sebastien/cpp/apr-2/doc/Makefile.am
new file mode 100644
index 0000000000..c5f29b0d6b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/doc/Makefile.am
@@ -0,0 +1,30 @@
+# 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.
+
+if WANT_DOXYGEN
+
+BUILT_SOURCES = doxygen/index.html
+
+doxygen/index.html: Doxyfile
+ doxygen
+
+endif
+
+datadir=$(prefix)/doc
+
+clean:
+ rm -rf doxygen
diff --git a/sandbox/sebastien/cpp/apr-2/etc/Makefile.am b/sandbox/sebastien/cpp/apr-2/etc/Makefile.am
new file mode 100644
index 0000000000..c9ca6d854f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/etc/Makefile.am
@@ -0,0 +1,21 @@
+# 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.
+
+EXTRA_DIST = git-exclude svn-config svn-ignore
+
+dist_noinst_SCRIPTS = httpd-ipcrm memgrind
+
diff --git a/sandbox/sebastien/cpp/apr-2/etc/git-exclude b/sandbox/sebastien/cpp/apr-2/etc/git-exclude
new file mode 100644
index 0000000000..77c26ac5f3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/etc/git-exclude
@@ -0,0 +1,115 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+# Generic ignores
+target/
+work/
+tmp/
+build/
+*_build
+.project
+.cproject
+.classpath
+*.log
+junit*.properties
+surefire*.properties
+.settings/
+.deployables/
+.wtpmodules/
+.pydevproject
+.buildpath
+.svn/
+.cvs/
+.dotest/
+*.la
+*.lo
+*.o
+*.in
+*.so
+Makefile
+.deps/
+.libs/
+m4/
+*.m4
+config.guess
+config.sub
+config.status
+depcomp
+install-sh
+ltmain.sh
+missing
+stamp-h1
+autom4te.cache/
+deploy/
+libtool
+configure
+config.h
+Doxyfile
+*.tar
+*.tar.gz
+*-bin/
+*-src/
+*_Proxy.cpp
+*_Proxy.h
+*_Wrapper.cpp
+*_Wrapper.h
+gmon.out
+*~
+tags
+doxygen
+*.pyc
+*.class
+*.stamp
+*.jar
+*.prefix
+index.yaml
+core
+gen-cpp/
+
+# Specific ignores
+kernel-test
+string-test
+mem-test
+hash-test
+lambda-test
+parallel-test
+xml-test
+xsd-test
+atom-test
+eval-test
+eval-shell
+json-test
+client-test
+memcache-test
+curl-test
+scdl-test
+python-test
+python-shell
+jni-test
+java-test
+java-shell
+script-test
+axiom-test
+axis2-test
+qpid-test
+xmpp-test
+pgsql-test
+pgsql-standby-test
+tinycdb-test
+curl-get
+curl-connect
+rss-test
+scribe-cat
+js-test
+file-test
+xml-value
+value-xml
+json-value
+value-json
+element-value
+value-element
+
diff --git a/sandbox/sebastien/cpp/apr-2/etc/httpd-ipcrm b/sandbox/sebastien/cpp/apr-2/etc/httpd-ipcrm
new file mode 100755
index 0000000000..b457e7385f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/etc/httpd-ipcrm
@@ -0,0 +1,23 @@
+#!/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
+# 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.
+
+# Remove ipcs created by httpd
+
+ipcs -s | grep 0x | awk '{ print $2 }' | xargs -i -t ipcrm -s {}
+
diff --git a/sandbox/sebastien/cpp/apr-2/etc/memgrind b/sandbox/sebastien/cpp/apr-2/etc/memgrind
new file mode 100755
index 0000000000..1a220cd5d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/etc/memgrind
@@ -0,0 +1,23 @@
+#!/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
+# 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.
+
+# Run valgrind to analyze memory usage and track memory leaks
+
+valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes $* 2>&1 | tee memgrind.log
+
diff --git a/sandbox/sebastien/cpp/apr-2/etc/svn-config b/sandbox/sebastien/cpp/apr-2/etc/svn-config
new file mode 100644
index 0000000000..4f8cb41685
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/etc/svn-config
@@ -0,0 +1,136 @@
+### This file configures various client-side behaviors.
+###
+### The commented-out examples below are intended to demonstrate
+### how to use this file.
+
+### Section for authentication and authorization customizations.
+[auth]
+### Set store-passwords to 'no' to avoid storing passwords in the
+### auth/ area of your config directory. It defaults to 'yes'.
+### Note that this option only prevents saving of *new* passwords;
+### it doesn't invalidate existing passwords. (To do that, remove
+### the cache files by hand as described in the Subversion book.)
+# store-passwords = no
+### Set store-auth-creds to 'no' to avoid storing any subversion
+### credentials in the auth/ area of your config directory.
+### It defaults to 'yes'. Note that this option only prevents
+### saving of *new* credentials; it doesn't invalidate existing
+### caches. (To do that, remove the cache files by hand.)
+# store-auth-creds = no
+
+### Section for configuring external helper applications.
+[helpers]
+### Set editor to the command used to invoke your text editor.
+### This will override the environment variables that Subversion
+### examines by default to find this information ($EDITOR,
+### et al).
+# editor-cmd = editor (vi, emacs, notepad, etc.)
+### Set diff-cmd to the absolute path of your 'diff' program.
+### This will override the compile-time default, which is to use
+### Subversion's internal diff implementation.
+# diff-cmd = diff_program (diff, gdiff, etc.)
+### Set diff3-cmd to the absolute path of your 'diff3' program.
+### This will override the compile-time default, which is to use
+### Subversion's internal diff3 implementation.
+# diff3-cmd = diff3_program (diff3, gdiff3, etc.)
+### Set diff3-has-program-arg to 'true' or 'yes' if your 'diff3'
+### program accepts the '--diff-program' option.
+# diff3-has-program-arg = [true | false]
+
+### Section for configuring tunnel agents.
+[tunnels]
+### Configure svn protocol tunnel schemes here. By default, only
+### the 'ssh' scheme is defined. You can define other schemes to
+### be used with 'svn+scheme://hostname/path' URLs. A scheme
+### definition is simply a command, optionally prefixed by an
+### environment variable name which can override the command if it
+### is defined. The command (or environment variable) may contain
+### arguments, using standard shell quoting for arguments with
+### spaces. The command will be invoked as:
+### <command> <hostname> svnserve -t
+### (If the URL includes a username, then the hostname will be
+### passed to the tunnel agent as <user>@<hostname>.) If the
+### built-in ssh scheme were not predefined, it could be defined
+### as:
+# ssh = $SVN_SSH ssh
+### If you wanted to define a new 'rsh' scheme, to be used with
+### 'svn+rsh:' URLs, you could do so as follows:
+# rsh = rsh
+### Or, if you wanted to specify a full path and arguments:
+# rsh = /path/to/rsh -l myusername
+### On Windows, if you are specifying a full path to a command,
+### use a forward slash (/) or a paired backslash (\\) as the
+### path separator. A single backslash will be treated as an
+### escape for the following character.
+
+### Section for configuring miscelleneous Subversion options.
+[miscellany]
+### Set global-ignores to a set of whitespace-delimited globs
+### which Subversion will ignore in its 'status' output.
+# global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store
+### Set log-encoding to the default encoding for log messages
+# log-encoding = latin1
+### Set use-commit-times to make checkout/update/switch/revert
+### put last-committed timestamps on every file touched.
+# use-commit-times = yes
+### Set no-unlock to prevent 'svn commit' from automatically
+### releasing locks on files.
+# no-unlock = yes
+### Set enable-auto-props to 'yes' to enable automatic properties
+### for 'svn add' and 'svn import', it defaults to 'no'.
+### Automatic properties are defined in the section 'auto-props'.
+enable-auto-props = yes
+
+### Section for configuring automatic properties.
+[auto-props]
+### The format of the entries is:
+### file-name-pattern = propname[=value][;propname[=value]...]
+### The file-name-pattern can contain wildcards (such as '*' and
+### '?'). All entries which match will be applied to the file.
+### Note that auto-props functionality must be enabled, which
+### is typically done by setting the 'enable-auto-props' option.
+# *.c = svn:eol-style=native
+# *.cpp = svn:eol-style=native
+# *.h = svn:eol-style=native
+# *.dsp = svn:eol-style=CRLF
+# *.dsw = svn:eol-style=CRLF
+# *.sh = svn:eol-style=native;svn:executable
+# *.txt = svn:eol-style=native
+# *.png = svn:mime-type=image/png
+# *.jpg = svn:mime-type=image/jpeg
+# Makefile = svn:eol-style=native
+
+*.c = svn:eol-style=native;svn:keywords=Rev Date
+*.cpp = svn:eol-style=native;svn:keywords=Rev Date
+*.h = svn:eol-style=native;svn:keywords=Rev Date
+*.dsp = svn:eol-style=CRLF
+*.dsw = svn:eol-style=CRLF
+*.sh = svn:eol-style=native;svn:executable;svn:keywords=Rev Date
+*.bat = svn:eol-style=native;svn:keywords=Rev Date
+*.txt = svn:eol-style=native;svn:keywords=Rev Date
+*.png = svn:mime-type=image/png
+*.jpg = svn:mime-type=image/jpeg
+*.am = svn:eol-style=native;svn:keywords=Rev Date
+*.ac = svn:eol-style=native;svn:keywords=Rev Date
+*.xml = svn:eol-style=native;svn:keywords=Rev Date
+*.xsd = svn:eol-style=native;svn:keywords=Rev Date
+*.html = svn:eol-style=native;svn:keywords=Rev Date
+*.wsdl = svn:eol-style=native;svn:keywords=Rev Date
+*.xsd = svn:eol-style=native;svn:keywords=Rev Date
+*.composite = svn:eol-style=native;svn:keywords=Rev Date
+*.componentType = svn:eol-style=native;svn:keywords=Rev Date
+*.rb = svn:eol-style=native;svn:keywords=Rev Date
+*.py = svn:eol-style=native;svn:keywords=Rev Date
+*.php = svn:eol-style=native;svn:keywords=Rev Date
+*.js = svn:eol-style=native;svn:keywords=Rev Date
+*.java = svn:eol-style=native;svn:keywords=Rev Date
+*.properties = svn:eol-style=native;svn:keywords=Rev Date
+*.jelly = svn:eol-style=native;svn:keywords=Rev Date
+*.ipr = svn:eol-style=native
+*.iml = svn:eol-style=native
+*.project = svn:eol-style=native
+*.classpath = svn:eol-style=native
+README = svn:eol-style=native;svn:keywords=Rev Date
+LICENSE = svn:eol-style=native
+NOTICE = svn:eol-style=native
+
diff --git a/sandbox/sebastien/cpp/apr-2/etc/svn-ignore b/sandbox/sebastien/cpp/apr-2/etc/svn-ignore
new file mode 100644
index 0000000000..e93f10efc4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/etc/svn-ignore
@@ -0,0 +1,58 @@
+configure
+Makefile.in
+depcomp
+config.guess
+config.h
+config.sub
+ltmain.sh
+Makefile
+config.status
+stamp-h1
+config.h.in
+libtool
+autom4te.cache
+missing
+aclocal.m4
+install-sh
+.deps
+*.dat
+.libs
+tmp
+build
+.project
+.cdtproject
+.settings
+*_Proxy.cpp
+*_Proxy.h
+*_Wrapper.cpp
+*_Wrapper.h
+.pydevproject
+.buildpath
+*.lib
+*.dll
+*.exe
+*.suo
+*.ncb
+*.user
+*.pdb
+Debug
+Release
+gmon.out
+m4
+*.tar.gz
+*.pyc
+*.log
+*-bin
+*-src
+Doxyfile
+*~
+tags
+doxygen
+*.stamp
+*.class
+*.jar
+*.prefix
+target
+index.yaml
+core
+gen-cpp
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/Makefile.am b/sandbox/sebastien/cpp/apr-2/kernel/Makefile.am
new file mode 100644
index 0000000000..a112ab5d0d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/Makefile.am
@@ -0,0 +1,50 @@
+# 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.
+
+
+
+includedir = $(prefix)/include/kernel
+include_HEADERS = *.hpp
+
+string_test_SOURCES = string-test.cpp
+
+noinst_test_LTLIBRARIES = libdynlib-test.la
+noinst_testdir = `pwd`/tmp
+libdynlib_test_la_SOURCES = dynlib-test.cpp
+noinst_DATA = libdynlib-test.so
+libdynlib-test.so:
+ ln -s .libs/libdynlib-test.so
+
+kernel_test_SOURCES = kernel-test.cpp
+
+lambda_test_SOURCES = lambda-test.cpp
+
+mem_test_SOURCES = mem-test.cpp
+
+parallel_test_SOURCES = parallel-test.cpp
+
+xml_test_SOURCES = xml-test.cpp
+xml_test_LDFLAGS = -lxml2
+
+xsd_test_SOURCES = xsd-test.cpp
+xsd_test_LDFLAGS = -lxml2
+
+hash_test_SOURCES = hash-test.cpp
+
+noinst_PROGRAMS = string-test kernel-test lambda-test hash-test mem-test parallel-test xml-test xsd-test
+TESTS = string-test kernel-test lambda-test hash-test mem-test parallel-test xml-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/config.hpp b/sandbox/sebastien/cpp/apr-2/kernel/config.hpp
new file mode 100644
index 0000000000..195612428e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/config.hpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_config_hpp
+#define tuscany_config_hpp
+
+#include "ap_config.h"
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "../config.h"
+
+/**
+ * Platform configuration and debug functions.
+ */
+
+namespace tuscany
+{
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Add string watch members to important classes to help watch them in a debugger.
+ */
+#define WANT_MAINTAINER_WATCH
+
+/**
+ * Increment / decrement a debug counter.
+ */
+bool debug_inc(long int& c) {
+ c++;
+ return true;
+}
+
+bool debug_dec(long int& c) {
+ c--;
+ return true;
+}
+
+#else
+
+#define debug_inc(c)
+#define debug_dec(c)
+
+#endif
+
+/**
+ * Attribute used to mark unused parameters.
+ */
+#ifndef unused
+#define unused __attribute__ ((unused))
+#endif
+
+}
+#endif /* tuscany_config_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/dynlib-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/dynlib-test.cpp
new file mode 100644
index 0000000000..419fa29db5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/dynlib-test.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test library.
+ */
+
+#include "function.hpp"
+
+namespace tuscany {
+namespace test {
+
+ const int cppsquare(int x) {
+ return x * x;
+ }
+
+}
+}
+
+extern "C" {
+
+ const int csquare(const int x) {
+ return tuscany::test::cppsquare(x);
+ }
+
+ const tuscany::lambda<int(const int)> csquarel() {
+ return tuscany::lambda<int(const int)>(tuscany::test::cppsquare);
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/dynlib.hpp b/sandbox/sebastien/cpp/apr-2/kernel/dynlib.hpp
new file mode 100644
index 0000000000..9f55dc4a49
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/dynlib.hpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_dlib_hpp
+#define tuscany_dlib_hpp
+
+/**
+ * Simple dynamic library access functions.
+ */
+
+#include <dlfcn.h>
+
+#include "function.hpp"
+#include "gc.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+
+/**
+ * OS specific dynamic library file extension.
+ */
+#ifdef IS_DARWIN
+const string dynlibExt(".dylib");
+#else
+const string dynlibExt(".so");
+#endif
+
+/**
+ * Represents a reference to a dynamic library.
+ */
+class lib {
+public:
+ lib() : h(NULL), owner(false) {
+ }
+
+ lib(const string& name) : name(name), h(dlopen(c_str(name), RTLD_NOW)), owner(true) {
+ if (h == NULL)
+ h = mkfailure<void*>(string("Could not load library: ") + name + ": " + dlerror());
+ }
+
+ lib(const lib& l) : name(l.name), h(l.h), owner(false) {
+ }
+
+ ~lib() {
+ if (!owner)
+ return;
+ if (!hasContent(h) || content(h) == NULL)
+ return;
+ dlclose(content(h));
+ }
+
+private:
+ template<typename S> friend const failable<lambda<S> > dynlambda(const string& name, const lib& l);
+
+ const string name;
+ failable<void*> h;
+ bool owner;
+};
+
+/**
+ * Find a lambda function in a dynamic library.
+ */
+template<typename S> const failable<lambda<S> > dynlambda(const string& name, const lib& l) {
+ if (!hasContent(l.h))
+ return mkfailure<lambda<S> >(reason(l.h));
+ const void* s = dlsym(content(l.h), c_str(name));
+ if (s == NULL)
+ return mkfailure<lambda<S> >(string("Could not load symbol: ") + name);
+ return lambda<S>((S*)s);
+}
+
+}
+#endif /* tuscany_dlib_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/element.hpp b/sandbox/sebastien/cpp/apr-2/kernel/element.hpp
new file mode 100644
index 0000000000..1c443886d1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/element.hpp
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_element_hpp
+#define tuscany_element_hpp
+
+/**
+ * Functions to help represent data as lists of elements and attributes.
+ */
+
+#include "list.hpp"
+#include "value.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Tags used to tag lists of elements and attributes.
+ */
+const value attribute("attribute");
+const value element("element");
+const string atsign("@");
+
+/**
+ * Returns true if a value is an element.
+ */
+bool isElement(const value& v) {
+ if (!isList(v) || isNil(v) || element != car<value>(v))
+ return false;
+ return true;
+}
+
+/**
+ * Returns true if a value is an attribute.
+ */
+bool isAttribute(const value& v) {
+ if (!isList(v) || isNil(v) || attribute != car<value>(v))
+ return false;
+ return true;
+}
+
+/**
+ * Returns the name of an attribute.
+ */
+const value attributeName(const list<value>& l) {
+ return cadr(l);
+}
+
+/**
+ * Returns the value of an attribute.
+ */
+const value attributeValue(const list<value>& l) {
+ return caddr(l);
+}
+
+/**
+ * Returns the name of an element.
+ */
+const value elementName(const list<value>& l) {
+ return cadr(l);
+}
+
+/**
+ * Returns true if an element has children.
+ */
+const bool elementHasChildren(const list<value>& l) {
+ return !isNil(cddr(l));
+}
+
+/**
+ * Returns the children of an element.
+ */
+const list<value> elementChildren(const list<value>& l) {
+ return cddr(l);
+}
+
+/**
+ * Returns true if an element has a value.
+ */
+const value elementHasValue(const list<value>& l) {
+ const list<value> r = reverse(l);
+ if (isSymbol(car(r)))
+ return false;
+ if(isList(car(r)) && !isNil((list<value>)car(r)) && isSymbol(car<value>(car(r))))
+ return false;
+ return true;
+}
+
+/**
+ * Returns the value of an element.
+ */
+const value elementValue(const list<value>& l) {
+ return car(reverse(l));
+}
+
+/**
+ * Convert an element to a value.
+ */
+const bool elementToValueIsList(const value& v) {
+ if (!isList(v))
+ return false;
+ const list<value> l = v;
+ return (isNil(l) || !isSymbol(car(l)));
+}
+
+const value elementToValue(const value& t) {
+ const list<value> elementsToValues(const list<value>& e);
+
+ // Convert an attribute
+ if (isTaggedList(t, attribute))
+ return mklist<value>(c_str(atsign + attributeName(t)), attributeValue(t));
+
+ // Convert an element
+ if (isTaggedList(t, element)) {
+
+ // Convert an element's value
+ if (elementHasValue(t)) {
+
+ // Convert a single value
+ if (!elementToValueIsList(elementValue(t)))
+ return mklist(elementName(t), elementValue(t));
+
+ // Convert a list value
+ return cons(elementName(t), mklist<value>(elementsToValues(elementValue(t))));
+ }
+
+ // Convert an element's children
+ return cons(elementName(t), elementsToValues(elementChildren(t)));
+ }
+
+ // Convert a value
+ if (!isList(t))
+ return t;
+ return elementsToValues(t);
+}
+
+/**
+ * Convert a list of elements to a list of values.
+ */
+const bool elementToValueIsSymbol(const value& v) {
+ if (!isList(v))
+ return false;
+ const list<value> l = v;
+ if (isNil(l))
+ return false;
+ if (!isSymbol(car(l)))
+ return false;
+ return true;
+}
+
+const list<value> elementToValueGroupValues(const value& v, const list<value>& l) {
+ if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l)))
+ return cons(v, l);
+ if (car<value>(car(l)) != car<value>(v))
+ return cons(v, l);
+ if (!elementToValueIsList(cadr<value>(car(l)))) {
+ const value g = mklist<value>(car<value>(v), mklist<value>(cdr<value>(v), cdr<value>(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+ }
+ const value g = mklist<value>(car<value>(v), cons<value>(cdr<value>(v), (list<value>)cadr<value>(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+
+}
+
+const list<value> elementsToValues(const list<value>& e) {
+ if (isNil(e))
+ return e;
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)));
+}
+
+/**
+ * Convert a value to an element.
+ */
+const value valueToElement(const value& t) {
+ const list<value> valuesToElements(const list<value>& l);
+
+ // Convert a name value pair
+ if (isList(t) && !isNil((list<value>)t) && isSymbol(car<value>(t))) {
+ const value n = car<value>(t);
+ const value v = isNil(cdr<value>(t))? value() : cadr<value>(t);
+
+ // Convert a single value to an attribute or an element
+ if (!isList(v)) {
+ if (substr(n, 0, 1) == atsign)
+ return mklist<value>(attribute, substr(n, 1), v);
+ return mklist(element, n, v);
+ }
+
+ // Convert a list value
+ if (isNil((list<value>)v) || !isSymbol(car<value>(v)))
+ return cons(element, cons(n, mklist<value>(valuesToElements(v))));
+
+ // Convert a nested name value pair value
+ return cons(element, cons(n, valuesToElements(cdr<value>(t))));
+ }
+
+ // Convert a value
+ if (!isList(t))
+ return t;
+ return valuesToElements(t);
+}
+
+/**
+ * Convert a list of values to a list of elements.
+ */
+const list<value> valuesToElements(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(valueToElement(car(l)), valuesToElements(cdr(l)));
+}
+
+/**
+ * Returns a selector lambda function which can be used to filter
+ * elements against the given element pattern.
+ */
+struct selectorLambda {
+ const list<value> select;
+ selectorLambda(const list<value>& s) : select(s) {
+ }
+ const bool evalSelect(const list<value>& s, const list<value> v) const {
+ if (isNil(s))
+ return true;
+ if (isNil(v))
+ return false;
+ if (car(s) != car(v))
+ return false;
+ return evalSelect(cdr(s), cdr(v));
+ }
+ const bool operator()(const value& v) const {
+ if (!isList(v))
+ return false;
+ return evalSelect(select, v);
+ }
+};
+
+const lambda<bool(const value&)> selector(const list<value> s) {
+ return selectorLambda(s);
+}
+
+/**
+ * Returns the value of the attribute with the given name.
+ */
+struct filterAttribute {
+ const value name;
+ filterAttribute(const value& n) : name(n) {
+ }
+ const bool operator()(const value& v) const {
+ return isAttribute(v) && attributeName((list<value>)v) == name;
+ }
+};
+
+const value attributeValue(const value& name, const value& l) {
+ const list<value> f = filter<value>(filterAttribute(name), list<value>(l));
+ if (isNil(f))
+ return value();
+ return caddr<value>(car(f));
+}
+
+/**
+ * Returns child elements with the given name.
+ */
+struct filterElement {
+ const value name;
+ filterElement(const value& n) : name(n) {
+ }
+ const bool operator()(const value& v) const {
+ return isElement(v) && elementName((list<value>)v) == name;
+ }
+};
+
+const value elementChildren(const value& name, const value& l) {
+ return filter<value>(filterElement(name), list<value>(l));
+}
+
+/**
+ * Return the child element with the given name.
+ */
+const value elementChild(const value& name, const value& l) {
+ const list<value> f = elementChildren(name, l);
+ if (isNil(f))
+ return value();
+ return car(f);
+}
+
+}
+#endif /* tuscany_element_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/fstream.hpp b/sandbox/sebastien/cpp/apr-2/kernel/fstream.hpp
new file mode 100644
index 0000000000..99fc51565f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/fstream.hpp
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_fstream_hpp
+#define tuscany_fstream_hpp
+
+/**
+ * File based streams.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include "string.hpp"
+#include "stream.hpp"
+
+namespace tuscany {
+
+/*
+ * Output stream backed by a FILE.
+ */
+class ofstream : public ostream {
+public:
+ ofstream(const string& path) : file(fopen(c_str(path), "wb")), owner(true) {
+ }
+
+ ofstream(FILE* file) : file(file), owner(false) {
+ }
+
+ ofstream(const ofstream& os) : file(os.file), owner(false) {
+ }
+
+ ~ofstream() {
+ if (!owner)
+ return;
+ if (file == NULL)
+ return;
+ fclose(file);
+ }
+
+ const bool fail() {
+ return file == NULL;
+ }
+
+ ofstream& vprintf(const char* fmt, ...) {
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (file, fmt, args);
+ va_end (args);
+ return *this;
+ }
+
+ ofstream& write(const string& s) {
+ fwrite(c_str(s), 1, length(s), file);
+ return *this;
+ }
+
+ ofstream& flush() {
+ fflush(file);
+ return *this;
+ }
+
+private:
+ FILE* file;
+ bool owner;
+};
+
+/*
+ * Input stream backed by a FILE.
+ */
+class ifstream : public istream {
+public:
+ ifstream(const string& path) : file(fopen(c_str(path), "rb")), owner(true) {
+ }
+
+ ifstream(FILE* file) : file(file), owner(false) {
+ }
+
+ ifstream(const ifstream& is) : file(is.file), owner(false) {
+ }
+
+ ~ifstream() {
+ if (!owner)
+ return;
+ if (file == NULL)
+ return;
+ fclose(file);
+ }
+
+ const size_t read(void* buf, size_t size) {
+ return fread(buf, 1, size, file);
+ }
+
+ const bool eof() {
+ return feof(file);
+ }
+
+ const bool fail() {
+ return file == NULL;
+ }
+
+ const int get() {
+ return fgetc(file);
+ }
+
+ const int peek() {
+ int c = fgetc(file);
+ if (c == -1)
+ return c;
+ ungetc(c, file);
+ return c;
+ }
+
+private:
+ FILE* file;
+ bool owner;
+};
+
+/**
+ * Standard streams.
+ */
+ofstream cout(stdout);
+ofstream cerr(stderr);
+ifstream cin(stdin);
+
+/**
+ * Streams used for logging.
+ */
+
+/**
+ * Format the current time.
+ */
+const string logTime() {
+ const time_t t = ::time(NULL);
+ const tm* lt = localtime(&t);
+ char ft[32];
+ strftime(ft, 31, "%a %b %d %H:%M:%S %Y", lt);
+ return ft;
+}
+
+/*
+ * Log stream.
+ */
+class logfstream : public ostream {
+public:
+ logfstream(FILE* file, const string& type) : file(file), type(type), owner(false), head(false) {
+ }
+
+ logfstream(const logfstream& os) : file(os.file), type(type), owner(false), head(os.head) {
+ }
+
+ ~logfstream() {
+ if (!owner)
+ return;
+ if (file == NULL)
+ return;
+ fclose(file);
+ }
+
+ logfstream& vprintf(const char* fmt, ...) {
+ whead();
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (file, fmt, args);
+ va_end (args);
+ return *this;
+ }
+
+ logfstream& write(const string& s) {
+ whead();
+ fwrite(c_str(s), 1, length(s), file);
+ if (s == "\n")
+ head = false;
+ return *this;
+ }
+
+ logfstream& flush() {
+ fflush(file);
+ return *this;
+ }
+
+private:
+ FILE* file;
+ const string type;
+ bool owner;
+ bool head;
+
+ logfstream& whead() {
+ if (head)
+ return *this;
+ head = true;
+ *this << "[" << logTime() << "] [" << type << "] ";
+ return *this;
+ }
+};
+
+/**
+ * Info and failure log streams.
+ */
+logfstream cinfo(stderr, "info");
+logfstream cfailure(stderr, "error");
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug log stream and debug functions.
+ */
+logfstream cdebug(stderr, "debug");
+
+/**
+ * Log a debug message.
+ */
+const bool debugLog(const string& msg) {
+ cdebug << msg << endl;
+ return true;
+}
+
+/**
+ * Log a debug message and a value.
+ */
+template<typename V> const bool debugLog(const V& v, const string& msg) {
+ cdebug << msg << ": " << v << endl;
+ return true;
+}
+
+#define debug(...) tuscany::debugLog(__VA_ARGS__)
+
+#else
+
+#define debug(...)
+
+#endif
+
+}
+
+#endif /* tuscany_fstream_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/function.hpp b/sandbox/sebastien/cpp/apr-2/kernel/function.hpp
new file mode 100644
index 0000000000..701e0f1fa9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/function.hpp
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_function_hpp
+#define tuscany_function_hpp
+
+/**
+ * Lambda function type.
+ */
+
+#include <utility>
+#include "fstream.hpp"
+#include "gc.hpp"
+#include "config.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug counters.
+ */
+long int countProxies;
+long int countFProxies = 0;
+long int countCProxies = 0;
+long int countLambdas = 0;
+long int countELambdas = 0;
+long int countCLambdas = 0;
+long int countFLambdas = 0;
+
+bool resetLambdaCounters() {
+ countLambdas = countELambdas = countCLambdas = countFLambdas = countProxies = countFProxies = countCProxies = 0;
+ return true;
+}
+
+bool checkLambdaCounters() {
+ return countLambdas == 0;
+}
+
+bool printLambdaCounters() {
+ cout << "countLambdas " << countLambdas << endl;
+ cout << "countELambdas " << countELambdas << endl;
+ cout << "countFLambdas " << countFLambdas << endl;
+ cout << "countCLambdas " << countCLambdas << endl;
+ cout << "countProxies " << countProxies << endl;
+ cout << "countFProxies " << countFProxies << endl;
+ cout << "countCProxies " << countCProxies << endl;
+ return true;
+}
+
+#else
+
+#define resetLambdaCounters()
+#define checkLambdaCounters() true
+#define printLambdaCounters()
+
+#endif
+
+/**
+ * Lambda function type.
+ */
+
+template<typename R, typename... P> class Callable {
+public:
+ Callable() {
+ }
+
+ virtual const size_t size() const = 0;
+
+ virtual const R operator()(P... p) const = 0;
+
+ virtual ~Callable() {
+ }
+
+ template<typename F> class Proxy: public Callable {
+ public:
+ Proxy(const F& f) : function(f) {
+ debug_inc(countProxies);
+ debug_inc(countFProxies);
+ }
+
+ Proxy(const Proxy& p) : function(p.function) {
+ debug_inc(countProxies);
+ debug_inc(countCProxies);
+ }
+
+ ~Proxy() {
+ debug_dec(countProxies);
+ }
+
+ virtual const R operator() (P... p) const {
+ return function(std::forward<P>(p)...);
+ }
+
+ virtual const size_t size() const {
+ return sizeof(function);
+ }
+
+ private:
+ const F function;
+ };
+};
+
+template<typename S> class lambda;
+
+template<typename R, typename... P> class lambda<R(P...)> {
+public:
+ lambda() : callable(0) {
+ debug_inc(countLambdas);
+ debug_inc(countELambdas);
+ }
+
+ template<typename F> lambda(const F f) {
+ debug_inc(countLambdas);
+ debug_inc(countFLambdas);
+
+ typedef typename CallableType::template Proxy<F> ProxyType;
+ callable = gc_ptr<CallableType>(new (gc_new<ProxyType>()) ProxyType(f));
+ }
+
+ lambda(const lambda& l) {
+ debug_inc(countLambdas);
+ debug_inc(countCLambdas);
+ callable = l.callable;
+ }
+
+ const lambda& operator=(const lambda& l) {
+ if (this == &l)
+ return *this;
+ callable = l.callable;
+ return *this;
+ }
+
+ ~lambda() {
+ debug_dec(countLambdas);
+ }
+
+ const bool operator==(const lambda& l) const {
+ if (this == &l)
+ return true;
+ return callable == l.callable;
+ }
+
+ const bool operator!=(const lambda& l) const {
+ return !this->operator==(l);
+ }
+
+ const R operator()(P... p) const {
+ return (*callable)(std::forward<P>(p)...);
+ }
+
+ template<typename S> friend ostream& operator<<(ostream&, const lambda<S>&);
+ template<typename S> friend const bool isNil(const lambda<S>& l);
+
+private:
+ typedef Callable<R,P...> CallableType;
+ gc_ptr<CallableType> callable;
+};
+
+template<typename S> ostream& operator<<(ostream& out, const lambda<S>& l) {
+ return out << "lambda::" << l.callable;
+}
+
+/**
+ * Return true if a lambda is nil.
+ */
+template<typename S> const bool isNil(const lambda<S>& l) {
+ return ((void*)l.callable) == 0;
+}
+
+/**
+ * Curry a lambda function.
+ */
+template<typename R, typename T, typename... P> class curried {
+public:
+ curried(const lambda<R(T, P...)>& f, const T& v): v(v), f(f) {
+ }
+
+ const R operator()(P... p) const {
+ return f(v, std::forward<P>(p)...);
+ }
+
+private:
+ const T v;
+ const lambda<R(T, P...)>f;
+};
+
+template<typename R, typename T, typename... P> const lambda<R(P...)> curry(const lambda<R(T, P...)>& f, const T& t) {
+ return curried<R, T, P...>(f, t);
+}
+
+template<typename R, typename T, typename U, typename... P> const lambda<R(P...)> curry(const lambda<R(T, U, P...)>& f, const T& t, const U& u) {
+ return curry(curry(f, t), u);
+}
+
+template<typename R, typename T, typename U, typename V, typename... P> const lambda<R(P...)> curry(const lambda<R(T, U, V, P...)>& f, const T& t, const U& u, const V& v) {
+ return curry(curry(curry(f, t), u), v);
+}
+
+/**
+ * A lambda function that returns the given value.
+ */
+template<typename T> class returnResult {
+public:
+ returnResult(const T& v) :
+ v(v) {
+ }
+ const T operator()() const {
+ return v;
+ }
+private:
+ const T v;
+};
+
+template<typename T> const lambda<T()> result(const T& v) {
+ return returnResult<T> (v);
+}
+
+}
+#endif /* tuscany_function_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/gc.hpp b/sandbox/sebastien/cpp/apr-2/kernel/gc.hpp
new file mode 100644
index 0000000000..09dcd1e5ac
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/gc.hpp
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_gc_hpp
+#define tuscany_gc_hpp
+
+/**
+ * Garbage collected memory management, using APR memory pools.
+ */
+
+#include <stdlib.h>
+#include <apr_general.h>
+#include <apr_pools.h>
+#include <assert.h>
+#include <new>
+#include "config.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Pointer to a value.
+ */
+template<typename T> class gc_ptr {
+public:
+ gc_ptr(T* ptr = NULL) throw() : ptr(ptr) {
+ }
+
+ ~gc_ptr() throw() {
+ }
+
+ gc_ptr(const gc_ptr& r) throw() : ptr(r.ptr) {
+ }
+
+ gc_ptr& operator=(const gc_ptr& r) throw() {
+ if(this == &r)
+ return *this;
+ ptr = r.ptr;
+ return *this;
+ }
+
+ const bool operator==(const gc_ptr& r) const throw() {
+ if (this == &r)
+ return true;
+ return ptr == r.ptr;
+ }
+
+ const bool operator!=(const gc_ptr& r) const throw() {
+ return !this->operator==(r);
+ }
+
+ T& operator*() const throw() {
+ return *ptr;
+ }
+
+ T* operator->() const throw() {
+ return ptr;
+ }
+
+ operator T*() const throw() {
+ return ptr;
+ }
+
+ T* ptr;
+};
+
+/**
+ * Garbage collected APR memory pool.
+ */
+class gc_pool {
+public:
+ gc_pool() : apr_pool(NULL) {
+ }
+
+ gc_pool(apr_pool_t* p) : apr_pool(p) {
+ }
+
+ gc_pool(const gc_pool& pool) : apr_pool(pool.apr_pool) {
+ }
+
+ gc_pool& operator=(const gc_pool& pool) {
+ if (this == &pool)
+ return *this;
+ apr_pool = pool.apr_pool;
+ return *this;
+ }
+
+private:
+ friend apr_pool_t* pool(const gc_pool& pool);
+ friend class gc_global_pool_t;
+ friend class gc_scoped_pool;
+
+ apr_pool_t* apr_pool;
+};
+
+/**
+ * Make a new APR pool.
+ */
+apr_pool_t* mkpool() {
+ apr_pool_t* p = NULL;
+ apr_pool_create(&p, NULL);
+ assert(p != NULL);
+ return p;
+}
+
+/**
+ * Return the APR pool used by a gc_pool.
+ */
+apr_pool_t* pool(const gc_pool& pool) {
+ return pool.apr_pool;
+}
+
+/**
+ * Destroy a memory pool.
+ */
+const bool destroy(const gc_pool& p) {
+ apr_pool_destroy(pool(p));
+ return true;
+}
+
+/**
+ * Initialize APR.
+ */
+class gc_apr_context_t {
+public:
+ gc_apr_context_t() {
+ apr_initialize();
+ }
+} gc_apr_context;
+
+/**
+ * Maintain a stack of memory pools.
+ */
+#ifdef WANT_THREADS
+__thread
+#endif
+apr_pool_t* gc_pool_stack = NULL;
+
+/**
+ * Return the current memory pool.
+ */
+apr_pool_t* gc_current_pool() {
+ apr_pool_t* apr_pool = gc_pool_stack;
+ if (apr_pool != NULL)
+ return apr_pool;
+
+ // Create a parent pool for the current thread
+ apr_pool_create(&apr_pool, NULL);
+ assert(apr_pool != NULL);
+ gc_pool_stack = apr_pool;
+ return apr_pool;
+}
+
+/**
+ * Push a pool onto the stack.
+ */
+apr_pool_t* gc_push_pool(apr_pool_t* pool) {
+ apr_pool_t* p = gc_pool_stack;
+ gc_pool_stack = pool;
+ return p;
+}
+
+/**
+ * Pop a pool from the stack.
+ */
+apr_pool_t* gc_pop_pool(apr_pool_t* pool) {
+ apr_pool_t* p = gc_pool_stack;
+ gc_pool_stack = pool;
+ return p;
+}
+
+/**
+ * A memory pool scope, used to setup a scope in which a particular pool
+ * will be used for all allocations.
+ */
+class gc_scoped_pool : public gc_pool {
+public:
+
+ gc_scoped_pool() : gc_pool(NULL), prev(gc_current_pool()), owner(true) {
+ apr_pool_create(&apr_pool, NULL);
+ assert(apr_pool != NULL);
+ gc_push_pool(apr_pool);
+ }
+
+ gc_scoped_pool(apr_pool_t* pool) : gc_pool(pool), prev(gc_current_pool()), owner(false) {
+ gc_push_pool(apr_pool);
+ }
+
+ ~gc_scoped_pool() {
+ if (owner)
+ apr_pool_destroy(apr_pool);
+ gc_pop_pool(prev);
+ }
+
+private:
+ gc_scoped_pool(const unused gc_scoped_pool& pool) : gc_pool(pool.apr_pool), prev(NULL), owner(false) {
+ }
+
+ apr_pool_t* prev;
+ bool owner;
+};
+
+/**
+ * Allocates a pointer to an object allocated from a memory pool and
+ * register a cleanup callback for it.
+ */
+template<typename T> apr_status_t gc_pool_cleanup(void* v) {
+ T* t = static_cast<T*>(v);
+ t->~T();
+ return APR_SUCCESS;
+}
+
+template<typename T> T* gc_new(apr_pool_t* p) {
+ void* gc_new_ptr = apr_palloc(p, sizeof(T));
+ assert(gc_new_ptr != NULL);
+ apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup<T>, apr_pool_cleanup_null) ;
+ return static_cast<T*>(gc_new_ptr);
+}
+
+template<typename T> T* gc_new(const gc_pool& p) {
+ return gc_new<T>(pool(p));
+}
+
+template<typename T> T* gc_new() {
+ return gc_new<T>(gc_current_pool());
+}
+
+template<typename T> apr_status_t gc_pool_acleanup(void* v) {
+ size_t* m = static_cast<size_t*>(v);
+ size_t n = *m;
+ T* t = (T*)(m + 1);
+ for (size_t i = 0; i < n; i++, t++)
+ t->~T();
+ return APR_SUCCESS;
+}
+
+template<typename T> T* gc_anew(apr_pool_t* p, size_t n) {
+ size_t* gc_anew_ptr = static_cast<size_t*>(apr_palloc(p, sizeof(size_t) + sizeof(T[n])));
+ assert(gc_anew_ptr != NULL);
+ *gc_anew_ptr = n;
+ apr_pool_cleanup_register(p, gc_anew_ptr, gc_pool_acleanup<T>, apr_pool_cleanup_null) ;
+ return (T*)(gc_anew_ptr + 1);
+}
+
+template<typename T> T* gc_anew(const gc_pool& p, size_t n) {
+ return gc_anew<T>(pool(p), n);
+}
+
+template<typename T> T* gc_anew(size_t n) {
+ return gc_anew<T>(gc_current_pool(), n);
+}
+
+/**
+ * Allocate an array of chars.
+ */
+char* gc_cnew(apr_pool_t* p, size_t n) {
+ char* gc_cnew_ptr = static_cast<char*>(apr_palloc(p, n));
+ assert(gc_cnew_ptr != NULL);
+ return gc_cnew_ptr;
+}
+
+char* gc_cnew(size_t n) {
+ return gc_cnew(gc_current_pool(), n);
+}
+
+}
+
+#endif /* tuscany_gc_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/hash-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/hash-test.cpp
new file mode 100644
index 0000000000..b794e38920
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/hash-test.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test hash functions.
+ */
+
+#include <assert.h>
+#include "string.hpp"
+#include "hash.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+bool testCrc32hash() {
+ const string key("This is a test key");
+ unsigned int h = crc32hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+bool testTimes33hash() {
+ const string key("This is a test key");
+ unsigned int h = times33hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+bool testMurmurhash() {
+ const string key("This is a test key");
+ unsigned int h = murmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+bool testPortablemurmurhash() {
+ const string key("This is a test key");
+ unsigned int h = portablemurmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+}
+
+struct crc32hashTest {
+ const string key;
+ crc32hashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = crc32hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+struct times33hashTest {
+ const string key;
+ times33hashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = times33hash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+struct murmurhashTest {
+ const string key;
+ murmurhashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = murmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+struct portablemurmurhashTest {
+ const string key;
+ portablemurmurhashTest(const string& key) : key(key) {
+ }
+ bool operator()() const {
+ unsigned int h = portablemurmurhash(c_str(key), length(key));
+ assert(h != 0);
+ return true;
+ }
+};
+
+bool testHashPerf() {
+ const string key("This is a test key");
+ const int count = 100000;
+
+ const lambda<bool()> crc32 = crc32hashTest(key);
+ cout << "crc32hash test " << time(crc32, 5, count) << " ms" << endl;
+ const lambda<bool()> times33 = times33hashTest(key);
+ cout << "times33hash test " << time(times33, 5, count) << " ms" << endl;
+ const lambda<bool()> murmur = murmurhashTest(key);
+ cout << "murmurhash test " << time(murmur, 5, count) << " ms" << endl;
+ const lambda<bool()> portablemurmur = portablemurmurhashTest(key);
+ cout << "portable murmurhash test " << time(portablemurmur, 5, count) << " ms" << endl;
+
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testCrc32hash();
+ tuscany::testTimes33hash();
+ tuscany::testMurmurhash();
+ tuscany::testPortablemurmurhash();
+ tuscany::testHashPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/hash.hpp b/sandbox/sebastien/cpp/apr-2/kernel/hash.hpp
new file mode 100644
index 0000000000..9de13dd690
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/hash.hpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_hash_hpp
+#define tuscany_hash_hpp
+
+/**
+ * Fast hash functions.
+ */
+
+#include <apr_hash.h>
+#include <apr_memcache.h>
+
+namespace tuscany
+{
+
+/**
+ * Apache apr-util CRC32 hash function.
+ *
+ * See srclib/apr-util/memcache/apr_memcache.c from the Apache HTTPD
+ * source tree. Reproducing the comments from apr_memcache.c here:
+ *
+ * The crc32 functions and data were originally written by Spencer
+ * Garrett <srg@quick.com> and were gleaned from the PostgreSQL source
+ * tree at contrib/ltree/crc32.[ch] and from FreeBSD at
+ * src/usr.bin/cksum/crc32.c.
+ */
+const unsigned int crc32hash(const char* data, const size_t len) {
+ return (unsigned int)apr_memcache_hash_default(NULL, data, len);
+}
+
+/**
+ * Apache apr tables default hash function.
+ *
+ * See srclib/apr/tables/apr_hash.c from the Apache HTTPD source tree.
+ * Reproducing the comments from apr_hash.c here:
+ *
+ * This is the popular `times 33' hash algorithm which is used by
+ * perl and also appears in Berkeley DB. This is one of the best
+ * known hash functions for strings because it is both computed
+ * very fast and distributes very well.
+ *
+ * The originator may be Dan Bernstein but the code in Berkeley DB
+ * cites Chris Torek as the source. The best citation I have found
+ * is "Chris Torek, Hash function for text in C, Usenet message
+ * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich
+ * Salz's USENIX 1992 paper about INN which can be found at
+ * <http://citeseer.nj.nec.com/salz92internetnews.html>.
+ *
+ * The magic of number 33, i.e. why it works better than many other
+ * constants, prime or not, has never been adequately explained by
+ * anyone. So I try an explanation: if one experimentally tests all
+ * multipliers between 1 and 256 (as I did while writing a low-level
+ * data structure library some time ago) one detects that even
+ * numbers are not useable at all. The remaining 128 odd numbers
+ * (except for the number 1) work more or less all equally well.
+ * They all distribute in an acceptable way and this way fill a hash
+ * table with an average percent of approx. 86%.
+ *
+ * If one compares the chi^2 values of the variants (see
+ * Bob Jenkins ``Hashing Frequently Asked Questions'' at
+ * http://burtleburtle.net/bob/hash/hashfaq.html for a description
+ * of chi^2), the number 33 not even has the best value. But the
+ * number 33 and a few other equally good numbers like 17, 31, 63,
+ * 127 and 129 have nevertheless a great advantage to the remaining
+ * numbers in the large set of possible multipliers: their multiply
+ * operation can be replaced by a faster operation based on just one
+ * shift plus either a single addition or subtraction operation. And
+ * because a hash function has to both distribute good _and_ has to
+ * be very fast to compute, those few numbers should be preferred.
+ *
+ * -- Ralf S. Engelschall <rse@engelschall.com>
+ */
+const unsigned int times33hash(const char* data, const size_t len) {
+ apr_ssize_t l = len;
+ return apr_hashfunc_default(data, &l);
+}
+
+/**
+ * A very fast, non-cryptographic hash suitable for general hash-based
+ * lookup. See http://murmurhash.googlepages.com/ for more details.
+ *
+ * Original code by Austin Appleby, released to the public domain and under
+ * the MIT license.
+ *
+ * Compiles down to ~52 instructions on x86.
+ * Passes chi^2 tests for practically all keysets & bucket sizes.
+ * Excellent avalanche behavior. Maximum bias is under 0.5%.
+ * Passes Bob Jenkin's frog.c torture-test. No collisions possible for 4 byte
+ * keys, no small 1 to 7 bit differentials.
+ */
+const unsigned int murmurhash(const char* key, const size_t klen) {
+ unsigned int len = (unsigned int)klen;
+ const unsigned int seed = 0;
+
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char* data = (const unsigned char*)key;
+ while(len >= 4) {
+ unsigned int k = *(unsigned int*)data;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+/**
+ * An endian and alignment neutral, but half the speed, version of
+ * the murmur hash.
+ */
+const unsigned int portablemurmurhash(const char* key, const size_t klen) {
+ unsigned int len = (unsigned int)klen;
+ const unsigned int seed = 0;
+
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char* data = (const unsigned char *)key;
+ while(len >= 4) {
+ unsigned int k;
+ k = data[0];
+ k |= data[1] << 8;
+ k |= data[2] << 16;
+ k |= data[3] << 24;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len) {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+const unsigned int hashselect(const unsigned int hash, const unsigned int max) {
+ return hash % max;
+}
+
+}
+#endif /* tuscany_hash_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/kernel-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/kernel-test.cpp
new file mode 100644
index 0000000000..9b87397b96
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/kernel-test.cpp
@@ -0,0 +1,603 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test kernel functions.
+ */
+
+#include <assert.h>
+#include "string.hpp"
+#include "sstream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "dynlib.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+struct inc {
+ int i;
+ inc(int i) :
+ i(i) {
+ }
+ const int operator()(const int x) const {
+ return x + i;
+ }
+};
+
+const int square(const int x) {
+ return x * x;
+}
+
+int mapLambda(lambda<int(const int)> f, int v) {
+ return f(v);
+}
+
+bool testLambda() {
+ const lambda<int(const int)> sq(square);
+ assert(sq(2) == 4);
+ assert(mapLambda(sq, 2) == 4);
+ assert(mapLambda(square, 2) == 4);
+
+ const lambda<int(const int)> incf(inc(10));
+ assert(incf(1) == 11);
+ assert(mapLambda(incf, 1) == 11);
+ assert(mapLambda(inc(10), 1) == 11);
+
+ lambda<int(const int)> l;
+ l = incf;
+ assert(l(1) == 11);
+ l = square;
+ assert(l(2) == 4);
+ return true;
+}
+
+bool testLambdaGC() {
+ resetLambdaCounters();
+ {
+ gc_scoped_pool gc;
+ testLambda();
+ }
+ assert(checkLambdaCounters());
+ return true;
+}
+
+int countElements = 0;
+
+struct Element {
+ int i;
+
+ Element() : i(0) {
+ countElements++;
+ }
+
+ Element(int i) : i(i) {
+ countElements++;
+ }
+
+ Element(const Element& o) : i(o.i) {
+ countElements++;
+ }
+
+ ~Element() {
+ countElements--;
+ }
+
+ const bool operator==(const Element& o) const {
+ return o.i == i;
+ }
+};
+ostream& operator<<(ostream& out, const Element& v) {
+ out << v.i ;
+ return out;
+}
+
+bool testCons() {
+ assert(car(cons(2, mklist(3))) == 2);
+ assert(car(cdr(cons(2, mklist(3)))) == 3);
+ assert(isNil(cdr(cdr(cons(2, mklist(3))))));
+
+ assert(cons(Element(1), mklist(Element(2))) == mklist(Element(1), Element(2)));
+ return true;
+}
+
+bool testListGC() {
+ resetLambdaCounters();
+ resetListCounters();
+ countElements = 0;
+ {
+ gc_scoped_pool gc;
+ testCons();
+ }
+ assert(checkLambdaCounters());
+ assert(checkListCounters());
+ assert(countElements == 0);
+ return true;
+}
+
+bool testOut() {
+ ostringstream os1;
+ os1 << list<int> ();
+ assert(str(os1) == "()");
+
+ ostringstream os2;
+ os2 << mklist(1, 2, 3);
+ assert(str(os2) == "(1 2 3)");
+ return true;
+}
+
+bool testEquals() {
+ assert(list<int>() == list<int>());
+ assert(mklist(1, 2) == mklist(1, 2));
+ assert(list<int>() != mklist(1, 2));
+ assert(mklist(1, 2, 3) == mklist(1, 2, 3));
+ assert(mklist(1, 2) != mklist(1, 2, 3));
+ return true;
+}
+
+bool testLength() {
+ assert(0 == length(list<int>()));
+ assert(1 == length(mklist(1)));
+ assert(2 == length(cons(1, mklist(2))));
+ return true;
+}
+
+bool testAppend() {
+ assert(car(append(mklist(1), mklist(2))) == 1);
+ assert(car(cdr(append(mklist(1), mklist(2)))) == 2);
+ assert(car(cdr(cdr(append(mklist(1), mklist(2, 3))))) == 3);
+ assert(isNil(cdr(cdr(cdr(append(mklist(1), mklist(2, 3)))))));
+
+ assert(list<int>() + 1 + 2 + 3 == mklist(1, 2, 3));
+ return true;
+}
+
+struct Complex {
+ int x;
+ int y;
+ Complex() {
+ }
+ Complex(int x, int y) :
+ x(x), y(y) {
+ }
+};
+ostream& operator<<(ostream& out, const Complex& v) {
+ out << "[" << v.x << ":" << v.y << "]";
+ return out;
+}
+
+bool testComplex() {
+ const list<Complex> p = mklist(Complex(1, 2), Complex(3, 4));
+ assert(car(p).x == 1);
+ assert(car(cdr(p)).x == 3);
+ assert(isNil(cdr(cdr(p))));
+ return true;
+}
+
+bool testMap() {
+ assert(isNil(map<int, int>(square, list<int>())));
+
+ const list<int> m = map<int, int>(square, mklist(2, 3));
+ assert(car(m) == 4);
+ assert(car(cdr(m)) == 9);
+
+ return true;
+}
+
+const int add(const int x, const int y) {
+ return x + y;
+}
+
+bool testReduce() {
+ const lambda<int(const int, const int)> r(add);
+ assert(reduce(r, 0, mklist(1, 2, 3)) == 6);
+ return true;
+}
+
+bool isPositive(const int x) {
+ if(x >= 0)
+ return true;
+ else
+ return false;
+}
+
+bool testFilter() {
+ assert(car(filter<int>(isPositive, mklist(1, -1, 2, -2))) == 1);
+ assert(cadr(filter<int>(isPositive, mklist(1, -1, 2, -2))) == 2);
+ return true;
+}
+
+bool testMember() {
+ assert(isNil(member(4, mklist(1, 2, 3))));
+ assert(car(member(1, mklist(1, 2, 3))) == 1);
+ assert(car(member(2, mklist(1, 2, 3))) == 2);
+ assert(car(member(3, mklist(1, 2, 3))) == 3);
+ return true;
+}
+
+bool testReverse() {
+ assert(isNil(reverse(list<int>())));
+ assert(car(reverse(mklist(1, 2, 3))) == 3);
+ assert(cadr(reverse(mklist(1, 2, 3))) == 2);
+ return true;
+}
+
+bool testListRef() {
+ assert(listRef(mklist(1), 0) == 1);
+ assert(listRef(mklist(1, 2, 3), 0) == 1);
+ assert(listRef(mklist(1, 2, 3), 1) == 2);
+ assert(listRef(mklist(1, 2, 3), 2) == 3);
+ return true;
+}
+
+bool testAssoc() {
+ const list<list<string> > l = mklist(mklist<string>("x", "X"), mklist<string>("a", "A"), mklist<string>("y", "Y"), mklist<string>("a", "AA"));
+ assert(assoc<string>("a", l) == mklist<string>("a", "A"));
+ assert(isNil(assoc<string>("z", l)));
+
+ const list<list<value> > u = mklist(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"), mklist<value>("a", "AA"));
+ assert(assoc<value>("a", u) == mklist<value>("a", "A"));
+
+ const list<value> v = mklist<value>(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"), mklist<value>("a", "AA"));
+ assert(assoc<value>("a", v) == mklist<value>("a", "A"));
+ return true;
+}
+
+bool testZip() {
+ const list<string> k = mklist<string>("x", "a", "y", "a");
+ const list<string> v = mklist<string>("X", "A", "Y", "AA");
+ const list<list<string> > z = mklist(k, v);
+ const list<list<string> > u = mklist(mklist<string>("x", "X"), mklist<string>("a", "A"), mklist<string>("y", "Y"), mklist<string>("a", "AA"));
+ assert(zip(k, v) == u);
+ assert(unzip(u) == z);
+ return true;
+}
+
+bool testTokenize() {
+ assert(tokenize("/", "") == list<string>());
+ assert(tokenize("/", "aaa") == mklist<string>("aaa"));
+ assert(tokenize("/", "aaa/bbb/ccc/ddd") == mklist<string>("aaa", "bbb", "ccc", "ddd"));
+ assert(tokenize("/", "/bbb/ccc/ddd") == mklist<string>("", "bbb", "ccc", "ddd"));
+ assert(tokenize("/", "/bbb/ccc/") == mklist<string>("", "bbb", "ccc"));
+ assert(tokenize("/", "/bbb//ccc/") == mklist<string>("", "bbb", "", "ccc"));
+ assert(tokenize("/", "abc/def/") == mklist<string>("abc", "def"));
+
+ assert(join("/", list<string>()) == "");
+ assert(join("/", mklist<string>("aaa")) == "aaa");
+ assert(join("/", mklist<string>("aaa", "bbb", "ccc", "ddd")) == "aaa/bbb/ccc/ddd");
+ assert(join("/", mklist<string>("", "bbb", "ccc", "ddd")) == "/bbb/ccc/ddd");
+ assert(join("/", mklist<string>("bbb", "ccc", "")) == "bbb/ccc/");
+ assert(join("/", mklist<string>("bbb", "", "ccc")) == "bbb//ccc");
+ return true;
+}
+
+double testSeqMap(double x) {
+ return x;
+}
+
+double testSeqReduce(unused double v, double accum) {
+ return accum + 1.0;
+}
+
+bool testSeq() {
+ resetLambdaCounters();
+ resetListCounters();
+
+ list<double> s = seq(0.0, 1000.0);
+ assert(1001 == length(s));
+
+ assert(1001 == length(map<double, double>(testSeqMap, s)));
+
+ assert(801 == length(member(200.0, s)));
+ assert(201 == length(member(200.0, reverse(s))));
+
+ assert(1001 == (reduce<double, double>(testSeqReduce, 0.0, s)));
+ return true;
+}
+
+value valueSquare(list<value> x) {
+ return (int)car(x) * (int)car(x);
+}
+
+bool testValue() {
+ assert(value(true) == value(true));
+ assert(value(1) == value(1));
+ assert(value("abcd") == value("abcd"));
+ lambda<value(const list<value>&)> vl(valueSquare);
+ assert(value(vl) == value(vl));
+ assert(value(mklist<value>(1, 2)) == value(mklist<value>(1, 2)));
+
+ const list<value> v = mklist<value>(mklist<value>("x", "X"), mklist<value>("a", "A"), mklist<value>("y", "Y"));
+ assert(cadr((list<list<value> >)value(v)) == mklist<value>("a", "A"));
+
+ const value pv(gc_ptr<value>(new (gc_new<value>()) value(1)));
+ assert(*(gc_ptr<value>)pv == value(1));
+
+ const list<value> lpv = mklist<value>(gc_ptr<value>(new (gc_new<value>()) value(1)), gc_ptr<value>(new (gc_new<value>()) value(2)));
+ assert(*(gc_ptr<value>)car(lpv) == value(1));
+ return true;
+}
+
+bool testValueGC() {
+ resetLambdaCounters();
+ resetListCounters();
+ resetValueCounters();
+ {
+ gc_scoped_pool gc;
+ testValue();
+ }
+ assert(checkValueCounters());
+ assert(checkLambdaCounters());
+ assert(checkListCounters());
+ return true;
+}
+
+bool testTree() {
+ const list<value> t = mktree<value>("a", list<value>(), list<value>());
+ const list<value> ct = constree<value>("d", constree<value>("f", constree<value>("c", constree<value>("e", constree<value>("b", t)))));
+ const list<value> mt = mktree(mklist<value>("d", "f", "c", "e", "b", "a"));
+ assert(mt == ct);
+ const list<value> l = flatten<value>(mt);
+ assert(length(l) == 6);
+ assert(car(l) == "a");
+ assert(car(reverse(l)) == "f");
+ const list<value> bt = mkbtree<value>(l);
+ assert(car(bt) == "c");
+ return true;
+}
+
+const list<value> lta(const string& x) {
+ return mklist<value>(c_str(x), c_str(x + x));
+}
+
+bool testTreeAssoc() {
+ const list<value> t = mktree<value>(lta("a"), list<value>(), list<value>());
+ const list<value> at = constree<value>(lta("d"), constree<value>(lta("f"), constree<value>(lta("c"), constree<value>(lta("e"), constree<value>(lta("b"), t)))));
+ const list<value> l = flatten<value>(at);
+ assert(length(l) == 6);
+ assert(car(l) == mklist<value>("a", "aa"));
+ assert(car(reverse(l)) == mklist<value>("f", "ff"));
+ const list<value> bt = mkbtree<value>(l);
+ assert(car(bt) == mklist<value>("c", "cc"));
+ assert(assoctree<value>("a", bt) == mklist<value>("a", "aa"));
+ assert(assoctree<value>("b", bt) == mklist<value>("b", "bb"));
+ assert(assoctree<value>("f", bt) == mklist<value>("f", "ff"));
+ assert(isNil(assoctree<value>("x", bt)));
+ return true;
+}
+
+double fib_aux(double n, double a, double b) {
+ if(n == 0.0)
+ return a;
+ return fib_aux(n - 1.0, b, a + b);
+}
+
+double fib(double n) {
+ return fib_aux(n, 0.0, 1.0);
+}
+
+struct fibMapPerf {
+ const bool operator()() const {
+ list<double> s = seq(0.0, 999.0);
+ list<double> r = map<double, double>(fib, s);
+ assert(1000 == length(r));
+ return true;
+ }
+};
+
+struct nestedFibMapPerf {
+ const lambda<double(const double)> fib;
+ nestedFibMapPerf(const lambda<double(const double)>& fib) : fib(fib) {
+ }
+ const bool operator()() const {
+ list<double> s = seq(0.0, 999.0);
+ list<double> r = map<double, double>(fib, s);
+ assert(1000 == length(r));
+ return true;
+ }
+};
+
+bool testCppPerf() {
+ {
+ const lambda<bool()> fml = fibMapPerf();
+ cout << "Fibonacci map test " << (time(fml, 1, 1) / 1000) << " ms" << endl;
+ }
+
+ {
+ struct nested {
+ static double fib(double n) {
+ struct nested {
+ static double fib_aux(double n, double a, double b) {
+ if(n == 0.0)
+ return a;
+ return fib_aux(n - 1.0, b, a + b);
+ }
+ };
+ return nested::fib_aux(n, 0.0, 1.0);
+ }
+ };
+
+ const lambda<bool()> nfml = nestedFibMapPerf(lambda<double(const double)>(nested::fib));
+ cout << "Nested Fibonacci map test " << (time(nfml, 1, 1) / 1000) << " ms" << endl;
+ }
+ return true;
+}
+
+const id<int> idF(const int v) {
+ return v * 2;
+}
+
+const id<int> idG(const int v) {
+ return v * 3;
+}
+
+const id<int> idH(const int v) {
+ return idF(v) >> idG;
+}
+
+bool testIdMonad() {
+ const id<int> m(2);
+ assert(m >> idF == idF(2));
+ assert(m >> unit<int>() == m);
+ assert(m >> idF >> idG == m >> idH);
+ return true;
+}
+
+const maybe<int> maybeF(const int v) {
+ return v * 2;
+}
+
+const maybe<int> maybeG(const int v) {
+ return v * 3;
+}
+
+const maybe<int> maybeH(const int v) {
+ return maybeF(v) >> maybeG;
+}
+
+bool testMaybeMonad() {
+ const maybe<int> m(2);
+ assert(m >> maybeF == maybeF(2));
+ assert((m >> just<int>()) == m);
+ assert(m >> maybeF >> maybeG == m >> maybeH);
+
+ assert(maybe<int>() >> maybeF >> maybeG == maybe<int>());
+ return true;
+}
+
+const failable<int> failableF(const int v) {
+ return v * 2;
+}
+
+const failable<int> failableG(const int v) {
+ return v * 3;
+}
+
+const failable<int> failableH(const int v) {
+ return failableF(v) >> failableG;
+}
+
+bool testFailableMonad() {
+ const failable<int> m(2);
+ assert(m >> failableF == failableF(2));
+ assert((m >> success<int, string>()) == m);
+ assert(m >> failableF >> failableG == m >> failableH);
+
+ cout << "Failable monad test... " << endl;
+ failable<int> ooops = mkfailure<int>("test");
+ assert(reason(ooops) == "test");
+ assert(ooops >> failableF >> failableG == ooops);
+ return true;
+}
+
+struct tickInc {
+ const double v;
+ tickInc(const double v) : v(v) {
+ }
+ const scp<int, double> operator()(int s) const {
+ return scp<int, double>(s + 1, v);
+ }
+};
+
+const state<int, double> tick(const double v) {
+ return transformer<int, double>(tickInc(v));
+}
+
+const state<int, double> stateF(const double v) {
+ return result<int, double>(v * 2.0) >> tick;
+}
+
+const state<int, double> stateG(const double v) {
+ return result<int, double>(v + 5);
+}
+
+const state<int, double> stateH(const double v) {
+ return stateF(v) >> stateG;
+}
+
+bool testStateMonad() {
+ const lambda<state<int, double>(const double)> r(result<int, double>);
+
+ state<int, double> m = result<int, double>(2.0);
+ assert((m >> stateF)(0) == stateF(2.0)(0));
+ assert(1 == (int)(m >> stateF)(0));
+ assert((m >> r)(0) == m(0));
+ assert((m >> stateF >> stateG)(0) == (m >> stateH)(0));
+
+ return true;
+}
+
+bool testDynLib() {
+ const lib dl(string("./libdynlib-test") + dynlibExt);
+ const failable<lambda<int(const int)> > sq(dynlambda<int(const int)>("csquare", dl));
+ assert(hasContent(sq));
+ lambda<int(const int)> l(content(sq));
+ assert(l(2) == 4);
+
+ const failable<lambda<lambda<int(const int)>()> > sql(dynlambda<lambda<int(const int)>()>("csquarel", dl));
+ assert(hasContent(sql));
+ lambda<lambda<int(const int)>()> ll(content(sql));
+ assert(ll()(3) == 9);
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testLambda();
+ tuscany::testLambdaGC();
+ tuscany::testCons();
+ tuscany::testListGC();
+ tuscany::testOut();
+ tuscany::testEquals();
+ tuscany::testLength();
+ tuscany::testAppend();
+ tuscany::testComplex();
+ tuscany::testMap();
+ tuscany::testReduce();
+ tuscany::testFilter();
+ tuscany::testMember();
+ tuscany::testReverse();
+ tuscany::testListRef();
+ tuscany::testAssoc();
+ tuscany::testZip();
+ tuscany::testTokenize();
+ tuscany::testSeq();
+ tuscany::testValue();
+ tuscany::testValueGC();
+ tuscany::testTree();
+ tuscany::testTreeAssoc();
+ tuscany::testCppPerf();
+ tuscany::testIdMonad();
+ tuscany::testMaybeMonad();
+ tuscany::testFailableMonad();
+ tuscany::testStateMonad();
+ tuscany::testDynLib();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/lambda-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/lambda-test.cpp
new file mode 100644
index 0000000000..a72f01fb43
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/lambda-test.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test C++0x lambda expressions.
+ */
+
+#include <assert.h>
+#include "function.hpp"
+#include "sstream.hpp"
+#include "fstream.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_GCC45
+
+const lambda<const int(const int)> inc(const int i) {
+ return [=](const int x)->const int {
+ return x + i;
+ };
+}
+
+const int square(const int x) {
+ return x * x;
+}
+
+int mapLambda(const lambda<const int(const int)> f, int v) {
+ return f(v);
+}
+
+bool testLambda() {
+ const lambda<const int(const int)> sq = square;
+ assert(sq(2) == 4);
+ assert(mapLambda(square, 2) == 4);
+ assert(mapLambda(sq, 2) == 4);
+ assert(mapLambda([](const int x)->const int { return x * x; }, 2) == 4);
+
+ const lambda<int(int)> incf = inc(10);
+ assert(incf(1) == 11);
+ assert(mapLambda(incf, 1) == 11);
+ assert(mapLambda(inc(10), 1) == 11);
+
+ lambda<const int(const int)> l;
+ l = incf;
+ assert(l(1) == 11);
+ l = square;
+ assert(l(2) == 4);
+ return true;
+}
+
+const double fib_aux(const double n, const double a, const double b) {
+ return n == 0.0? a : fib_aux(n - 1.0, b, a + b);
+}
+
+const bool fibMapPerf() {
+ list<double> s = seq(0.0, 4999.0);
+ list<double> r = map<double, double>([](const double n)->const double { return fib_aux(n, 0.0, 1.0); }, s);
+ assert(5000 == length(r));
+ return true;
+}
+
+bool testCppPerf() {
+ cout << "Fibonacci map test " << (time([]()->const bool { return fibMapPerf(); }, 1, 1) / 5000) << " ms" << endl;
+ return true;
+}
+
+#endif
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+#ifdef WANT_GCC45
+ tuscany::testLambda();
+ tuscany::testCppPerf();
+#else
+ tuscany::cout << "Skipped GCC 4.5 tests" << tuscany::endl;
+#endif
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/list.hpp b/sandbox/sebastien/cpp/apr-2/kernel/list.hpp
new file mode 100644
index 0000000000..a8dbcc1b0c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/list.hpp
@@ -0,0 +1,587 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_list_hpp
+#define tuscany_list_hpp
+
+/**
+ * Simple list functions.
+ */
+
+#include <assert.h>
+#include "string.hpp"
+#include "fstream.hpp"
+#include "function.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug utilities. Counters used to track instances of lists, and
+ * macro used to write the contents of a list in a string, easier to
+ * watch in a debugger than the list itself.
+ */
+long countLists = 0;
+long countILists = 0;
+long countCLists = 0;
+long countELists = 0;
+
+bool resetListCounters() {
+ countLists = countILists = countCLists = countELists = 0;
+ return true;
+}
+
+bool checkListCounters() {
+ return countLists == 0;
+}
+
+bool printListCounters() {
+ cout << "countLists " << countLists << endl;
+ cout << "countELists " << countELists << endl;
+ cout << "countILists " << countILists << endl;
+ cout << "countCLists " << countCLists << endl;
+ return true;
+}
+
+#else
+
+#define resetListCounters()
+#define checkListCounters() true
+#define printListCounters()
+
+#endif
+
+#ifdef WANT_MAINTAINER_WATCH
+
+#define debug_watchList() do { \
+ this->watch = watchList(*this); \
+ } while (0)
+
+#else
+
+#define debug_watchList();
+
+#endif
+
+/**
+ * A car/cdr lisp-like pair, base structure to construct lists.
+ */
+
+template<typename T> class list {
+public:
+
+ list() {
+ debug_inc(countLists);
+ debug_inc(countELists);
+ debug_watchList();
+ }
+
+ list(const T car, const lambda<list<T>()>& cdr) : car(car), cdr(cdr) {
+ debug_inc(countLists);
+ debug_inc(countILists);
+ debug_watchList();
+ }
+
+ list(const list& p) : car(p.car), cdr(p.cdr) {
+ debug_inc(countLists);
+ debug_inc(countCLists);
+#ifdef WANT_MAINTAINER_WATCH
+ watch = p.watch;
+#endif
+ }
+
+ const list<T>& operator=(const list<T>& p) {
+ if(this == &p)
+ return *this;
+ car = p.car;
+ cdr = p.cdr;
+#ifdef WANT_MAINTAINER_WATCH
+ watch = p.watch;
+#endif
+ return *this;
+ }
+
+ ~list() {
+ debug_dec(countLists);
+ }
+
+ const bool operator==(const list<T>& p) const {
+ if(this == &p)
+ return true;
+ if(isNil(cdr))
+ return isNil(p.cdr);
+ if(isNil(p.cdr))
+ return false;
+ if(!(car == p.car))
+ return false;
+ if(cdr == p.cdr)
+ return true;
+ return cdr() == p.cdr();
+ }
+
+ const bool operator<(const list<T>& p) const {
+ if(this == &p)
+ return false;
+ if (isNil(cdr))
+ return !isNil(p.cdr);
+ if (isNil(p.cdr))
+ return false;
+ if (car < p.car)
+ return true;
+ if (car != p.car)
+ return false;
+ return cdr() < p.cdr();
+ }
+
+ const bool operator>(const list<T>& p) const {
+ if(this == &p)
+ return false;
+ if (isNil(cdr))
+ return false;
+ if (isNil(p.cdr))
+ return true;
+ if (car > p.car)
+ return true;
+ if (car != p.car)
+ return false;
+ return cdr() > p.cdr();
+ }
+
+ const bool operator!=(const list<T>& p) const {
+ return !this->operator==(p);
+ }
+
+ operator const list<list<T> >() const {
+ return (list<list<T> >)T(*this);
+ }
+
+private:
+#ifdef WANT_MAINTAINER_WATCH
+ template<typename X> friend const string watchList(const list<X>& p);
+ string watch;
+#endif
+
+ template<typename X> friend const bool isNil(const list<X>& p);
+ template<typename X> friend const X car(const list<X>& p);
+ template<typename X> friend const list<X> cdr(const list<X>& p);
+
+ T car;
+ lambda<list<T>()> cdr;
+};
+
+#ifdef WANT_MAINTAINER_WATCH
+
+/**
+ * Debug utility used to write the contents of a list to a string, easier
+ * to watch than the list itself in a debugger.
+ */
+template<typename T> const string watchList(const list<T>& p) {
+ if(isNil(p))
+ return "()";
+ odebugstream os;
+ os << "(" << car(p) << " ...)";
+ return str(os);
+}
+
+#endif
+
+/**
+ * Returns true if the given list is nil.
+ */
+template<typename T> const bool isNil(const list<T>& p) {
+ return isNil(p.cdr);
+}
+
+/**
+ * Write a list to an output stream.
+ */
+template<typename T> ostream& writeHelper(ostream& out, const list<T>& l) {
+ if (isNil(l))
+ return out;
+ out << " " << car(l);
+ return writeHelper(out, cdr(l));
+}
+
+template<typename T> ostream& operator<<(ostream& out, const list<T>& l) {
+ if(isNil(l))
+ return out << "()";
+ out << "(" << car(l);
+ writeHelper<T>(out, cdr(l));
+ return out << ")";
+}
+
+/**
+ * Construct a (lazy) list from a value and a lambda function that returns the cdr.
+ */
+template<typename T> const list<T> cons(const T& car, const lambda<list<T>()>& cdr) {
+ return list<T> (car, cdr);
+}
+
+/**
+ * Construct a list from a value and a cdr list.
+ */
+template<typename T> const list<T> cons(const T& car, const list<T>& cdr) {
+ return list<T> (car, result(cdr));
+}
+
+/**
+ * Cons variations for use with the reduce and reduceRight functions.
+ */
+template<typename T> const list<T> lcons(const list<T>& cdr, const T& car) {
+ return cons<T>(car, cdr);
+}
+
+template<typename T> const list<T> rcons(const T& car, const list<T>& cdr) {
+ return cons<T>(car, cdr);
+}
+
+/**
+ * Construct a list of one value.
+ */
+template<typename T> const list<T> mklist(const T& car) {
+ return list<T> (car, result(list<T> ()));
+}
+
+/**
+ * Construct a list of two values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b) {
+ return cons(a, mklist(b));
+}
+
+/**
+ * Construct a list of three values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c) {
+ return cons(a, cons(b, mklist(c)));
+}
+
+/**
+ * Construct a list of four values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d) {
+ return cons(a, cons(b, cons(c, mklist(d))));
+}
+
+/**
+ * Construct a list of five values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e) {
+ return cons(a, cons(b, cons(c, cons(d, mklist(e)))));
+}
+
+/**
+ * Construct a list of six values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f) {
+ return cons(a, cons(b, cons(c, cons(d, cons(e, mklist(f))))));
+}
+
+/**
+ * Returns the car of a list.
+ */
+template<typename T> const T car(const list<T>& p) {
+ // Abort if trying to access the car of a nil list
+ assert(!isNil(p.cdr));
+ return p.car;
+}
+
+/**
+ * Returns the cdr of a list.
+ */
+template<typename T> const list<T> cdr(const list<T>& p) {
+ return p.cdr();
+}
+
+/**
+ * Returns the car of the cdr (the 2nd element) of a list.
+ */
+template<typename T> const T cadr(const list<T>& p) {
+ return car(cdr(p));
+}
+
+/**
+ * Returns the 3rd element of a list.
+ */
+template<typename T> const T caddr(const list<T>& p) {
+ return car(cdr(cdr(p)));
+}
+
+/**
+ * Returns the 4th element of a list.
+ */
+template<typename T> const T cadddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(p))));
+}
+
+/**
+ * Returns the 5th element of a list.
+ */
+template<typename T> const T caddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(p)))));
+}
+
+/**
+ * Returns the 6th element of a list.
+ */
+template<typename T> const T cadddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(cdr(p))))));
+}
+
+/**
+ * Returns the 7th element of a list.
+ */
+template<typename T> const T caddddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(cdr(cdr(p)))))));
+}
+
+/**
+ * Returns the 8th element of a list.
+ */
+template<typename T> const T cadddddddr(const list<T>& p) {
+ return car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(p))))))));
+}
+
+/**
+ * Returns the cdr of a cdr of a list.
+ */
+template<typename T> const list<T> cddr(const list<T>& p) {
+ return cdr(cdr(p));
+}
+
+/**
+ * Returns the cdr of a cdr of the cdr of a list.
+ */
+template<typename T> const list<T> cdddr(const list<T>& p) {
+ return cdr(cdr(cdr(p)));
+}
+
+/**
+ * Returns the length of a list.
+ */
+template<typename T> struct lengthRef {
+ const size_t operator()(const size_t c, const list<T>& p) {
+ if(isNil(p))
+ return c;
+ return (*this)(c + 1, cdr(p));
+ }
+};
+
+template<typename T> const size_t length(const list<T>& p) {
+ return lengthRef<T> ()(0, p);
+}
+
+/**
+ * Appends a list and a lambda function returning a list.
+ */
+template<typename T> struct appendCdr {
+ const list<T> a;
+ const lambda<list<T>()> fb;
+ appendCdr(const list<T>& a, const lambda<list<T>()>& fb) :
+ a(a), fb(fb) {
+ }
+ const list<T> operator()() const {
+ return append(a, fb);
+ }
+};
+
+template<typename T> const list<T> append(const list<T>&a, const lambda<list<T>()>& fb) {
+ if(isNil(a))
+ return fb();
+
+ return cons<T>(car(a), appendCdr<T> (cdr(a), fb));
+}
+
+/**
+ * Appends two lists.
+ */
+template<typename T> const list<T> append(const list<T>&a, const list<T>& b) {
+ return append(a, result(b));
+}
+
+/**
+ * Append a value to a list.
+ */
+template<typename T> const list<T> operator+(const list<T>& l, const T& v) {
+ return append(l, mklist(v));
+}
+
+template<typename T, typename V> const list<T> operator+(const list<T>& l, const V& v) {
+ return append(l, mklist<T>(v));
+}
+
+/**
+ * Map a lambda function on a list.
+ */
+template<typename T, typename R> const list<R> map(const lambda<R(const T)>& f, const list<T>& p) {
+ if(isNil(p))
+ return list<R> ();
+ return cons(f(car(p)), map(f, cdr(p)));
+}
+
+/**
+ * Run a reduce lambda function on a list.
+ */
+template<typename T, typename R> struct reduceAccumulate {
+ const lambda<R(const R&, const T&)> f;
+ reduceAccumulate(const lambda<R(const R, const T)>& f) :
+ f(f) {
+ }
+ R operator()(const R& acc, const list<T>& p) const {
+ if(isNil(p))
+ return acc;
+ return (*this)(f(acc, car(p)), cdr(p));
+ }
+};
+
+template<typename T, typename R> const R reduce(const lambda<R(const R, const T)>& f, const R& initial, const list<T>& p) {
+ return reduceAccumulate<T, R> (f)(initial, p);
+}
+
+template<typename T, typename R> struct reduceRightAccumulate {
+ const lambda<R(const T&, const R&)> f;
+ reduceRightAccumulate(const lambda<R(const T, const R)>& f) :
+ f(f) {
+ }
+ R operator()(const list<T>& p, const R& acc) const {
+ if(isNil(p))
+ return acc;
+ return (*this)(cdr(p), f(car(p), acc));
+ }
+};
+
+template<typename T, typename R> const R reduceRight(const lambda<R(const T, const R)>& f, const R& initial, const list<T>& p) {
+ return reduceRightAccumulate<T, R> (f)(p, initial);
+}
+
+/**
+ * Run a filter lambda function on a list.
+ */
+template<typename T> const list<T> filter(const lambda<bool(const T)>& f, const list<T>& p) {
+ if(isNil(p))
+ return list<T> ();
+ if(f(car(p))) {
+ const lambda<list<T>(const lambda<bool(const T)>, const list<T>)> ff(filter<T>);
+ return cons(car(p), curry(ff, f, cdr(p)));
+ }
+ return filter(f, cdr(p));
+}
+
+/**
+ * Returns a list pointing to a member of a list.
+ */
+template<typename T> const list<T> member(const T& t, const list<T>& p) {
+ if(isNil(p))
+ return list<T> ();
+ if(t == car(p))
+ return p;
+ return member(t, cdr(p));
+}
+
+/**
+ * Reverse a list.
+ */
+template<typename T> const list<T> reverseIter(const list<T>& acc, const list<T>& p) {
+ if(isNil(p))
+ return acc;
+ return reverseIter(cons(car(p), acc), cdr(p));
+}
+
+template<typename T> const list<T> reverse(const list<T>& p) {
+ return reverseIter(list<T> (), p);
+}
+
+template<typename T> const list<T> seq(const T& start, const T& end);
+
+template<typename T> struct seqGenerate {
+ const T start;
+ const T end;
+ seqGenerate(const T& start, const T&end) :
+ start(start), end(end) {
+ }
+ const list<T> operator()() const {
+ return seq<T> (start, end);
+ }
+};
+
+/**
+ * Returns a sequence of values between the given bounds.
+ */
+template<typename T> const list<T> seq(const T& start, const T& end) {
+ if(start == end)
+ return mklist(start);
+ if(start < end)
+ return cons<T>(start, seqGenerate<T> (start + 1, end));
+ return cons<T>(start, seqGenerate<T> (start - 1, end));
+}
+
+/**
+ * Returns the i-th element of a list.
+ */
+template<typename T> const T listRef(const list<T>& l, const size_t i) {
+ if (i == 0)
+ return car(l);
+ return listRef(cdr(l), i - 1);
+}
+
+/**
+ * Returns the first pair matching a key from a list of key value pairs.
+ */
+template<typename T> const list<T> assoc(const T& k, const list<list<T> >& p) {
+ if(isNil(p))
+ return list<T> ();
+ if(k == car(car(p)))
+ return car(p);
+ return assoc(k, cdr(p));
+}
+
+/**
+ * Returns a list of lists containing elements from two input lists.
+ */
+template<typename T> const list<list<T> > zip(const list<T>& a, const list<T>& b) {
+ if (isNil(a) || isNil(b))
+ return list<list<T> >();
+ return cons<list<T> >(mklist<T>(car(a), car(b)), zip(cdr(a), cdr(b)));
+}
+
+/**
+ * Converts a list of key value pairs to a list containing the list of keys and the list of values.
+ */
+template<typename T> const list<T> unzipKeys(const list<list<T> >& l) {
+ if (isNil(l))
+ return list<T>();
+ return cons(car(car(l)), unzipKeys(cdr(l)));
+}
+
+template<typename T> const list<T> unzipValues(const list<list<T> >& l) {
+ if (isNil(l))
+ return list<T>();
+ return cons(cadr(car(l)), unzipValues(cdr(l)));
+}
+
+template<typename T> const list<list<T> > unzip(const list<list<T> >& l) {
+ return mklist<list<T> >(unzipKeys(l), unzipValues(l));
+}
+
+}
+
+#endif /* tuscany_list_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/mem-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/mem-test.cpp
new file mode 100644
index 0000000000..b1164a5a36
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/mem-test.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test memory allocation functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "gc.hpp"
+#include "function.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+int countElements = 0;
+int maxElements = 0;
+
+class Element {
+public:
+ Element() : i(0) {
+ countElements++;
+ if (countElements > maxElements)
+ maxElements = countElements;
+ }
+
+ Element(int i) : i(i) {
+ countElements++;
+ if (countElements > maxElements)
+ maxElements = countElements;
+ }
+
+ Element(const Element& o) : i(o.i) {
+ countElements++;
+ if (countElements > maxElements)
+ maxElements = countElements;
+ }
+
+ ~Element() {
+ countElements--;
+ }
+
+ const bool operator==(const Element& o) const {
+ return o.i == i;
+ }
+
+private:
+ friend ostream& operator<<(ostream& out, const Element& v);
+
+ int i;
+ char c[20];
+};
+
+ostream& operator<<(ostream& out, const Element& v) {
+ out << v.i ;
+ return out;
+}
+
+bool poolAlloc(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ p[count - 1] = new (gc_new<Element>()) Element();
+ return poolAlloc(p, count - 1);
+};
+
+bool poolFree(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ // Do nothing to free the element, but cycle through them just
+ // to get a fair comparison with the other memory alloc tests
+ return poolFree(p, count - 1);
+};
+
+struct poolAllocPerf {
+ const int n;
+ Element** p;
+ poolAllocPerf(const int n) : n(n), p(new Element*[n]) {
+ }
+ const bool operator()() const {
+ gc_scoped_pool gc;
+ poolAlloc(p, n);
+ return true;
+ }
+};
+
+bool testPoolAllocPerf() {
+ const int count = 100000;
+ const lambda<bool()> pl = poolAllocPerf(count);
+ maxElements = 0;
+ cout << "Memory pool alloc test " << (time(pl, 1, 1) / count) << " ms" << endl;
+ assert(countElements == 0);
+ assert(maxElements == count);
+ return true;
+}
+
+bool stdAlloc(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ p[count - 1] = new Element();
+ return stdAlloc(p, count - 1);
+};
+
+bool stdFree(Element** p, const int count) {
+ if (count == 0)
+ return true;
+ delete p[count -1];
+ return stdFree(p, count - 1);
+};
+
+struct stdAllocPerf {
+ const int n;
+ Element** p;
+ stdAllocPerf(const int n) : n(n), p(new Element*[n]) {
+ }
+ const bool operator()() const {
+ stdAlloc(p, n);
+ stdFree(p, n);
+ return true;
+ }
+};
+
+bool testStdAllocPerf() {
+ const int count = 100000;
+ const lambda<bool()> sl = stdAllocPerf(count);
+ maxElements = 0;
+ cout << "Memory standard alloc test " << (time(sl, 1, 1) / count) << " ms" << endl;
+ assert(countElements == 0);
+ assert(maxElements == count);
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testPoolAllocPerf();
+ tuscany::testStdAllocPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/monad.hpp b/sandbox/sebastien/cpp/apr-2/kernel/monad.hpp
new file mode 100644
index 0000000000..d87a382ee1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/monad.hpp
@@ -0,0 +1,493 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_monad_hpp
+#define tuscany_monad_hpp
+
+/**
+ * Simple monad implementations.
+ */
+
+#include "function.hpp"
+#include "string.hpp"
+#include "stream.hpp"
+#include "sstream.hpp"
+#include "fstream.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Identity monad. Just wraps a value.
+ * To get the value in the monad, just cast it to the value type.
+ */
+template<typename V> class id {
+public:
+ id(const V& v) : v(v) {
+ }
+
+ const id<V>& operator=(const id<V>& m) {
+ if(this == &m)
+ return *this;
+ v = m.v;
+ return *this;
+ }
+
+ const bool operator!=(const id<V>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const id<V>& m) const {
+ if (&m == this)
+ return true;
+ return v == m.v;
+ }
+
+private:
+ const V v;
+
+ template<typename X> friend const X content(const id<X>& m);
+};
+
+/**
+ * Write an identity monad to a stream.
+ */
+template<typename V> ostream& operator<<(ostream& out, const id<V>& m) {
+ out << content(m);
+ return out;
+}
+
+/**
+ * Returns the content of an identity monad.
+ */
+template<typename V> const V content(const id<V>& m) {
+ return m.v;
+}
+
+/**
+ * Return an identity monad from a value.
+ */
+template<typename V> const id<V> mkunit(const V& v) {
+ return id<V>(v);
+}
+
+template<typename V> const lambda<id<V>(const V)> unit() {
+ return mkunit<V>;
+}
+
+/**
+ * Bind a function to an identity monad. Pass the value in the monad to the function.
+ */
+template<typename R, typename V> const id<R> operator>>(const id<V>& m, const lambda<id<R>(const V)>& f) {
+ return f(content(m));
+}
+
+template<typename R, typename V> const id<R> operator>>(const id<V>& m, const id<R> (* const f)(const V)) {
+ return f(content(m));
+}
+
+/**
+ * Maybe monad. Used to represent an optional value, which may be there or not.
+ * To get the value in the monad, just cast it to the value type.
+ */
+template<typename V> class maybe {
+public:
+ maybe(const V& v) : hasv(true), v(v) {
+ }
+
+ maybe() : hasv(false) {
+ }
+
+ const maybe<V>& operator=(const maybe<V>& m) {
+ if(this == &m)
+ return *this;
+ hasv = m.hasv;
+ if (hasv)
+ v = m.v;
+ return *this;
+ }
+
+ const bool operator!=(const maybe<V>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const maybe<V>& m) const {
+ if (this == &m)
+ return true;
+ if (!hasv)
+ return !m.hasv;
+ return m.hasv && v == m.v;
+ }
+
+private:
+ const bool hasv;
+ V v;
+
+ template<typename X> friend const bool hasContent(const maybe<X>& m);
+ template<typename X> friend const X content(const maybe<X>& m);
+};
+
+/**
+ * Write a maybe monad to a stream.
+ */
+template<typename V> ostream& operator<<(ostream& out, const maybe<V>& m) {
+ if (!hasContent(m)) {
+ out << "nothing";
+ return out;
+ }
+ out << content(m);
+ return out;
+}
+
+/**
+ * Return a maybe monad with a value in it.
+ */
+template<typename V> const maybe<V> mkjust(const V& v) {
+ return maybe<V>(v);
+}
+
+template<typename V> const lambda<maybe<V>(const V)> just() {
+ return mkjust<V>;
+}
+
+/**
+ * Returns true if a maybe monad contains a content.
+ */
+template<typename V> const bool hasContent(const maybe<V>& m) {
+ return m.hasv;
+}
+
+/**
+ * Returns the content of a maybe monad.
+ */
+template<typename V> const V content(const maybe<V>& m) {
+ return m.v;
+}
+
+/**
+ * Bind a function to a maybe monad. Passes the value in the monad to the function
+ * if present, or does nothing if there's no value.
+ */
+template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const lambda<maybe<R>(const V)>& f) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const maybe<R> (* const f)(const V)) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+/**
+ * Failable monad. Used to represent either a success value or a failure.
+ * To get the value in the monad, just cast it to the value type.
+ * To get the failure in the monad, cast it to the failure type.
+ */
+template<typename V, typename F = string> class failable {
+public:
+ failable() : hasv(false) {
+ }
+
+ failable(const V& v) : hasv(true), v(v) {
+ }
+
+ failable(const failable<V, F>& m) : hasv(m.hasv), v(m.v), f(m.f) {
+ }
+
+ const failable<V, F>& operator=(const failable<V, F>& m) {
+ if (&m == this)
+ return *this;
+ hasv = m.hasv;
+ v = m.v;
+ f = m.f;
+ return *this;
+ }
+
+ const bool operator!=(const failable<V, F>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const failable<V, F>& m) const {
+ if (this == &m)
+ return true;
+ if (!hasv)
+ return !m.hasv && f == m.f;
+ return m.hasv && v == m.v;
+ }
+
+private:
+ failable(const bool hasv, const F& f) : hasv(hasv), f(f) {
+ }
+
+ template<typename A, typename B> friend const bool hasContent(const failable<A, B>& m);
+ template<typename A, typename B> friend const A content(const failable<A, B>& m);
+ template<typename A, typename B> friend const B reason(const failable<A, B>& m);
+ template<typename A, typename B> friend const failable<A, B> mkfailure(const B& f);
+ template<typename A> friend const failable<A, string> mkfailure();
+
+ bool hasv;
+ V v;
+ F f;
+};
+
+/**
+ * Write a failable monad to a stream.
+ */
+template<typename V, typename F> ostream& operator<<(ostream& out, const failable<V, F>& m) {
+ if (!hasContent(m)) {
+ out << reason(m);
+ return out;
+ }
+ out << content(m);
+ return out;
+}
+
+/**
+ * Returns a failable monad with a success value in it.
+ */
+template<typename V, typename F> const failable<V, F> mksuccess(const V& v) {
+ return failable<V, F>(v);
+}
+
+template<typename V, typename F> const lambda<failable<V, F>(const V)> success() {
+ return mksuccess<V, F>;
+}
+
+/**
+ * Returns a failable monad with a failure in it.
+ */
+template<typename V, typename F> const failable<V, F> mkfailure(const F& f) {
+#ifdef WANT_MAINTAINER_MODE
+ ostringstream os;
+ os << f;
+ if (length(str(os)) != 0)
+ debug(f, "failable::mkfailure");
+#endif
+ return failable<V, F>(false, f);
+}
+
+template<typename V> const failable<V> mkfailure(const char* f) {
+ return mkfailure<V, string>(string(f));
+}
+
+template<typename V> const failable<V> mkfailure() {
+ return failable<V, string>(false, string());
+}
+
+template<typename V, typename F> const lambda<failable<V, F>(const V)> failure() {
+ return mkfailure<V, F>;
+}
+
+/**
+ * Returns true if the monad contains a content.
+ */
+template<typename V, typename F> const bool hasContent(const failable<V, F>& m) {
+ return m.hasv;
+}
+
+/**
+ * Returns the content of a failable monad.
+ */
+template<typename V, typename F> const V content(const failable<V, F>& m) {
+ return m.v;
+}
+
+/**
+ * Returns the reason for failure of a failable monad.
+ */
+template<typename V, typename F> const F reason(const failable<V, F>& m) {
+ return m.f;
+}
+
+/**
+ * Bind a function to a failable monad. Passes the success value in the monad to the function
+ * if present, or does nothing if there's no value and a failure instead.
+ */
+template<typename R, typename FR, typename V, typename FV>
+const failable<R, FR> operator>>(const failable<V, FV>& m, const lambda<failable<R, FR>(const V)>& f) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+template<typename R, typename FR, typename V, typename FV>
+const failable<R, FR> operator>>(const failable<V, FV>& m, const failable<R, FR> (* const f)(const V)) {
+ if (!hasContent(m))
+ return m;
+ return f(content(m));
+}
+
+/**
+ * State + content pair data type used by the state monad.
+ */
+template<typename S, typename V> class scp {
+public:
+ scp(const S& s, const V& v) : s(s), v(v) {
+ }
+
+ operator const S() const {
+ return s;
+ }
+
+ operator const V() const {
+ return v;
+ }
+
+ const scp<S, V>& operator=(const scp<S, V>& p) {
+ if(this == &p)
+ return *this;
+ s = p.s;
+ v = p.v;
+ return *this;
+ }
+
+ const bool operator!=(const scp<S, V>& p) const {
+ return !this->operator==(p);
+ }
+
+ const bool operator==(const scp<S, V>& p) const {
+ if (this == &p)
+ return true;
+ return s == p.s && v == p.v;
+ }
+
+private:
+ const S s;
+ const V v;
+
+ template<typename A, typename B> friend const A scpstate(const scp<A, B>& m);
+ template<typename A, typename B> friend const B content(const scp<A, B>& m);
+};
+
+/**
+ * Returns the state of a state-content pair.
+ */
+template<typename S, typename V> const S scpstate(const scp<S, V>& m) {
+ return m.s;
+}
+
+/**
+ * Returns the content of a state-content pair.
+ */
+template<typename S, typename V> const S content(const scp<S, V>& m) {
+ return m.v;
+}
+
+/**
+ * State monad. Used to represent the combination of a state and a content.
+ */
+template<typename S, typename V> class state {
+public:
+ state(const lambda<scp<S, V>(const S)>& f) : f(f) {
+ }
+
+ const scp<S, V> operator()(const S& s) const {
+ return f(s);
+ }
+
+ const state<S, V>& operator=(const state<S, V>& m) {
+ if(this == &m)
+ return *this;
+ f = m.f;
+ return *this;
+ }
+
+ const bool operator!=(const state<S, V>& m) const {
+ return !this->operator==(m);
+ }
+
+ const bool operator==(const state<S, V>& m) const {
+ if (this == &m)
+ return true;
+ return f == m.f;
+ }
+
+private:
+ const lambda<scp<S, V>(const S)> f;
+};
+
+/**
+ * Write a state monad to a stream.
+ */
+template<typename S, typename V> ostream& operator<<(ostream& out, const state<S, V>& m) {
+ const S s = m;
+ const V v = m;
+ out << '(' << s << ' ' << v << ')';
+ return out;
+}
+
+/**
+ * Return a state monad carrying a result content.
+ */
+template<typename S, typename V> struct returnState {
+ const V v;
+ returnState(const V& v) : v(v) {
+ }
+ const scp<S, V> operator()(const S& s) const {
+ return scp<S, V>(s, v);
+ }
+};
+
+template<typename S, typename V> const state<S, V> result(const V& v) {
+ return state<S, V>(returnState<S, V>(v));
+}
+
+/**
+ * Return a state monad with a transformer function.
+ * A transformer function takes a state and returns an scp pair carrying a content and a
+ * new (transformed) state.
+ */
+template<typename S, typename V> const state<S, V> transformer(const lambda<scp<S, V>(const S)>& f) {
+ return state<S, V>(f);
+}
+
+/**
+ * Bind a function to a state monad. The function takes a content and returns a state
+ * monad carrying a return content.
+ */
+template<typename S, typename A, typename B> struct stateBind {
+ const state<S, A> st;
+ const lambda<state<S, B>(const A)>f;
+
+ stateBind(const state<S, A>& st, const lambda<state<S, B>(const A)>& f) : st(st), f(f) {
+ }
+
+ const scp<S, B> operator()(const S& is) const {
+ const scp<S, A> iscp = st(is);
+ const state<S, B> m = f((A)iscp);
+ return m((S)iscp);
+ }
+};
+
+template<typename S, typename A, typename B>
+const state<S, B> operator>>(const state<S, A>& st, const lambda<state<S, B>(const A)>& f) {
+ return state<S, B>(stateBind<S, A , B>(st, f));
+}
+
+template<typename S, typename A, typename B>
+const state<S, B> operator>>(const state<S, A>& st, const state<S, B> (* const f)(const A)) {
+ return state<S, B>(stateBind<S, A , B>(st, f));
+}
+
+}
+#endif /* tuscany_monad_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/parallel-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/parallel-test.cpp
new file mode 100644
index 0000000000..2969dd0637
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/parallel-test.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test parallel functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "perf.hpp"
+#include "parallel.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_THREADS
+
+int inci = 0;
+
+struct incPerf {
+ incPerf() {
+ }
+ const bool operator()() const {
+ inci = inci + 1;
+ return true;
+ }
+};
+
+int addi = 0;
+
+struct addAndFetchPerf {
+ addAndFetchPerf() {
+ }
+ const bool operator()() const {
+ __sync_add_and_fetch(&addi, 1);
+ return true;
+ }
+};
+
+int muxi = 0;
+
+struct mutexPerf {
+ pthread_mutex_t* mutex;
+ mutexPerf(pthread_mutex_t* mutex) : mutex(mutex) {
+ }
+ const bool operator()() const {
+ pthread_mutex_lock(mutex);
+ muxi = muxi + 1;
+ pthread_mutex_unlock(mutex);
+ return true;
+ }
+};
+
+__thread int tlsi = 0;
+
+struct tlsPerf {
+ tlsPerf() {
+ }
+ const bool operator()() const {
+ tlsi = tlsi + 1;
+ return true;
+ }
+};
+
+bool testAtomicPerf() {
+ const int count = 100000;
+ {
+ const lambda<bool()> l = incPerf();
+ cout << "Non-atomic inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(inci == count + 1000);
+ }
+ {
+ const lambda<bool()> l = addAndFetchPerf();
+ cout << "Atomic inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(addi == count + 1000);
+ }
+ {
+ pthread_mutex_t mutex;
+ pthread_mutex_init(&mutex, NULL);
+ const lambda<bool()> l = mutexPerf(&mutex);
+ cout << "Locked inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(muxi == count + 1000);
+ pthread_mutex_destroy(&mutex);
+ }
+ {
+ const lambda<bool()> l = tlsPerf();
+ cout << "Thread local inc test " << time(l, 1000, count) << " ms" << endl;
+ assert(tlsi == count + 1000);
+ }
+ return true;
+}
+
+const int mtsquare(const int x) {
+ for(int i = 0; i < 10000000; i++)
+ ;
+ return x * x;
+}
+
+bool checkResults(const list<future<int> > r, int i) {
+ if (isNil(r))
+ return true;
+ assert(car(r) == i * i);
+ checkResults(cdr(r), i + 1);
+ return true;
+}
+
+const list<future<int> > submitSquares(worker& w, const int max, const int i) {
+ if (i == max)
+ return list<future<int> >();
+ const lambda<int()> func = curry(lambda<int(const int)> (mtsquare), i);
+ return cons(submit(w, func), submitSquares(w, max, i + 1));
+}
+
+bool testWorker() {
+ worker w(20);
+ {
+ const lambda<int()> func = curry(lambda<int(const int)> (mtsquare), 2);
+ assert(submit(w, func) == 4);
+ }
+ {
+ const int max = 20;
+ const list<future<int> > r(submitSquares(w, max, 0));
+ checkResults(r, 0);
+ }
+ shutdown(w);
+ return true;
+}
+
+#endif
+
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+#ifdef WANT_THREADS
+ tuscany::testAtomicPerf();
+ tuscany::testWorker();
+#else
+ tuscany::cout << "Skipped multi-thread tests" << tuscany::endl;
+#endif
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/parallel.hpp b/sandbox/sebastien/cpp/apr-2/kernel/parallel.hpp
new file mode 100644
index 0000000000..09829f0758
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/parallel.hpp
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_parallel_hpp
+#define tuscany_parallel_hpp
+
+/**
+ * Simple parallel work execution functions.
+ */
+
+#ifdef WANT_THREADS
+#include <pthread.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+
+#include "function.hpp"
+#include "list.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_THREADS
+
+/**
+ * Returns the current thread id.
+ */
+long int threadId() {
+ return syscall(__NR_gettid);
+}
+
+/**
+ * Represents a value which will be know in the future.
+ */
+template<typename T> class future {
+
+private:
+ template<typename X> class futureValue {
+ public:
+ futureValue() : hasValue(false) {
+ pthread_mutex_init(&valueMutex, NULL);
+ pthread_cond_init(&valueCond, NULL);
+ }
+
+ futureValue(const futureValue& fv) : valueMutex(fv.valueMutex), valueCond(fv.valueCond), hasValue(fv.hasValue), value(fv.value) {
+ }
+
+ ~futureValue() {
+ //pthread_mutex_destroy(&valueMutex);
+ //pthread_cond_destroy(&valueCond);
+ }
+
+ bool set(const T& v) {
+ pthread_mutex_lock(&valueMutex);
+ if(hasValue) {
+ pthread_mutex_unlock(&valueMutex);
+ return false;
+ }
+ hasValue = true;
+ value = v;
+ pthread_mutex_unlock(&valueMutex);
+ pthread_cond_broadcast(&valueCond);
+ return true;
+ }
+
+ const T get() {
+ pthread_mutex_lock(&valueMutex);
+ while(!hasValue) {
+ pthread_cond_wait(&valueCond, &valueMutex);
+ }
+ const T& v = value;
+ pthread_mutex_unlock(&valueMutex);
+ return v;
+ }
+
+ private:
+ pthread_mutex_t valueMutex;
+ pthread_cond_t valueCond;
+ bool hasValue;
+ X value;
+ };
+
+ gc_ptr<futureValue<T> > fvalue;
+
+ template<typename X> friend const X get(const future<X>& f);
+ template<typename X> friend bool set(const future<X>& f, const X& v);
+
+public:
+ future() : fvalue(new (gc_new<futureValue<T> >()) futureValue<T>()) {
+ }
+
+ ~future() {
+ }
+
+ future(const future& f) : fvalue(f.fvalue) {
+ }
+
+ const future& operator=(const future& f) {
+ if (&f == this)
+ return *this;
+ fvalue = f.fvalue;
+ return *this;
+ }
+
+ const future& operator=(const T& v) const {
+ fvalue->set(v);
+ return *this;
+ }
+
+ operator const T() const {
+ return fvalue->get();
+ }
+};
+
+/**
+ * A bounded thread safe queue.
+ */
+template<typename T> class wqueue {
+public:
+ wqueue(size_t max) : max(max), size(0), tail(0), head(0), values(new (gc_anew<T>(max)) T[max]) {
+ pthread_mutex_init(&mutex, NULL);
+ pthread_cond_init(&full, NULL);
+ pthread_cond_init(&empty, NULL);
+ }
+
+ wqueue(const wqueue& wq) : max(wq.max), size(wq.size), tail(wq.tail), head(wq.head), mutex(wq.mutex), full(wq.full), empty(wq.empty), values(wq.values) {
+ }
+
+ ~wqueue() {
+ //pthread_mutex_destroy(&mutex);
+ //pthread_cond_destroy(&full);
+ //pthread_cond_destroy(&empty);
+ }
+
+private:
+ const size_t max;
+ size_t size;
+ size_t tail;
+ size_t head;
+ pthread_mutex_t mutex;
+ pthread_cond_t full;
+ pthread_cond_t empty;
+ gc_ptr<T> values;
+
+ template<typename X> friend const size_t enqueue(wqueue<X>& q, const X& v);
+ template<typename X> friend const X dequeue(wqueue<X>& q);
+};
+
+/**
+ * Adds an element to the tail of the queue.
+ */
+template<typename T> const size_t enqueue(wqueue<T>&q, const T& v) {
+ pthread_mutex_lock(&q.mutex);
+ while(q.size == q.max)
+ pthread_cond_wait(&q.full, &q.mutex);
+ q.values[q.tail] = v;
+ q.tail = (q.tail + 1) % q.max;
+ q.size++;
+ pthread_mutex_unlock(&q.mutex);
+ pthread_cond_broadcast(&q.empty);
+ return q.size;
+}
+
+/**
+ * Returns the element at the head of the queue.
+ */
+template<typename T> const T dequeue(wqueue<T>& q) {
+ pthread_mutex_lock(&q.mutex);
+ while(q.size == 0)
+ pthread_cond_wait(&q.empty, &q.mutex);
+ const T v = q.values[q.head];
+ q.head = (q.head + 1) % q.max;
+ q.size--;
+ pthread_mutex_unlock(&q.mutex);
+ pthread_cond_broadcast(&q.full);
+ return v;
+}
+
+/**
+ * The worker thread function.
+ */
+void *workerThreadFunc(void *arg) {
+ int ost;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ost);
+ int ot;
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &ot);
+
+ wqueue<lambda<bool()> >* work = reinterpret_cast<wqueue<lambda<bool()> >*>(arg);
+ while(dequeue(*work)())
+ ;
+ return NULL;
+}
+
+/**
+ * Returns a list of worker threads.
+ */
+const list<pthread_t> workerThreads(wqueue<lambda<bool()> >& wqueue, const size_t count) {
+ if (count == 0)
+ return list<pthread_t>();
+ pthread_t thread;
+ pthread_create(&thread, NULL, workerThreadFunc, &wqueue);
+ return cons(thread, workerThreads(wqueue, count - 1));
+}
+
+/**
+ * A worker, implemented with a work queue and a pool of threads.
+ */
+class worker {
+private:
+
+ // The worker holds a reference to a sharedWorker, to avoid non-thread-safe
+ // copies of the queue and thread pool when a worker is copied
+ class sharedWorker {
+ public:
+ sharedWorker(size_t max) : work(wqueue<lambda<bool()> >(max)), threads(workerThreads(work, max)) {
+ }
+
+ wqueue<lambda<bool()> > work;
+ const list<pthread_t> threads;
+ };
+
+public:
+ worker(size_t max) : w(*(new (gc_new<sharedWorker>()) sharedWorker(max))) {
+ }
+
+ worker(const worker& wk) : w(wk.w) {
+ }
+
+private:
+ sharedWorker& w;
+
+ template<typename X> friend const future<X> submit(worker& w, const lambda<X()>& func);
+ friend const bool shutdown(worker& w);
+ friend const bool cancel(worker& w);
+};
+
+/**
+ * Function used to wrap work submitted to a worker.
+ */
+template<typename R> bool submitFunc(const lambda<R()>& func, const future<R>& fut) {
+ fut = func();
+ return true;
+}
+
+/**
+ * Submits work to a worker.
+ */
+template<typename R> const future<R> submit(worker& w, const lambda<R()>& func) {
+ const future<R> fut;
+ const lambda<bool()> f = curry(lambda<bool(const lambda<R()>, future<R>)>(submitFunc<R>), func, fut);
+ enqueue(w.w.work, f);
+ return fut;
+}
+
+/**
+ * Enqueues shutdown requests.
+ */
+const bool shutdownEnqueue(const list<pthread_t>& threads, wqueue<lambda<bool()> >& work) {
+ if (isNil(threads))
+ return true;
+ enqueue(work, result(false));
+ return shutdownEnqueue(cdr(threads), work);
+}
+
+/**
+ * Waits for shut down threads to terminate.
+ */
+const bool shutdownJoin(const list<pthread_t>& threads) {
+ if (isNil(threads))
+ return true;
+ pthread_join(car(threads), NULL);
+ return shutdownJoin(cdr(threads));
+}
+
+/**
+ * Shutdown a worker.
+ */
+const bool shutdown(worker& w) {
+ shutdownEnqueue(w.w.threads, w.w.work);
+ shutdownJoin(w.w.threads);
+ return true;
+}
+
+/**
+ * Cancel a worker.
+ */
+const bool cancel(const list<pthread_t>& threads) {
+ if (isNil(threads))
+ return true;
+ pthread_cancel(car(threads));
+ return cancel(cdr(threads));
+}
+
+const bool cancel(worker& w) {
+ cancel(w.w.threads);
+ return true;
+}
+
+#endif
+
+}
+#endif /* tuscany_parallel_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/perf.hpp b/sandbox/sebastien/cpp/apr-2/kernel/perf.hpp
new file mode 100644
index 0000000000..f5004d015b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/perf.hpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_perf_hpp
+#define tuscany_perf_hpp
+
+/**
+ * Functions to help measure performance.
+ */
+
+#include <sys/time.h>
+#include <time.h>
+
+#include "function.hpp"
+
+namespace tuscany
+{
+
+/**
+ * Measure the time required to perform a function in msec.
+ */
+struct timeLambda {
+ const lambda<bool()> f;
+ timeLambda(const lambda<bool()>& f) : f(f) {
+ }
+ bool operator()(const long count) const {
+ if (count == 0)
+ return true;
+ f();
+ (*this)(count - 1);
+ return true;
+ }
+};
+
+const double time(const lambda<bool()>& f, const long warmup, const long count) {
+ const lambda<bool(long)> tl = timeLambda(f);
+ struct timeval start;
+ struct timeval end;
+
+ tl(warmup);
+ gettimeofday(&start, NULL);
+ tl(count);
+ gettimeofday(&end, NULL);
+
+ const long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
+ return (double)t / (double)count;
+}
+
+}
+#endif /* tuscany_perf_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/sstream.hpp b/sandbox/sebastien/cpp/apr-2/kernel/sstream.hpp
new file mode 100644
index 0000000000..770c169e09
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/sstream.hpp
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_sstream_hpp
+#define tuscany_sstream_hpp
+
+/**
+ * Char buffer based streams.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <memory.h>
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+
+namespace tuscany {
+
+/**
+ * Instrumentable memcpy.
+ */
+void* stream_memcpy(void* t, const void* s, const size_t n) {
+ return memcpy(t, s, n);
+}
+
+/**
+ * Output stream backed by a char buffer.
+ */
+class ostringstream : public ostream {
+public:
+ ostringstream() : len(0) {
+ }
+
+ ~ostringstream() {
+ }
+
+ ostringstream(const ostringstream& os) {
+ len = os.len;
+ buf = os.buf;
+ }
+
+ ostringstream& vprintf(const char* fmt, ...) {
+ va_list args;
+ string s;
+ va_start (args, fmt);
+ s.len = vsnprintf(NULL, 0, fmt, args);
+ s.buf = gc_cnew(s.len + 1);
+ va_start (args, fmt);
+ vsnprintf(s.buf, s.len + 1, fmt, args);
+ buf = cons(s, buf);
+ len += s.len;
+ va_end (args);
+ return *this;
+ }
+
+ ostringstream& write(const string& s) {
+ buf = cons(s, buf);
+ len += s.len;
+ return *this;
+ }
+
+ ostringstream& flush() {
+ return *this;
+ }
+
+private:
+ static const bool strHelper(const list<string> l, char* buf) {
+ if (isNil(l))
+ return true;
+ const string c = car(l);
+ char* b = buf - length(c);
+ memcpy(b, c_str(c), length(c));
+ return strHelper(cdr(l), b);
+ }
+
+ const string str() {
+ if (isNil(buf))
+ return string();
+ string s;
+ s.len = len;
+ s.buf = gc_cnew(s.len + 1);
+ strHelper(buf, s.buf + len);
+ s.buf[s.len] = '\0';
+ return s;
+ }
+
+ friend const string str(ostringstream& os);
+
+ size_t len;
+ list<string> buf;
+};
+
+/**
+ * Return a string representation of a stream.
+ */
+const string str(ostringstream& os) {
+ return os.str();
+}
+
+/**
+ * Input stream backed by a char buffer
+ */
+class istringstream : public istream {
+public:
+ istringstream(const string& s) {
+ cur = 0;
+ const size_t slen = length(s);
+ len = slen;
+ buf = c_str(s);
+ }
+
+ ~istringstream() {
+ }
+
+ istringstream(const istringstream& is) {
+ len = is.len;
+ cur = is.cur;
+ buf = is.buf;
+ }
+
+ const size_t read(void* b, size_t size) {
+ const size_t n = len - cur;
+ if (n == 0)
+ return 0;
+ if (n > size) {
+ stream_memcpy(b, buf + cur, size);
+ cur = cur + size;
+ return size;
+ }
+ stream_memcpy(b, buf + cur, n);
+ cur = cur + n;
+ return n;
+ }
+
+ const bool eof() {
+ return cur == len;
+ }
+
+ const bool fail() {
+ return false;
+ }
+
+ const int get() {
+ if (eof())
+ return -1;
+ const int c = buf[cur];
+ cur += 1;
+ return c;
+ }
+
+ const int peek() {
+ if (eof())
+ return -1;
+ return buf[cur];
+ }
+
+private:
+ size_t len;
+ size_t cur;
+ const char* buf;
+};
+
+/**
+ * Tokenize a string into a list of strings.
+ */
+const list<string> tokenize(const char* sep, const string& str) {
+ struct nested {
+ static const list<string> tokenize(const char* sep, const string& str, const size_t start = 0) {
+ if (start >= length(str))
+ return list<string>();
+ const size_t i = find(str, sep, start);
+ if (i == length(str))
+ return mklist(string(substr(str, start)));
+ return cons(string(substr(str, start, i - start)), tokenize(sep, str, i + 1));
+ }
+ };
+ return nested::tokenize(sep, str, 0);
+}
+
+/**
+ * Join a list of strings into a single string.
+ */
+const string join(const char* sep, const list<string>& l) {
+ struct nested {
+ static ostringstream& join(const char* sep, const list<string>& l, ostringstream& os) {
+ if (isNil(l))
+ return os;
+ os << car(l);
+ if (!isNil(cdr(l)))
+ os << sep;
+ return join(sep, cdr(l), os);
+ }
+ };
+ ostringstream os;
+ return str(nested::join(sep, l, os));
+}
+
+/**
+ * Returns a lazy list view of an input stream.
+ */
+struct ilistRead{
+ istream &is;
+ ilistRead(istream& is) : is(is) {
+ }
+ const list<string> operator()() {
+ char buffer[1024];
+ const size_t n = read(is, buffer, sizeof(buffer));
+ if (n ==0)
+ return list<string>();
+ return cons(string(buffer, n), (*this)());
+ }
+};
+
+const list<string> streamList(istream& is) {
+ return ilistRead(is)();
+}
+
+/**
+ * Fragment the first element of a list of strings to fit the given max length.
+ */
+const list<string> fragment(list<string> l, size_t max) {
+ const string s = car(l);
+ if (length(s) <= max)
+ return l;
+ return cons(substr(s, 0, max), cons(substr(s, max), cdr(l)));
+}
+
+/**
+ * Write a list of strings to an output stream.
+ */
+ostream& write(const list<string>& l, ostream& os) {
+ if(isNil(l))
+ return os;
+ os << car(l);
+ return write(cdr(l), os);
+}
+
+}
+
+#endif /* tuscany_sstream_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/stream.hpp b/sandbox/sebastien/cpp/apr-2/kernel/stream.hpp
new file mode 100644
index 0000000000..2a27f5a948
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/stream.hpp
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_stream_hpp
+#define tuscany_stream_hpp
+
+/**
+ * Basic stream type and functions.
+ */
+
+#include <stdarg.h>
+#include "config.hpp"
+#include "gc.hpp"
+#include "string.hpp"
+
+namespace tuscany {
+
+/**
+ * Base output stream.
+ */
+class ostream {
+public:
+ virtual ostream& vprintf(const char* fmt, ...) = 0;
+ virtual ostream& write(const string& s) = 0;
+ virtual ostream& flush() = 0;
+};
+
+/**
+ * Flush a stream.
+ */
+ostream& flush(ostream& os) {
+ return os.flush();
+}
+
+/**
+ * Write simple values to a stream.
+ */
+ostream& operator<<(ostream& os, const char* v) {
+ return os.vprintf("%s", v);
+}
+
+ostream& operator<<(ostream& os, const unsigned char* v) {
+ return os.vprintf("%s", v);
+}
+
+ostream& operator<<(ostream& os, const char v) {
+ return os.vprintf("%c", v);
+}
+
+ostream& operator<<(ostream& os, const int v) {
+ return os.vprintf("%d", v);
+}
+
+ostream& operator<<(ostream& os, const unsigned int v) {
+ return os.vprintf("%u", v);
+}
+
+ostream& operator<<(ostream& os, const long int v) {
+ return os.vprintf("%ld", v);
+}
+
+ostream& operator<<(ostream& os, const long unsigned int v) {
+ return os.vprintf("%lu", v);
+}
+
+ostream& operator<<(ostream& os, const double v) {
+ return os.vprintf("%.10g", v);
+}
+
+ostream& operator<<(ostream& os, const void* v) {
+ return os.vprintf("%p", v);
+}
+
+ostream& operator<<(ostream& os, const string& v) {
+ return os.write(v);
+}
+
+class stream_endl {
+} endl;
+
+ostream& operator<<(ostream& os, unused const stream_endl e) {
+ os.write("\n");
+ return os.flush();
+}
+
+/*
+ * Input stream.
+ */
+class istream {
+public:
+ virtual const size_t read(void* buf, size_t size) = 0;
+ virtual const bool eof() = 0;
+ virtual const bool fail() = 0;
+ virtual const int get() = 0;
+ virtual const int peek() = 0;
+};
+
+/**
+ * Read from an input stream.
+ */
+const size_t read(istream& is, void * buf, size_t size) {
+ return is.read(buf, size);
+}
+
+/**
+ * Return true if the end of an input stream has been reached.
+ */
+const bool eof(istream& is) {
+ return is.eof();
+}
+
+/**
+ * Return true if an input stream can't be accessed.
+ */
+const bool fail(istream& is) {
+ return is.fail();
+}
+
+/**
+ * Read a character from a stream.
+ */
+const int get(istream& is) {
+ return is.get();
+}
+
+/**
+ * Peek a character from a stream.
+ */
+const int peek(istream& is) {
+ return is.peek();
+}
+
+template<typename T> ostream& operator<<(ostream& out, const gc_ptr<T>& p) {
+ return out << p.ptr;
+}
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug stream implementation with no dependencies on anything else.
+ */
+class odebugstream : public ostream {
+public:
+ odebugstream() {
+ }
+
+ odebugstream& vprintf(const char* fmt, ...) {
+ va_list args;
+ string s;
+ va_start (args, fmt);
+ s.len = vsnprintf(NULL, 0, fmt, args);
+ s.buf = gc_cnew(s.len + 1);
+ va_start (args, fmt);
+ vsnprintf(s.buf, s.len + 1, fmt, args);
+ buf = buf + s;
+ va_end (args);
+ return *this;
+ }
+
+ odebugstream& write(const string& s) {
+ buf = buf + s;
+ return *this;
+ }
+
+ odebugstream& flush() {
+ return *this;
+ }
+
+private:
+ friend const string str(odebugstream& os);
+
+ string buf;
+};
+
+const string str(odebugstream& os) {
+ return os.buf;
+}
+
+#endif
+
+}
+
+#endif /* tuscany_stream_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/string-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/string-test.cpp
new file mode 100644
index 0000000000..23fa2b9457
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/string-test.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test string functions.
+ */
+
+#include <assert.h>
+#include <string>
+#include "sstream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "perf.hpp"
+
+namespace tuscany {
+
+bool testCopies() {
+ resetStringCopyCounters();
+ string x("abcd");
+ assert(checkStringCopyCounters(1));
+ resetStringCopyCounters();
+ string y = string("abcd");
+ assert(checkStringCopyCounters(1));
+ resetStringCopyCounters();
+ string z = y;
+ assert(checkStringCopyCounters(0));
+ resetStringCopyCounters();
+ const list<string> pl = list<string>() + "abcd" + "efgh";
+ printStringCopyCounters();
+ resetStringCopyCounters();
+ const list<string> cl = cons<string>("efgh", mklist<string>("abcd"));
+ printStringCopyCounters();
+ return true;
+}
+
+bool testString() {
+ const string s("abcd");
+ assert(length(s) == 4);
+ assert(!strcmp(c_str(s), "abcd"));
+
+ assert(s == "abcd");
+ assert(s == string("abcd"));
+ assert(s != "zbcd");
+
+ assert(s < "zbcd");
+ assert(s < "zbc");
+ assert(s < "abzd");
+ assert(s < "abcdz");
+
+ assert(s > "Abcd");
+ assert(s > "Abc");
+ assert(s > "abCd");
+ assert(s > "Abcdz");
+
+ const string x = "abcd";
+ assert(!strcmp(c_str(x), "abcd"));
+
+ const string y = string("abcd");
+ assert(!strcmp(c_str(y), "abcd"));
+
+ assert(string("ab") + "cd" == "abcd");
+
+ assert(find("abcd", "cd") == 2);
+ assert(find("abcd", "xy") == length("abcd"));
+ assert(substr("abcdef", 4) == "ef");
+ assert(substr("abcdef", 4, 2) == "ef");
+ assert(substr("abcdef", 4, 3) == "ef");
+ assert(substr("abcdef", 6, 3) == "");
+ return true;
+}
+
+bool testStream() {
+ ostringstream os;
+ os << "ab" << "cd";
+ cout << str(os) << endl;
+ assert(str(os) == "abcd");
+
+ ostringstream cs;
+ cs << "\'";
+ assert(str(cs) == "\'");
+ cs << '\'';
+ assert(str(cs) == "\'\'");
+
+ istringstream is("abcd");
+ char b[2];
+ assert(read(is, b, 2) == 2);
+ assert(string("ab") == string(b, 2));
+ assert(eof(is) == false);
+ assert(read(is, b, 2) == 2);
+ assert(string("cd") == string(b, 2));
+ assert(eof(is) == true);
+ assert(read(is, b, 2) == 0);
+ return true;
+}
+
+std::string stdAdd(std::string& x, std::string& y) {
+ return x + y;
+}
+
+string add(string& x, string& y) {
+ return x + y;
+}
+
+char charBuffer[16384];
+
+struct addStrings{
+ const size_t size;
+ addStrings(const size_t size) : size(size) {
+ }
+ bool operator()() const {
+ const size_t sz = size / 4;
+ string x(charBuffer, sz);
+ string y(charBuffer, sz);
+ assert(length(add(x, y)) == sz * 2);
+ return true;
+ }
+};
+
+struct addStdStrings{
+ const size_t size;
+ addStdStrings(const size_t size) : size(size) {
+ }
+ bool operator()() const {
+ const size_t sz = size / 4;
+ std::string x(charBuffer, sz);
+ std::string y(charBuffer, sz);
+ assert(stdAdd(x, y).length() == (unsigned int)(sz * 2));
+ return true;
+ }
+};
+
+bool testStringPerf() {
+ memset(charBuffer, 'A', 16384);
+ charBuffer[16384] = '\0';
+
+ const int count = 100000;
+ {
+ const lambda<bool()> a16 = addStrings(16);
+ cout << "string test " << time(a16, 5, count) << " ms" << endl;
+ const lambda<bool()> a32 =addStrings(32);
+ cout << "string test " << time(a32, 5, count) << " ms" << endl;
+ const lambda<bool()> a256 =addStrings(256);
+ cout << "string test " << time(a256, 5, count) << " ms" << endl;
+ const lambda<bool()> a1024 =addStrings(1024);
+ cout << "string test " << time(a1024, 5, count) << " ms" << endl;
+ const lambda<bool()> a4096 =addStrings(4096);
+ cout << "string test " << time(a4096, 5, count) << " ms" << endl;
+ }
+ {
+ const lambda<bool()> a16 =addStdStrings(16);
+ cout << "Std string test " << time(a16, 5, count) << " ms" << endl;
+ const lambda<bool()> a32 =addStdStrings(32);
+ cout << "Std string test " << time(a32, 5, count) << " ms" << endl;
+ const lambda<bool()> a256 =addStdStrings(256);
+ cout << "Std string test " << time(a256, 5, count) << " ms" << endl;
+ const lambda<bool()> a1024 =addStdStrings(1024);
+ cout << "Std string test " << time(a1024, 5, count) << " ms" << endl;
+ const lambda<bool()> a4096 =addStdStrings(4096);
+ cout << "Std string test " << time(a4096, 5, count) << " ms" << endl;
+ }
+
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testCopies();
+ tuscany::testString();
+ tuscany::testStream();
+ tuscany::testStringPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/string.hpp b/sandbox/sebastien/cpp/apr-2/kernel/string.hpp
new file mode 100644
index 0000000000..cf7b4092d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/string.hpp
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_string_hpp
+#define tuscany_string_hpp
+
+/**
+ * Simple and fast string type backed by a char buffer
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+#include "gc.hpp"
+
+namespace tuscany {
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug utilities. Counters used to track string copies.
+ */
+long countStringCopies = 0;
+
+bool resetStringCopyCounters() {
+ countStringCopies = 0;
+ return true;
+}
+
+bool checkStringCopyCounters(long c) {
+ return countStringCopies == c;
+}
+
+bool printStringCopyCounters() {
+ printf("countStringCopies %ld\n", countStringCopies);
+ return true;
+}
+
+#else
+
+#define resetStringCopyCounters()
+#define checkStringCopyCounters(c) true
+#define printStringCopyCounters()
+
+#endif
+
+/**
+ * Instrumented memcpy.
+ */
+void* string_memcpy(void* t, const void* s, const size_t n) {
+#ifdef WANT_MAINTAINER_MODE
+ countStringCopies += 1;
+#endif
+ return memcpy(t, s, n);
+}
+
+char stringEmptyBuffer[1] = { '\0' };
+
+/**
+ * String class. The maximum string size is specified as a template parameter.
+ */
+class string {
+public:
+ string() : len(0) {
+ buf = stringEmptyBuffer;
+ }
+
+ string(const char* s) {
+ len = strlen(s);
+ if (len == 0) {
+ buf = stringEmptyBuffer;
+ return;
+ }
+ buf = gc_cnew(len + 1);
+ string_memcpy(buf, s, len + 1);
+ }
+
+ string(const char* s, const size_t n) {
+ len = n;
+ if (len == 0) {
+ buf = stringEmptyBuffer;
+ return;
+ }
+ buf = gc_cnew(len + 1);
+ string_memcpy(buf, s, len);
+ buf[len] = '\0';
+ }
+
+ string(const size_t n, const char c) {
+ len = n;
+ if (len == 0) {
+ buf = stringEmptyBuffer;
+ return;
+ }
+ buf = gc_cnew(len + 1);
+ memset(buf, c, n);
+ buf[len] = '\0';
+ }
+
+ string(const string& s) {
+ len = s.len;
+ buf = s.buf;
+ }
+
+ const string& operator=(const string& s) {
+ if (&s == this)
+ return *this;
+ len = s.len;
+ buf = s.buf;
+ return *this;
+ }
+
+ const bool operator==(const string& s) const {
+ if (len != s.len)
+ return false;
+ if (buf == s.buf)
+ return true;
+ return memcmp(buf, s.buf, len) == 0;
+ }
+
+ const bool operator!=(const string& s) const {
+ return !(*this == s);
+ }
+
+ const bool operator==(const char* s) const {
+ if (buf == s)
+ return true;
+ return strcmp(buf, s) == 0;
+ }
+
+ const bool operator!=(const char* s) const {
+ return !(*this == s);
+ }
+
+ const bool operator<(const string& s) const {
+ const size_t n = len < s.len? len : s.len;
+ const int c = memcmp(buf, s.buf, n);
+ if (c < 0)
+ return true;
+ if (c == 0)
+ return len < s.len;
+ return false;
+ }
+
+ const bool operator>(const string& s) const {
+ const size_t n = len < s.len? len : s.len;
+ int c = memcmp(buf, s.buf, n);
+ if (c > 0)
+ return true;
+ if (c == 0)
+ return len > s.len;
+ return false;
+ }
+
+private:
+#ifdef WANT_MAINTAINER_MODE
+ friend class odebugstream;
+#endif
+ friend class ostringstream;
+ friend const string operator+(const string& a, const string& b);
+ friend const string operator+(const string& a, const char* b);
+ friend const size_t length(const string& s);
+ friend const char* c_str(const string& s);
+ friend const size_t find(const string& s1, const char* s2, const size_t start);
+ friend const string substr(const string& s, const size_t pos, const size_t n);
+
+ size_t len;
+ char* buf;
+};
+
+/**
+ * Adds two strings.
+ */
+const string operator+(const string& a, const string& b) {
+ string s;
+ s.len = a.len + b.len;
+ s.buf = gc_cnew(s.len + 1);
+ string_memcpy(s.buf, a.buf, a.len);
+ string_memcpy(s.buf + a.len, b.buf, b.len);
+ s.buf[s.len] = '\0';
+ return s;
+}
+
+const string operator+(const string& a, const char* b) {
+ string s;
+ const size_t blen = strlen(b);
+ s.len = a.len + blen;
+ s.buf = gc_cnew(s.len + 1);
+ string_memcpy(s.buf, a.buf, a.len);
+ string_memcpy(s.buf + a.len, b, blen);
+ s.buf[s.len] = '\0';
+ return s;
+}
+
+/**
+ * Returns the length of a string.
+ */
+const size_t length(const string& s) {
+ return s.len;
+}
+
+/**
+ * Returns a string as a C zero terminated string.
+ */
+const char* c_str(const string& s) {
+ return s.buf;
+}
+
+/**
+ * Find the first occurrence of string s2 in s1, starting at the given position.
+ */
+const size_t find(const string& s1, const char* s2, const size_t start) {
+ if (start >= s1.len)
+ return s1.len;
+ const char *f = strstr(s1.buf + start, s2);
+ if (f == NULL)
+ return s1.len;
+ return f - s1.buf;
+}
+
+const size_t find(const string& s1, const char* s2) {
+ return find(s1, s2, 0);
+}
+
+/**
+ * Return true if string s1 contains s2.
+ */
+const bool contains(const string& s1, const char* s2) {
+ return find(s1, s2) != length(s1);
+}
+
+/**
+ * Find the first occurence of any character from a string in a string.
+ */
+const size_t find_first_of(const string& s1, const string& s2) {
+ return strcspn(c_str(s1), c_str(s2));
+}
+
+/**
+ * Find the first occurence of a character in a string.
+ */
+const size_t find(const string& s, const char c) {
+ const char* cs = c_str(s);
+ const char* f = strchr(cs, c);
+ if (f == NULL)
+ return length(s);
+ return f - cs;
+}
+
+/**
+ * Find the last occurence of a character in a string.
+ */
+const size_t find_last(const string& s, const char c) {
+ const char* cs = c_str(s);
+ const char* f = strrchr(cs, c);
+ if (f == NULL)
+ return length(s);
+ return f - cs;
+}
+
+/**
+ * Return a substring of a string.
+ */
+const string substr(const string& s, const size_t pos, const size_t n) {
+ if (pos >= s.len)
+ return string();
+ if (pos + n > s.len)
+ return string(s.buf + pos, s.len - pos);
+ return string(s.buf + pos, n);
+}
+
+const string substr(const string& s, const size_t pos) {
+ return substr(s, pos, length(s));
+}
+
+/**
+ * Common string constants.
+ */
+
+string trueString("true");
+string falseString("false");
+string emptyString("");
+
+}
+
+#endif /* tuscany_string_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/tree.hpp b/sandbox/sebastien/cpp/apr-2/kernel/tree.hpp
new file mode 100644
index 0000000000..89a131c324
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/tree.hpp
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_tree_hpp
+#define tuscany_tree_hpp
+
+/**
+ * Functions to work with trees.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+
+namespace tuscany {
+
+/**
+ * Make a tree from a leaf and two branches.
+ */
+template<typename T> const list<T> mktree(const T& e, const list<T>& left, const list<T>& right) {
+ return mklist<T>(e, left, right);
+}
+
+/**
+ * Find a leaf with the given key in a tree.
+ */
+template<typename T> const list<T> assoctree(const T& k, const list<T>& tree) {
+ if (isNil(tree))
+ return tree;
+ if (k == car<T>(car(tree)))
+ return car(tree);
+ if (k < car<T>(car(tree)))
+ return assoctree<T>(k, cadr(tree));
+ return assoctree<T>(k, caddr(tree));
+}
+
+/**
+ * Construct a new tree from a leaf and a tree.
+ */
+template<typename T> const list<T> constree(const T& e, const list<T>& tree) {
+ if (isNil(tree))
+ return mktree(e, list<T>(), list<T>());
+ if (e == car(tree))
+ return tree;
+ if (e < car(tree))
+ return mktree<T>(car(tree), constree<T>(e, cadr(tree)), caddr(tree));
+ return mktree<T>(car(tree), cadr(tree), constree<T>(e, caddr(tree)));
+}
+
+/**
+ * Make a tree from an unordered list of leaves.
+ */
+template<typename T> const list<T> mktree(const list<T>& l) {
+ if (isNil(l))
+ return l;
+ return constree(car(l), mktree(cdr(l)));
+}
+
+/**
+ * Convert a tree to an ordered list of leaves.
+ */
+template<typename T> const list<T> flatten(const list<T>& tree) {
+ if (isNil(tree))
+ return tree;
+ return append<T>(flatten<T>(cadr(tree)), cons<T>(car(tree), flatten<T>(caddr(tree))));
+}
+
+/**
+ * Sort a list.
+ */
+template<typename T> const list<T> sort(const list<T>& l) {
+ return flatten(mktree(l));
+}
+
+/**
+ * Make a balanced tree from an ordered list of leaves.
+ */
+template<typename T> const list<T> btreeHelper(const list<T>& elements, const size_t n) {
+ if (n == 0)
+ return cons<T>(list<T>(), elements);
+ const size_t leftSize = (n - 1) / 2; {
+ const list<T> leftResult = btreeHelper<T>(elements, leftSize); {
+ const list<T> leftTree = car(leftResult);
+ const list<T> nonLeftElements = cdr(leftResult);
+ const size_t rightSize = n - (leftSize + 1); {
+ const T thisEntry = car(nonLeftElements);
+ const list<T> rightResult = btreeHelper<T>(cdr(nonLeftElements), rightSize); {
+ const list<T> rightTree = car(rightResult);
+ const list<T> remainingElements = cdr(rightResult); {
+ return cons<T>(mktree<T>(thisEntry, leftTree, rightTree), remainingElements);
+ }
+ }
+ }
+ }
+ }
+}
+
+template<typename T> const list<T> mkbtree(const list<T>& elements) {
+ return car(btreeHelper<T>(elements, length(elements)));
+}
+
+}
+
+#endif /* tuscany_tree_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/value.hpp b/sandbox/sebastien/cpp/apr-2/kernel/value.hpp
new file mode 100644
index 0000000000..211873ef0c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/value.hpp
@@ -0,0 +1,624 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_value_hpp
+#define tuscany_value_hpp
+
+/**
+ * Generic value type.
+ */
+
+#include <stdlib.h>
+#include <apr_uuid.h>
+#include <apr_time.h>
+
+#include "string.hpp"
+#include "sstream.hpp"
+#include "gc.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "monad.hpp"
+
+namespace tuscany
+{
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug utilities. Counters used to track instances of values, and
+ * macro used to write the contents of a value in a string, easier to
+ * watch in a debugger than the value itself.
+ */
+long int countValues = 0;
+long int countEValues = 0;
+long int countCValues = 0;
+long int countVValues = 0;
+
+bool resetValueCounters() {
+ countValues = countEValues = countCValues = countVValues = 0;
+ return true;
+}
+
+bool checkValueCounters() {
+ return countValues == 0;
+}
+
+bool printValueCounters() {
+ cout << "countValues " << countValues << endl;
+ cout << "countEValues " << countEValues << endl;
+ cout << "countCValues " << countCValues << endl;
+ cout << "countVValues " << countVValues << endl;
+ return true;
+}
+
+#else
+
+#define resetValueCounters()
+#define checkValueCounters() true
+#define printValueCounters()
+
+#endif
+
+#ifdef WANT_MAINTAINER_WATCH
+
+#define debug_watchValue() do { \
+ this->watch = watchValue(*this); \
+ } while (0)
+
+#else
+
+#define debug_watchValue()
+
+#endif
+
+class value;
+
+class value {
+public:
+
+ enum ValueType {
+ Undefined, Symbol, String, List, Number, Bool, Lambda, Ptr
+ };
+
+ value() : type(value::Undefined) {
+ debug_inc(countValues);
+ debug_inc(countEValues);
+ debug_watchValue();
+ }
+
+ value(const value& v) {
+ debug_inc(countValues);
+ debug_inc(countCValues);
+ type = v.type;
+ switch(type) {
+ case value::List:
+ lst() = v.lst();
+ case value::Lambda:
+ func() = v.func();
+ case value::Symbol:
+ str() = v.str();
+ case value::String:
+ str() = v.str();
+ case value::Number:
+ num() = v.num();
+ case value::Bool:
+ boo() = v.boo();
+ case value::Ptr:
+ ptr() = v.ptr();
+ default:
+ break;
+ }
+#ifdef WANT_MAINTAINER_WATCH
+ watch = v.watch;
+#endif
+ }
+
+ virtual ~value() {
+ debug_dec(countValues);
+ }
+
+ value(const lambda<value(const list<value>&)>& func) : type(value::Lambda), data(vdata(func)) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const string& str) : type(value::String), data(vdata(result(str))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const char* str) : type(value::Symbol), data(vdata(result(string(str)))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const list<value>& lst) : type(value::List), data(vdata(result(lst))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const list<list<value> >& l) : type(value::List), data(vdata(result(listOfValues(l)))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const double num) : type(value::Number), data(vdata(result(num))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const int num) : type(value::Number), data(vdata(result((double)num))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const bool boo) : type(value::Bool), data(vdata(result(boo))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const gc_ptr<value> ptr) : type(value::Ptr), data(vdata(result(ptr))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const failable<value>& m) : type(value::List),
+ data(vdata(result(hasContent(m)? mklist<value>(content(m)) : mklist<value>(value(), reason(m))))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ value(const maybe<value>& m) : type(value::List),
+ data(vdata(result(hasContent(m)? mklist<value>(content(m)) : list<value>()))) {
+ debug_inc(countValues);
+ debug_inc(countVValues);
+ debug_watchValue();
+ }
+
+ const value& operator=(const value& v) {
+ if(this == &v)
+ return *this;
+ type = v.type;
+ switch(type) {
+ case value::List:
+ lst() = v.lst();
+ case value::Lambda:
+ func() = v.func();
+ case value::Symbol:
+ str() = v.str();
+ case value::String:
+ str() = v.str();
+ case value::Number:
+ num() = v.num();
+ case value::Bool:
+ boo() = v.boo();
+ case value::Ptr:
+ ptr() = v.ptr();
+ default:
+ break;
+ }
+#ifdef WANT_MAINTAINER_WATCH
+ watch = v.watch;
+#endif
+ return *this;
+ }
+
+ const bool operator!=(const value& v) const {
+ return !this->operator==(v);
+ }
+
+ const bool operator==(const value& v) const {
+ if(this == &v)
+ return true;
+ switch(type) {
+ case value::Undefined:
+ return true;
+ case value::List:
+ return v.type == value::List && lst()() == v.lst()();
+ case value::Lambda:
+ return v.type == value::Lambda && func() == v.func();
+ case value::Symbol:
+ case value::String:
+ return str()() == (string)v;
+ case value::Number:
+ return num()() == (double)v;
+ case value::Bool:
+ return boo()() == (bool)v;
+ case value::Ptr:
+ return v.type == value::Ptr && ptr()() == v.ptr()();
+ default:
+ return false;
+ }
+ }
+
+ const bool operator<(const value& v) const {
+ if(this == &v)
+ return false;
+ switch(type) {
+ case value::List:
+ return v.type == value::List && lst()() < v.lst()();
+ case value::Symbol:
+ case value::String:
+ return str()() < (string)v;
+ case value::Bool:
+ return boo()() < (bool)v;
+ case value::Number:
+ return num()() < (double)v;
+ default:
+ return false;
+ }
+ }
+
+ const bool operator>(const value& v) const {
+ if(this == &v)
+ return false;
+ switch(type) {
+ case value::List:
+ return v.type == value::List && lst()() > v.lst()();
+ case value::Symbol:
+ case value::String:
+ return str()() > (string)v;
+ case value::Bool:
+ return boo()() > (bool)v;
+ case value::Number:
+ return num()() > (double)v;
+ default:
+ return false;
+ }
+ }
+
+ const value operator()(const list<value>& args) const {
+ return func()(args);
+ }
+
+ operator const string() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return str()();
+ case value::Number: {
+ ostringstream os;
+ os << num()();
+ return tuscany::str(os);
+ }
+ case value::Bool:
+ return boo()()? trueString : falseString;
+ default:
+ return emptyString;
+ }
+ }
+
+ operator const double() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return atof(c_str(str()()));
+ case value::Number:
+ return (double)num()();
+ case value::Bool:
+ return boo()()? 1.0 : 0.0;
+ default:
+ return 0.0;
+ }
+ }
+
+ operator const int() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return atoi(c_str(str()()));
+ case value::Number:
+ return (int)num()();
+ case value::Bool:
+ return boo()()? 1 : 0;
+ default:
+ return 0;
+ }
+ }
+
+ operator const bool() const {
+ switch(type) {
+ case value::Symbol:
+ case value::String:
+ return str()() == string("true");
+ case value::Number:
+ return (int)num()() != 0;
+ case value::Bool:
+ return boo()();
+ default:
+ return 0;
+ }
+ }
+
+ operator const gc_ptr<value>() const {
+ return ptr()();
+ }
+
+ operator const list<value>() const {
+ return lst()();
+ }
+
+ operator const list<list<value> >() const {
+ return listOfListOfValues(lst()());
+ }
+
+ operator const lambda<value(const list<value>&)>() const {
+ return func();
+ }
+
+private:
+ template<typename T> lambda<T>& vdata() const {
+ return *reinterpret_cast<lambda<T> *> (const_cast<lambda<char()> *> (&data));
+ }
+
+ template<typename T> const lambda<char()>& vdata(const T& v) const {
+ return *reinterpret_cast<const lambda<char()> *> (&v);
+ }
+
+ lambda<double()>& num() const {
+ return vdata<double()> ();
+ }
+
+ lambda<bool()>& boo() const {
+ return vdata<bool()> ();
+ }
+
+ lambda<gc_ptr<value>()>& ptr() const {
+ return vdata<gc_ptr<value>()> ();
+ }
+
+ lambda<string()>& str() const {
+ return vdata<string()> ();
+ }
+
+ lambda<list<value>()>& lst() const {
+ return vdata<list<value>()> ();
+ }
+
+ lambda<value(const list<value>&)>& func() const {
+ return vdata<value(const list<value>&)> ();
+ }
+
+ const list<value> listOfValues(const list<list<value> >& l) const {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(car(l), listOfValues(cdr(l)));
+ }
+
+ const list<list<value> > listOfListOfValues(const list<value>& l) const {
+ if (isNil(l))
+ return list<list<value> >();
+ return cons<list<value> >(list<value>(car(l)), listOfListOfValues(cdr(l)));
+ }
+
+ friend ostream& operator<<(ostream&, const value&);
+ friend const value::ValueType type(const value& v);
+
+#ifdef WANT_MAINTAINER_WATCH
+ friend const string watchValue(const value& v);
+ string watch;
+#endif
+
+ ValueType type;
+ lambda<char()> data;
+};
+
+#ifdef WANT_MAINTAINER_WATCH
+
+/**
+ * Debug utility used to write the contents of a value to a string, easier
+ * to watch than the value itself in a debugger.
+ */
+const string watchValue(const value& v) {
+ if (v.type == value::List)
+ return watchList<value>(v);
+ odebugstream os;
+ os << v;
+ return str(os);
+}
+
+#endif
+
+/**
+ * Write a value to a stream.
+ */
+ostream& operator<<(ostream& out, const value& v) {
+ switch(v.type) {
+ case value::List:
+ return out << v.lst()();
+ case value::Lambda:
+ return out << "lambda::" << v.func();
+ case value::Symbol:
+ return out << v.str()();
+ case value::String:
+ return out << '\"' << v.str()() << '\"';
+ case value::Number:
+ return out << v.num()();
+ case value::Bool:
+ if(v.boo()())
+ return out << "true";
+ else
+ return out << "false";
+ case value::Ptr: {
+ const gc_ptr<value> p = v.ptr()();
+ if (p == gc_ptr<value>(NULL))
+ return out << "gc_ptr::null";
+ return out << "gc_ptr::" << p;
+ }
+ default:
+ return out << "undefined";
+ }
+}
+
+/**
+ * Returns the type of a value.
+ */
+const value::ValueType type(const value& v) {
+ return v.type;
+}
+
+/**
+ * Returns true if a value is nil.
+ */
+const bool isNil(const value& v) {
+ return type(v) == value::Undefined;
+}
+
+/**
+ * Returns true if a value is a lambda.
+ */
+const bool isLambda(const value& v) {
+ return type(v) == value::Lambda;
+}
+
+/**
+ * Returns true if a value is a string.
+ */
+const bool isString(const value& v) {
+ return type(v) == value::String;
+}
+
+/**
+ * Returns true if a value is a symbol.
+ */
+const bool isSymbol(const value& v) {
+ return type(v) == value::Symbol;
+}
+
+/**
+ * Returns true if a value is a list.
+ */
+const bool isList(const value& v) {
+ return type(v) == value::List;
+}
+
+/**
+ * Returns true if a value is a number.
+ */
+const bool isNumber(const value& v) {
+ return type(v) == value::Number;
+}
+
+/**
+ * Returns true if a value is a boolean.
+ */
+const bool isBool(const value& v) {
+ return type(v) == value::Bool;
+}
+
+/**
+ * Returns true if a value is a pointer.
+ */
+const bool isPtr(const value& v) {
+ return type(v) == value::Ptr;
+}
+
+/**
+ * Returns true if a value is a tagged list.
+ */
+const bool isTaggedList(const value& exp, value tag) {
+ if(isList(exp) && !isNil((list<value>)exp))
+ return car((list<value>)exp) == tag;
+ return false;
+}
+
+/**
+ * Make a list of values from a list of other things.
+ */
+template<typename T> const list<value> mkvalues(const list<T>& l) {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(car(l), mkvalues(cdr(l)));
+}
+
+/**
+ * Convert a list of values to a list of other things.
+ */
+template<typename T> const list<T> convertValues(const list<value>& l) {
+ if (isNil(l))
+ return list<T>();
+ return cons<T>(car(l), convertValues<T>(cdr(l)));
+}
+
+/**
+ * Convert a path string value to a list of values.
+ */
+const list<string> pathTokens(const char* p) {
+ if (p == NULL || p[0] == '\0')
+ return list<string>();
+ if (p[0] == '/')
+ return tokenize("/", p + 1);
+ return tokenize("/", p);
+}
+
+const list<value> pathValues(const value& p) {
+ return mkvalues(pathTokens(c_str(p)));
+}
+
+/**
+ * Convert a path represented as a list of values to a string value.
+ */
+const value path(const list<value>& p) {
+ if (isNil(p))
+ return "";
+ return string("/") + car(p) + path(cdr(p));
+}
+
+/**
+ * Make a uuid value.
+ */
+const value mkuuid() {
+ apr_uuid_t id;
+ apr_uuid_get(&id);
+ char buf[APR_UUID_FORMATTED_LENGTH];
+ apr_uuid_format(buf, &id);
+ return value(string(buf, APR_UUID_FORMATTED_LENGTH));
+}
+
+/**
+ * Make a random alphanumeric value.
+ */
+const int intrand() {
+ const apr_uint64_t now = apr_time_now();
+ srand((unsigned int)(((now >> 32) ^ now) & 0xffffffff));
+ return rand() & 0x0FFFF;
+}
+
+const value mkrand() {
+ char buf[32];
+ const char* an = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ for (int i =0; i < 32; i++)
+ buf[i] = an[intrand() % 62];
+ return value(string(buf, 32));
+}
+
+}
+#endif /* tuscany_value_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/xml-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/xml-test.cpp
new file mode 100644
index 0000000000..c83a65fd92
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/xml-test.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test XML handling functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+
+const string currencyXML =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<composite xmlns=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "
+"xmlns:t=\"http://tuscany.apache.org/xmlns/sca/1.1\" "
+"targetNamespace=\"http://services\" "
+"name=\"currency\">"
+"<component name=\"CurrencyConverterWebService\">"
+"<implementation.java class=\"services.CurrencyConverterImpl\"/>"
+"<service name=\"CurrencyConverter\">"
+"<binding.ws/>"
+"</service>"
+"</component>"
+"<component name=\"CurrencyConverterWebService2\">"
+"<implementation.java class=\"services.CurrencyConverterImpl2\"/>"
+"<service name=\"CurrencyConverter2\">"
+"<binding.atom/>"
+"</service>"
+"<property name=\"currency\">US</property>"
+"</component>"
+"</composite>"
+"\n";
+
+const string customerXML =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<customer>"
+"<name>jdoe</name>"
+"<address><city>san francisco</city><state>ca</state></address>"
+"<account><id>1234</id><balance>1000</balance></account>"
+"<account><id>6789</id><balance>2000</balance></account>"
+"<account><id>4567</id><balance>3000</balance></account>"
+"</customer>"
+"\n";
+
+
+const bool isName(const value& token) {
+ return isTaggedList(token, attribute) && attributeName(token) == "name";
+}
+
+bool testReadXML() {
+ {
+ istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ }
+ {
+ istringstream is(currencyXML);
+ const list<value> c = readXML(streamList(is));
+
+ const value composite = car(c);
+ assert(isTaggedList(composite, element));
+ assert(elementName(composite) == "composite");
+ assert(attributeValue(car(filter<value>(isName, elementChildren(composite)))) == string("currency"));
+ }
+ return true;
+}
+
+ostream* xmlWriter(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+bool testWriteXML() {
+ {
+ istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, c);
+ assert(str(os) == customerXML);
+ }
+ {
+ istringstream is(currencyXML);
+ const list<value> c = readXML(streamList(is));
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, c);
+ assert(str(os) == currencyXML);
+ }
+ return true;
+}
+
+bool testElements() {
+ {
+ const list<value> ad = mklist<value>(mklist<value>("city", string("san francisco")), mklist<value>("state", string("ca")));
+ const list<value> ac1 = mklist<value>(mklist<value>("id", string("1234")), mklist<value>("balance", 1000));
+ const list<value> ac2 = mklist<value>(mklist<value>("id", string("6789")), mklist<value>("balance", 2000));
+ const list<value> ac3 = mklist<value>(mklist<value>("id", string("4567")), mklist<value>("balance", 3000));
+ {
+ const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", string("jdoe")), cons<value>("address", ad), mklist<value>("account", mklist<value>(ac1, ac2, ac3))));
+ const list<value> e = valuesToElements(c);
+ const list<value> v = elementsToValues(e);
+ assert(v == c);
+
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == customerXML);
+ }
+ {
+ const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", string("jdoe")), cons<value>("address", ad), cons<value>("account", ac1), cons<value>("account", ac2), cons<value>("account", ac3)));
+ const list<value> e = valuesToElements(c);
+ const list<value> v = elementsToValues(e);
+
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == customerXML);
+ }
+ }
+ {
+ istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ const list<value> v = elementsToValues(c);
+ const list<value> e = valuesToElements(v);
+ ostringstream os;
+ writeXML<ostream*>(xmlWriter, &os, e);
+ assert(str(os) == customerXML);
+ }
+ return true;
+}
+
+bool testValues() {
+ {
+ const list<value> l = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
+ const list<value> e = valuesToElements(l);
+ const failable<list<string> > lx = writeXML(e);
+ ostringstream os;
+ write(content(lx), os);
+ istringstream is(str(os));
+ const list<value> x = readXML(streamList(is));
+ const list<value> v = elementsToValues(x);
+ assert(v == l);
+ }
+ return true;
+}
+
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::testReadXML();
+ tuscany::testWriteXML();
+ tuscany::testElements();
+ tuscany::testValues();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/xml.hpp b/sandbox/sebastien/cpp/apr-2/kernel/xml.hpp
new file mode 100644
index 0000000000..3459592c97
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/xml.hpp
@@ -0,0 +1,378 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_xml_hpp
+#define tuscany_xml_hpp
+
+/**
+ * XML read/write functions.
+ */
+
+#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/xmlschemas.h>
+#include <libxml/globals.h>
+#include "string.hpp"
+#include "list.hpp"
+#include "stream.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+
+/**
+ * Initializes the libxml2 library.
+ */
+class XMLParser {
+public:
+ XMLParser() {
+ xmlInitParser();
+ }
+} xmlParser;
+
+/**
+ * Encapsulates a libxml2 xmlTextReader and its state.
+ */
+class XMLReader {
+public:
+ enum TokenType {
+ None = 0, Element = 1, Attribute = 2, Text = 3, EndElement = 15, Identifier = 100, End = 101
+ };
+
+ XMLReader(xmlTextReaderPtr xml) : xml(xml), tokenType(None), isEmptyElement(false), hasValue(false), hasAttributes(false) {
+ xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1);
+ xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1);
+ }
+
+ ~XMLReader() {
+ xmlTextReaderClose(xml);
+ xmlFreeTextReader(xml);
+ }
+
+ /**
+ * Read the next XML token and return its type.
+ */
+ int read() {
+ if (tokenType == End)
+ return tokenType;
+ if (tokenType == Element) {
+ isEmptyElement = xmlTextReaderIsEmptyElement(xml);
+ hasAttributes = xmlTextReaderHasAttributes(xml);
+ return tokenType = Identifier;
+ }
+ if (tokenType == Identifier && hasAttributes && xmlTextReaderMoveToFirstAttribute(xml) == 1)
+ return tokenType = Attribute;
+ if (tokenType == Attribute && xmlTextReaderMoveToNextAttribute(xml) == 1)
+ return tokenType = Attribute;
+ if (isEmptyElement && (tokenType == Identifier || tokenType == Attribute))
+ return tokenType = EndElement;
+ if (!xmlTextReaderRead(xml))
+ return tokenType = End;
+ return tokenType = xmlTextReaderNodeType(xml);
+ }
+
+ operator xmlTextReaderPtr() const {
+ return xml;
+ }
+
+private:
+ const xmlTextReaderPtr xml;
+ int tokenType;
+ bool isEmptyElement;
+ bool hasValue;
+ bool hasAttributes;
+};
+
+/**
+ * Constants used to tag XML tokens.
+ */
+const value endElement("<");
+const value startElement(">");
+
+/**
+ * Read an XML identifier.
+ */
+const value readIdentifier(XMLReader& reader) {
+ const char* name = (const char*)xmlTextReaderConstName(reader);
+ return name;
+}
+
+/**
+ * Read XML text.
+ */
+const value readText(XMLReader& reader) {
+ const char *val = (const char*)xmlTextReaderConstValue(reader);
+ return string(val);
+}
+
+/**
+ * Read an XML attribute.
+ */
+const value readAttribute(XMLReader& reader) {
+ const char *name = (const char*)xmlTextReaderConstName(reader);
+ const char *val = (const char*)xmlTextReaderConstValue(reader);
+ return mklist<value>(attribute, name, string(val));
+}
+
+/**
+ * Read an XML token.
+ */
+const value readToken(XMLReader& reader) {
+ const int tokenType = reader.read();
+ if (tokenType == XMLReader::None || tokenType == XMLReader::End)
+ return value();
+ if (tokenType == XMLReader::Element)
+ return startElement;
+ if (tokenType == XMLReader::Identifier)
+ return readIdentifier(reader);
+ if (tokenType == XMLReader::Attribute)
+ return readAttribute(reader);
+ if (tokenType == XMLReader::Text)
+ return readText(reader);
+ if (tokenType == XMLReader::EndElement)
+ return endElement;
+ return readToken(reader);
+}
+
+/**
+ * Read a list of values from XML tokens.
+ */
+const list<value> readList(const list<value>& listSoFar, XMLReader& reader) {
+ const value token = readToken(reader);
+ if(isNil(token) || endElement == token)
+ return reverse(listSoFar);
+ if(startElement == token)
+ return readList(cons<value>(readList(mklist(element), reader), listSoFar), reader);
+ return readList(cons(token, listSoFar), reader);
+}
+
+/**
+ * Read a list of values from a libxml2 XML reader.
+ */
+const list<value> read(XMLReader& reader) {
+ value nextToken = readToken(reader);
+ if (startElement == nextToken)
+ return mklist<value>(readList(mklist(element), reader));
+ return list<value>();
+}
+
+/**
+ * Context passed to the read callback function.
+ */
+class XMLReadContext {
+public:
+ XMLReadContext(const list<string>& ilist) : ilist(ilist) {
+ }
+ list<string> ilist;
+};
+
+/**
+ * Callback function called by libxml2 to read XML.
+ */
+int readCallback(void *context, char* buffer, int len) {
+ XMLReadContext& rc = *static_cast<XMLReadContext*>(context);
+ if (isNil(rc.ilist))
+ return 0;
+ const list<string> f(fragment(rc.ilist, len));
+ const string s(car(f));
+ rc.ilist = cdr(f);
+ memcpy(buffer, c_str(s), length(s));
+ return (int)length(s);
+}
+
+/**
+ * Return true if a list of strings contains an XML document.
+ */
+const bool isXML(const list<string>& ls) {
+ if (isNil(ls))
+ return false;
+ return substr(car(ls), 0, 5) == "<?xml";
+}
+
+/**
+ * Read a list of values from a list of strings representing an XML document.
+ */
+const list<value> readXML(const list<string>& ilist) {
+ XMLReadContext cx(ilist);
+ xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET);
+ if (xml == NULL)
+ return list<value>();
+ XMLReader reader(xml);
+ return read(reader);
+}
+
+/**
+ * Default encoding used to write XML documents.
+ */
+const char* encoding = "UTF-8";
+
+
+/**
+ * Write a list of XML element or attribute tokens.
+ */
+const list<value> expandElementValues(const value& n, const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(value(cons<value>(element, cons<value>(n, (list<value>)car(l)))), expandElementValues(n, cdr(l)));
+}
+
+const failable<bool> writeList(const list<value>& l, const xmlTextWriterPtr xml) {
+ if (isNil(l))
+ return true;
+
+ // Write an attribute
+ const value token(car(l));
+ if (isTaggedList(token, attribute)) {
+ if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)c_str(string(attributeName(token))), (const xmlChar*)c_str(string(attributeValue(token)))) < 0)
+ return mkfailure<bool>("xmlTextWriterWriteAttribute failed");
+
+ } else if (isTaggedList(token, element)) {
+
+ // Write an element containing a value
+ if (elementHasValue(token)) {
+ const value v = elementValue(token);
+ if (isList(v)) {
+
+ // Write an element per entry in a list of values
+ const list<value> e = expandElementValues(elementName(token), v);
+ writeList(e, xml);
+
+ } else {
+
+ // Write an element with a single value
+ if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0)
+ return mkfailure<bool>("xmlTextWriterStartElement failed");
+
+ // Write its children
+ const failable<bool> w = writeList(elementChildren(token), xml);
+ if (!hasContent(w))
+ return w;
+
+ if (xmlTextWriterEndElement(xml) < 0)
+ return mkfailure<bool>("xmlTextWriterEndElement failed");
+ }
+ }
+ else {
+
+ // Write an element
+ if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0)
+ return mkfailure<bool>("xmlTextWriterStartElement failed");
+
+ // Write its children
+ const failable<bool> w = writeList(elementChildren(token), xml);
+ if (!hasContent(w))
+ return w;
+
+ if (xmlTextWriterEndElement(xml) < 0)
+ return mkfailure<bool>("xmlTextWriterEndElement failed");
+ }
+ } else {
+
+ // Write XML text
+ if (xmlTextWriterWriteString(xml, (const xmlChar*)c_str(string(token))) < 0)
+ return mkfailure<bool>("xmlTextWriterWriteString failed");
+ }
+
+ // Go on
+ return writeList(cdr(l), xml);
+}
+
+/**
+ * Write a list of values to a libxml2 XML writer.
+ */
+const failable<bool> write(const list<value>& l, const xmlTextWriterPtr xml, bool xmlTag) {
+ if (xmlTag) {
+ if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0)
+ return mkfailure<bool>(string("xmlTextWriterStartDocument failed"));
+ }
+
+ const failable<bool> w = writeList(l, xml);
+ if (!hasContent(w))
+ return w;
+
+ if (xmlTag) {
+ if (xmlTextWriterEndDocument(xml) < 0)
+ return mkfailure<bool>("xmlTextWriterEndDocument failed");
+ }
+ return true;
+}
+
+/**
+ * Context passed to the write callback function.
+ */
+template<typename R> class XMLWriteContext {
+public:
+ XMLWriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
+ }
+ const lambda<R(const string&, const R)> reduce;
+ R accum;
+};
+
+/**
+ * Callback function called by libxml2 to write XML out.
+ */
+template<typename R> int writeCallback(void *context, const char* buffer, int len) {
+ XMLWriteContext<R>& cx = *static_cast<XMLWriteContext<R>*>(context);
+ cx.accum = cx.reduce(string(buffer, len), cx.accum);
+ return len;
+}
+
+/**
+ * Convert a list of values to an XML document.
+ */
+template<typename R> const failable<R> writeXML(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const bool xmlTag) {
+ XMLWriteContext<R> cx(reduce, initial);
+ xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback<R>, NULL, &cx, NULL);
+ if (out == NULL)
+ return mkfailure<R>("xmlOutputBufferCreateIO failed");
+ xmlTextWriterPtr xml = xmlNewTextWriter(out);
+ if (xml == NULL)
+ return mkfailure<R>("xmlNewTextWriter failed");
+
+ const failable<bool> w = write(l, xml, xmlTag);
+ xmlFreeTextWriter(xml);
+ if (!hasContent(w)) {
+ return mkfailure<R>(reason(w));
+ }
+ return cx.accum;
+}
+
+template<typename R> const failable<R> writeXML(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML(reduce, initial, l, true);
+}
+
+/**
+ * Convert a list of values to a list of strings representing an XML document.
+ */
+const failable<list<string> > writeXML(const list<value>& l, const bool xmlTag) {
+ const failable<list<string> > ls = writeXML<list<string> >(rcons<string>, list<string>(), l, xmlTag);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+const failable<list<string> > writeXML(const list<value>& l) {
+ return writeXML(l, true);
+}
+
+}
+#endif /* tuscany_xml_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/kernel/xsd-test.cpp b/sandbox/sebastien/cpp/apr-2/kernel/xsd-test.cpp
new file mode 100644
index 0000000000..fbd2ee6dca
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/kernel/xsd-test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test validation of a composite file against an SCDL schema.
+ */
+
+#include "string.hpp"
+#include "fstream.hpp"
+#include <libxml/xmlreader.h>
+#include <libxml/xmlschemas.h>
+
+namespace tuscany {
+
+bool printNode(xmlTextReaderPtr reader) {
+ const xmlChar* name = xmlTextReaderConstName(reader);
+ if(name == NULL)
+ name = (xmlChar *)"<unknown>";
+ const xmlChar* value = xmlTextReaderConstValue(reader);
+ cerr << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " "
+ << xmlTextReaderIsEmptyElement(reader) << " " << xmlTextReaderHasValue(reader);
+ if(value == NULL)
+ cerr << endl;
+ else
+ cerr << value << endl;
+ return true;
+}
+
+int xmlRead(void *context, char* buffer, int len) {
+ return (int)fread(buffer, 1, len, (FILE*)context);
+}
+
+int xmlClose(void *context) {
+ fclose((FILE*)context);
+ return 0;
+}
+
+bool readFile(const char*xsdfilename, const char *filename) {
+ cout << "Loading schema " << xsdfilename << endl;
+ const xmlDocPtr xsddoc = xmlReadFile(xsdfilename, NULL, XML_PARSE_NONET);
+ const xmlSchemaParserCtxtPtr xsdctx = xmlSchemaNewDocParserCtxt(xsddoc);
+ const xmlSchemaPtr xsd = xmlSchemaParse(xsdctx);
+ const xmlSchemaValidCtxtPtr validctx = xmlSchemaNewValidCtxt(xsd);
+
+ cout << "Reading file " << filename << endl;
+ FILE* file = fopen(filename, "r");
+ if (file != NULL) {
+ const xmlTextReaderPtr reader = xmlReaderForIO(xmlRead, xmlClose, file, filename, NULL, XML_PARSE_NONET);
+ xmlTextReaderSetParserProp(reader, XML_PARSER_DEFAULTATTRS, 1);
+ xmlTextReaderSetParserProp(reader, XML_PARSER_SUBST_ENTITIES, 1);
+
+ if(reader != NULL) {
+ xmlTextReaderSchemaValidateCtxt(reader, validctx, 0);
+
+ int rc;
+ while((rc = xmlTextReaderRead(reader)) == 1) {
+ printNode(reader);
+ }
+ if(xmlTextReaderIsValid(reader) != 1)
+ cout << "Could not validate document" << endl;
+ xmlFreeTextReader(reader);
+ if(rc != 0)
+ cout << "Could not parse document" << endl;
+ } else
+ cout << "Could not create parser" << endl;
+ } else
+ cout << "Could not open document" << endl;
+
+ xmlSchemaFreeValidCtxt(validctx);
+ xmlSchemaFree(xsd);
+ xmlSchemaFreeParserCtxt(xsdctx);
+
+ return true;
+}
+
+}
+
+int main(int argc, char **argv) {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ if(argc != 3)
+ return 1;
+
+ tuscany::readFile(argv[1], argv[2]);
+
+ xmlCleanupParser();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/Makefile.am
new file mode 100644
index 0000000000..a0fa000791
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/Makefile.am
@@ -0,0 +1,19 @@
+# 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.
+
+SUBDIRS = scheme atom rss js json scdl http server python java openid oauth wsgi
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/atom/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/atom/Makefile.am
new file mode 100644
index 0000000000..9a628ca969
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/atom/Makefile.am
@@ -0,0 +1,25 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/atom
+
+atom_test_SOURCES = atom-test.cpp
+atom_test_LDFLAGS = -lxml2
+
+noinst_PROGRAMS = atom-test
+TESTS = atom-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/atom/atom-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/atom/atom-test.cpp
new file mode 100644
index 0000000000..4acc720816
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/atom/atom-test.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test ATOM data conversion functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "atom.hpp"
+
+namespace tuscany {
+namespace atom {
+
+ostream* writer(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
+ "<content type=\"application/xml\">"
+ "<item>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</item>"
+ "</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
+ "</entry>\n");
+
+string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
+ "<content type=\"text\">Apple</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
+ "</entry>\n");
+
+string incompleteEntry("<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title>item</title><content type=\"text/xml\">"
+ "<Item xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</Item>"
+ "</content>"
+ "</entry>");
+
+string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id></id>"
+ "<content type=\"application/xml\">"
+ "<Item xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</Item>"
+ "</content><link href=\"\"/>"
+ "</entry>\n");
+
+bool testEntry() {
+ {
+ const list<value> i = list<value>() + element + value("item")
+ + value(list<value>() + element + value("name") + value(string("Apple")))
+ + value(list<value>() + element + value("price") + value(string("$2.99")));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ ostringstream os;
+ writeATOMEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemEntry);
+ }
+ {
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), string("Apple"));
+ ostringstream os;
+ writeATOMEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemTextEntry);
+ }
+ {
+ const list<value> a = content(readATOMEntry(mklist(itemEntry)));
+ ostringstream os;
+ writeATOMEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemEntry);
+ }
+ {
+ const list<value> a = content(readATOMEntry(mklist(itemTextEntry)));
+ ostringstream os;
+ writeATOMEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemTextEntry);
+ }
+ {
+ const list<value> a = content(readATOMEntry(mklist(incompleteEntry)));
+ ostringstream os;
+ writeATOMEntry<ostream*>(writer, &os, a);
+ assert(str(os) == completedEntry);
+ }
+ return true;
+}
+
+string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">Feed</title>"
+ "<id>1234</id>"
+ "</feed>\n");
+
+string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">Feed</title>"
+ "<id>1234</id>"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
+ "<content type=\"application/xml\">"
+ "<item>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</item>"
+ "</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
+ "</entry>"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>"
+ "<content type=\"application/xml\">"
+ "<item>"
+ "<name>Orange</name><price>$3.55</price>"
+ "</item>"
+ "</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c\"/>"
+ "</entry>"
+ "</feed>\n");
+
+bool testFeed() {
+ {
+ ostringstream os;
+ writeATOMFeed<ostream*>(writer, &os, mklist<value>("Feed", "1234"));
+ assert(str(os) == emptyFeed);
+ }
+ {
+ const list<value> a = content(readATOMFeed(mklist(emptyFeed)));
+ ostringstream os;
+ writeATOMFeed<ostream*>(writer, &os, a);
+ assert(str(os) == emptyFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "item" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + (list<value>() + element + "item"
+ + (list<value>() + element + "name" + "Apple")
+ + (list<value>() + element + "price" + "$2.99")))
+ + (list<value>() + "item" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + (list<value>() + element + "item"
+ + (list<value>() + element + "name" + "Orange")
+ + (list<value>() + element + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ ostringstream os;
+ writeATOMFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "item" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + valueToElement(list<value>() + "item"
+ + (list<value>() + "name" + "Apple")
+ + (list<value>() + "price" + "$2.99")))
+ + (list<value>() + "item" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + valueToElement(list<value>() + "item"
+ + (list<value>() + "name" + "Orange")
+ + (list<value>() + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ ostringstream os;
+ writeATOMFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ {
+ const list<value> a = content(readATOMFeed(mklist(itemFeed)));
+ ostringstream os;
+ writeATOMFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::atom::testEntry();
+ tuscany::atom::testFeed();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/atom/atom.hpp b/sandbox/sebastien/cpp/apr-2/modules/atom/atom.hpp
new file mode 100644
index 0000000000..253be9bdd6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/atom/atom.hpp
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_atom_hpp
+#define tuscany_atom_hpp
+
+/**
+ * ATOM data conversion functions.
+ */
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+namespace atom {
+
+/**
+ * Convert a list of elements to a list of values representing an ATOM entry.
+ */
+const list<value> entryElementsToValues(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> li = filter<value>(selector(mklist<value>(element, "id")), e);
+ const value i = isNil(li)? value(emptyString) : elementValue(car(li));
+ const list<value> lc = filter<value>(selector(mklist<value>(element, "content")), e);
+ return mklist<value>(t, i, elementValue(car(lc)));
+}
+
+/**
+ * Convert a list of elements to a list of values representing ATOM entries.
+ */
+const list<value> entriesElementsToValues(const list<value>& e) {
+ if (isNil(e))
+ return e;
+ return cons<value>(entryElementsToValues(car(e)), entriesElementsToValues(cdr(e)));
+}
+
+/**
+ * Return true if a list of strings contains an ATOM feed.
+ */
+const bool isATOMFeed(const list<string>& ls) {
+ if (!isXML(ls))
+ return false;
+ return contains(car(ls), "<feed") && contains(car(ls), "=\"http://www.w3.org/2005/Atom\"");
+}
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM entry.
+ */
+const failable<list<value> > readATOMEntry(const list<string>& ilist) {
+ const list<value> e = readXML(ilist);
+ if (isNil(e))
+ return mkfailure<list<value> >("Empty entry");
+ return entryElementsToValues(car(e));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to a value.
+ */
+const value entryValue(const list<value>& e) {
+ const list<value> v = elementsToValues(mklist<value>(caddr(e)));
+ return cons(car(e), mklist<value>(cadr(e), isList(car(v))? (value)cdr<value>(car(v)) : car(v)));
+}
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM feed.
+ */
+const failable<list<value> > readATOMFeed(const list<string>& ilist) {
+ const list<value> f = readXML(ilist);
+ if (isNil(f))
+ return mkfailure<list<value> >("Empty feed");
+ const list<value> t = filter<value>(selector(mklist<value>(element, "title")), car(f));
+ const list<value> i = filter<value>(selector(mklist<value>(element, "id")), car(f));
+ const list<value> e = filter<value>(selector(mklist<value>(element, "entry")), car(f));
+ if (isNil(e))
+ return mklist<value>(elementValue(car(t)), elementValue(car(i)));
+ return cons<value>(elementValue(car(t)), cons(elementValue(car(i)), entriesElementsToValues(e)));
+}
+
+/**
+ * Convert an ATOM feed containing elements to an ATOM feed containing values.
+ */
+const list<value> feedValuesLoop(const list<value> e) {
+ if (isNil(e))
+ return e;
+ return cons<value>(entryValue(car(e)), feedValuesLoop(cdr(e)));
+}
+
+const list<value> feedValues(const list<value>& e) {
+ return cons(car<value>(e), cons<value>(cadr<value>(e), feedValuesLoop(cddr<value>(e))));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to a list of elements.
+ * The first two values in the list are the entry title and id.
+ */
+const list<value> entryElement(const list<value>& l) {
+ return list<value>()
+ + element + "entry" + (list<value>() + attribute + "xmlns" + "http://www.w3.org/2005/Atom")
+ + (list<value>() + element + "title" + (list<value>() + attribute + "type" + "text") + car(l))
+ + (list<value>() + element + "id" + cadr(l))
+ + (list<value>() + element + "content"
+ + (list<value>() + attribute + "type" + (isList(caddr(l))? "application/xml" : "text")) + caddr(l))
+ + (list<value>() + element + "link" + (list<value>() + attribute + "href" + cadr(l)));
+}
+
+/**
+ * Convert a list of values representing ATOM entries to a list of elements.
+ */
+const list<value> entriesElements(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(entryElement(car(l)), entriesElements(cdr(l)));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to an ATOM entry.
+ * The first two values in the list are the entry id and title.
+ */
+template<typename R> const failable<R> writeATOMEntry(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML<R>(reduce, initial, mklist<value>(entryElement(l)));
+}
+
+const failable<list<string> > writeATOMEntry(const list<value>& l) {
+ const failable<list<string> > ls = writeATOMEntry<list<string> >(rcons<string>, list<string>(), l);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert a list of values representing an ATOM feed to an ATOM feed.
+ * The first two values in the list are the feed id and title.
+ */
+template<typename R> const failable<R> writeATOMFeed(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ const list<value> f = list<value>()
+ + element + "feed" + (list<value>() + attribute + "xmlns" + "http://www.w3.org/2005/Atom")
+ + (list<value>() + element + "title" + (list<value>() + attribute + "type" + "text") + car(l))
+ + (list<value>() + element + "id" + cadr(l));
+ if (isNil(cddr(l)))
+ return writeXML<R>(reduce, initial, mklist<value>(f));
+ const list<value> fe = append(f, entriesElements(cddr(l)));
+ return writeXML<R>(reduce, initial, mklist<value>(fe));
+}
+
+/**
+ * Convert a list of values representing an ATOM feed to a list of strings.
+ * The first two values in the list are the feed id and title.
+ */
+const failable<list<string> > writeATOMFeed(const list<value>& l) {
+ const failable<list<string> > ls = writeATOMFeed<list<string>>(rcons<string>, list<string>(), l);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert an ATOM entry containing a value to an ATOM entry containing an item element.
+ */
+const list<value> entryValuesToElements(const list<value> val) {
+ if (isList(caddr(val)))
+ return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(cons<value>("item", (list<value>)caddr(val))))));
+ return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(mklist<value>("item", caddr(val))))));
+}
+
+/**
+ * Convert an ATOM feed containing values to an ATOM feed containing elements.
+ */
+const list<value> feedValuesToElementsLoop(const list<value> val) {
+ if (isNil(val))
+ return val;
+ return cons<value>(entryValuesToElements(car(val)), feedValuesToElementsLoop(cdr(val)));
+}
+
+const list<value> feedValuesToElements(const list<value>& val) {
+ return cons(car<value>(val), cons<value>(cadr<value>(val), feedValuesToElementsLoop(cddr<value>(val))));
+}
+
+}
+}
+
+#endif /* tuscany_atom_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/http/Makefile.am
new file mode 100644
index 0000000000..a47b83fbf0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/Makefile.am
@@ -0,0 +1,65 @@
+# 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.
+
+INCLUDES = -I${HTTPD_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/http
+
+dist_mod_SCRIPTS = httpd-conf httpd-addr httpd-start httpd-stop httpd-restart ssl-ca-conf ssl-cert-conf ssl-cert-find httpd-ssl-conf basic-auth-conf cert-auth-conf form-auth-conf open-auth-conf passwd-auth-conf group-auth-conf proxy-conf proxy-ssl-conf proxy-member-conf proxy-ssl-member-conf vhost-conf vhost-ssl-conf tunnel-ssl-conf httpd-worker-conf httpd-event-conf
+moddir=$(prefix)/modules/http
+
+curl_test_SOURCES = curl-test.cpp
+curl_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+curl_get_SOURCES = curl-get.cpp
+curl_get_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+curl_connect_SOURCES = curl-connect.cpp
+curl_connect_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+mod_LTLIBRARIES = libmod_tuscany_ssltunnel.la libmod_tuscany_openauth.la
+noinst_DATA = libmod_tuscany_ssltunnel.so libmod_tuscany_openauth.so
+
+libmod_tuscany_ssltunnel_la_SOURCES = mod-ssltunnel.cpp
+libmod_tuscany_ssltunnel_la_LDFLAGS = -lxml2 -lcurl -lmozjs
+libmod_tuscany_ssltunnel.so:
+ ln -s .libs/libmod_tuscany_ssltunnel.so
+
+libmod_tuscany_openauth_la_SOURCES = mod-openauth.cpp
+libmod_tuscany_openauth_la_LDFLAGS = -lxml2 -lcurl -lmozjs
+libmod_tuscany_openauth.so:
+ ln -s .libs/libmod_tuscany_openauth.so
+
+mod_DATA = httpd.prefix httpd-apachectl.prefix httpd-modules.prefix curl.prefix
+nobase_dist_mod_DATA = conf/*
+
+EXTRA_DIST = htdocs/index.html htdocs/login/index.html htdocs/logout/index.html
+
+httpd.prefix: $(top_builddir)/config.status
+ echo ${HTTPD_PREFIX} >httpd.prefix
+httpd-apachectl.prefix: $(top_builddir)/config.status
+ echo ${HTTPD_APACHECTL_PREFIX} >httpd-apachectl.prefix
+httpd-modules.prefix: $(top_builddir)/config.status
+ echo ${HTTPD_MODULES_PREFIX} >httpd-modules.prefix
+curl.prefix: $(top_builddir)/config.status
+ echo ${CURL_PREFIX} >curl.prefix
+
+dist_noinst_SCRIPTS = httpd-test http-test proxy-test
+noinst_PROGRAMS = curl-test curl-get curl-connect
+TESTS = httpd-test http-test proxy-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/basic-auth-conf b/sandbox/sebastien/cpp/apr-2/modules/http/basic-auth-conf
new file mode 100755
index 0000000000..c3018e1174
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/basic-auth-conf
@@ -0,0 +1,41 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD basic authentication configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Generate basic authentication configuration
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: basic-auth-conf $*
+# Require clients to present a userid + password for HTTP
+# basic authentication
+<Location />
+AuthType Basic
+AuthName "$host"
+AuthBasicProvider file
+Require valid-user
+</Location>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/cert-auth-conf b/sandbox/sebastien/cpp/apr-2/modules/http/cert-auth-conf
new file mode 100755
index 0000000000..c6720c7ae4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/cert-auth-conf
@@ -0,0 +1,52 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD certificate-based authentication configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Generate authentication configuration
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: cert-auth-conf $*
+# Require clients to present a valid client certificate
+SSLVerifyClient require
+SSLVerifyDepth 1
+
+<Location />
+AuthType Basic
+AuthName "$host"
+AuthBasicProvider file
+Require valid-user
+</Location>
+
+EOF
+
+# Create password file and certificate-based users
+cat >>$root/conf/httpd.passwd <<EOF
+/C=US/ST=CA/L=San Francisco/O=$host/OU=server/CN=$host:\$1\$OXLyS...\$Owx8s2/m9/gfkcRVXzgoE/
+/C=US/ST=CA/L=San Francisco/O=$host/OU=proxy/CN=$host:\$1\$OXLyS...\$Owx8s2/m9/gfkcRVXzgoE/
+/C=US/ST=CA/L=San Francisco/O=$host/OU=tunnel/CN=$host:\$1\$OXLyS...\$Owx8s2/m9/gfkcRVXzgoE/
+/C=US/ST=CA/L=San Francisco/O=localhost/OU=server/CN=localhost:\$1\$OXLyS...\$Owx8s2/m9/gfkcRVXzgoE/
+/C=US/ST=CA/L=San Francisco/O=localhost/OU=tunnel/CN=localhost:\$1\$OXLyS...\$Owx8s2/m9/gfkcRVXzgoE/
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/conf/mime.types b/sandbox/sebastien/cpp/apr-2/modules/http/conf/mime.types
new file mode 100644
index 0000000000..4279f51bca
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/conf/mime.types
@@ -0,0 +1,607 @@
+# 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.
+
+# This file controls what Internet media types are sent to the client for
+# given file extension(s). Sending the correct media type to the client
+# is important so they know how to handle the content of the file.
+# Extra types can either be added here or by using an AddType directive
+# in your config files. For more information about Internet media types,
+# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
+# registry is at <http://www.iana.org/assignments/media-types/>.
+
+# MIME type Extensions
+application/activemessage
+application/andrew-inset ez
+application/applefile
+application/atom+xml atom
+application/atomicmail
+application/batch-smtp
+application/beep+xml
+application/cals-1840
+application/cnrp+xml
+application/commonground
+application/cpl+xml
+application/cybercash
+application/dca-rft
+application/dec-dx
+application/dvcs
+application/edi-consent
+application/edifact
+application/edi-x12
+application/eshop
+application/font-tdpfr
+application/http
+application/hyperstudio
+application/iges
+application/index
+application/index.cmd
+application/index.obj
+application/index.response
+application/index.vnd
+application/iotp
+application/ipp
+application/isup
+application/mac-binhex40 hqx
+application/mac-compactpro cpt
+application/macwriteii
+application/marc
+application/mathematica
+application/mathml+xml mathml
+application/msword doc
+application/news-message-id
+application/news-transmission
+application/ocsp-request
+application/ocsp-response
+application/octet-stream bin dms lha lzh exe class so dll dmg
+application/oda oda
+application/ogg ogg
+application/parityfec
+application/pdf pdf
+application/pgp-encrypted
+application/pgp-keys
+application/pgp-signature
+application/pkcs10
+application/pkcs7-mime
+application/pkcs7-signature
+application/pkix-cert
+application/pkix-crl
+application/pkixcmp
+application/postscript ai eps ps
+application/prs.alvestrand.titrax-sheet
+application/prs.cww
+application/prs.nprend
+application/prs.plucker
+application/qsig
+application/rdf+xml rdf
+application/reginfo+xml
+application/remote-printing
+application/riscos
+application/rtf
+application/sdp
+application/set-payment
+application/set-payment-initiation
+application/set-registration
+application/set-registration-initiation
+application/sgml
+application/sgml-open-catalog
+application/sieve
+application/slate
+application/smil smi smil
+application/srgs gram
+application/srgs+xml grxml
+application/timestamp-query
+application/timestamp-reply
+application/tve-trigger
+application/vemmi
+application/vnd.3gpp.pic-bw-large
+application/vnd.3gpp.pic-bw-small
+application/vnd.3gpp.pic-bw-var
+application/vnd.3gpp.sms
+application/vnd.3m.post-it-notes
+application/vnd.accpac.simply.aso
+application/vnd.accpac.simply.imp
+application/vnd.acucobol
+application/vnd.acucorp
+application/vnd.adobe.xfdf
+application/vnd.aether.imp
+application/vnd.amiga.ami
+application/vnd.anser-web-certificate-issue-initiation
+application/vnd.anser-web-funds-transfer-initiation
+application/vnd.audiograph
+application/vnd.blueice.multipass
+application/vnd.bmi
+application/vnd.businessobjects
+application/vnd.canon-cpdl
+application/vnd.canon-lips
+application/vnd.cinderella
+application/vnd.claymore
+application/vnd.commerce-battelle
+application/vnd.commonspace
+application/vnd.contact.cmsg
+application/vnd.cosmocaller
+application/vnd.criticaltools.wbs+xml
+application/vnd.ctc-posml
+application/vnd.cups-postscript
+application/vnd.cups-raster
+application/vnd.cups-raw
+application/vnd.curl
+application/vnd.cybank
+application/vnd.data-vision.rdz
+application/vnd.dna
+application/vnd.dpgraph
+application/vnd.dreamfactory
+application/vnd.dxr
+application/vnd.ecdis-update
+application/vnd.ecowin.chart
+application/vnd.ecowin.filerequest
+application/vnd.ecowin.fileupdate
+application/vnd.ecowin.series
+application/vnd.ecowin.seriesrequest
+application/vnd.ecowin.seriesupdate
+application/vnd.enliven
+application/vnd.epson.esf
+application/vnd.epson.msf
+application/vnd.epson.quickanime
+application/vnd.epson.salt
+application/vnd.epson.ssf
+application/vnd.ericsson.quickcall
+application/vnd.eudora.data
+application/vnd.fdf
+application/vnd.ffsns
+application/vnd.fints
+application/vnd.flographit
+application/vnd.framemaker
+application/vnd.fsc.weblaunch
+application/vnd.fujitsu.oasys
+application/vnd.fujitsu.oasys2
+application/vnd.fujitsu.oasys3
+application/vnd.fujitsu.oasysgp
+application/vnd.fujitsu.oasysprs
+application/vnd.fujixerox.ddd
+application/vnd.fujixerox.docuworks
+application/vnd.fujixerox.docuworks.binder
+application/vnd.fut-misnet
+application/vnd.grafeq
+application/vnd.groove-account
+application/vnd.groove-help
+application/vnd.groove-identity-message
+application/vnd.groove-injector
+application/vnd.groove-tool-message
+application/vnd.groove-tool-template
+application/vnd.groove-vcard
+application/vnd.hbci
+application/vnd.hhe.lesson-player
+application/vnd.hp-hpgl
+application/vnd.hp-hpid
+application/vnd.hp-hps
+application/vnd.hp-pcl
+application/vnd.hp-pclxl
+application/vnd.httphone
+application/vnd.hzn-3d-crossword
+application/vnd.ibm.afplinedata
+application/vnd.ibm.electronic-media
+application/vnd.ibm.minipay
+application/vnd.ibm.modcap
+application/vnd.ibm.rights-management
+application/vnd.ibm.secure-container
+application/vnd.informix-visionary
+application/vnd.intercon.formnet
+application/vnd.intertrust.digibox
+application/vnd.intertrust.nncp
+application/vnd.intu.qbo
+application/vnd.intu.qfx
+application/vnd.irepository.package+xml
+application/vnd.is-xpr
+application/vnd.japannet-directory-service
+application/vnd.japannet-jpnstore-wakeup
+application/vnd.japannet-payment-wakeup
+application/vnd.japannet-registration
+application/vnd.japannet-registration-wakeup
+application/vnd.japannet-setstore-wakeup
+application/vnd.japannet-verification
+application/vnd.japannet-verification-wakeup
+application/vnd.jisp
+application/vnd.kde.karbon
+application/vnd.kde.kchart
+application/vnd.kde.kformula
+application/vnd.kde.kivio
+application/vnd.kde.kontour
+application/vnd.kde.kpresenter
+application/vnd.kde.kspread
+application/vnd.kde.kword
+application/vnd.kenameaapp
+application/vnd.koan
+application/vnd.liberty-request+xml
+application/vnd.llamagraphics.life-balance.desktop
+application/vnd.llamagraphics.life-balance.exchange+xml
+application/vnd.lotus-1-2-3
+application/vnd.lotus-approach
+application/vnd.lotus-freelance
+application/vnd.lotus-notes
+application/vnd.lotus-organizer
+application/vnd.lotus-screencam
+application/vnd.lotus-wordpro
+application/vnd.mcd
+application/vnd.mediastation.cdkey
+application/vnd.meridian-slingshot
+application/vnd.micrografx.flo
+application/vnd.micrografx.igx
+application/vnd.mif mif
+application/vnd.minisoft-hp3000-save
+application/vnd.mitsubishi.misty-guard.trustweb
+application/vnd.mobius.daf
+application/vnd.mobius.dis
+application/vnd.mobius.mbk
+application/vnd.mobius.mqy
+application/vnd.mobius.msl
+application/vnd.mobius.plc
+application/vnd.mobius.txf
+application/vnd.mophun.application
+application/vnd.mophun.certificate
+application/vnd.motorola.flexsuite
+application/vnd.motorola.flexsuite.adsi
+application/vnd.motorola.flexsuite.fis
+application/vnd.motorola.flexsuite.gotap
+application/vnd.motorola.flexsuite.kmr
+application/vnd.motorola.flexsuite.ttc
+application/vnd.motorola.flexsuite.wem
+application/vnd.mozilla.xul+xml xul
+application/vnd.ms-artgalry
+application/vnd.ms-asf
+application/vnd.ms-excel xls
+application/vnd.ms-lrm
+application/vnd.ms-powerpoint ppt
+application/vnd.ms-project
+application/vnd.ms-tnef
+application/vnd.ms-works
+application/vnd.ms-wpl
+application/vnd.mseq
+application/vnd.msign
+application/vnd.music-niff
+application/vnd.musician
+application/vnd.netfpx
+application/vnd.noblenet-directory
+application/vnd.noblenet-sealer
+application/vnd.noblenet-web
+application/vnd.novadigm.edm
+application/vnd.novadigm.edx
+application/vnd.novadigm.ext
+application/vnd.obn
+application/vnd.osa.netdeploy
+application/vnd.palm
+application/vnd.pg.format
+application/vnd.pg.osasli
+application/vnd.powerbuilder6
+application/vnd.powerbuilder6-s
+application/vnd.powerbuilder7
+application/vnd.powerbuilder7-s
+application/vnd.powerbuilder75
+application/vnd.powerbuilder75-s
+application/vnd.previewsystems.box
+application/vnd.publishare-delta-tree
+application/vnd.pvi.ptid1
+application/vnd.pwg-multiplexed
+application/vnd.pwg-xhtml-print+xml
+application/vnd.quark.quarkxpress
+application/vnd.rapid
+application/vnd.s3sms
+application/vnd.sealed.net
+application/vnd.seemail
+application/vnd.shana.informed.formdata
+application/vnd.shana.informed.formtemplate
+application/vnd.shana.informed.interchange
+application/vnd.shana.informed.package
+application/vnd.smaf
+application/vnd.sss-cod
+application/vnd.sss-dtf
+application/vnd.sss-ntf
+application/vnd.street-stream
+application/vnd.svd
+application/vnd.swiftview-ics
+application/vnd.triscape.mxs
+application/vnd.trueapp
+application/vnd.truedoc
+application/vnd.ufdl
+application/vnd.uplanet.alert
+application/vnd.uplanet.alert-wbxml
+application/vnd.uplanet.bearer-choice
+application/vnd.uplanet.bearer-choice-wbxml
+application/vnd.uplanet.cacheop
+application/vnd.uplanet.cacheop-wbxml
+application/vnd.uplanet.channel
+application/vnd.uplanet.channel-wbxml
+application/vnd.uplanet.list
+application/vnd.uplanet.list-wbxml
+application/vnd.uplanet.listcmd
+application/vnd.uplanet.listcmd-wbxml
+application/vnd.uplanet.signal
+application/vnd.vcx
+application/vnd.vectorworks
+application/vnd.vidsoft.vidconference
+application/vnd.visio
+application/vnd.visionary
+application/vnd.vividence.scriptfile
+application/vnd.vsf
+application/vnd.wap.sic
+application/vnd.wap.slc
+application/vnd.wap.wbxml wbxml
+application/vnd.wap.wmlc wmlc
+application/vnd.wap.wmlscriptc wmlsc
+application/vnd.webturbo
+application/vnd.wrq-hp3000-labelled
+application/vnd.wt.stf
+application/vnd.wv.csp+wbxml
+application/vnd.xara
+application/vnd.xfdl
+application/vnd.yamaha.hv-dic
+application/vnd.yamaha.hv-script
+application/vnd.yamaha.hv-voice
+application/vnd.yellowriver-custom-menu
+application/voicexml+xml vxml
+application/watcherinfo+xml
+application/whoispp-query
+application/whoispp-response
+application/wita
+application/wordperfect5.1
+application/x-bcpio bcpio
+application/x-cdlink vcd
+application/x-chess-pgn pgn
+application/x-compress
+application/x-cpio cpio
+application/x-csh csh
+application/x-director dcr dir dxr
+application/x-dvi dvi
+application/x-futuresplash spl
+application/x-gtar gtar
+application/x-gzip
+application/x-hdf hdf
+application/x-javascript js
+application/x-koan skp skd skt skm
+application/x-latex latex
+application/x-netcdf nc cdf
+application/x-sh sh
+application/x-shar shar
+application/x-shockwave-flash swf
+application/x-stuffit sit
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-tar tar
+application/x-tcl tcl
+application/x-tex tex
+application/x-texinfo texinfo texi
+application/x-troff t tr roff
+application/x-troff-man man
+application/x-troff-me me
+application/x-troff-ms ms
+application/x-ustar ustar
+application/x-wais-source src
+application/x400-bp
+application/xhtml+xml xhtml xht
+application/xslt+xml xslt
+application/xml xml xsl
+application/xml-dtd dtd
+application/xml-external-parsed-entity
+application/zip zip
+audio/32kadpcm
+audio/amr
+audio/amr-wb
+audio/basic au snd
+audio/cn
+audio/dat12
+audio/dsr-es201108
+audio/dvi4
+audio/evrc
+audio/evrc0
+audio/g722
+audio/g.722.1
+audio/g723
+audio/g726-16
+audio/g726-24
+audio/g726-32
+audio/g726-40
+audio/g728
+audio/g729
+audio/g729D
+audio/g729E
+audio/gsm
+audio/gsm-efr
+audio/l8
+audio/l16
+audio/l20
+audio/l24
+audio/lpc
+audio/midi mid midi kar
+audio/mpa
+audio/mpa-robust
+audio/mp4a-latm
+audio/mpeg mpga mp2 mp3
+audio/parityfec
+audio/pcma
+audio/pcmu
+audio/prs.sid
+audio/qcelp
+audio/red
+audio/smv
+audio/smv0
+audio/telephone-event
+audio/tone
+audio/vdvi
+audio/vnd.3gpp.iufp
+audio/vnd.cisco.nse
+audio/vnd.cns.anp1
+audio/vnd.cns.inf1
+audio/vnd.digital-winds
+audio/vnd.everad.plj
+audio/vnd.lucent.voice
+audio/vnd.nortel.vbk
+audio/vnd.nuera.ecelp4800
+audio/vnd.nuera.ecelp7470
+audio/vnd.nuera.ecelp9600
+audio/vnd.octel.sbc
+audio/vnd.qcelp
+audio/vnd.rhetorex.32kadpcm
+audio/vnd.vmx.cvsd
+audio/x-aiff aif aiff aifc
+audio/x-alaw-basic
+audio/x-mpegurl m3u
+audio/x-pn-realaudio ram ra
+audio/x-pn-realaudio-plugin
+application/vnd.rn-realmedia rm
+audio/x-wav wav
+chemical/x-pdb pdb
+chemical/x-xyz xyz
+image/bmp bmp
+image/cgm cgm
+image/g3fax
+image/gif gif
+image/ief ief
+image/jpeg jpeg jpg jpe
+image/naplps
+image/png png
+image/prs.btif
+image/prs.pti
+image/svg+xml svg
+image/t38
+image/tiff tiff tif
+image/tiff-fx
+image/vnd.cns.inf2
+image/vnd.djvu djvu djv
+image/vnd.dwg
+image/vnd.dxf
+image/vnd.fastbidsheet
+image/vnd.fpx
+image/vnd.fst
+image/vnd.fujixerox.edmics-mmr
+image/vnd.fujixerox.edmics-rlc
+image/vnd.globalgraphics.pgb
+image/vnd.mix
+image/vnd.ms-modi
+image/vnd.net-fpx
+image/vnd.svf
+image/vnd.wap.wbmp wbmp
+image/vnd.xiff
+image/x-cmu-raster ras
+image/x-icon ico
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-rgb rgb
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+message/delivery-status
+message/disposition-notification
+message/external-body
+message/http
+message/news
+message/partial
+message/rfc822
+message/s-http
+message/sip
+message/sipfrag
+model/iges igs iges
+model/mesh msh mesh silo
+model/vnd.dwf
+model/vnd.flatland.3dml
+model/vnd.gdl
+model/vnd.gs-gdl
+model/vnd.gtw
+model/vnd.mts
+model/vnd.parasolid.transmit.binary
+model/vnd.parasolid.transmit.text
+model/vnd.vtu
+model/vrml wrl vrml
+multipart/alternative
+multipart/appledouble
+multipart/byteranges
+multipart/digest
+multipart/encrypted
+multipart/form-data
+multipart/header-set
+multipart/mixed
+multipart/parallel
+multipart/related
+multipart/report
+multipart/signed
+multipart/voice-message
+text/calendar ics ifb
+text/css css
+text/directory
+text/enriched
+text/html html htm
+text/parityfec
+text/plain asc txt
+text/prs.lines.tag
+text/rfc822-headers
+text/richtext rtx
+text/rtf rtf
+text/sgml sgml sgm
+text/t140
+text/tab-separated-values tsv
+text/uri-list
+text/vnd.abc
+text/vnd.curl
+text/vnd.dmclientscript
+text/vnd.fly
+text/vnd.fmi.flexstor
+text/vnd.in3d.3dml
+text/vnd.in3d.spot
+text/vnd.iptc.nitf
+text/vnd.iptc.newsml
+text/vnd.latex-z
+text/vnd.motorola.reflex
+text/vnd.ms-mediapackage
+text/vnd.net2phone.commcenter.command
+text/vnd.sun.j2me.app-descriptor
+text/vnd.wap.si
+text/vnd.wap.sl
+text/vnd.wap.wml wml
+text/vnd.wap.wmlscript wmls
+text/x-setext etx
+text/xml
+text/xml-external-parsed-entity
+video/bmpeg
+video/bt656
+video/celb
+video/dv
+video/h261
+video/h263
+video/h263-1998
+video/h263-2000
+video/jpeg
+video/mp1s
+video/mp2p
+video/mp2t
+video/mp4v-es
+video/mpv
+video/mpeg mpeg mpg mpe
+video/nv
+video/parityfec
+video/pointer
+video/quicktime qt mov
+video/smpte292m
+video/vnd.fvt
+video/vnd.motorola.video
+video/vnd.motorola.videop
+video/vnd.mpegurl mxu m4u
+video/vnd.nokia.interleaved-multimedia
+video/vnd.objectvideo
+video/vnd.vivo
+video/x-msvideo avi
+video/x-sgi-movie movie
+x-conference/x-cooltalk ice
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/curl-connect.cpp b/sandbox/sebastien/cpp/apr-2/modules/http/curl-connect.cpp
new file mode 100644
index 0000000000..432ccc2000
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/curl-connect.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTP connect command line test tool.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "http.hpp"
+
+namespace tuscany {
+namespace http {
+
+const bool testConnect(const string& url, const string& ca = "", const string& cert = "", const string& key = "") {
+ gc_scoped_pool p;
+
+ CURLSession cs(ca, cert, key);
+ const failable<bool> crc = connect(url, cs);
+ assert(hasContent(crc));
+
+ apr_pollset_t* pollset;
+ apr_status_t cprc = apr_pollset_create(&pollset, 2, pool(p), 0);
+ assert(cprc == APR_SUCCESS);
+ apr_socket_t* csock = sock(0, p);
+ const apr_pollfd_t* cpollfd = pollfd(csock, APR_POLLIN | APR_POLLERR | APR_POLLNVAL | APR_POLLHUP, p);
+ apr_pollset_add(pollset, cpollfd);
+ apr_socket_t* tsock = sock(cs);
+ const apr_pollfd_t* tpollfd = pollfd(tsock, APR_POLLIN | APR_POLLERR | APR_POLLNVAL | APR_POLLHUP, p);
+ apr_pollset_add(pollset, tpollfd);
+
+ const apr_pollfd_t* pollfds;
+ apr_int32_t pollcount;
+ for(;;) {
+ apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds);
+ assert(pollrc == APR_SUCCESS);
+
+ for (; pollcount > 0; pollcount--, pollfds++) {
+ if (pollfds->rtnevents & APR_POLLIN) {
+ char data[8192];
+ if (pollfds->desc.s == csock) {
+ const size_t rl = ::read(0, data, sizeof(data));
+ if (rl == (size_t)-1)
+ return false;
+ if (rl > 0) {
+ const failable<bool> src = http::send(data, rl, cs);
+ assert(hasContent(src));
+ }
+ }
+ else {
+ const failable<size_t> frl = http::recv(data, sizeof(data), cs);
+ assert(hasContent(frl));
+ const size_t rl = content(frl);
+ if (rl == 0)
+ return true;
+ const size_t wl = ::write(0, data, rl);
+ assert(wl == rl);
+ }
+ continue;
+ }
+ assert(!(pollfds->rtnevents & (APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)));
+ }
+ }
+ return true;
+}
+
+}
+}
+
+int main(unused const int argc, const char** argv) {
+ if (argc > 2)
+ tuscany::http::testConnect(tuscany::string(argv[1]), tuscany::string(argv[2]), tuscany::string(argv[3]), tuscany::string(argv[4]));
+ else
+ tuscany::http::testConnect(tuscany::string(argv[1]));
+ return 0;
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/curl-get.cpp b/sandbox/sebastien/cpp/apr-2/modules/http/curl-get.cpp
new file mode 100644
index 0000000000..762423bebb
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/curl-get.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTP GET command line test tool.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "http.hpp"
+
+namespace tuscany {
+namespace http {
+
+const bool testGet(const string& url, const string& ca = "", const string& cert = "", const string& key = "") {
+ CURLSession ch(ca, cert, key);
+ const failable<value> val = get(url, ch);
+ assert(hasContent(val));
+ cout << content(val) << endl;
+ return true;
+}
+
+}
+}
+
+int main(unused const int argc, const char** argv) {
+ if (argc > 2)
+ tuscany::http::testGet(tuscany::string(argv[1]), tuscany::string(argv[2]), tuscany::string(argv[3]), tuscany::string(argv[4]));
+ else
+ tuscany::http::testGet(tuscany::string(argv[1]));
+ return 0;
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/curl-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/http/curl-test.cpp
new file mode 100644
index 0000000000..a7b8fd90b6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/curl-test.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "http.hpp"
+
+namespace tuscany {
+namespace http {
+
+string testURI = "http://localhost:8090";
+
+ostream* curlWriter(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+const bool testGet() {
+ CURLSession ch("", "", "");
+ {
+ ostringstream os;
+ const failable<list<ostream*> > r = get<ostream*>(curlWriter, &os, testURI, ch);
+ assert(hasContent(r));
+ assert(contains(str(os), "HTTP/1.1 200 OK"));
+ assert(contains(str(os), "It works"));
+ }
+ {
+ const failable<value> r = getcontent(testURI, ch);
+ assert(hasContent(r));
+ assert(contains(car(reverse(list<value>(content(r)))), "It works"));
+ }
+ return true;
+}
+
+struct getLoop {
+ CURLSession& ch;
+ getLoop(CURLSession& ch) : ch(ch) {
+ }
+ const bool operator()() const {
+ const failable<value> r = getcontent(testURI, ch);
+ assert(hasContent(r));
+ assert(contains(car(reverse(list<value>(content(r)))), "It works"));
+ return true;
+ }
+};
+
+const bool testGetPerf() {
+ CURLSession ch("", "", "");
+ lambda<bool()> gl = getLoop(ch);
+ cout << "Static GET test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ tuscany::http::testURI = tuscany::string("http://") + tuscany::http::hostname() + ":8090";
+
+ tuscany::http::testGet();
+ tuscany::http::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/form-auth-conf b/sandbox/sebastien/cpp/apr-2/modules/http/form-auth-conf
new file mode 100755
index 0000000000..a9077116da
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/form-auth-conf
@@ -0,0 +1,54 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD form authentication configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Generate form authentication configuration
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: form-auth-conf $*
+# Require clients to present a userid + password through form-based
+# authentication
+<Location />
+AuthType Form
+AuthName "$host"
+AuthFormProvider file
+AuthFormLoginRequiredLocation /login
+AuthFormLogoutLocation /
+Session On
+SessionCookieName TuscanyFormAuth path=/;secure=TRUE
+#SessionCryptoPassphrase secret
+Require valid-user
+</Location>
+
+<Location /login/dologin>
+SetHandler form-login-handler
+</Location>
+
+<Location /logout/dologout>
+SetHandler form-logout-handler
+</Location>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/group-auth-conf b/sandbox/sebastien/cpp/apr-2/modules/http/group-auth-conf
new file mode 100755
index 0000000000..dc8dad8641
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/group-auth-conf
@@ -0,0 +1,44 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+user=$2
+group="members"
+
+# Add user to group
+cat $root/conf/httpd.groups | awk " BEGIN { found = 0 } /$group: / { printf \"%s %s\n\", \$0, \"$user\"; found = 1 } !/$group: / { printf \"%s\n\", \$0 } END { if (found == 0) printf \"%s: %s\n\", \"$group\", \"$user\" } " >$root/conf/.httpd.groups.tmp 2>/dev/null
+cp $root/conf/.httpd.groups.tmp $root/conf/httpd.groups
+rm $root/conf/.httpd.groups.tmp
+
+# Generate HTTPD group authorization configuration
+conf=`cat $root/conf/auth.conf | grep "Generated by: group-auth-conf"`
+if [ "$conf" = "" ]; then
+ cat >>$root/conf/auth.conf <<EOF
+# Generated by: group-auth-conf $1
+# Allow group member access to root location
+<Location />
+AuthGroupFile "$root/conf/httpd.groups"
+Require group members
+</Location>
+
+EOF
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/index.html
new file mode 100644
index 0000000000..1bfb3e30c2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/index.html
@@ -0,0 +1,21 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>It works!</h1></body></html>
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/login/index.html b/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/login/index.html
new file mode 100644
index 0000000000..3f312e4ca4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/login/index.html
@@ -0,0 +1,40 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in</h1>
+
+<script type="text/javascript">
+function submitFormSignin() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.formSignin.httpd_location.value = '/';
+ document.formSignin.submit();
+}
+</script>
+
+<form name="formSignin" method="POST" action="/login/dologin">
+<table border="0">
+<tr><td>Username:</td><td><input type="text" name="httpd_username" value=""/></td></tr>
+<tr><td>Password:</td><td><input type="password" name="httpd_password" value=""/></td></tr>
+<tr><td><input type="button" onclick="submitFormSignin()" value="Sign in"/></td><td></td></tr>
+</table>
+<input type="hidden" name="httpd_location" value="/"/>
+</form>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/logout/index.html b/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/logout/index.html
new file mode 100644
index 0000000000..1ac6e39a1c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/htdocs/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyFormAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/http-test b/sandbox/sebastien/cpp/apr-2/modules/http/http-test
new file mode 100755
index 0000000000..0db47fe189
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/http-test
@@ -0,0 +1,32 @@
+#!/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
+# 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.
+
+# Setup
+./httpd-conf tmp localhost 8090 htdocs
+./httpd-start tmp
+sleep 2
+
+# Test
+./curl-test
+rc=$?
+
+# Cleanup
+./httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/http.hpp b/sandbox/sebastien/cpp/apr-2/modules/http/http.hpp
new file mode 100644
index 0000000000..95b904435d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/http.hpp
@@ -0,0 +1,663 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_http_hpp
+#define tuscany_http_hpp
+
+/**
+ * CURL HTTP client functions.
+ */
+
+#include <unistd.h>
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+#include <apr_network_io.h>
+#include <apr_portable.h>
+#include <apr_poll.h>
+
+#include "string.hpp"
+#include "gc.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "../atom/atom.hpp"
+#include "../rss/rss.hpp"
+#include "../json/json.hpp"
+
+namespace tuscany {
+namespace http {
+
+/**
+ * CURL library runtime, one per process.
+ */
+class CURLRuntime {
+public:
+ CURLRuntime() {
+ curl_global_init(CURL_GLOBAL_ALL);
+ }
+} curlRuntime;
+
+/**
+ * Represents a CURL session handle.
+ */
+class CURLSession {
+public:
+ CURLSession() : h(NULL), p(NULL), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL), owner(false), ca(""), cert(""), key("") {
+ }
+
+ CURLSession(const string& ca, const string& cert, const string& key) : h(curl_easy_init()), p(gc_pool(mkpool())), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL), owner(true), ca(ca), cert(cert), key(key) {
+ }
+
+ CURLSession(const CURLSession& c) : h(c.h), p(c.p), sock(c.sock), wpollset(c.wpollset), wpollfd(c.wpollfd), rpollset(c.rpollset), rpollfd(c.rpollfd), owner(false), ca(c.ca), cert(c.cert), key(c.key) {
+ }
+
+ ~CURLSession() {
+ if (!owner)
+ return;
+ if (h == NULL)
+ return;
+ curl_easy_cleanup(h);
+ destroy(p);
+ }
+
+private:
+ CURL* h;
+ gc_pool p;
+ apr_socket_t* sock;
+ apr_pollset_t* wpollset;
+ apr_pollfd_t* wpollfd;
+ apr_pollset_t* rpollset;
+ apr_pollfd_t* rpollfd;
+ bool owner;
+
+ friend CURL* handle(const CURLSession& cs);
+ friend apr_socket_t* sock(const CURLSession& cs);
+ friend const failable<bool> connect(const string& url, CURLSession& cs);
+ friend const failable<bool> send(const char* c, const size_t l, const CURLSession& cs);
+ friend const failable<size_t> recv(char* c, const size_t l, const CURLSession& cs);
+
+public:
+ string ca;
+ string cert;
+ string key;
+};
+
+/**
+ * Returns the CURL handle used by a CURL session.
+ */
+CURL* handle(const CURLSession& cs) {
+ return cs.h;
+}
+
+/**
+ * Return an apr_socket_t for the socket used by a CURL session.
+ */
+apr_socket_t* sock(const CURLSession& cs) {
+ return cs.sock;
+}
+
+/**
+ * Convert a socket fd to an apr_socket_t.
+ */
+apr_socket_t* sock(const int sd, const gc_pool& p) {
+ int fd = sd;
+ apr_socket_t* s = NULL;
+ apr_os_sock_put(&s, &fd, pool(p));
+ return s;
+}
+
+/**
+ * Convert a CURL return code to an error string.
+ */
+const string curlreason(CURLcode rc) {
+ return curl_easy_strerror(rc);
+}
+
+/**
+ * Convert an APR status to an error string.
+ */
+const string apreason(apr_status_t rc) {
+ char buf[256];
+ return apr_strerror(rc, buf, sizeof(buf));
+}
+
+/**
+ * Setup a CURL session
+ */
+const failable<CURL*> setup(const string& url, const CURLSession& cs) {
+
+ // Init CURL session
+ CURL* ch = handle(cs);
+ curl_easy_reset(ch);
+ curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0");
+
+ // Setup protocol options
+ curl_easy_setopt(ch, CURLOPT_TCP_NODELAY, true);
+ curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_easy_setopt(ch, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
+
+ // Setup SSL options
+ if (cs.ca != "") {
+ debug(cs.ca, "http::setup::ca");
+ curl_easy_setopt(ch, CURLOPT_CAINFO, c_str(cs.ca));
+ curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, true);
+ curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, 2);
+ } else
+ curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, false);
+ if (cs.cert != "") {
+ debug(cs.cert, "http::setup::cert");
+ curl_easy_setopt(ch, CURLOPT_SSLCERT, c_str(cs.cert));
+ curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM");
+ }
+ if (cs.key != "") {
+ debug(cs.key, "http::setup::key");
+ curl_easy_setopt(ch, CURLOPT_SSLKEY, c_str(cs.key));
+ curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM");
+ }
+
+ // Set target URL
+ curl_easy_setopt(ch, CURLOPT_URL, c_str(url));
+
+ return ch;
+}
+
+/**
+ * Context passed to the read callback function.
+ */
+class CURLReadContext {
+public:
+ CURLReadContext(const list<string>& ilist) : ilist(ilist) {
+ }
+ list<string> ilist;
+};
+
+/**
+ * Called by CURL to read data to send.
+ */
+size_t readCallback(void *ptr, size_t size, size_t nmemb, void *data) {
+ CURLReadContext& rcx = *static_cast<CURLReadContext*>(data);
+ if (isNil(rcx.ilist))
+ return 0;
+ const list<string> f(fragment(rcx.ilist, size * nmemb));
+ const string s = car(f);
+ rcx.ilist = cdr(f);
+ memcpy(ptr, c_str(s), length(s));
+ return length(s);
+}
+
+/**
+ * Context passed to CURL write callback function.
+ */
+template<typename R> class CURLWriteContext {
+public:
+ CURLWriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) {
+ }
+ const lambda<R(const string&, const R)> reduce;
+ R accum;
+};
+
+/**
+ * Called by CURL to write received data.
+ */
+template<typename R> size_t writeCallback(void *ptr, size_t size, size_t nmemb, void *data) {
+ CURLWriteContext<R>& wcx = *(static_cast<CURLWriteContext<R>*> (data));
+ const size_t realsize = size * nmemb;
+ wcx.accum = wcx.reduce(string((const char*)ptr, realsize), wcx.accum);
+ return realsize;
+}
+
+/**
+ * Apply an HTTP verb to a list containing a list of headers and a list of content, and
+ * a reduce function used to process the response.
+ */
+curl_slist* headers(curl_slist* cl, const list<string>& h) {
+ if (isNil(h))
+ return cl;
+ return headers(curl_slist_append(cl, c_str(string(car(h)))), cdr(h));
+}
+
+template<typename R> const failable<list<R> > apply(const list<list<string> >& hdr, const lambda<R(const string&, const R)>& reduce, const R& initial, const string& url, const string& verb, const CURLSession& cs) {
+ debug(url, "http::apply::url");
+ debug(verb, "http::apply::verb");
+
+ // Setup the CURL session
+ const failable<CURL*> fch = setup(url, cs);
+ if (!hasContent(fch))
+ return mkfailure<list<R>>(reason(fch));
+ CURL* ch = content(fch);
+
+ // Set the request headers
+ curl_slist* hl = headers(NULL, car(hdr));
+ if (hl != NULL)
+ curl_easy_setopt(ch, CURLOPT_HTTPHEADER, hl);
+
+ // Convert request body to a string
+ // TODO use HTTP chunking instead
+ ostringstream os;
+ write(cadr(hdr), os);
+ const string s = str(os);
+ const size_t sz = length(s);
+
+ // Setup the read, write header and write data callbacks
+ CURLReadContext rcx(mklist(s));
+ curl_easy_setopt(ch, CURLOPT_READFUNCTION, (size_t (*)(void*, size_t, size_t, void*))readCallback);
+ curl_easy_setopt(ch, CURLOPT_READDATA, &rcx);
+ CURLWriteContext<R> hcx(reduce, initial);
+ curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, (size_t (*)(void*, size_t, size_t, void*))(writeCallback<R>));
+ curl_easy_setopt(ch, CURLOPT_HEADERDATA, &hcx);
+ CURLWriteContext<R> wcx(reduce, initial);
+ curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, (size_t (*)(void*, size_t, size_t, void*))(writeCallback<R>));
+ curl_easy_setopt(ch, CURLOPT_WRITEDATA, &wcx);
+
+ // Apply the HTTP verb
+ if (verb == "POST") {
+ curl_easy_setopt(ch, CURLOPT_POST, true);
+ curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, sz);
+ } else if (verb == "PUT") {
+ curl_easy_setopt(ch, CURLOPT_UPLOAD, true);
+ curl_easy_setopt(ch, CURLOPT_INFILESIZE, sz);
+ } else if (verb == "DELETE")
+ curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, "DELETE");
+ const CURLcode rc = curl_easy_perform(ch);
+
+ // Free the headers
+ if (hl != NULL)
+ curl_slist_free_all(hl);
+
+ // Return the HTTP return code or content
+ if (rc)
+ return mkfailure<list<R> >(string(curl_easy_strerror(rc)));
+ long httprc;
+ curl_easy_getinfo (ch, CURLINFO_RESPONSE_CODE, &httprc);
+ if (httprc != 200 && httprc != 201) {
+ ostringstream es;
+ es << "HTTP code " << httprc;
+ return mkfailure<list<R> >(str(es));
+ }
+ return mklist<R>(hcx.accum, wcx.accum);
+}
+
+/**
+ * Evaluate an expression remotely, at the given URL.
+ */
+const failable<value> evalExpr(const value& expr, const string& url, const CURLSession& cs) {
+ debug(url, "http::evalExpr::url");
+ debug(expr, "http::evalExpr::input");
+
+ // Convert expression to a JSON-RPC request
+ js::JSContext cx;
+ const failable<list<string> > jsreq = json::jsonRequest(1, car<value>(expr), cdr<value>(expr), cx);
+ if (!hasContent(jsreq))
+ return mkfailure<value>(reason(jsreq));
+
+ // POST it to the URL
+ const list<string> h = mklist<string>("Content-Type: application/json-rpc");
+ const failable<list<list<string> > > res = apply<list<string> >(mklist<list<string> >(h, content(jsreq)), rcons<string>, list<string>(), url, "POST", cs);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+
+ // Parse and return JSON-RPC result
+ const failable<value> rval = json::jsonResultValue(cadr<list<string> >(content(res)), cx);
+ debug(rval, "http::evalExpr::result");
+ if (!hasContent(rval))
+ return mkfailure<value>(reason(rval));
+ return content(rval);
+}
+
+/**
+ * Find and return a header.
+ */
+const failable<string> header(const char* prefix, const list<string>& h) {
+ if (isNil(h))
+ return mkfailure<string>(string("Couldn't find header: ") + prefix);
+ const string s = car(h);
+ if (find(s, prefix) != 0)
+ return header(prefix, cdr(h));
+ const string l(substr(s, length(prefix)));
+ return substr(l, 0, find_first_of(l, "\r\n"));
+}
+
+/**
+ * Find and return a location header.
+ */
+const failable<string> location(const list<string>& h) {
+ return header("Location: ", h);
+}
+
+/**
+ * Convert a location to an entry id.
+ */
+const failable<value> entryId(const failable<string> l) {
+ if (!hasContent(l))
+ return mkfailure<value>(reason(l));
+ const string ls(content(l));
+ return value(mklist<value>(string(substr(ls, find_last(ls, '/') + 1))));
+}
+
+/**
+ * Find and return a content-type header.
+ */
+const failable<string> contentType(const list<string>& h) {
+ return header("Content-Type: ", h);
+}
+
+/**
+ * HTTP GET, return the resource at the given URL.
+ */
+template<typename R> const failable<list<R> > get(const lambda<R(const string&, const R)>& reduce, const R& initial, const string& url, const CURLSession& cs) {
+ debug(url, "http::get::url");
+ const list<list<string> > req = mklist(list<string>(), list<string>());
+ return apply(req, reduce, initial, url, "GET", cs);
+}
+
+/**
+ * HTTP GET, return a list of values representing the resource at the given URL.
+ */
+const failable<value> getcontent(const string& url, const CURLSession& cs) {
+ debug(url, "http::get::url");
+
+ // Get the contents of the resource at the given URL
+ const failable<list<list<string> > > res = get<list<string>>(rcons<string>, list<string>(), url, cs);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+ const list<string> ls(reverse(cadr(content(res))));
+
+ // Return the content as a list of values
+ const value val(mkvalues(ls));
+ debug(val, "http::get::result");
+ return val;
+}
+
+/**
+ * HTTP GET, return a list of values representing the resource at the given URL.
+ */
+const failable<value> get(const string& url, const CURLSession& cs) {
+ debug(url, "http::get::url");
+
+ // Get the contents of the resource at the given URL
+ const failable<list<list<string> > > res = get<list<string> >(rcons<string>, list<string>(), url, cs);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+ const string ct(content(contentType(car(content(res)))));
+ debug(ct, "http::get::contentType");
+
+ const list<string> ls(reverse(cadr(content(res))));
+ debug(ls, "http::get::content");
+
+ if (contains(ct, "application/atom+xml;type=entry")) {
+ // Read an ATOM entry
+ const value val(atom::entryValue(content(atom::readATOMEntry(ls))));
+ debug(val, "http::get::result");
+ return val;
+ }
+ if (contains(ct, "application/atom+xml;type=feed") || atom::isATOMFeed(ls)) {
+ // Read an ATOM feed
+ const value val(atom::feedValues(content(atom::readATOMFeed(ls))));
+ debug(val, "http::get::result");
+ return val;
+ }
+ if (contains(ct, "application/rss+xml") || rss::isRSSFeed(ls)) {
+ // Read an RSS feed
+ const value val(rss::feedValues(content(rss::readRSSFeed(ls))));
+ debug(val, "http::get::result");
+ return val;
+ }
+ if (contains(ct, "text/javascript") || contains(ct, "application/json") || json::isJSON(ls)) {
+ // Read a JSON document
+ js::JSContext cx;
+ const value val(json::jsonValues(content(json::readJSON(ls, cx))));
+ debug(val, "http::get::result");
+ return val;
+ }
+ if (contains(ct, "text/xml") || contains(ct, "application/xml") || isXML(ls)) {
+ // Read an XML document
+ const value val(elementsToValues(readXML(ls)));
+ debug(val, "http::get::result");
+ return val;
+ }
+
+ // Return the content type and a content list
+ const value val(mklist<value>(ct, mkvalues(ls)));
+ debug(val, "http::get::result");
+ return val;
+}
+
+/**
+ * HTTP POST.
+ */
+const failable<value> post(const value& val, const string& url, const CURLSession& cs) {
+
+ // Convert value to an ATOM entry
+ const failable<list<string> > entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
+ if (!hasContent(entry))
+ return mkfailure<value>(reason(entry));
+ debug(url, "http::post::url");
+ debug(content(entry), "http::post::input");
+
+ // POST it to the URL
+ const list<string> h = mklist<string>("Content-Type: application/atom+xml");
+ const list<list<string> > req = mklist<list<string> >(h, content(entry));
+ const failable<list<list<string> > > res = apply<list<string>>(req, rcons<string>, list<string>(), url, "POST", cs);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+
+ // Return the new entry id from the HTTP location header
+ const failable<value> eid(entryId(location(car(content(res)))));
+ debug(eid, "http::post::result");
+ return eid;
+}
+
+/**
+ * HTTP PUT.
+ */
+const failable<value> put(const value& val, const string& url, const CURLSession& cs) {
+
+ // Convert value to an ATOM entry
+ const failable<list<string> > entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
+ if (!hasContent(entry))
+ return mkfailure<value>(reason(entry));
+ debug(url, "http::put::url");
+ debug(content(entry), "http::put::input");
+
+ // PUT it to the URL
+ const list<string> h = mklist<string>("Content-Type: application/atom+xml");
+ const list<list<string> > req = mklist<list<string> >(h, content(entry));
+ const failable<list<list<string> > > res = apply<list<string> >(req, rcons<string>, list<string>(), url, "PUT", cs);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+
+ debug(true, "http::put::result");
+ return value(true);
+}
+
+/**
+ * HTTP DELETE.
+ */
+const failable<value, string> del(const string& url, const CURLSession& cs) {
+ debug(url, "http::delete::url");
+
+ const list<list<string> > req = mklist(list<string>(), list<string>());
+ const failable<list<list<string> > > res = apply<list<string> >(req, rcons<string>, list<string>(), url, "DELETE", cs);
+ if (!hasContent(res))
+ return mkfailure<value>(reason(res));
+
+ debug(true, "http::delete::result");
+ return value(true);
+}
+
+/**
+ * Returns the current host name.
+ */
+const string hostname() {
+ char h[256];
+ if (gethostname(h, 256) == -1)
+ return "localhost";
+ return h;
+}
+
+/**
+ * Create an APR pollfd for a socket.
+ */
+apr_pollfd_t* pollfd(apr_socket_t* s, const int e, const gc_pool& p) {
+ apr_pollfd_t* pfd = gc_new<apr_pollfd_t>(p);
+ pfd->p = pool(p);
+ pfd->desc_type = APR_POLL_SOCKET;
+ pfd->reqevents = (apr_int16_t)e;
+ pfd->rtnevents = (apr_int16_t)e;
+ pfd->desc.s = s;
+ pfd->client_data = NULL;
+ return pfd;
+}
+
+/**
+ * Connect to a URL.
+ */
+const failable<bool> connect(const string& url, CURLSession& cs) {
+ debug(url, "http::connect::url");
+
+ // Setup the CURL session
+ const failable<CURL*> fch = setup(url, cs);
+ if (!hasContent(fch))
+ return mkfailure<bool>(reason(fch));
+ CURL* ch = content(fch);
+
+ // Connect
+ curl_easy_setopt(ch, CURLOPT_CONNECT_ONLY, true);
+ const CURLcode rc = curl_easy_perform(ch);
+ if (rc)
+ return mkfailure<bool>(string(curl_easy_strerror(rc)));
+
+ // Convert the connected socket to an apr_socket_t
+ int sd;
+ const CURLcode grc = curl_easy_getinfo(ch, CURLINFO_LASTSOCKET, &sd);
+ if (grc)
+ return mkfailure<bool>(string(curl_easy_strerror(grc)));
+ cs.sock = sock(sd, cs.p);
+
+ // Create pollsets and pollfds which can be used to poll the socket
+ apr_status_t rpcrc = apr_pollset_create(&cs.rpollset, 1, pool(cs.p), 0);
+ if (rpcrc != APR_SUCCESS)
+ return mkfailure<bool>(apreason(rpcrc));
+ cs.rpollfd = pollfd(cs.sock, APR_POLLIN, cs.p);
+ apr_pollset_add(cs.rpollset, cs.rpollfd);
+ apr_status_t wpcrc = apr_pollset_create(&cs.wpollset, 1, pool(cs.p), 0);
+ if (wpcrc != APR_SUCCESS)
+ return mkfailure<bool>(apreason(wpcrc));
+ cs.wpollfd = pollfd(cs.sock, APR_POLLOUT, cs.p);
+ apr_pollset_add(cs.wpollset, cs.wpollfd);
+
+ return true;
+}
+
+/**
+ * Send an array of chars.
+ */
+const failable<bool> send(const char* c, const size_t l, const CURLSession& cs) {
+
+ // Send the data
+ size_t wl = 0;
+ const CURLcode rc = curl_easy_send(cs.h, c, (size_t)l, &wl);
+ if (rc == CURLE_OK && wl == (size_t)l)
+ return true;
+ if (rc != CURLE_AGAIN)
+ return mkfailure<bool>(curlreason(rc));
+
+ // If the socket was not ready, wait for it to become ready
+ const apr_pollfd_t* pollfds;
+ apr_int32_t pollcount;
+ apr_status_t pollrc = apr_pollset_poll(cs.wpollset, -1, &pollcount, &pollfds);
+ if (pollrc != APR_SUCCESS)
+ return mkfailure<bool>(apreason(pollrc));
+
+ // Send what's left
+ return send(c + wl, l - wl, cs);
+}
+
+/**
+ * Receive an array of chars.
+ */
+const failable<size_t> recv(char* c, const size_t l, const CURLSession& cs) {
+
+ // Receive data
+ size_t rl;
+ const CURLcode rc = curl_easy_recv(cs.h, c, (size_t)l, &rl);
+ if (rc == CURLE_OK)
+ return (size_t)rl;
+ if (rc == 1)
+ return 0;
+ if (rc != CURLE_AGAIN)
+ return mkfailure<size_t>(curlreason(rc));
+
+ // If the socket was not ready, wait for it to become ready
+ const apr_pollfd_t* pollfds;
+ apr_int32_t pollcount;
+ apr_status_t pollrc = apr_pollset_poll(cs.rpollset, -1, &pollcount, &pollfds);
+ if (pollrc != APR_SUCCESS)
+ return mkfailure<size_t>(apreason(pollrc));
+
+ // Receive again
+ return recv(c, l, cs);
+}
+
+/**
+ * HTTP client proxy function.
+ */
+struct proxy {
+ proxy(const string& uri, const string& ca, const string& cert, const string& key, const gc_pool& p) : p(p), uri(uri), ca(ca), cert(cert), key(key), cs(*(new (gc_new<CURLSession>(p)) CURLSession(ca, cert, key))) {
+ }
+
+ const value operator()(const list<value>& args) const {
+ const value fun = car(args);
+ if (fun == "get") {
+ const failable<value> val = get(uri + path(cadr(args)), cs);
+ return content(val);
+ }
+ if (fun == "post") {
+ const failable<value> val = post(caddr(args), uri + path(cadr(args)), cs);
+ return content(val);
+ }
+ if (fun == "put") {
+ const failable<value> val = put(caddr(args), uri + path(cadr(args)), cs);
+ return content(val);
+ }
+ if (fun == "delete") {
+ const failable<value> val = del(uri + path(cadr(args)), cs);
+ return content(val);
+ }
+ const failable<value> val = evalExpr(args, uri, cs);
+ return content(val);
+ }
+
+ const gc_pool p;
+ const string uri;
+ const string ca;
+ const string cert;
+ const string key;
+ const CURLSession& cs;
+};
+
+}
+}
+
+#endif /* tuscany_http_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-addr b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-addr
new file mode 100755
index 0000000000..62fc775ea7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-addr
@@ -0,0 +1,54 @@
+#!/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
+# 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.
+
+# Parse a string in the form ip-addr:local-port/public-port
+addr=`echo $2 | awk -F "/" '{ print $1 }'`
+ip=`echo $addr | awk -F ":" '{ print $1 }'`
+port=`echo $addr | awk -F ":" '{ print $2 }'`
+if [ "$port" = "" ]; then
+ port=$ip
+ ip=""
+ listen=$port
+ vhost="*:$port"
+else
+ listen="$ip:$port"
+ vhost="$ip:$port"
+fi
+pport=`echo $2 | awk -F "/" '{ print $2 }'`
+if [ "$pport" = "" ]; then
+ pport=$port
+fi
+
+# Return the requested part
+if [ "$1" = "ip" ]; then
+ echo $ip
+fi
+if [ "$1" = "port" ]; then
+ echo $port
+fi
+if [ "$1" = "pport" ]; then
+ echo $pport
+fi
+if [ "$1" = "listen" ]; then
+ echo $listen
+fi
+if [ "$1" = "vhost" ]; then
+ echo $vhost
+fi
+return 0
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-conf b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-conf
new file mode 100755
index 0000000000..37fa2e4051
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-conf
@@ -0,0 +1,255 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+jsprefix=`readlink -f $here/../js`
+
+host=$2
+port=`$here/httpd-addr port $3`
+pport=`$here/httpd-addr pport $3`
+listen=`$here/httpd-addr listen $3`
+vhost=`$here/httpd-addr vhost $3`
+
+mkdir -p $4
+htdocs=`readlink -f $4`
+
+user=`id -un`
+group=`id -gn`
+
+modules_prefix=`cat $here/httpd-modules.prefix`
+
+mkdir -p $root
+mkdir -p $root/logs
+mkdir -p $root/conf
+cat >$root/conf/httpd.conf <<EOF
+# Generated by: httpd-conf $*
+# Apache HTTPD server configuration
+
+# Main server name
+ServerName http://$host:$pport
+PidFile $root/logs/httpd.pid
+
+# Load configured MPM
+Include conf/mpm.conf
+
+# Load required modules
+Include conf/modules.conf
+
+# Basic security precautions
+User $user
+Group $group
+ServerSignature Off
+ServerTokens Prod
+Timeout 45
+LimitRequestBody 1048576
+HostNameLookups Off
+
+# Log HTTP requests
+# [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
+LogLevel info
+ErrorLog $root/logs/error_log
+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
+CustomLog $root/logs/access_log combined
+CookieTracking on
+CookieName TuscanyVisitorId
+
+# Configure Mime types
+TypesConfig $here/conf/mime.types
+
+# Set default document root
+DocumentRoot $htdocs
+DirectoryIndex index.html
+
+# Protect server files
+<Directory />
+Options None
+AllowOverride None
+Require all denied
+</Directory>
+
+# Configure authentication
+Include conf/auth.conf
+
+# Allow access to public locations
+<Location /login>
+AuthType None
+Require all granted
+</Location>
+<Location /logout>
+AuthType None
+Require all granted
+</Location>
+<Location /public>
+AuthType None
+Require all granted
+</Location>
+<Location /favicon.ico>
+AuthType None
+Require all granted
+</Location>
+
+# Listen on HTTP port
+Listen $listen
+
+# Setup HTTP virtual host
+<VirtualHost $vhost>
+ServerName http://$host:$pport
+
+RewriteEngine on
+RewriteCond %{HTTP_HOST} !^$host [NC]
+RewriteRule .* http://$host:$pport%{REQUEST_URI} [R,L]
+
+Include conf/svhost.conf
+
+# Allow access to document root
+<Directory "$htdocs">
+Options FollowSymLinks
+AuthType None
+Require all granted
+</Directory>
+
+# Allow access to root location
+<Location />
+Options FollowSymLinks
+AuthType None
+Require all granted
+</Location>
+
+</VirtualHost>
+
+EOF
+
+# Run with the prefork MPM
+cat >$root/conf/mpm.conf <<EOF
+# Generated by: httpd-conf $*
+LoadModule mpm_prefork_module ${modules_prefix}/modules/mod_mpm_prefork.so
+
+EOF
+
+# Generate modules list
+cat >$root/conf/modules.conf <<EOF
+# Generated by: httpd-conf $*
+# Load a minimal set of modules, the load order is important
+# (e.g. load mod_headers before mod_rewrite, so its hooks execute
+# after mod_rewrite's hooks)
+LoadModule alias_module ${modules_prefix}/modules/mod_alias.so
+LoadModule authn_file_module ${modules_prefix}/modules/mod_authn_file.so
+LoadModule authn_core_module ${modules_prefix}/modules/mod_authn_core.so
+LoadModule authz_host_module ${modules_prefix}/modules/mod_authz_host.so
+LoadModule authz_groupfile_module ${modules_prefix}/modules/mod_authz_groupfile.so
+LoadModule authz_user_module ${modules_prefix}/modules/mod_authz_user.so
+LoadModule authz_core_module ${modules_prefix}/modules/mod_authz_core.so
+LoadModule auth_basic_module ${modules_prefix}/modules/mod_auth_basic.so
+LoadModule auth_digest_module ${modules_prefix}/modules/mod_auth_digest.so
+LoadModule auth_form_module ${modules_prefix}/modules/mod_auth_form.so
+LoadModule request_module ${modules_prefix}/modules/mod_request.so
+LoadModule deflate_module ${modules_prefix}/modules/mod_deflate.so
+LoadModule filter_module ${modules_prefix}/modules/mod_filter.so
+LoadModule proxy_module ${modules_prefix}/modules/mod_proxy.so
+LoadModule proxy_connect_module ${modules_prefix}/modules/mod_proxy_connect.so
+LoadModule proxy_http_module ${modules_prefix}/modules/mod_proxy_http.so
+LoadModule proxy_balancer_module ${modules_prefix}/modules/mod_proxy_balancer.so
+LoadModule lbmethod_byrequests_module ${modules_prefix}/modules/mod_lbmethod_byrequests.so
+LoadModule headers_module ${modules_prefix}/modules/mod_headers.so
+LoadModule ssl_module ${modules_prefix}/modules/mod_ssl.so
+LoadModule socache_shmcb_module ${modules_prefix}/modules/mod_socache_shmcb.so
+LoadModule rewrite_module ${modules_prefix}/modules/mod_rewrite.so
+LoadModule mime_module ${modules_prefix}/modules/mod_mime.so
+LoadModule status_module ${modules_prefix}/modules/mod_status.so
+LoadModule asis_module ${modules_prefix}/modules/mod_asis.so
+LoadModule negotiation_module ${modules_prefix}/modules/mod_negotiation.so
+LoadModule dir_module ${modules_prefix}/modules/mod_dir.so
+LoadModule setenvif_module ${modules_prefix}/modules/mod_setenvif.so
+<IfModule !log_config_module>
+LoadModule log_config_module ${modules_prefix}/modules/mod_log_config.so
+</IfModule>
+LoadModule logio_module ${modules_prefix}/modules/mod_logio.so
+LoadModule usertrack_module ${modules_prefix}/modules/mod_usertrack.so
+LoadModule vhost_alias_module ${modules_prefix}/modules/mod_vhost_alias.so
+LoadModule cgi_module ${modules_prefix}/modules/mod_cgi.so
+LoadModule unixd_module ${modules_prefix}/modules/mod_unixd.so
+LoadModule session_module ${modules_prefix}/modules/mod_session.so
+#LoadModule session_crypto_module ${modules_prefix}/modules/mod_session_crypto.so
+LoadModule session_cookie_module ${modules_prefix}/modules/mod_session_cookie.so
+LoadModule slotmem_shm_module ${modules_prefix}/modules/mod_slotmem_shm.so
+LoadModule ratelimit_module ${modules_prefix}/modules/mod_ratelimit.so
+LoadModule reqtimeout_module ${modules_prefix}/modules/mod_reqtimeout.so
+
+LoadModule mod_tuscany_ssltunnel $here/libmod_tuscany_ssltunnel.so
+LoadModule mod_tuscany_openauth $here/libmod_tuscany_openauth.so
+
+EOF
+
+# Generate auth configuration
+cat >$root/conf/auth.conf <<EOF
+# Generated by: httpd-conf $*
+# Authentication configuration
+
+# Allow authorized access to document root
+<Directory "$htdocs">
+Options FollowSymLinks
+Require all granted
+</Directory>
+
+# Allow authorized access to root location
+<Location />
+Options FollowSymLinks
+AuthUserFile "$root/conf/httpd.passwd"
+Require all granted
+</Location>
+
+EOF
+
+# Create password and group files
+cat >$root/conf/httpd.passwd <<EOF
+# Generated by: httpd-conf $*
+EOF
+
+cat >$root/conf/httpd.groups <<EOF
+# Generated by: httpd-conf $*
+EOF
+
+# Generate vhost configuration
+cat >$root/conf/vhost.conf <<EOF
+# Generated by: httpd-conf $*
+# Virtual host configuration
+UseCanonicalName Off
+
+EOF
+
+cat >$root/conf/svhost.conf <<EOF
+# Generated by: httpd-conf $*
+# Static virtual host configuration
+Include conf/vhost.conf
+
+EOF
+
+cat >$root/conf/dvhost.conf <<EOF
+# Generated by: httpd-conf $*
+# Mass dynamic virtual host configuration
+Include conf/vhost.conf
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-event-conf b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-event-conf
new file mode 100755
index 0000000000..58923d9dd9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-event-conf
@@ -0,0 +1,35 @@
+#!/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
+# 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.
+
+# Configure HTTPD to run with the event MPM
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+modules_prefix=`cat $here/httpd-modules.prefix`
+
+mkdir -p $root
+mkdir -p $root/conf
+cat >$root/conf/mpm.conf <<EOF
+# Generated by: httpd-event-conf $*
+# Use HTTPD event MPM
+LoadModule mpm_event_module ${modules_prefix}/modules/mod_mpm_event.so
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-restart b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-restart
new file mode 100755
index 0000000000..3e3b687f98
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-restart
@@ -0,0 +1,25 @@
+#!/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
+# 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.
+
+# Restart httpd server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+apachectl=`cat $here/httpd-apachectl.prefix`
+$apachectl -k graceful -d $root -f $root/conf/httpd.conf
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-ssl-conf b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-ssl-conf
new file mode 100755
index 0000000000..5882a18cb4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-ssl-conf
@@ -0,0 +1,163 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD SSL configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+gport=`echo $conf | awk '{ print $7 }'`
+port=`$here/httpd-addr port $gport`
+pport=`$here/httpd-addr pport $gport`
+
+sslpport=`$here/httpd-addr pport $2`
+sslport=`$here/httpd-addr listen $2`
+sslvhost=`$here/httpd-addr vhost $2`
+
+htdocs=`echo $conf | awk '{ print $8 }'`
+mkdir -p $htdocs
+htdocs=`readlink -f $htdocs`
+
+# Extract organization name from our CA certificate
+org=`openssl x509 -noout -subject -nameopt multiline -in $root/cert/ca.crt | grep organizationName | awk -F "= " '{ print $2 }'`
+
+# Generate HTTPD configuration
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+
+# Configure SSL support
+AddType application/x-x509-ca-cert .crt
+AddType application/x-pkcs7-crl .crl
+SSLPassPhraseDialog builtin
+SSLSessionCache "shmcb:$root/logs/ssl_scache(512000)"
+SSLSessionCacheTimeout 300
+Mutex "file:$root/logs" ssl-cache
+SSLRandomSeed startup builtin
+SSLRandomSeed connect builtin
+
+# Listen on HTTPS port
+Listen $sslport
+
+# HTTPS virtual host
+<VirtualHost $sslvhost>
+ServerName https://$host:$sslpport
+
+Include conf/svhost-ssl.conf
+
+# Allow the server admin to view the server status
+<Location /server-status>
+SetHandler server-status
+HostnameLookups on
+Require user admin
+</Location>
+
+</VirtualHost>
+
+EOF
+
+# Generate HTTP vhost configuration
+cat >>$root/conf/svhost.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+# Redirect HTTP traffic to HTTPS
+<Location />
+RewriteEngine on
+RewriteCond %{SERVER_PORT} ^$port$ [OR]
+RewriteCond %{SERVER_PORT} ^$pport$
+RewriteRule .* https://$host:$sslpport%{REQUEST_URI} [R,L]
+</Location>
+
+EOF
+
+cat >>$root/conf/dvhost.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+# Redirect HTTP traffic to HTTPS
+<Location />
+RewriteEngine on
+RewriteCond %{SERVER_PORT} ^$port$ [OR]
+RewriteCond %{SERVER_PORT} ^$pport$
+RewriteRule .* https://%{SERVER_NAME}:$sslpport%{REQUEST_URI} [R,L]
+</Location>
+
+EOF
+
+# Generate HTTPS vhost configuration
+cat >$root/conf/vhost-ssl.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+# Virtual host configuration
+UseCanonicalName Off
+
+# Enable SSL
+SSLEngine on
+SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
+BrowserMatch ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
+SSLOptions +StrictRequire +OptRenegotiate +FakeBasicAuth
+
+# Require clients to use SSL and authenticate
+<Location />
+SSLRequireSSL
+SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128
+</Location>
+
+# Log SSL requests
+# [timestamp] [sslaccess] remote-host remote-ident remote-user SSL-protocol
+# 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
+CustomLog $root/logs/ssl_access_log sslcombined
+
+EOF
+
+proxycert="server"
+if [ "$proxyconf" != "" ]; then
+ proxycert="proxy"
+fi
+
+cat >$root/conf/svhost-ssl.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+# Static virtual host configuration
+Include conf/vhost-ssl.conf
+
+# Declare SSL certificates used in this virtual host
+SSLCACertificateFile "$root/cert/ca.crt"
+SSLCertificateChainFile "$root/cert/ca.crt"
+SSLCertificateFile "$root/cert/server.crt"
+SSLCertificateKeyFile "$root/cert/server.key"
+
+EOF
+
+cat >$root/conf/dvhost-ssl.conf <<EOF
+# Mass dynamic virtual host configuration
+# Generated by: httpd-ssl-conf $*
+Include conf/vhost-ssl.conf
+
+# Declare wildcard SSL certificates used in this virtual host
+SSLCACertificateFile "$root/cert/ca.crt"
+SSLCertificateChainFile "$root/cert/ca.crt"
+SSLCertificateFile "$root/cert/vhost.crt"
+SSLCertificateKeyFile "$root/cert/vhost.key"
+
+# Declare proxy SSL client certificates
+SSLProxyCACertificateFile "$root/cert/ca.crt"
+SSLProxyMachineCertificateFile "$root/cert/$proxycert.pem"
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-start b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-start
new file mode 100755
index 0000000000..5c006d1b54
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-start
@@ -0,0 +1,25 @@
+#!/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
+# 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.
+
+# Start httpd server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+apachectl=`cat $here/httpd-apachectl.prefix`
+$apachectl -E $root/logs/error_log -k start -d $root -f $root/conf/httpd.conf
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-stop b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-stop
new file mode 100755
index 0000000000..09ac5d035f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-stop
@@ -0,0 +1,25 @@
+#!/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
+# 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.
+
+# Stop httpd server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+apachectl=`cat $here/httpd-apachectl.prefix`
+$apachectl -k graceful-stop -d $root -f $root/conf/httpd.conf
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-test b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-test
new file mode 100755
index 0000000000..a3b9145871
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-test
@@ -0,0 +1,40 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+
+# Setup
+./httpd-conf tmp localhost 8090 htdocs
+./httpd-start tmp
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Cleanup
+./httpd-stop tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd-worker-conf b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-worker-conf
new file mode 100755
index 0000000000..bb6bca4562
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd-worker-conf
@@ -0,0 +1,35 @@
+#!/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
+# 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.
+
+# Configure HTTPD to run with the worker MPM
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+modules_prefix=`cat $here/httpd-modules.prefix`
+
+mkdir -p $root
+mkdir -p $root/conf
+cat >$root/conf/mpm.conf <<EOF
+# Generated by: httpd-worker-conf $*
+# Use HTTPD worker MPM
+LoadModule mpm_worker_module ${modules_prefix}/modules/mod_mpm_worker.so
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/httpd.hpp b/sandbox/sebastien/cpp/apr-2/modules/http/httpd.hpp
new file mode 100644
index 0000000000..78d292dc89
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/httpd.hpp
@@ -0,0 +1,689 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_httpd_hpp
+#define tuscany_httpd_hpp
+
+/**
+ * HTTPD module implementation functions.
+ */
+
+#include <apr_strings.h>
+#include <apr_fnmatch.h>
+#include <apr_lib.h>
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+#include <apr_base64.h>
+
+#include <httpd.h>
+// Hack to workaround compile error with HTTPD 2.3.8
+#define new new_
+#include <http_config.h>
+#undef new
+#include <http_core.h>
+#include <http_connection.h>
+#include <http_request.h>
+#include <http_protocol.h>
+// Hack to workaround compile error with HTTPD 2.3.8
+#define aplog_module_index aplog_module_index = 0
+#include <http_log.h>
+#undef aplog_module_index
+#undef APLOG_MODULE_INDEX
+#define APLOG_MODULE_INDEX (aplog_module_index ? *aplog_module_index : APLOG_NO_MODULE)
+#include <http_main.h>
+#include <util_script.h>
+#include <util_md5.h>
+#include <http_config.h>
+#include <http_log.h>
+#include <ap_mpm.h>
+#include <mod_core.h>
+#include <ap_provider.h>
+#include <mod_auth.h>
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "sstream.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+
+namespace tuscany {
+namespace httpd {
+
+/**
+ * Returns a server-scoped module configuration.
+ */
+template<typename C> void* makeServerConf(apr_pool_t* p, server_rec* s) {
+ return new (gc_new<C>(p)) C(p, s);
+}
+
+template<typename C> const C& serverConf(const request_rec* r, const module* mod) {
+ return *(C*)ap_get_module_config(r->server->module_config, mod);
+}
+
+template<typename C> C& serverConf(const server_rec* s, const module* mod) {
+ return *(C*)ap_get_module_config(s->module_config, mod);
+}
+
+template<typename C> C& serverConf(const cmd_parms* cmd, const module* mod) {
+ return *(C*)ap_get_module_config(cmd->server->module_config, mod);
+}
+
+/**
+ * Returns a directory-scoped module configuration.
+ */
+template<typename C> void* makeDirConf(apr_pool_t *p, char* d) {
+ return new (gc_new<C>(p)) C(p, d);
+}
+
+template<typename C> const C& dirConf(const request_rec* r, const module* mod) {
+ return *(C*)ap_get_module_config(r->per_dir_config, mod);
+}
+
+template<typename C> C& dirConf(const void* c) {
+ return *(C*)c;
+}
+
+/**
+ * Return the name of a server.
+ */
+const string serverName(const server_rec* s, const string& def = "localhost") {
+ ostringstream n;
+ n << (s->server_scheme != NULL? s->server_scheme : "http") << "://"
+ << (s->server_hostname != NULL? s->server_hostname : def) << ":"
+ << (s->port != 0? s->port : 80)
+ << (s->path != NULL? string(s->path, s->pathlen) : "");
+ return str(n);
+}
+
+/**
+ * Determine the name of a server from an HTTP request.
+ */
+const string serverName(request_rec* r, const string& def = "localhost") {
+ ostringstream n;
+ const char* hn = ap_get_server_name(r);
+ n << (r->server->server_scheme != NULL? r->server->server_scheme : "http") << "://"
+ << (hn != NULL? hn : (r->server->server_hostname != NULL? r->server->server_hostname : def)) << ":"
+ << (r->server->port != 0? r->server->port : 80)
+ << (r->server->path != NULL? string(r->server->path, r->server->pathlen) : "");
+ return str(n);
+}
+
+/**
+ * Return the host name for a server.
+ */
+const string hostName(const server_rec* s, const string& def = "localhost") {
+ return s->server_hostname != NULL? s->server_hostname : def;
+}
+
+/**
+ * Return the host name from an HTTP request.
+ */
+const string hostName(request_rec* r, const string& def = "localhost") {
+ const char* hn = ap_get_server_name(r);
+ return hn != NULL? hn : (r->server->server_hostname != NULL? r->server->server_hostname : def);
+}
+
+/**
+ * Return the first subdomain name in a host name.
+ */
+const string subdomain(const string& host) {
+ return substr(host, 0, find(host, '.'));
+}
+
+/**
+ * Return true if a request is targeting a virtual host.
+ */
+const bool isVirtualHostRequest(const server_rec* s, request_rec* r) {
+ return hostName(r) != hostName(s);
+}
+
+/**
+ * Return true if a URI is absolute.
+ */
+const bool isAbsolute(const string& uri) {
+ return contains(uri, "://");
+}
+
+/**
+ * Return the protocol scheme for a server.
+ */
+const string scheme(const server_rec* s, const string& def = "http") {
+ return s->server_scheme != NULL? s->server_scheme : def;
+}
+
+/**
+ * Return the protocol scheme from an HTTP request.
+ */
+const string scheme(request_rec* r, const string& def = "http") {
+ return r->server->server_scheme != NULL? r->server->server_scheme : def;
+}
+
+/**
+ * Return the content type of a request.
+ */
+const string contentType(const request_rec* r) {
+ const char* ct = apr_table_get(r->headers_in, "Content-Type");
+ if (ct == NULL)
+ return "";
+ return ct;
+}
+
+/**
+ * Return the remaining part of a uri after the given path (aka the path info.)
+ */
+const list<value> pathInfo(const list<value>& uri, const list<value>& path) {
+ if (isNil(path))
+ return uri;
+ return pathInfo(cdr(uri), cdr(path));
+}
+
+/**
+ * Convert a URI and a path to an absolute URL.
+ */
+const string url(const string& uri, const list<value>& p, request_rec* r) {
+ const string u = uri + path(p);
+ return ap_construct_url(r->pool, c_str(u), r);
+}
+
+/**
+ * Convert a URI to an absolute URL.
+ */
+const string url(const string& uri, request_rec* r) {
+ return ap_construct_url(r->pool, c_str(uri), r);
+}
+
+/**
+ * Escape a URI.
+ */
+const char escape_c2x[] = "0123456789ABCDEF";
+const string escape(const string& uri) {
+ debug(uri, "httpd::escape::uri");
+ char* copy = (char*)apr_palloc(gc_current_pool(), 3 * length(uri) + 3);
+ const unsigned char* s = (const unsigned char *)c_str(uri);
+ unsigned char* d = (unsigned char*)copy;
+ unsigned c;
+ while ((c = *s)) {
+ if (apr_isalnum(c) || c == '_')
+ *d++ = (unsigned char)c;
+ else if (c == ' ')
+ *d++ = '+';
+ else {
+ *d++ = '%';
+ *d++ = escape_c2x[c >> 4];
+ *d++ = escape_c2x[c & 0xf];
+ }
+ ++s;
+ }
+ *d = '\0';
+ debug(copy, "httpd::escape::result");
+ return copy;
+}
+
+/**
+ * Unescape a URI.
+ */
+const string unescape(const string& uri) {
+ debug(uri, "httpd::unescape::uri");
+ char* b = const_cast<char*>(c_str(string(c_str(uri))));
+ ap_unescape_url(b);
+ debug(b, "httpd::unescape::result");
+ return b;
+}
+
+/**
+ * Returns a list of key value pairs from the args in a query string.
+ */
+const list<value> queryArg(const string& s) {
+ debug(s, "httpd::queryArg::string");
+ const list<string> t = tokenize("=", s);
+ if (isNil(cdr(t)))
+ return mklist<value>(c_str(car(t)), "");
+ return mklist<value>(c_str(car(t)), cadr(t));
+}
+
+const string fixupQueryArgs(const string& a) {
+ const list<string> t = tokenize("?", a);
+ if (isNil(t) || isNil(cdr(t)))
+ return a;
+ return join("&", t);
+}
+
+const list<list<value> > queryArgs(const string& a) {
+ return map<string, list<value>>(queryArg, tokenize("&", fixupQueryArgs(a)));
+}
+
+/**
+ * Returns a list of key value pairs from the args in an HTTP request.
+ */
+const list<list<value> > queryArgs(const request_rec* r) {
+ if (r->args == NULL)
+ return list<list<value> >();
+ return queryArgs(r->args);
+}
+
+/**
+ * Converts a list of key value pairs to a query string.
+ */
+ostringstream& queryString(const list<list<value> > args, ostringstream& os) {
+ if (isNil(args))
+ return os;
+ debug(car(args), "httpd::queryString::arg");
+ os << car(car(args)) << "=" << c_str(cadr(car(args)));
+ if (!isNil(cdr(args)))
+ os << "&";
+ return queryString(cdr(args), os);
+}
+
+const string queryString(const list<list<value> > args) {
+ ostringstream os;
+ return str(queryString(args, os));
+}
+
+/**
+ * Converts the args received in a POST to a list of key value pairs.
+ */
+const list<list<value> > postArgs(const list<value>& a) {
+ if (isNil(a))
+ return list<list<value> >();
+ const list<value> l = car(a);
+ return cons(l, postArgs(cdr(a)));
+}
+
+/**
+ * Setup the HTTP read policy.
+ */
+const int setupReadPolicy(request_rec* r) {
+ const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
+ if(rc != OK)
+ return rc;
+ ap_should_client_block(r);
+ if(r->read_chunked == true && r->remaining == 0)
+ r->chunked = true;
+ //apr_table_setn(r->headers_out, "Connection", "close");
+ return OK;
+}
+
+/**
+ * Read the content of a POST or PUT.
+ */
+const list<string> read(request_rec* r) {
+ char b[1024];
+ const size_t n = ap_get_client_block(r, b, sizeof(b));
+ if (n <= 0)
+ return list<string>();
+ return cons(string(b, n), read(r));
+}
+
+/**
+ * Write an HTTP result.
+ */
+const failable<int> writeResult(const failable<list<string> >& ls, const string& ct, request_rec* r) {
+ if (!hasContent(ls))
+ return mkfailure<int>(reason(ls));
+ ostringstream os;
+ write(content(ls), os);
+ const string ob(str(os));
+ debug(ob, "httpd::writeResult");
+
+ // Make sure browsers come back and check for updated dynamic content
+ apr_table_setn(r->headers_out, "Expires", "Tue, 01 Jan 1980 00:00:00 GMT");
+
+ // Compute and return an Etag for the returned content
+ const string etag(ap_md5(r->pool, (const unsigned char*)c_str(ob)));
+
+ // Check for an If-None-Match header and just return a 304 not-modified status
+ // if the Etag matches the Etag presented by the client, to save bandwith
+ const char* match = apr_table_get(r->headers_in, "If-None-Match");
+ apr_table_setn(r->headers_out, "ETag", apr_pstrdup(r->pool, c_str(etag)));
+ if (match != NULL && etag == match) {
+
+ r->status = HTTP_NOT_MODIFIED;
+ return OK;
+ }
+ ap_set_content_type(r, apr_pstrdup(r->pool, c_str(ct)));
+ ap_rputs(c_str(ob), r);
+ return OK;
+}
+
+/**
+ * Report a request execution status.
+ */
+const int reportStatus(const failable<int>& rc) {
+ debug(rc, "httpd::reportStatus::rc");
+ if (!hasContent(rc))
+ return HTTP_INTERNAL_SERVER_ERROR;
+ return content(rc);
+}
+
+/**
+ * Construct a redirect URI.
+ */
+const string redirectURI(const string& file, const string& pi) {
+ return file + pi;
+}
+
+const string redirectURI(const string& file, const string& pi, const string& args) {
+ return file + pi + "?" + args;
+}
+
+/**
+ * Convert a value to an HTTPD request struc
+ */
+request_rec* request(const value& v) {
+ return (request_rec*)(long)(double)v;
+}
+
+/**
+ * Convert an HTTPD request struct to a value
+ */
+const value requestValue(request_rec* r) {
+ return value((double)(long)r);
+}
+
+/**
+ * Update request filters in an HTTPD redirect request.
+ * Similar to httpd/modules/http/http_request.c::update_r_in_filters.
+ */
+const bool redirectFilters(ap_filter_t* f, request_rec* from, request_rec* to) {
+ if (f == NULL)
+ return true;
+ if (f->r == from)
+ f->r = to;
+ return redirectFilters(f->next, from, to);
+}
+
+/**
+ * Create an HTTPD internal redirect request.
+ * Similar to httpd/modules/http/http_request.c::internal_internal_redirect.
+ */
+extern "C" {
+ AP_DECLARE(ap_conf_vector_t*) ap_create_request_config(apr_pool_t *p);
+}
+
+const failable<request_rec*, int> internalRedirectRequest(const string& nr_uri, request_rec* r) {
+ if (ap_is_recursion_limit_exceeded(r))
+ return mkfailure<request_rec*, int>(HTTP_INTERNAL_SERVER_ERROR);
+
+ // Create a new request
+ request_rec* nr = (request_rec*)apr_pcalloc(r->pool, sizeof(request_rec));
+ nr->connection = r->connection;
+ nr->server = r->server;
+ nr->pool = r->pool;
+ nr->method = r->method;
+ nr->method_number = r->method_number;
+ nr->allowed_methods = ap_make_method_list(nr->pool, 2);
+ ap_parse_uri(nr, apr_pstrdup(nr->pool, c_str(nr_uri)));
+ nr->filename = apr_pstrdup(nr->pool, c_str(string("/redirected:") + nr_uri));
+ nr->request_config = ap_create_request_config(r->pool);
+ nr->per_dir_config = r->server->lookup_defaults;
+ nr->prev = r;
+ r->next = nr;
+
+ // Run create request hook
+ ap_run_create_request(nr);
+
+ // Inherit protocol info from the original request
+ nr->the_request = r->the_request;
+ nr->allowed = r->allowed;
+ nr->status = r->status;
+ nr->assbackwards = r->assbackwards;
+ nr->header_only = r->header_only;
+ nr->protocol = r->protocol;
+ nr->proto_num = r->proto_num;
+ nr->hostname = r->hostname;
+ nr->request_time = r->request_time;
+ nr->main = r->main;
+ nr->headers_in = r->headers_in;
+ nr->headers_out = apr_table_make(r->pool, 12);
+ nr->err_headers_out = r->err_headers_out;
+ nr->subprocess_env = r->subprocess_env;
+ nr->notes = apr_table_make(r->pool, 5);
+ nr->allowed_methods = ap_make_method_list(nr->pool, 2);
+ nr->htaccess = r->htaccess;
+ nr->no_cache = r->no_cache;
+ nr->expecting_100 = r->expecting_100;
+ nr->no_local_copy = r->no_local_copy;
+ nr->read_length = r->read_length;
+ nr->vlist_validator = r->vlist_validator;
+ nr->user = r->user;
+
+ // Setup input and output filters
+ nr->proto_output_filters = r->proto_output_filters;
+ nr->proto_input_filters = r->proto_input_filters;
+ nr->output_filters = nr->proto_output_filters;
+ nr->input_filters = nr->proto_input_filters;
+ if (nr->main)
+ ap_add_output_filter_handle(ap_subreq_core_filter_handle, NULL, nr, nr->connection);
+ redirectFilters(nr->input_filters, r, nr);
+ redirectFilters(nr->output_filters, r, nr);
+ const int rrc = ap_run_post_read_request(nr);
+ if (rrc != OK && rrc != DECLINED)
+ return mkfailure<request_rec*, int>(rrc);
+
+ return nr;
+}
+
+/**
+ * Process an HTTPD internal redirect request.
+ * Similar to httpd/modules/http/http_request.c::ap_internal_redirect.
+ */
+extern "C" {
+ AP_DECLARE(int) ap_invoke_handler(request_rec *r);
+}
+
+const int internalRedirect(request_rec* nr) {
+ int status = ap_run_quick_handler(nr, 0);
+ if (status == DECLINED) {
+ status = ap_process_request_internal(nr);
+ if (status == OK)
+ status = ap_invoke_handler(nr);
+ }
+ if (status != OK) {
+ nr->status = status;
+ return OK;
+ }
+ ap_finalize_request_protocol(nr);
+ return OK;
+}
+
+/**
+ * Create and process an HTTPD internal redirect request.
+ */
+const int internalRedirect(const string& uri, request_rec* r) {
+ debug(uri, "httpd::internalRedirect");
+ const failable<request_rec*, int> nr = httpd::internalRedirectRequest(uri, r);
+ if (!hasContent(nr))
+ return reason(nr);
+ return httpd::internalRedirect(content(nr));
+}
+
+/**
+ * Create an HTTPD sub request.
+ * Similar to httpd/server/request.c::make_sub_request
+ */
+const failable<request_rec*, int> internalSubRequest(const string& nr_uri, request_rec* r) {
+ if (ap_is_recursion_limit_exceeded(r))
+ return mkfailure<request_rec*, int>(HTTP_INTERNAL_SERVER_ERROR);
+
+ // Create a new sub pool
+ apr_pool_t *nrp;
+ apr_pool_create(&nrp, r->pool);
+ apr_pool_tag(nrp, "subrequest");
+
+ // Create a new POST request
+ request_rec* nr = (request_rec*)apr_pcalloc(nrp, sizeof(request_rec));
+ nr->connection = r->connection;
+ nr->server = r->server;
+ nr->pool = nrp;
+ nr->method = "POST";
+ nr->method_number = M_POST;
+ nr->allowed_methods = ap_make_method_list(nr->pool, 2);
+ ap_parse_uri(nr, apr_pstrdup(nr->pool, c_str(nr_uri)));
+ nr->filename = apr_pstrdup(nr->pool, c_str(string("/subreq:") + nr_uri));
+ nr->request_config = ap_create_request_config(r->pool);
+ nr->per_dir_config = r->server->lookup_defaults;
+
+ // Inherit some of the protocol info from the parent request
+ nr->the_request = r->the_request;
+ nr->hostname = r->hostname;
+ nr->request_time = r->request_time;
+ nr->allowed = r->allowed;
+ nr->status = HTTP_OK;
+ nr->assbackwards = r->assbackwards;
+ nr->header_only = r->header_only;
+ nr->protocol = const_cast<char*>("INCLUDED");
+ nr->hostname = r->hostname;
+ nr->request_time = r->request_time;
+ nr->main = r;
+ nr->headers_in = apr_table_make(r->pool, 12);
+ nr->headers_out = apr_table_make(r->pool, 12);
+ nr->err_headers_out = apr_table_make(nr->pool, 5);
+ nr->subprocess_env = r->subprocess_env;
+ nr->subprocess_env = apr_table_copy(nr->pool, r->subprocess_env);
+ nr->notes = apr_table_make(r->pool, 5);
+ nr->htaccess = r->htaccess;
+ nr->no_cache = r->no_cache;
+ nr->expecting_100 = r->expecting_100;
+ nr->no_local_copy = r->no_local_copy;
+ nr->read_length = 0;
+ nr->vlist_validator = r->vlist_validator;
+ nr->user = r->user;
+
+ // Setup input and output filters
+ nr->proto_output_filters = r->proto_output_filters;
+ nr->proto_input_filters = r->proto_input_filters;
+ nr->output_filters = nr->proto_output_filters;
+ nr->input_filters = nr->proto_input_filters;
+ ap_add_output_filter_handle(ap_subreq_core_filter_handle, NULL, nr, nr->connection);
+
+ // Run create request hook
+ ap_run_create_request(nr);
+ nr->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
+
+ return nr;
+}
+
+/**
+ * Return an HTTP external redirect request.
+ */
+const int externalRedirect(const string& uri, request_rec* r) {
+ debug(uri, "httpd::externalRedirect");
+ r->status = HTTP_MOVED_TEMPORARILY;
+ apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, c_str(uri)));
+ r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/") + uri));
+ return HTTP_MOVED_TEMPORARILY;
+}
+
+/**
+ * Put a value in the process user data.
+ */
+const bool putUserData(const string& k, const void* v, const server_rec* s) {
+ apr_pool_userdata_set((const void *)v, c_str(k), apr_pool_cleanup_null, s->process->pool);
+ return true;
+}
+
+/**
+ * Return a user data value.
+ */
+const void* userData(const string& k, const server_rec* s) {
+ void* v = NULL;
+ apr_pool_userdata_get(&v, c_str(k), s->process->pool);
+ return v;
+}
+
+#ifdef WANT_MAINTAINER_MODE
+
+/**
+ * Debug log.
+ */
+
+/**
+ * Log an optional value.
+ */
+const char* debugOptional(const char* s) {
+ if (s == NULL)
+ return "";
+ return s;
+}
+
+/**
+ * Log a header
+ */
+int debugHeader(unused void* r, const char* key, const char* value) {
+ cdebug << " header key: " << key << ", value: " << value << endl;
+ return 1;
+}
+
+/**
+ * Log an environment variable
+ */
+int debugEnv(unused void* r, const char* key, const char* value) {
+ cdebug << " var key: " << key << ", value: " << value << endl;
+ return 1;
+}
+
+/**
+ * Log a note.
+ */
+int debugNote(unused void* r, const char* key, const char* value) {
+ cdebug << " note key: " << key << ", value: " << value << endl;
+ return 1;
+}
+
+/**
+ * Log a request.
+ */
+const bool debugRequest(request_rec* r, const string& msg) {
+ cdebug << msg << ":" << endl;
+ cdebug << " unparsed uri: " << debugOptional(r->unparsed_uri) << endl;
+ cdebug << " uri: " << debugOptional(r->uri) << endl;
+ cdebug << " path info: " << debugOptional(r->path_info) << endl;
+ cdebug << " filename: " << debugOptional(r->filename) << endl;
+ cdebug << " uri tokens: " << pathTokens(r->uri) << endl;
+ cdebug << " args: " << debugOptional(r->args) << endl;
+ cdebug << " server: " << debugOptional(r->server->server_hostname) << endl;
+ cdebug << " protocol: " << debugOptional(r->protocol) << endl;
+ cdebug << " method: " << debugOptional(r->method) << endl;
+ cdebug << " method number: " << r->method_number << endl;
+ cdebug << " content type: " << contentType(r) << endl;
+ cdebug << " content encoding: " << debugOptional(r->content_encoding) << endl;
+ apr_table_do(debugHeader, r, r->headers_in, NULL);
+ cdebug << " user: " << debugOptional(r->user) << endl;
+ cdebug << " auth type: " << debugOptional(r->ap_auth_type) << endl;
+ apr_table_do(debugEnv, r, r->subprocess_env, NULL);
+ apr_table_do(debugNote, r, r->notes, NULL);
+ return true;
+}
+
+#define httpdDebugRequest(r, msg) httpd::debugRequest(r, msg)
+
+#else
+
+#define httpdDebugRequest(r, msg)
+
+#endif
+
+}
+}
+
+#endif /* tuscany_httpd_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/mod-openauth.cpp b/sandbox/sebastien/cpp/apr-2/modules/http/mod-openauth.cpp
new file mode 100644
index 0000000000..b43624f08d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/mod-openauth.cpp
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module for Tuscany Open authentication.
+ *
+ * This module allows multiple authentication mechanisms to co-exist in a
+ * single Web site:
+ * - OAuth1 using Tuscany's mod-tuscany-oauth1
+ * - OAuth2 using Tuscany's mod-tuscany-oauth2
+ * - OpenID using mod_auth_openid
+ * - Form-based using HTTPD's mod_auth_form
+ * - SSL certificate using SSLFakeBasicAuth and mod_auth_basic
+ */
+
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "httpd.hpp"
+#include "http.hpp"
+#include "openauth.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_openauth;
+}
+
+namespace tuscany {
+namespace openauth {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+};
+
+/**
+ * Directory configuration.
+ */
+class DirConf {
+public:
+ DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") {
+ }
+
+ const gc_pool p;
+ const char* dir;
+ bool enabled;
+ string login;
+};
+
+/**
+ * Return the user info from a form auth session cookie.
+ */
+const failable<value> userInfo(const value& sid, const string& realm) {
+ const list<list<value>> info = httpd::queryArgs(sid);
+ debug(info, "modopenauth::userInfo::info");
+ const list<value> user = assoc<value>(realm + "-user", info);
+ if (isNil(user))
+ return mkfailure<value>("Couldn't retrieve user id");
+ const list<value> pw = assoc<value>(realm + "-pw", info);
+ if (isNil(pw))
+ return mkfailure<value>("Couldn't retrieve password");
+ return value(mklist<value>(mklist<value>("realm", realm), mklist<value>("id", cadr(user)), mklist<value>("password", cadr(pw))));
+}
+
+/**
+ * Return the user info from a basic auth header.
+ */
+const failable<value> userInfo(const char* header, const string& realm, request_rec* r) {
+ debug(header, "modopenauth::userInfo::header");
+ if (strcasecmp(ap_getword(r->pool, &header, ' '), "Basic"))
+ return mkfailure<value>("Wrong authentication scheme");
+
+ while (apr_isspace(*header))
+ header++;
+ char *decoded_line = (char*)apr_palloc(r->pool, apr_base64_decode_len(header) + 1);
+ int length = apr_base64_decode(decoded_line, header);
+ decoded_line[length] = '\0';
+
+ const string user(ap_getword_nulls(r->pool, const_cast<const char**>(&decoded_line), ':'));
+ const string pw(decoded_line);
+
+ return value(mklist<value>(mklist<value>("realm", realm), mklist<value>("id", user), mklist<value>("password", pw)));
+}
+
+/**
+ * Handle an authenticated request.
+ */
+const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+ debug(info, "modopenauth::authenticated::info");
+
+ // Store user info in the request
+ const list<value> realm = assoc<value>("realm", info);
+ if (isNil(realm) || isNil(cdr(realm)))
+ return mkfailure<int>("Couldn't retrieve realm");
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
+
+ const list<value> id = assoc<value>("id", info);
+ if (isNil(id) || isNil(cdr(id)))
+ return mkfailure<int>("Couldn't retrieve user id");
+ r->user = apr_pstrdup(r->pool, c_str(cadr(id)));
+
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(id))));
+ return OK;
+}
+
+/**
+ * Run the authnz hooks to try to authenticate a request.
+ */
+const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r) {
+ const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION);
+ if (!provider || !provider->check_password)
+ return mkfailure<int>("No Authn provider configured");
+ apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER);
+ const authn_status auth_result = provider->check_password(r, c_str(user), c_str(pw));
+ apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
+ if (auth_result != AUTH_GRANTED)
+ return mkfailure<int>("Authentication failure for: " + user);
+ return OK;
+}
+
+/**
+ * Check user authentication.
+ */
+static int checkAuthn(request_rec *r) {
+ // Decline if we're not enabled or AuthType is not set to Open
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth);
+ if (!dc.enabled)
+ return DECLINED;
+ const char* atype = ap_auth_type(r);
+ if (atype == NULL || strcasecmp(atype, "Open"))
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modopenauth::checkAuthn::input");
+
+ // Get session id from the request
+ const maybe<string> sid = sessionID(r);
+ if (hasContent(sid)) {
+ // Decline if the session id was not created by this module
+ const string stype = substr(content(sid), 0, 7);
+ if (stype == "OAuth2_" || stype == "OAuth1_" || stype == "OpenID_")
+ return DECLINED;
+
+ // Retrieve the auth realm
+ const char* aname = ap_auth_name(r);
+ if (aname == NULL)
+ return httpd::reportStatus(mkfailure<int>("Missing AuthName"));
+
+ // Extract user info from the session id
+ const failable<value> info = userInfo(content(sid), aname);
+ if (hasContent(info)) {
+
+ // Try to authenticate the request
+ const value cinfo = content(info);
+ const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", cinfo)), cadr(assoc<value>("password", cinfo)), r);
+ if (!hasContent(authz)) {
+
+ // Authentication failed, redirect to login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(login(dc.login, r));
+ }
+
+ // Successfully authenticated, store the user info in the request
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authenticated(cinfo, r));
+ }
+ }
+
+ // Get basic auth header from the request
+ const char* header = apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authorization" : "Authorization");
+ if (header != NULL) {
+
+ // Retrieve the auth realm
+ const char* aname = ap_auth_name(r);
+ if (aname == NULL)
+ return httpd::reportStatus(mkfailure<int>("Missing AuthName"));
+
+ // Extract user info from the session id
+ const failable<value> info = userInfo(header, aname, r);
+ if (hasContent(info)) {
+
+ // Try to authenticate the request
+ const value cinfo = content(info);
+ const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", cinfo)), cadr(assoc<value>("password", cinfo)), r);
+ if (!hasContent(authz)) {
+
+ // Authentication failed, redirect to login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(login(dc.login, r));
+ }
+
+ // Successfully authenticated, store the user info in the request
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authenticated(cinfo, r));
+ }
+ }
+
+ // Get the request args
+ const list<list<value> > args = httpd::queryArgs(r);
+
+ // Decline if the request is for another authentication provider
+ if (!isNil(assoc<value>("openid_identifier", args)))
+ return DECLINED;
+ if (!isNil(assoc<value>("mod_oauth1_step", args)))
+ return DECLINED;
+ if (!isNil(assoc<value>("mod_oauth2_step", args)))
+ return DECLINED;
+
+ // Redirect to the login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(login(dc.login, r));
+}
+
+/**
+ * Process the module configuration.
+ */
+int postConfigMerge(ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ debug(httpd::serverName(s), "modopenauth::postConfigMerge::serverName");
+
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_openauth);
+ debug(httpd::serverName(s), "modopenauth::postConfig::serverName");
+
+ // Merge server configurations
+ return postConfigMerge(sc, s);
+}
+
+/**
+ * Child process initialization.
+ */
+void childInit(apr_pool_t* p, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_openauth);
+ if(psc == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_openauth loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+ ServerConf& sc = *psc;
+
+ // Merge the updated configuration into the virtual hosts
+ postConfigMerge(sc, s->next);
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confEnabled(cmd_parms *cmd, void *c, const int arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.enabled = (bool)arg;
+ return NULL;
+}
+const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.login = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_FLAG("AuthOpenAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "Tuscany Open Auth authentication On | Off"),
+ AP_INIT_TAKE1("AuthOpenAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "Tuscany Open Auth login page"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+void registerHooks(unused apr_pool_t *p) {
+ ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_check_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
+}
+
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_openauth = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::openauth::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::openauth::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::openauth::commands, tuscany::openauth::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/mod-ssltunnel.cpp b/sandbox/sebastien/cpp/apr-2/modules/http/mod-ssltunnel.cpp
new file mode 100644
index 0000000000..d2c53b462e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/mod-ssltunnel.cpp
@@ -0,0 +1,361 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module used to tunnel traffic over an HTTPS connection.
+ */
+
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "httpd.hpp"
+#include "http.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_ssltunnel;
+}
+
+namespace tuscany {
+namespace httpd {
+namespace modssltunnel {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ string pass;
+ string host;
+ string path;
+ string ca;
+ string cert;
+ string key;
+};
+
+extern "C" {
+extern module AP_DECLARE_DATA core_module;
+}
+
+/**
+ * Process the module configuration.
+ */
+int M_SSLTUNNEL;
+int postConfigMerge(ServerConf& mainsc, apr_pool_t* p, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_ssltunnel);
+ debug(httpd::serverName(s), "modwiring::postConfigMerge::serverName");
+
+ // Merge configuration from main server
+ if (length(sc.ca) == 0 && length(mainsc.ca) !=0)
+ sc.ca = mainsc.ca;
+ if (length(sc.cert) == 0 && length(mainsc.cert) !=0)
+ sc.cert = mainsc.cert;
+ if (length(sc.key) == 0 && length(mainsc.key) !=0)
+ sc.key = mainsc.key;
+
+ // Parse the configured TunnelPass URI
+ if (length(sc.pass) != 0) {
+ apr_uri_t uri;
+ apr_status_t prc = apr_uri_parse(p, c_str(sc.pass), &uri);
+ if (prc != APR_SUCCESS) {
+ mkfailure<int>("Couldn't parse TunnelPass: " + sc.pass + ", " + http::apreason(prc));
+ return prc;
+ }
+ sc.host = uri.hostname;
+ sc.path = uri.path;
+ }
+ return postConfigMerge(mainsc, p, s->next);
+}
+
+int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_ssltunnel);
+ debug(httpd::serverName(s), "modwiring::postConfig::serverName");
+
+ // Register the SSLTUNNEL method
+ M_SSLTUNNEL = ap_method_register(p, "SSLTUNNEL");
+
+ // Merge and process server configurations
+ return postConfigMerge(sc, p, s);
+}
+
+/**
+ * Close a connection.
+ */
+const int close(conn_rec* conn, apr_socket_t* csock) {
+ debug("modssltunnel::close");
+ apr_socket_close(csock);
+ conn->aborted = 1;
+ return OK;
+}
+
+/**
+ * Abort a connection.
+ */
+const int abort(conn_rec* conn, apr_socket_t* csock, const string& reason) {
+ debug("modssltunnel::abort");
+ apr_socket_close(csock);
+ conn->aborted = 1;
+ return httpd::reportStatus(mkfailure<int>(reason));
+}
+
+/**
+ * Tunnel traffic from a client connection to a target URL.
+ */
+int tunnel(conn_rec* conn, const string& ca, const string& cert, const string& key, const string& url, const string& preamble, const gc_pool& p, unused ap_filter_t* ifilter, ap_filter_t* ofilter) {
+
+ // Create input/output bucket brigades
+ apr_bucket_brigade* ib = apr_brigade_create(pool(p), conn->bucket_alloc);
+ apr_bucket_brigade* ob = apr_brigade_create(pool(p), conn->bucket_alloc);
+
+ // Get client connection socket
+ apr_socket_t* csock = (apr_socket_t*)ap_get_module_config(conn->conn_config, &core_module);
+
+ // Open connection to target
+ http::CURLSession cs(ca, cert, key);
+ const failable<bool> crc = http::connect(url, cs);
+ if (!hasContent(crc))
+ return abort(conn, csock, reason(crc));
+ apr_socket_t* tsock = http::sock(cs);
+
+ // Send preamble
+ if (length(preamble) != 0) {
+ debug(preamble, "modssltunnel::tunnel::sendPreambleToTarget");
+ const failable<bool> src = http::send(c_str(preamble), length(preamble), cs);
+ if (!hasContent(src))
+ return abort(conn, csock, string("Couldn't send to target: ") + reason(src));
+ }
+
+ // Create a pollset for the client and target sockets
+ apr_pollset_t* pollset;
+ apr_status_t cprc = apr_pollset_create(&pollset, 2, pool(p), 0);
+ if (cprc != APR_SUCCESS)
+ return abort(conn, csock, http::apreason(cprc));
+ const apr_pollfd_t* cpollfd = http::pollfd(csock, APR_POLLIN, p);
+ apr_pollset_add(pollset, cpollfd);
+ const apr_pollfd_t* tpollfd = http::pollfd(tsock, APR_POLLIN, p);
+ apr_pollset_add(pollset, tpollfd);
+
+ // Relay traffic in both directions until end of stream
+ const apr_pollfd_t* pollfds = cpollfd;
+ apr_int32_t pollcount = 1;
+ for(;;) {
+ for (; pollcount > 0; pollcount--, pollfds++) {
+ if (pollfds->rtnevents & APR_POLLIN) {
+ if (pollfds->desc.s == csock) {
+
+ // Receive buckets from client
+ const apr_status_t getrc = ap_get_brigade(conn->input_filters, ib, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
+ if (getrc != APR_SUCCESS)
+ return abort(conn, csock, string("Couldn't receive from client"));
+
+ for (apr_bucket* bucket = APR_BRIGADE_FIRST(ib); bucket != APR_BRIGADE_SENTINEL(ib); bucket = APR_BUCKET_NEXT(bucket)) {
+ if (APR_BUCKET_IS_FLUSH(bucket))
+ continue;
+
+ // Client connection closed
+ if (APR_BUCKET_IS_EOS(bucket))
+ return close(conn, csock);
+
+ const char *data;
+ apr_size_t rl;
+ apr_bucket_read(bucket, &data, &rl, APR_BLOCK_READ);
+ if (rl > 0) {
+ debug(string(data, rl), "modssltunnel::tunnel::sendToTarget");
+
+ // Send to target
+ const failable<bool> src = http::send(data, rl, cs);
+ if (!hasContent(src))
+ return abort(conn, csock, string("Couldn't send to target: ") + reason(src));
+ }
+ }
+ apr_brigade_cleanup(ib);
+ } else {
+
+ // Receive from target
+ char data[8192];
+ const failable<size_t> frl = http::recv(data, sizeof(data), cs);
+ if (!hasContent(frl))
+ return abort(conn, csock, string("Couldn't receive from target") + reason(frl));
+ const size_t rl = content(frl);
+
+ // Target connection closed
+ if (rl == 0)
+ return close(conn, csock);
+
+ // Send bucket to client
+ debug(string(data, rl), "modssltunnel::tunnel::sendToClient");
+ APR_BRIGADE_INSERT_TAIL(ob, apr_bucket_transient_create(data, rl, conn->bucket_alloc));
+ APR_BRIGADE_INSERT_TAIL(ob, apr_bucket_flush_create(conn->bucket_alloc));
+ if (ap_pass_brigade(ofilter, ob) != APR_SUCCESS)
+ return abort(conn, csock, "Couldn't send data bucket to client");
+ apr_brigade_cleanup(ob);
+ }
+ }
+
+ // Error
+ if (pollfds->rtnevents & (APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
+ if (pollfds->desc.s == csock)
+ return abort(conn, csock, "Couldn't receive from client");
+ else
+ return abort(conn, csock, "Couldn't receive from target");
+ }
+ }
+
+ // Poll the client and target sockets
+ debug("modssltunnel::tunnel::poll");
+ apr_status_t pollrc = apr_pollset_poll(pollset, -1, &pollcount, &pollfds);
+ if (pollrc != APR_SUCCESS)
+ return abort(conn, csock, "Couldn't poll sockets");
+ debug(pollcount, "modssltunnel::tunnel::pollfds");
+ }
+
+ // Close client connection
+ return close(conn, csock);
+}
+
+/**
+ * Return the first connection filter in a list of filters.
+ */
+ap_filter_t* connectionFilter(ap_filter_t* f) {
+ if (f == NULL)
+ return f;
+ if (f->frec->ftype < AP_FTYPE_CONNECTION)
+ return connectionFilter(f->next);
+ return f;
+}
+
+/**
+ * Process a client connection and relay it to a tunnel.
+ */
+int processConnection(conn_rec *conn) {
+ // Only allow configured virtual hosts
+ if (!conn->base_server->is_virtual)
+ return DECLINED;
+ if (ap_get_module_config(conn->base_server->module_config, &mod_tuscany_ssltunnel) == NULL)
+ return DECLINED;
+
+ gc_scoped_pool(conn->pool);
+ const ServerConf& sc = httpd::serverConf<ServerConf>(conn->base_server, &mod_tuscany_ssltunnel);
+ if (length(sc.pass) == 0)
+ return DECLINED;
+ debug(sc.pass, "modssltunnel::processConnection::pass");
+
+ // Run the tunnel
+ const string preamble = string("SSLTUNNEL ") + sc.path + string(" HTTP/1.1\r\nHost: ") + sc.host + string("\r\n\r\n");
+ debug(preamble, "modssltunnel::processConnection::preamble");
+ return tunnel(conn, sc.ca, sc.cert, sc.key, sc.pass, preamble, gc_pool(conn->pool), connectionFilter(conn->input_filters), connectionFilter(conn->output_filters));
+}
+
+/**
+ * Tunnel a SSLTUNNEL request to a target host/port.
+ */
+int handler(request_rec* r) {
+ if (r->method_number != M_SSLTUNNEL)
+ return DECLINED;
+
+ // Only allow HTTPS
+ if (strcmp(r->server->server_scheme, "https"))
+ return DECLINED;
+
+ // Build the target URL
+ debug(r->uri, "modssltunnel::handler::uri");
+ const list<value> path(pathValues(r->uri));
+ const string url = string(cadr(path)) + ":" + caddr(path);
+ debug(url, "modssltunnel::handler::target");
+
+ // Run the tunnel
+ return tunnel(r->connection, "", "", "", url, "", gc_pool(r->pool), connectionFilter(r->proto_input_filters), connectionFilter(r->proto_output_filters));
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confTunnelPass(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel);
+ sc.pass = arg;
+ return NULL;
+}
+const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel);
+ sc.ca = arg;
+ return NULL;
+}
+const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel);
+ sc.cert = arg;
+ return NULL;
+}
+const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_ssltunnel);
+ sc.key = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_TAKE1("TunnelPass", (const char*(*)())confTunnelPass, NULL, RSRC_CONF, "Tunnel server name"),
+ AP_INIT_TAKE1("TunnelSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "Tunnel SSL CA certificate file"),
+ AP_INIT_TAKE1("TunnelSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "Tunnel SSL certificate file"),
+ AP_INIT_TAKE1("TunnelSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "Tunnel SSL certificate key file"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+void registerHooks(unused apr_pool_t *p) {
+ ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_process_connection(processConnection, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+}
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_ssltunnel = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ NULL, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::httpd::modssltunnel::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::httpd::modssltunnel::commands, tuscany::httpd::modssltunnel::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/open-auth-conf b/sandbox/sebastien/cpp/apr-2/modules/http/open-auth-conf
new file mode 100755
index 0000000000..2bd5bc3504
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/open-auth-conf
@@ -0,0 +1,55 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD form authentication configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Generate form authentication configuration
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: open-auth-conf $*
+# Enable Tuscany open authentication
+<Location />
+AuthType Open
+AuthName "$host"
+AuthOpenAuth On
+AuthOpenAuthLoginPage /login
+Require valid-user
+</Location>
+
+# Use HTTPD form-based authentication
+<Location /login/dologin>
+AuthType Form
+AuthName "$host"
+AuthFormProvider file
+AuthFormLoginRequiredLocation /login
+AuthFormLogoutLocation /
+Session On
+SessionCookieName TuscanyOpenAuth path=/;secure=TRUE
+#SessionCryptoPassphrase secret
+Require valid-user
+SetHandler form-login-handler
+</Location>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/openauth.hpp b/sandbox/sebastien/cpp/apr-2/modules/http/openauth.hpp
new file mode 100644
index 0000000000..ff69a9732f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/openauth.hpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_openauth_hpp
+#define tuscany_openauth_hpp
+
+/**
+ * Tuscany Open auth support utility functions.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../json/json.hpp"
+#include "../http/httpd.hpp"
+#include "../http/http.hpp"
+
+namespace tuscany {
+namespace openauth {
+
+/**
+ * Return the session id from a request.
+ */
+const char* cookieName(const char* cs) {
+ if (*cs != ' ')
+ return cs;
+ return cookieName(cs + 1);
+}
+const maybe<string> sessionID(const list<string> c) {
+ if (isNil(c))
+ return maybe<string>();
+ const string cn = cookieName(c_str(car(c)));
+ const size_t i = find(cn, "=");
+ if (i < length(cn)) {
+ const list<string> kv = mklist<string>(substr(cn, 0, i), substr(cn, i+1));
+ if (!isNil(kv) && !isNil(cdr(kv))) {
+ if (car(kv) == "TuscanyOpenAuth")
+ return cadr(kv);
+ }
+ }
+ return sessionID(cdr(c));
+}
+
+const maybe<string> sessionID(const request_rec* r) {
+ const char* c = apr_table_get(r->headers_in, "Cookie");
+ debug(c, "openauth::sessionid::cookies");
+ if (c == NULL)
+ return maybe<string>();
+ return sessionID(tokenize(";", c));
+}
+
+/**
+ * Convert a session id to a cookie string.
+ */
+const string cookie(const string& sid) {
+ const time_t t = time(NULL) + 86400;
+ char exp[32];
+ strftime(exp, 32, "%a, %d-%b-%Y %H:%M:%S GMT", gmtime(&t));
+ const string c = string("TuscanyOpenAuth=") + sid + string(";path=/;expires=" + string(exp)) + ";secure=TRUE";
+ debug(c, "openauth::cookie");
+ return c;
+}
+
+/**
+ * Redirect to the configured login page.
+ */
+const failable<int> login(const string& page, request_rec* r) {
+ const list<list<value> > largs = mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(r->uri, r))));
+ const string loc = httpd::url(page, r) + string("?") + httpd::queryString(largs);
+ debug(loc, "openauth::login::uri");
+ return httpd::externalRedirect(loc, r);
+}
+
+}
+}
+
+#endif /* tuscany_openauth_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/passwd-auth-conf b/sandbox/sebastien/cpp/apr-2/modules/http/passwd-auth-conf
new file mode 100755
index 0000000000..89a3f19e4b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/passwd-auth-conf
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+user=$2
+pass=$3
+
+httpd_prefix=`cat $here/httpd.prefix`
+
+# Create password file
+touch $root/conf/httpd.passwd
+$httpd_prefix/bin/htpasswd -b $root/conf/httpd.passwd $user $pass 2>/dev/null
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/proxy-conf b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-conf
new file mode 100755
index 0000000000..e9abe8435f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-conf
@@ -0,0 +1,41 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD proxy balancer configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+cat >>$root/conf/vhost.conf <<EOF
+# Generated by: proxy-conf $*
+# Enable HTTP reverse proxy
+ProxyRequests Off
+ProxyPreserveHost On
+ProxyStatus On
+
+# Enable load balancing
+ProxyPass / balancer://cluster/
+
+<Proxy balancer://cluster>
+Require all granted
+ProxySet lbmethod=byrequests
+</Proxy>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/proxy-member-conf b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-member-conf
new file mode 100755
index 0000000000..ef9cb35e8a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-member-conf
@@ -0,0 +1,35 @@
+#!/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
+# 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.
+
+# Add a proxy balancer member
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+host=$2
+port=`$here/httpd-addr port $3`
+
+cat >>$root/conf/vhost.conf <<EOF
+# Generated by: proxy-member-conf $*
+# Add proxy balancer member
+BalancerMember balancer://cluster http://$host:$port
+ProxyPassReverse / http://$host:$port/
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-conf b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-conf
new file mode 100755
index 0000000000..f5e2bfc4a4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-conf
@@ -0,0 +1,72 @@
+#!/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
+# 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.
+
+# Generate a minimal HTTPD proxy balancer configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+cat >>$root/conf/vhost-ssl.conf <<EOF
+# Generated by: proxy-ssl-conf $*
+# Enable HTTPS reverse proxy
+ProxyRequests Off
+ProxyPreserveHost On
+ProxyStatus On
+SSLProxyEngine on
+SSLProxyCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
+
+# Verify server certificates
+SSLProxyVerify require
+SSLProxyVerifyDepth 1
+
+# Enable load balancing
+ProxyPass /balancer-manager !
+ProxyPass / balancer://sslcluster/
+
+<Proxy balancer://sslcluster>
+Require all granted
+ProxySet lbmethod=byrequests
+</Proxy>
+
+# Enable balancer manager
+<Location /balancer-manager>
+SetHandler balancer-manager
+HostnameLookups on
+Require user admin
+</Location>
+
+EOF
+
+cat >>$root/conf/svhost-ssl.conf <<EOF
+# Generated by: proxy-ssl-conf $*
+# Declare proxy SSL client certificates
+SSLProxyCACertificateFile "$root/cert/ca.crt"
+SSLProxyMachineCertificateFile "$root/cert/proxy.pem"
+
+EOF
+
+cat >>$root/conf/dvhost-ssl.conf <<EOF
+# Generated by: proxy-ssl-conf $*
+
+# Declare proxy SSL client certificates
+SSLProxyCACertificateFile "$root/cert/ca.crt"
+SSLProxyMachineCertificateFile "$root/cert/proxy.pem"
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-member-conf b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-member-conf
new file mode 100755
index 0000000000..b6bf055ad8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-ssl-member-conf
@@ -0,0 +1,43 @@
+#!/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
+# 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.
+
+# Add a proxy balancer member
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+host=$2
+sslport=`$here/httpd-addr port $3`
+
+cat >>$root/conf/svhost-ssl.conf <<EOF
+# Generated by: proxy-ssl-member-conf $*
+# Add proxy balancer member
+BalancerMember balancer://sslcluster https://$host:$sslport
+ProxyPassReverse / https://$host:$sslport/
+
+EOF
+
+cat >>$root/conf/dvhost-ssl.conf <<EOF
+# Generated by: proxy-ssl-member-conf $*
+# Add proxy balancer member
+BalancerMember balancer://sslcluster https://$host:$sslport
+ProxyPassReverse / https://$host:$sslport/
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/proxy-test b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-test
new file mode 100755
index 0000000000..b6c9a6a0d9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/proxy-test
@@ -0,0 +1,37 @@
+#!/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
+# 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.
+
+# Setup
+./httpd-conf tmp localhost 8091/8090 htdocs
+./httpd-start tmp
+./httpd-conf tmp/proxy localhost 8090 tmp/proxy/htdocs
+./proxy-conf tmp/proxy
+./proxy-member-conf tmp/proxy localhost 8091
+./httpd-start tmp/proxy
+sleep 2
+
+# Test
+./curl-test
+rc=$?
+
+# Cleanup
+./httpd-stop tmp/proxy
+./httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/ssl-ca-conf b/sandbox/sebastien/cpp/apr-2/modules/http/ssl-ca-conf
new file mode 100755
index 0000000000..e7b9f96ee2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/ssl-ca-conf
@@ -0,0 +1,96 @@
+#!/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
+# 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.
+
+# Generate a test certification authority certificate
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+host=$2
+
+# Don't override existing certificate
+if [ -f $root/cert/ca.crt ]; then
+ return 0
+fi
+
+# Generate openssl configuration
+mkdir -p $root/cert
+umask 0007
+cat >$root/cert/openssl-ca.conf <<EOF
+[ req ]
+default_bits = 1024
+encrypt_key = no
+prompt = no
+distinguished_name = req_distinguished_name
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+C = US
+ST = CA
+L = San Francisco
+O = $host
+OU = authority
+CN = $host
+emailAddress = admin@$host
+
+[ v3_ca ]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+basicConstraints = CA:true
+
+[ca]
+default_ca = ca_default
+
+[ca_default]
+certificate = $root/cert/ca.crt
+private_key = $root/cert/ca.key
+serial = $root/cert/ca-serial
+database = $root/cert/ca-database
+new_certs_dir = $root/cert
+default_md = sha1
+email_in_dn = no
+default_days = 365
+default_crl_days = 30
+policy = policy_any
+copy_extensions = none
+
+[ policy_any ]
+countryName = supplied
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+EOF
+
+rm -rf $root/cert/*.crt $root/cert/*.pem $root/cert/hash
+rm -f $root/cert/ca-database
+echo 1000 > $root/cert/ca-serial
+touch $root/cert/ca-database
+
+# Generate the certification authority certificate
+openssl req -new -x509 -config $root/cert/openssl-ca.conf -out $root/cert/ca.crt -keyout $root/cert/ca.key
+
+# Add to the hash directory and rehash
+mkdir -p $root/cert/hash
+cp $root/cert/ca.crt $root/cert/hash
+c_rehash $root/cert/hash
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-conf b/sandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-conf
new file mode 100755
index 0000000000..57c4522535
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-conf
@@ -0,0 +1,76 @@
+#!/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
+# 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.
+
+# Generate a test certificate
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+host=$2
+if [ "$3" != "" ]; then
+ certname=$3
+else
+ certname="server"
+fi
+
+# Don't regenerate the certificate if it already exists
+if [ -f $root/cert/$certname.crt ]; then
+ return 0
+fi
+
+# Generate openssl configuration
+mkdir -p $root/cert
+umask 0007
+cat >$root/cert/openssl-cert-$certname.conf <<EOF
+[ req ]
+default_bits = 1024
+encrypt_key = no
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+C = US
+ST = CA
+L = San Francisco
+O = $host
+OU = $certname
+CN = $host
+emailAddress = admin@$host
+EOF
+
+# Generate a certificate request
+openssl req -new -config $root/cert/openssl-cert-$certname.conf -out $root/cert/$certname-req.crt -keyout $root/cert/$certname.key
+
+# Generate a certificate, signed with our test certification authority certificate
+openssl ca -batch -config $root/cert/openssl-ca.conf -out $root/cert/$certname.crt -infiles $root/cert/$certname-req.crt
+
+# Export it to PKCS12 format, that's the format Web browsers want to import
+openssl pkcs12 -export -passout pass: -out $root/cert/$certname.p12 -inkey $root/cert/$certname.key -in $root/cert/$certname.crt -certfile $root/cert/ca.crt
+
+# Convert the certificate to PEM format and concatenate the key to it, for use
+# by mod_proxy
+openssl x509 -in $root/cert/$certname.crt -out $root/cert/$certname.pem
+cat $root/cert/$certname.key >> $root/cert/$certname.pem
+
+# Add to the hash directory and rehash
+mkdir -p $root/cert/hash
+cp $root/cert/$certname.crt $root/cert/hash
+cp $root/cert/$certname.pem $root/cert/hash
+c_rehash $root/cert/hash
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-find b/sandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-find
new file mode 100755
index 0000000000..b5aefb8e38
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/ssl-cert-find
@@ -0,0 +1,26 @@
+#!/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
+# 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.
+
+# List certificate files, useful to distribute them to another host
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+cd $root
+find -regex '.*\.\(\(crt\)\|\(pem\)\|\(p12\)\|\(key\)\|\(0\)\)' 2>/dev/null
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/tunnel-ssl-conf b/sandbox/sebastien/cpp/apr-2/modules/http/tunnel-ssl-conf
new file mode 100755
index 0000000000..8cf4ada20a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/tunnel-ssl-conf
@@ -0,0 +1,55 @@
+#!/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
+# 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.
+
+# Generate an SSL tunnel configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+port=`$here/httpd-addr port $2`
+sslhost=$3
+sslport=$4
+tport=$5
+
+# Generate HTTPD configuration
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: tunnel-ssl-conf $*
+# Tunnel TCP/IP traffic over HTTPS
+
+# Listen on local port
+Listen 127.0.0.1:$port
+
+# Tunnel virtual host
+<VirtualHost 127.0.0.1:$port>
+ServerName http://localhost:$port
+
+TunnelPass https://$sslhost:$sslport/tunnel/localhost/$tport
+
+# Declare SSL certificates used in this virtual host
+#TunnelSSLCACertificateFile "$root/cert/ca.crt"
+TunnelSSLCertificateFile "$root/cert/tunnel.crt"
+TunnelSSLCertificateKeyFile "$root/cert/tunnel.key"
+
+</VirtualHost>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/vhost-conf b/sandbox/sebastien/cpp/apr-2/modules/http/vhost-conf
new file mode 100755
index 0000000000..f45d448906
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/vhost-conf
@@ -0,0 +1,65 @@
+#!/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
+# 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.
+
+# Generate mass dynamic virtual hosting configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+addr=`echo $conf | awk '{ print $7 }'`
+port=`$here/httpd-addr port $addr`
+pport=`$here/httpd-addr pport $addr`
+vhost=`$here/httpd-addr vhost $addr`
+
+htdocs=`echo $conf | awk '{ print $8 }'`
+mkdir -p $htdocs
+htdocs=`readlink -f $htdocs`
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: vhost-conf $*
+# Enable mass dynamic virtual hosting
+NameVirtualHost $vhost
+
+<VirtualHost $vhost>
+ServerName http://vhost.$host:$pport
+ServerAlias *.$host
+VirtualDocumentRoot $htdocs/domains/%1/
+
+Include conf/dvhost.conf
+
+# Allow access to document root
+<Directory "$htdocs">
+Options FollowSymLinks
+AuthType None
+Require all granted
+</Directory>
+
+# Allow access to root location
+<Location />
+Options FollowSymLinks
+AuthType None
+Require all granted
+</Location>
+
+</VirtualHost>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/http/vhost-ssl-conf b/sandbox/sebastien/cpp/apr-2/modules/http/vhost-ssl-conf
new file mode 100755
index 0000000000..36b2a15412
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/http/vhost-ssl-conf
@@ -0,0 +1,53 @@
+#!/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
+# 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.
+
+# Generate mass dynamic virtual hosting configuration
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"`
+ssladdr=`echo $sslconf | awk '{ print $6 }'`
+sslport=`$here/httpd-addr port $ssladdr`
+sslpport=`$here/httpd-addr pport $ssladdr`
+sslvhost=`$here/httpd-addr vhost $ssladdr`
+
+htdocs=`echo $conf | awk '{ print $8 }'`
+mkdir -p $htdocs
+htdocs=`readlink -f $htdocs`
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: vhost-ssl-conf $*
+# Enable mass dynamic virtual hosting over HTTPS
+SSLStrictSNIVHostCheck Off
+
+# HTTPS dynamic virtual host
+NameVirtualHost $sslvhost
+<VirtualHost $sslvhost>
+ServerName https://vhost.$host:$sslpport
+ServerAlias *.$host
+VirtualDocumentRoot $htdocs/domains/%1/
+
+Include conf/dvhost-ssl.conf
+
+</VirtualHost>
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/java/Makefile.am
new file mode 100644
index 0000000000..39b7ad550a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/Makefile.am
@@ -0,0 +1,69 @@
+# 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.
+
+JAVAROOT = $(top_builddir)/modules/java
+
+if WANT_JAVA
+
+INCLUDES = -I${JAVA_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/java
+
+dist_mod_SCRIPTS = java-conf
+moddir = $(prefix)/modules/java
+
+prefix_DATA = java.prefix
+prefixdir = $(prefix)/modules/java
+java.prefix: $(top_builddir)/config.status
+ echo ${JAVA_PREFIX} >java.prefix
+
+EXTRA_DIST = domain-test.composite
+
+mod_LTLIBRARIES = libmod_tuscany_java.la
+libmod_tuscany_java_la_SOURCES = mod-java.cpp
+libmod_tuscany_java_la_LDFLAGS = -lxml2 -lcurl -lmozjs ${JAVA_LDFLAGS}
+noinst_DATA = libmod_tuscany_java.so
+libmod_tuscany_java.so:
+ ln -s .libs/libmod_tuscany_java.so
+
+jni_test_SOURCES = jni-test.cpp
+jni_test_LDFLAGS = ${JAVA_LDFLAGS}
+
+java_test_SOURCES = java-test.cpp
+java_test_LDFLAGS = ${JAVA_LDFLAGS}
+
+java_shell_SOURCES = java-shell.cpp
+java_shell_LDFLAGS = ${JAVA_LDFLAGS}
+
+dist_mod_JAVA = org/apache/tuscany/*.java test/*.java
+jardir = ${prefix}/modules/java
+jarfile = libmod-tuscany-java-${PACKAGE_VERSION}.jar
+jar_DATA = ${jarfile}
+${jarfile}: ${dist_mod_JAVA}
+ ${JAR} cf $@ org/apache/tuscany/*.class
+
+CLEANFILES = *.stamp ${jarfile} org/apache/tuscany/*.class test/*.class
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = server-test wiring-test
+noinst_PROGRAMS = jni-test java-test java-shell client-test
+TESTS = jni-test java-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/client-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/java/client-test.cpp
new file mode 100644
index 0000000000..d06c57721e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/client-test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "../server/client-test.hpp"
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ tuscany::server::testURI = "http://localhost:8090/java";
+
+ tuscany::server::testServer();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/domain-test.composite b/sandbox/sebastien/cpp/apr-2/modules/java/domain-test.composite
new file mode 100644
index 0000000000..190f2ff5bb
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/domain-test.composite
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://domain/test"
+ name="domain-test">
+
+ <component name="java-test">
+ <implementation.java class="test.ServerImpl"/>
+ <service name="test">
+ <t:binding.http uri="java"/>
+ </service>
+ </component>
+
+ <component name="client-test">
+ <implementation.java class="test.ClientImpl"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="ref" target="java-test">
+ <t:binding.http/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/driver.hpp b/sandbox/sebastien/cpp/apr-2/modules/java/driver.hpp
new file mode 100644
index 0000000000..ddfc057940
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/driver.hpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_java_driver_hpp
+#define tuscany_java_driver_hpp
+
+/**
+ * Java evaluator main driver loop.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "monad.hpp"
+#include "../scheme/driver.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace java {
+
+const value evalDriverLoop(const JavaRuntime& jr, const JavaClass jc, istream& in, ostream& out) {
+ scheme::promptForInput(scheme::evalInputPrompt, out);
+ value input = scheme::readValue(in);
+ if (isNil(input))
+ return input;
+ const failable<value> output = evalClass(jr, input, jc);
+ scheme::announceOutput(scheme::evalOutputPrompt, out);
+ scheme::userPrint(content(output), out);
+ return evalDriverLoop(jr, jc, in, out);
+}
+
+const bool evalDriverRun(const char* name, istream& in, ostream& out) {
+ scheme::setupDisplay(out);
+ JavaRuntime javaRuntime;
+ const failable<JavaClass> jc = readClass(javaRuntime, ".", name);
+ if (!hasContent(jc))
+ return true;
+ evalDriverLoop(javaRuntime, content(jc), in, out);
+ return true;
+}
+
+}
+}
+#endif /* tuscany_java_driver_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/eval.hpp b/sandbox/sebastien/cpp/apr-2/modules/java/eval.hpp
new file mode 100644
index 0000000000..11e57cb08a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/eval.hpp
@@ -0,0 +1,562 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_java_eval_hpp
+#define tuscany_java_eval_hpp
+
+/**
+ * Java component implementation evaluation logic.
+ */
+#include <jni.h>
+
+#include "list.hpp"
+#include "value.hpp"
+
+namespace tuscany {
+namespace java {
+
+/**
+ * Handle differences between various JNI APIs.
+ */
+#ifdef JAVA_HARMONY_VM
+#define JNI_VERSION JNI_VERSION_1_4
+#else
+#define JNI_VERSION JNI_VERSION_1_6
+#endif
+
+/**
+ * Represent a Java VM runtime.
+ */
+jobject JNICALL nativeInvoke(JNIEnv *env, jobject self, jobject proxy, jobject method, jobjectArray args);
+jobject JNICALL nativeUUID(JNIEnv *env);
+
+class JavaRuntime {
+public:
+ JavaRuntime() {
+
+ // Get existing JVM
+ jsize nvms = 0;
+ JNI_GetCreatedJavaVMs(&jvm, 1, &nvms);
+ if (nvms == 0) {
+
+ // Create a new JVM
+ JavaVMInitArgs args;
+ args.version = JNI_VERSION;
+ args.ignoreUnrecognized = JNI_FALSE;
+ JavaVMOption options[3];
+ args.options = options;
+ args.nOptions = 0;
+
+ // Configure classpath
+ const char* envcp = getenv("CLASSPATH");
+ const string cp = string("-Djava.class.path=") + (envcp == NULL? "." : envcp);
+ options[args.nOptions].optionString = const_cast<char*>(c_str(cp));
+ options[args.nOptions++].extraInfo = NULL;
+
+#ifdef WANT_MAINTAINER_MODE
+ // Enable assertions
+ options[args.nOptions++].optionString = const_cast<char*>("-ea");
+#endif
+
+ // Configure Java debugging
+ const char* jpdaopts = getenv("JPDA_OPTS");
+ if (jpdaopts != NULL) {
+ options[args.nOptions].optionString = const_cast<char*>(jpdaopts);
+ options[args.nOptions++].extraInfo = NULL;
+ } else {
+ const char* jpdaaddr = getenv("JPDA_ADDRESS");
+ if (jpdaaddr != NULL) {
+ const string jpda = string("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=") + jpdaaddr;
+ options[args.nOptions].optionString = const_cast<char*>(c_str(jpda));
+ options[args.nOptions++].extraInfo = NULL;
+ }
+ }
+
+ // Create the JVM
+#ifdef JAVA_HARMONY_VM
+ JNI_CreateJavaVM(&jvm, &env, &args);
+#else
+ JNI_CreateJavaVM(&jvm, (void**)&env, &args);
+#endif
+
+ } else {
+
+ // Just point to existing JVM
+ jvm->GetEnv((void**)&env, JNI_VERSION);
+ }
+
+ // Lookup System classes and methods
+ classClass = env->FindClass("java/lang/Class");
+ methodClass = env->FindClass("java/lang/reflect/Method");
+ objectClass = env->FindClass("java/lang/Object");
+ doubleClass = env->FindClass("java/lang/Double");
+ booleanClass = env->FindClass("java/lang/Boolean");
+ stringClass = env->FindClass("java/lang/String");
+ objectArrayClass = env->FindClass("[Ljava/lang/Object;");
+ iterableClass = env->FindClass("java/lang/Iterable");
+ classForName = env->GetStaticMethodID(classClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+ doubleValueOf = env->GetStaticMethodID(doubleClass, "valueOf", "(D)Ljava/lang/Double;");
+ doubleValue = env->GetMethodID(doubleClass, "doubleValue", "()D");
+ booleanValueOf = env->GetStaticMethodID(booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
+ booleanValue = env->GetMethodID(booleanClass, "booleanValue", "()Z");
+ declaredMethods = env->GetMethodID(classClass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
+ methodName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;");
+ parameterTypes = env->GetMethodID(methodClass, "getParameterTypes", "()[Ljava/lang/Class;");
+
+ // Lookup Tuscany classes and methods
+ loaderClass = env->FindClass("org/apache/tuscany/ClassLoader");
+ loaderValueOf = env->GetStaticMethodID(loaderClass, "valueOf", "(Ljava/lang/String;)Ljava/lang/ClassLoader;");
+ loaderForName = env->GetStaticMethodID(loaderClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+ invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler");
+ invokerValueOf = env->GetStaticMethodID(invokerClass, "valueOf", "(Ljava/lang/Class;J)Ljava/lang/Object;");
+ invokerStackTrace = env->GetStaticMethodID(invokerClass, "stackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;");
+ invokerLambda = env->GetFieldID(invokerClass, "lambda", "J");
+ iterableUtilClass = env->FindClass("org/apache/tuscany/IterableUtil");
+ iterableValueOf = env->GetStaticMethodID(iterableUtilClass, "list", "([Ljava/lang/Object;)Ljava/lang/Iterable;");
+ iterableIsNil = env->GetStaticMethodID(iterableUtilClass, "isNil", "(Ljava/lang/Object;)Z");
+ iterableCar = env->GetStaticMethodID(iterableUtilClass, "car", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ iterableCdr = env->GetStaticMethodID(iterableUtilClass, "cdr", "(Ljava/lang/Object;)Ljava/lang/Iterable;");
+ uuidClass = env->FindClass("org/apache/tuscany/UUIDUtil");
+
+ // Register our native invocation handler function
+ JNINativeMethod invokenm;
+ invokenm.name = const_cast<char*>("invoke");
+ invokenm.signature = const_cast<char*>("(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
+ invokenm.fnPtr = (void*)nativeInvoke;
+ env->RegisterNatives(invokerClass, &invokenm, 1);
+
+ // Register our native UUID function
+ JNINativeMethod uuidnm;
+ uuidnm.name = const_cast<char*>("uuid");
+ uuidnm.signature = const_cast<char*>("()Ljava/lang/String;");
+ uuidnm.fnPtr = (void*)nativeUUID;
+ env->RegisterNatives(uuidClass, &uuidnm, 1);
+ }
+
+ JavaVM* jvm;
+ JNIEnv* env;
+
+ jclass classClass;
+ jclass methodClass;
+ jclass objectClass;
+ jclass doubleClass;
+ jclass booleanClass;
+ jclass stringClass;
+ jclass objectArrayClass;
+ jclass iterableClass;
+ jmethodID doubleValueOf;
+ jmethodID doubleValue;
+ jmethodID booleanValueOf;
+ jmethodID booleanValue;
+ jmethodID declaredMethods;
+ jmethodID methodName;
+ jmethodID parameterTypes;
+ jmethodID classForName;
+ jclass loaderClass;
+ jmethodID loaderValueOf;
+ jmethodID loaderForName;
+ jclass invokerClass;
+ jmethodID invokerValueOf;
+ jmethodID invokerStackTrace;
+ jfieldID invokerLambda;
+ jclass iterableUtilClass;
+ jmethodID iterableValueOf;
+ jmethodID iterableCar;
+ jmethodID iterableCdr;
+ jmethodID iterableIsNil;
+ jclass uuidClass;
+};
+
+/**
+ * Return the last exception that occurred in a JVM.
+ */
+string lastException(const JavaRuntime& jr) {
+ if (!jr.env->ExceptionCheck())
+ return "No Exception";
+ const jthrowable ex = jr.env->ExceptionOccurred();
+ const jstring trace = (jstring)jr.env->CallStaticObjectMethod(jr.invokerClass, jr.invokerStackTrace, ex);
+ const char* c = jr.env->GetStringUTFChars(trace, NULL);
+ const string msg(c);
+ jr.env->ReleaseStringUTFChars(trace, c);
+ jr.env->ExceptionClear();
+ return msg;
+}
+
+/**
+ * Declare conversion functions.
+ */
+const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const value& v);
+const value jobjectToValue(const JavaRuntime& jr, const jobject o);
+const jobjectArray valuesToJarray(const JavaRuntime& jr, const list<value>& v);
+const list<value> jarrayToValues(const JavaRuntime& jr, const jobjectArray o);
+const list<value> jiterableToValues(const JavaRuntime& jr, const jobject o);
+
+/**
+ * Convert a Java class name to a JNI class name.
+ */
+const bool jniClassNameHelper(char* to, const char* from) {
+ if (*from == '\0') {
+ *to = '\0';
+ return true;
+ }
+ *to = *from == '.'? '/' : *from;
+ return jniClassNameHelper(to + 1, from + 1);
+}
+
+const string jniClassName(const string& from) {
+ char buf[length(from) + 1];
+ jniClassNameHelper(buf, c_str(from));
+ return string(buf);
+}
+
+/**
+ * Create a new Java object representing a lambda expression.
+ */
+class javaLambda {
+public:
+ javaLambda(const JavaRuntime& jr, const value& iface, const lambda<value(const list<value>&)>& func) : jr(jr), iface(iface), func(func) {
+ }
+
+ const value operator()(const list<value>& expr) const {
+ if (isNil(expr))
+ return func(expr);
+ const value& op(car(expr));
+ if (op == "equals")
+ return value(cadr(expr) == this);
+ if (op == "hashCode")
+ return value((double)(long)this);
+ if (op == "toString") {
+ ostringstream os;
+ os << this;
+ return value(string("org.apache.tuscany.InvocationHandler@") + (c_str(str(os)) + 2));
+ }
+ return func(expr);
+ }
+
+ const JavaRuntime& jr;
+ const value iface;
+ const lambda<value(const list<value>&)> func;
+};
+
+/**
+ * Native implementation of the InvocationHandler.invoke Java method.
+ * Dispatches the call to the lambda function wrapped in the invocation handler.
+ */
+jobject JNICALL nativeInvoke(JNIEnv* env, jobject self, unused jobject proxy, jobject method, jobjectArray args) {
+
+ // Retrieve the lambda function from the invocation handler
+ jclass clazz = env->GetObjectClass(self);
+ jfieldID f = env->GetFieldID(clazz, "lambda", "J");
+ const javaLambda& jl = *(javaLambda*)(long)env->GetLongField(self, f);
+
+ // Retrieve the function name
+ const jstring s = (jstring)env->CallObjectMethod(method, jl.jr.methodName);
+ const char* c = env->GetStringUTFChars(s, NULL);
+ const value func(c);
+ env->ReleaseStringUTFChars(s, c);
+
+ // Build the expression to evaluate, either (func, args[0], args[1], args[2]...)
+ // or just args[0] for the special eval(...) function
+ const list<value> expr = func == "eval"? (list<value>)car<value>(jarrayToValues(jl.jr, args)) : cons<value>(func, jarrayToValues(jl.jr, args));
+ debug(expr, "java::nativeInvoke::expr");
+
+ // Invoke the lambda function
+ value result = jl(expr);
+ debug(result, "java::nativeInvoke::result");
+
+ // Convert result to a jobject
+ return valueToJobject(jl.jr, value(), result);
+}
+
+/**
+ * Native implementation of IterableUtil.uuid. We are providing a native implementation
+ * of this function as java.util.UUID seems to behave differently with different JDKs.
+ */
+jobject JNICALL nativeUUID(JNIEnv* env) {
+ const value uuid = mkuuid();
+ return env->NewStringUTF(c_str(uuid));
+}
+
+/**
+ * Convert a lambda function to Java proxy.
+ */
+const jobject mkJavaLambda(const JavaRuntime& jr, unused const value& iface, const lambda<value(const list<value>&)>& l) {
+ const gc_ptr<javaLambda> jl = new (gc_new<javaLambda>()) javaLambda(jr, iface, l);
+ jclass jc = (jclass)(long)(double)iface;
+ const jobject obj = jr.env->CallStaticObjectMethod(jr.invokerClass, jr.invokerValueOf, jc, (long)(javaLambda*)jl);
+ return obj;
+}
+
+/**
+ * Convert a list of values to a Java jobjectArray.
+ */
+const jobjectArray valuesToJarrayHelper(const JavaRuntime& jr, jobjectArray a, const list<value>& v, const int i) {
+ if (isNil(v))
+ return a;
+ jr.env->SetObjectArrayElement(a, i, valueToJobject(jr, value(), car(v)));
+ return valuesToJarrayHelper(jr, a, cdr(v), i + 1);
+}
+
+const jobjectArray valuesToJarray(const JavaRuntime& jr, const list<value>& v) {
+ jobjectArray a = jr.env->NewObjectArray((jsize)length(v), jr.objectClass, NULL);
+ return valuesToJarrayHelper(jr, a, v, 0);
+}
+
+/**
+ * Convert a Java jobjectArray to a Java iterable.
+ */
+const jobject jarrayToJiterable(const JavaRuntime& jr, jobjectArray a) {
+ return jr.env->CallStaticObjectMethod(jr.iterableClass, jr.iterableValueOf, a);
+}
+
+/**
+ * Convert a value to a Java jobject.
+ */
+const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const value& v) {
+ switch (type(v)) {
+ case value::List:
+ return jarrayToJiterable(jr, valuesToJarray(jr, v));
+ case value::Lambda:
+ return mkJavaLambda(jr, jtype, v);
+ case value::Symbol:
+ return jr.env->NewStringUTF(c_str(string("'") + v));
+ case value::String:
+ return jr.env->NewStringUTF(c_str(v));
+ case value::Number:
+ return jr.env->CallStaticObjectMethod(jr.doubleClass, jr.doubleValueOf, (double)v);
+ case value::Bool:
+ return jr.env->CallStaticObjectMethod(jr.booleanClass, jr.booleanValueOf, (bool)v);
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Convert a list of values to an array of jvalues.
+ */
+const jvalue* valuesToJvaluesHelper(const JavaRuntime& jr, jvalue* a, const list<value>& types, const list<value>& v) {
+ if (isNil(v))
+ return a;
+ a->l = valueToJobject(jr, car(types), car(v));
+ return valuesToJvaluesHelper(jr, a + 1, cdr(types), cdr(v));
+}
+
+const jvalue* valuesToJvalues(const JavaRuntime& jr, const list<value>& types, const list<value>& v) {
+ const size_t n = length(v);
+ jvalue* a = new (gc_anew<jvalue>(n)) jvalue[n];
+ valuesToJvaluesHelper(jr, a, types, v);
+ return a;
+}
+
+/**
+ * Convert a Java jobjectArray to a list of values.
+ */
+const list<value> jarrayToValuesHelper(const JavaRuntime& jr, jobjectArray a, const int i, const int size) {
+ if (i == size)
+ return list<value>();
+ return cons(jobjectToValue(jr, jr.env->GetObjectArrayElement(a, i)), jarrayToValuesHelper(jr, a, i + 1, size));
+}
+
+const list<value> jarrayToValues(const JavaRuntime& jr, jobjectArray o) {
+ if (o == NULL)
+ return list<value>();
+ return jarrayToValuesHelper(jr, o, 0, jr.env->GetArrayLength(o));
+}
+
+/**
+ * Convert a Java Iterable to a list of values.
+ */
+const list<value> jiterableToValuesHelper(const JavaRuntime& jr, jobject o) {
+ if ((bool)jr.env->CallStaticBooleanMethod(jr.iterableUtilClass, jr.iterableIsNil, o))
+ return list<value>();
+ jobject car = jr.env->CallStaticObjectMethod(jr.iterableUtilClass, jr.iterableCar, o);
+ jobject cdr = jr.env->CallStaticObjectMethod(jr.iterableUtilClass, jr.iterableCdr, o);
+ return cons(jobjectToValue(jr, car), jiterableToValuesHelper(jr, cdr));
+}
+
+const list<value> jiterableToValues(const JavaRuntime& jr, jobject o) {
+ if (o == NULL)
+ return list<value>();
+ return jiterableToValuesHelper(jr, o);
+}
+
+/**
+ * Lambda function used to represent a Java callable object.
+ */
+struct javaCallable {
+ const JavaRuntime& jr;
+ const jobject obj;
+
+ javaCallable(const JavaRuntime& jr, const jobject obj) : jr(jr), obj(obj) {
+ }
+
+ const value operator()(const list<value>& args) const {
+ jobjectArray jargs = valuesToJarray(jr, args);
+ jobject result = jargs; //CallObject(func, jargs);
+ return jobjectToValue(jr, result);
+ }
+};
+
+/**
+ * Convert a Java jobject to a value.
+ */
+const value jobjectToValue(const JavaRuntime& jr, const jobject o) {
+ if (o == NULL)
+ return value();
+ const jclass clazz = jr.env->GetObjectClass(o);
+ if ((jr.env->IsSameObject(clazz, jr.stringClass))) {
+ const char* s = jr.env->GetStringUTFChars((jstring)o, NULL);
+ if (*s == '\'') {
+ const value v(s + 1);
+ jr.env->ReleaseStringUTFChars((jstring)o, s);
+ return v;
+ }
+ const value v = string(s);
+ jr.env->ReleaseStringUTFChars((jstring)o, s);
+ return v;
+ }
+ if (jr.env->IsSameObject(clazz, jr.booleanClass))
+ return value((bool)jr.env->CallBooleanMethod(o, jr.booleanValue));
+ if (jr.env->IsSameObject(clazz, jr.doubleClass))
+ return value((double)jr.env->CallDoubleMethod(o, jr.doubleValue));
+ if (jr.env->IsAssignableFrom(clazz, jr.iterableClass))
+ return jiterableToValues(jr, o);
+ if (jr.env->IsAssignableFrom(clazz, jr.objectArrayClass))
+ return jarrayToValues(jr, (jobjectArray)o);
+ return lambda<value(const list<value>&)>(javaCallable(jr, o));
+}
+
+/**
+ * Returns a balanced tree of the methods of a class.
+ */
+const value parameterTypeToValue(const jobject t) {
+ return value((double)(long)t);
+}
+
+const list<value> parameterTypesToValues(const JavaRuntime& jr, const jobjectArray t, const int i) {
+ if (i == 0)
+ return list<value>();
+ return cons<value>(parameterTypeToValue(jr.env->GetObjectArrayElement(t, i - 1)), parameterTypesToValues(jr, t, i - 1));
+}
+
+const value methodToValue(const JavaRuntime& jr, const jobject m) {
+ const jobject s = jr.env->CallObjectMethod(m, jr.methodName);
+ const char* c = jr.env->GetStringUTFChars((jstring)s, NULL);
+ const string& name = string(c);
+ jr.env->ReleaseStringUTFChars((jstring)s, c);
+
+ const jmethodID mid = jr.env->FromReflectedMethod(m);
+
+ const jobjectArray t = (jobjectArray)jr.env->CallObjectMethod(m, jr.parameterTypes);
+ const list<value> types = reverse(parameterTypesToValues(jr, t, jr.env->GetArrayLength(t)));
+
+ return cons<value>(c_str(name), cons<value>((double)(long)mid, types));
+}
+
+const list<value> methodsToValues(const JavaRuntime& jr, const jobjectArray m, const int i) {
+ if (i == 0)
+ return list<value>();
+ return cons<value>(methodToValue(jr, jr.env->GetObjectArrayElement(m, i - 1)), methodsToValues(jr, m, i - 1));
+}
+
+const list<value> methodsToValues(const JavaRuntime& jr, const jclass clazz) {
+ const jobjectArray m = (jobjectArray)jr.env->CallObjectMethod(clazz, jr.declaredMethods);
+ return methodsToValues(jr, m, jr.env->GetArrayLength(m));
+}
+
+/**
+ * Represents a Java Class.
+ */
+class JavaClass {
+public:
+ JavaClass() : loader(NULL), clazz(NULL), obj(NULL) {
+ }
+ JavaClass(const jobject loader, const jclass clazz, const jobject obj, const list<value> m) : loader(loader), clazz(clazz), obj(obj), m(m) {
+ }
+
+ const jobject loader;
+ const jclass clazz;
+ const jobject obj;
+ const list<value> m;
+};
+
+/**
+ * Read a class.
+ */
+const failable<JavaClass> readClass(const JavaRuntime& jr, const string& path, const string& name) {
+
+ // Create a class loader from the given path
+ const jobject jpath = jr.env->NewStringUTF(c_str(path));
+ jobject loader = jr.env->CallStaticObjectMethod(jr.loaderClass, jr.loaderValueOf, jpath);
+
+ // Load the class
+ const jobject jname = jr.env->NewStringUTF(c_str(name));
+ const jclass clazz = (jclass)jr.env->CallStaticObjectMethod(jr.loaderClass, jr.loaderForName, jname, JNI_TRUE, loader);
+ if (clazz == NULL)
+ return mkfailure<JavaClass>(string("Couldn't load class: ") + name + " : " + lastException(jr));
+
+ // Create an instance
+ const jmethodID constr = jr.env->GetMethodID(clazz, "<init>", "()V");
+ if (constr == NULL)
+ return mkfailure<JavaClass>(string("Couldn't find constructor: ") + name + " : " + lastException(jr));
+ const jobject obj = jr.env->NewObject(clazz, constr);
+ if (obj == NULL)
+ return mkfailure<JavaClass>(string("Couldn't construct object: ") + name + " : " + lastException(jr));
+
+ return JavaClass(loader, clazz, obj, methodsToValues(jr, clazz));
+}
+
+/**
+ * Evaluate an expression against a Java class.
+ */
+const failable<value> evalClass(const JavaRuntime& jr, const value& expr, const JavaClass jc) {
+ debug(expr, "java::evalClass::expr");
+
+ // Lookup the Java function named as the expression operand
+ const list<value> func = assoc<value>(car<value>(expr), jc.m);
+ if (isNil(func)) {
+
+ // The start, stop, and restart functions are optional
+ const value fn = car<value>(expr);
+ if (fn == "start" || fn == "stop")
+ return value(lambda<value(const list<value>&)>());
+
+ return mkfailure<value>(string("Couldn't find function: ") + car<value>(expr) + " : " + lastException(jr));
+ }
+ const jmethodID fid = (jmethodID)(long)(double)cadr(func);
+
+ // Convert args to Java jvalues
+ const jvalue* args = valuesToJvalues(jr, cddr(func), cdr<value>(expr));
+
+ // Call the Java function
+ const jobject result = jr.env->CallObjectMethodA(jc.obj, fid, const_cast<jvalue*>(args));
+ if (result == NULL)
+ return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastException(jr));
+
+ // Convert Java result to a value
+ const value v = jobjectToValue(jr, result);
+ debug(v, "java::evalClass::result");
+ return v;
+}
+
+}
+}
+#endif /* tuscany_java_eval_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/java-conf b/sandbox/sebastien/cpp/apr-2/modules/java/java-conf
new file mode 100755
index 0000000000..cf5faddb84
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/java-conf
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+# Generate a Java server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: java-conf $*
+# Support for Java SCA components
+LoadModule mod_tuscany_eval $here/libmod_tuscany_java.so
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/java-shell.cpp b/sandbox/sebastien/cpp/apr-2/modules/java/java-shell.cpp
new file mode 100644
index 0000000000..51df513990
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/java-shell.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Java evaluator shell, used for interactive testing of Java classes.
+ */
+
+#include <assert.h>
+#include "gc.hpp"
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+int main(const int argc, char** argv) {
+ tuscany::gc_scoped_pool pool;
+ if (argc != 2) {
+ tuscany::cerr << "Usage: java-shell <class name>" << tuscany::endl;
+ return 1;
+ }
+ tuscany::java::evalDriverRun(argv[1], tuscany::cin, tuscany::cout);
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/java-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/java/java-test.cpp
new file mode 100644
index 0000000000..f811a4f58d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/java-test.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Java evaluator.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+namespace tuscany {
+namespace java {
+
+bool testEvalExpr() {
+ gc_scoped_pool pool;
+ JavaRuntime javaRuntime;
+ {
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl");
+ assert(hasContent(obj));
+ const value exp = mklist<value>("mult", 2, 3);
+ const failable<value> r = evalClass(javaRuntime, exp, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(6));
+ }
+ {
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl");
+ assert(hasContent(obj));
+ const value exp = mklist<value>("even", 2);
+ const failable<value> r = evalClass(javaRuntime, exp, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.AdderImpl");
+ assert(hasContent(obj));
+ const value exp = mklist<value>("add", 2, 3);
+ const failable<value> r = evalClass(javaRuntime, exp, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(5));
+ }
+ {
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl");
+ assert(hasContent(obj));
+ const value exp = mklist<value>("square", mklist<value>(1, 2, 3));
+ const failable<value> r = evalClass(javaRuntime, exp, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == mklist<value>(1, 4, 9));
+ }
+ return true;
+}
+
+const value add(const list<value>& args) {
+ assert(car(args) == "add");
+ const double x = cadr(args);
+ const double y = caddr(args);
+ return x + y;
+}
+
+bool testEvalLambda() {
+ gc_scoped_pool pool;
+ JavaRuntime javaRuntime;
+ {
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl");
+ assert(hasContent(obj));
+ const value tcel = mklist<value>("add", 3, 4, lambda<value(const list<value>&)>(add));
+ const failable<value> r = evalClass(javaRuntime, tcel, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(7));
+ }
+ {
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl");
+ assert(hasContent(obj));
+ const value tcel = mklist<value>("addEval", 3, 4, lambda<value(const list<value>&)>(add));
+ const failable<value> r = evalClass(javaRuntime, tcel, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(7));
+ }
+ return true;
+}
+
+bool testClassLoader() {
+ gc_scoped_pool pool;
+ JavaRuntime javaRuntime;
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "org.apache.tuscany.ClassLoader$Test");
+ assert(hasContent(obj));
+ const value exp = mklist<value>("testClassLoader");
+ const failable<value> r = evalClass(javaRuntime, exp, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ return true;
+}
+
+bool testIterableUtil() {
+ gc_scoped_pool pool;
+ JavaRuntime javaRuntime;
+ const failable<JavaClass> obj = readClass(javaRuntime, ".", "org.apache.tuscany.IterableUtil$Test");
+ assert(hasContent(obj));
+ const value exp = mklist<value>("testList");
+ const failable<value> r = evalClass(javaRuntime, exp, content(obj));
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::java::testEvalExpr();
+ tuscany::java::testEvalLambda();
+ tuscany::java::testClassLoader();
+ tuscany::java::testIterableUtil();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/jni-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/java/jni-test.cpp
new file mode 100644
index 0000000000..727af13dc6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/jni-test.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Basic JNI test.
+ */
+
+#include <assert.h>
+#include <jni.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "fstream.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace java {
+
+#ifdef JAVA_HARMONY_VM
+#define JNI_VERSION JNI_VERSION_1_4
+#else
+#define JNI_VERSION JNI_VERSION_1_6
+#endif
+
+bool testJNI() {
+ gc_scoped_pool pool;
+ JavaVM* jvm;
+ JNIEnv* env;
+
+ JavaVMInitArgs args;
+ args.version = JNI_VERSION;
+ args.ignoreUnrecognized = JNI_FALSE;
+ JavaVMOption options[3];
+ args.options = options;
+ args.nOptions = 0;
+ const char* envcp = getenv("CLASSPATH");
+ const string cp = string("-Djava.class.path=") + (envcp == NULL? "." : envcp);
+ options[args.nOptions].optionString = const_cast<char*>(c_str(cp));
+ options[args.nOptions++].extraInfo = NULL;
+#ifdef JAVA_HARMONY_VM
+ JNI_CreateJavaVM(&jvm, &env, &args);
+#else
+ JNI_CreateJavaVM(&jvm, (void**)&env, &args);
+#endif
+
+ jclass classClass = env->FindClass("java/lang/Class");
+ assert(classClass != NULL);
+ jclass loaderClass = env->FindClass("org/apache/tuscany/ClassLoader");
+ assert(loaderClass != NULL);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::java::testJNI();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/mod-java.cpp b/sandbox/sebastien/cpp/apr-2/modules/java/mod-java.cpp
new file mode 100644
index 0000000000..510f9574b0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/mod-java.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module used to eval Java component implementations.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../server/mod-cpp.hpp"
+#include "../server/mod-eval.hpp"
+#include "mod-java.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+
+/**
+ * Apply a lifecycle start or restart event.
+ */
+struct javaLifecycle {
+ javaLifecycle(java::JavaRuntime& jr) : jr(jr) {
+ }
+ const value operator()(const list<value>& params) const {
+ const value func = car(params);
+ if (func == "javaRuntime")
+ return (gc_ptr<value>)(value*)(void*)&jr;
+ return lambda<value(const list<value>&)>();
+ }
+ java::JavaRuntime& jr;
+};
+
+const value applyLifecycle(unused const list<value>& params) {
+
+ // Create a Java runtime
+ java::JavaRuntime& jr = *(new (gc_new<java::JavaRuntime>()) java::JavaRuntime());
+
+ // Return the function to invoke on subsequent events
+ return failable<value>(lambda<value(const list<value>&)>(javaLifecycle(jr)));
+}
+
+/**
+ * Evaluate a Java component implementation and convert it to an applicable
+ * lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, const lambda<value(const list<value>&)>& lifecycle) {
+ const string itype(elementName(impl));
+ if (contains(itype, ".java")) {
+ const void* p = (gc_ptr<value>)lifecycle(mklist<value>("javaRuntime"));
+ return modjava::evalImplementation(path, impl, px, *(java::JavaRuntime*)p);
+ }
+ if (contains(itype, ".cpp"))
+ return modcpp::evalImplementation(path, impl, px);
+ return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype);
+}
+
+}
+}
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/mod-java.hpp b/sandbox/sebastien/cpp/apr-2/modules/java/mod-java.hpp
new file mode 100644
index 0000000000..e7da06e930
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/mod-java.hpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_modjava_hpp
+#define tuscany_modjava_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate Java
+ * component implementations.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modjava {
+
+/**
+ * Apply a Java component implementation function.
+ */
+struct applyImplementation {
+ java::JavaClass impl;
+ const list<value> px;
+ java::JavaRuntime& jr;
+ applyImplementation(const java::JavaClass& impl, const list<value>& px, java::JavaRuntime& jr) : impl(impl), px(px), jr(jr) {
+ }
+ const value operator()(const list<value>& params) const {
+ const value expr = append<value>(params, px);
+ debug(expr, "modeval::java::applyImplementation::input");
+ const failable<value> res = java::evalClass(jr, expr, impl);
+ const value val = !hasContent(res)? mklist<value>(value(), reason(res)) : mklist<value>(content(res));
+ debug(val, "modeval::java::applyImplementation::result");
+ return val;
+ }
+};
+
+/**
+ * Evaluate a Java component implementation and convert it to an applicable
+ * lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, java::JavaRuntime& jr) {
+ const string cn(attributeValue("class", impl));
+ const failable<java::JavaClass> jc = java::readClass(jr, path, cn);
+ if (!hasContent(jc))
+ return mkfailure<lambda<value(const list<value>&)> >(reason(jc));
+ return lambda<value(const list<value>&)>(applyImplementation(content(jc), px, jr));
+}
+
+}
+}
+}
+
+#endif /* tuscany_modjava_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/ClassLoader.java b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/ClassLoader.java
new file mode 100644
index 0000000000..ef7b2316fb
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/ClassLoader.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package org.apache.tuscany;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * Class loader used to load SCA component implementation classes.
+ */
+class ClassLoader extends URLClassLoader {
+
+ ClassLoader(final URL... urls) {
+ super(urls);
+ }
+
+ /**
+ * Create a class loader for an SCA contribution path.
+ */
+ static java.lang.ClassLoader valueOf(final String path) throws MalformedURLException {
+ return new ClassLoader(new File(path).toURI().toURL());
+ }
+
+ /**
+ * Load a class.
+ */
+ static Class<?> forName(final String name, final boolean resolve, final java.lang.ClassLoader loader) throws ClassNotFoundException {
+ return Class.forName(name, resolve, loader);
+ }
+
+ /**
+ * Test the class loader.
+ */
+ static class Test {
+ Boolean testClassLoader() {
+ try {
+ final Class<?> clazz = ClassLoader.forName("test.CalcImpl", true, ClassLoader.valueOf("."));
+ assert clazz != null;
+ } catch(final MalformedURLException e) {
+ throw new RuntimeException(e);
+ } catch(final ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+ }
+
+ public static void main(final String[] args) {
+ System.out.println("Testing...");
+
+ Test.class.getClassLoader().setDefaultAssertionStatus(true);
+ new Test().testClassLoader();
+
+ System.out.println("OK");
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/InvocationHandler.java b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/InvocationHandler.java
new file mode 100644
index 0000000000..06466fe9fc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/InvocationHandler.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.tuscany;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * Proxy Invocation handler used to represent SCA component references.
+ */
+class InvocationHandler implements java.lang.reflect.InvocationHandler {
+ final long lambda;
+
+ InvocationHandler(final long lambda) {
+ this.lambda = lambda;
+ }
+
+ /**
+ * Create a proxy for an interface and the lambda function representing
+ * an SCA component reference.
+ */
+ static Object valueOf(final Class<?> iface, final long lambda) {
+ return Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, new InvocationHandler(lambda));
+ }
+
+ /**
+ * Proxy invocation of a C++ function.
+ */
+ public native Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable;
+
+ /**
+ * Return the stack trace of an exception.
+ */
+ static String stackTrace(final Throwable e) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ return sw.toString();
+ }
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/IterableUtil.java b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/IterableUtil.java
new file mode 100644
index 0000000000..6d559f370a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/IterableUtil.java
@@ -0,0 +1,368 @@
+/*
+ * 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.
+ */
+
+package org.apache.tuscany;
+
+import static java.util.Arrays.*;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Utility functions to help work efficiently with iterable lists, inspired from Lisp.
+ */
+public class IterableUtil {
+
+ /**
+ * Convert an array or a variable list of arguments to an iterable list.
+ */
+ public static <T> Iterable<T> list(final Object... a) {
+ return new ArrayIterable<T>(a, 0);
+ }
+
+ /**
+ * Convert an iterable list to a java.util.Collection.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Collection<T> collection(final Object l) {
+ final Collection<T> c = new ArrayList<T>();
+ for(final Object x : (Iterable<?>)l)
+ c.add((T)x);
+ return c;
+ }
+
+ /**
+ * Construct a new list from an element and a list.
+ */
+ public static <T> Iterable<T> cons(final Object car, final Iterable<?> cdr) {
+ return new PairIterable<T>(car, cdr);
+ }
+
+ /**
+ * Return true if a list is nil (empty).
+ */
+ public static boolean isNil(final Object l) {
+ if(l instanceof BasicIterable<?>)
+ return ((BasicIterable<?>)l).isNil();
+ if(l instanceof Collection<?>)
+ return ((Collection<?>)l).isEmpty();
+ return !((Iterable<?>)l).iterator().hasNext();
+ }
+
+ /**
+ * Return the car (first element) of a list.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T car(final Object l) {
+ if(l instanceof BasicIterable<?>)
+ return ((BasicIterable<T>)l).car();
+ if(l instanceof List<?>)
+ return (T)((List<?>)l).get(0);
+ return (T)((Iterable<?>)l).iterator().next();
+ }
+
+ /**
+ * Return the cdr (rest after the first element) of a list.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Iterable<T> cdr(final Object l) {
+ if(l instanceof BasicIterable<?>)
+ return ((BasicIterable<T>)l).cdr();
+ if(l instanceof List<?>)
+ return new ListIterable<T>((List<?>)l, 1);
+ if(l instanceof Collection<?>)
+ return new ArrayIterable<T>(((Collection<?>)l).toArray(), 1);
+ return new Iterable<T>() {
+ public Iterator<T> iterator() {
+ final Iterator<T> i = ((Iterable<T>)l).iterator();
+ i.next();
+ return i;
+ }
+ };
+ }
+
+ /**
+ * Return the car of the cdr of a list.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T cadr(final Object l) {
+ return (T)car(cdr(l));
+ }
+
+ /**
+ * Return the cdr of the cdr of a list.
+ */
+ public static <T> Iterable<T> cddr(final Object l) {
+ return cdr(cdr(l));
+ }
+
+ /**
+ * Return the car of the cdr of the cdr of a list.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T caddr(final Object l) {
+ return (T)car(cddr(l));
+ }
+
+ /**
+ * Return the first pair matching a key from a list of key value pairs.
+ */
+ public static <T> Iterable<T> assoc(final Object k, final Object l) {
+ if(isNil(l))
+ return list();
+ if(k.equals(car(car(l))))
+ return car(l);
+ return assoc(k, cdr(l));
+ }
+
+ /**
+ * Internal base implementation class for iterable and immutable lists.
+ */
+ static abstract class BasicIterable<T> extends AbstractList<T> {
+ abstract T car();
+
+ abstract Iterable<T> cdr();
+
+ abstract Boolean isNil();
+
+ @Override
+ public int size() {
+ return this.isNil()? 0 : 1 + ((List<T>)this.cdr()).size();
+ }
+
+ @Override
+ public T get(final int index) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Internal implementation of a list backed by an array.
+ */
+ static class ArrayIterable<T> extends BasicIterable<T> {
+ final Object[] a;
+ final int start;
+
+ ArrayIterable(final Object[] a, final int start) {
+ this.a = a;
+ this.start = start;
+ }
+
+ @Override
+ Boolean isNil() {
+ return this.a.length - this.start == 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ T car() {
+ return (T)this.a[this.start];
+ }
+
+ @Override
+ BasicIterable<T> cdr() {
+ return new ArrayIterable<T>(this.a, this.start + 1);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new Iterator<T>() {
+ int i = ArrayIterable.this.start;
+
+ public boolean hasNext() {
+ return this.i < ArrayIterable.this.a.length;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T next() {
+ return (T)ArrayIterable.this.a[this.i++];
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ /**
+ * Internal implementation of a list backed by a java.util.List.
+ */
+ static class ListIterable<T> extends BasicIterable<T> {
+ final List<?> l;
+ final int start;
+
+ ListIterable(final List<?> l, final int start) {
+ this.l = l;
+ this.start = start;
+ }
+
+ @Override
+ Boolean isNil() {
+ return this.l.size() - this.start == 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ T car() {
+ return (T)this.l.get(this.start);
+ }
+
+ @Override
+ BasicIterable<T> cdr() {
+ return new ListIterable<T>(this.l, this.start + 1);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new Iterator<T>() {
+ int i = ListIterable.this.start;
+
+ public boolean hasNext() {
+ return this.i < ListIterable.this.l.size();
+ }
+
+ @SuppressWarnings("unchecked")
+ public T next() {
+ return (T)ListIterable.this.l.get(this.i++);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ /**
+ * Internal implementation of a list backed by an element / iterable pair.
+ */
+ static class PairIterable<T> extends BasicIterable<T> {
+ final Object car;
+ final Iterable<?> cdr;
+
+ PairIterable(final Object car, final Iterable<?> cdr) {
+ this.car = car;
+ this.cdr = cdr;
+ }
+
+ @Override
+ Boolean isNil() {
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ T car() {
+ return (T)this.car;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ Iterable<T> cdr() {
+ return (Iterable<T>)this.cdr;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new Iterator<T>() {
+ boolean carIterator = true;
+ Iterator<?> cdrIterator = PairIterable.this.cdr.iterator();
+
+ public boolean hasNext() {
+ if(this.carIterator)
+ return true;
+ return this.cdrIterator.hasNext();
+ }
+
+ @SuppressWarnings("unchecked")
+ public T next() {
+ if(this.carIterator) {
+ this.carIterator = false;
+ return (T)PairIterable.this.car;
+ }
+ return (T)this.cdrIterator.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ /**
+ * Test the list functions.
+ */
+ static class Test {
+ Boolean testList() {
+ final Iterable<Object> l = list(2, 3, 4);
+ assert car(l) == Integer.valueOf(2);
+ assert cadr(l) == Integer.valueOf(3);
+ assert caddr(l) == Integer.valueOf(4);
+
+ final Iterable<Object> c = cons(0, cons(1, l));
+ assert car(c) == Integer.valueOf(0);
+ assert cadr(c) == Integer.valueOf(1);
+ assert caddr(c) == Integer.valueOf(2);
+ assert c.toString().equals("[0, 1, 2, 3, 4]");
+
+ final Iterable<Object> cl = cons(0, cons(1, new ArrayList<Object>(asList(2, 3, 4))));
+ assert car(cl) == Integer.valueOf(0);
+ assert cadr(cl) == Integer.valueOf(1);
+ assert caddr(cl) == Integer.valueOf(2);
+ assert cl.toString().equals("[0, 1, 2, 3, 4]");
+
+ final List<Object> jl = new ArrayList<Object>(collection(cl));
+ assert jl.size() == 5;
+ assert jl.get(0) == Integer.valueOf(0);
+ assert jl.get(1) == Integer.valueOf(1);
+ assert jl.get(2) == Integer.valueOf(2);
+
+ final Iterable<Object> n = list();
+ assert isNil(n);
+ assert n.toString().equals("[]");
+
+ final Iterable<Object> cn = cons(0, n);
+ assert !isNil(cn);
+ assert isNil(cdr(cn));
+ assert cn.toString().equals("[0]");
+
+ final Iterable<Object> al = new ArrayList<Object>(Arrays.asList(1, 2, 3));
+ assert car(al) == Integer.valueOf(1);
+ assert cadr(al) == Integer.valueOf(2);
+ assert caddr(al) == Integer.valueOf(3);
+ return true;
+ }
+ }
+
+ public static void main(final String[] args) {
+ System.out.println("Testing...");
+
+ Test.class.getClassLoader().setDefaultAssertionStatus(true);
+ new Test().testList();
+
+ System.out.println("OK");
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/Service.java b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/Service.java
new file mode 100644
index 0000000000..a00d5b1b53
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/Service.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package org.apache.tuscany;
+
+/**
+ * Interface used to represent SCA component references providing both REST
+ * access to a resource and function application.
+ */
+public interface Service {
+
+ /**
+ * Post a new item to a collection of items.
+ */
+ Iterable<String> post(Iterable<String> collection, Iterable<?> item);
+
+ /**
+ * Return an item.
+ */
+ Iterable<?> get(Iterable<String> id);
+
+ /**
+ * Update an item.
+ */
+ boolean put(Iterable<String> id, Iterable<?> item);
+
+ /**
+ * Delete an item.
+ */
+ boolean delete(Iterable<String> id);
+
+ /**
+ * Evaluate an expression.
+ */
+ <T> T eval(Object... params);
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/UUIDUtil.java b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/UUIDUtil.java
new file mode 100644
index 0000000000..60076c62ca
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/org/apache/tuscany/UUIDUtil.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package org.apache.tuscany;
+
+/**
+ * A fast and portable UUID generator function.
+ */
+public class UUIDUtil {
+
+ /**
+ * Return a UUID.
+ */
+ public static native String uuid();
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/server-test b/sandbox/sebastien/cpp/apr-2/modules/java/server-test
new file mode 100755
index 0000000000..dba63a9525
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/server-test
@@ -0,0 +1,41 @@
+#!/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
+# 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.
+
+# Setup
+../http/httpd-conf tmp localhost 8090 ../server/htdocs
+../server/server-conf tmp
+./java-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+export CLASSPATH="`pwd`/libmod-tuscany-java-1.0.jar:`pwd`"
+
+../http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/Adder.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/Adder.java
new file mode 100644
index 0000000000..7236548c41
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/Adder.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package test;
+
+public interface Adder {
+
+ Double add(Double x, Double y);
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/AdderImpl.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/AdderImpl.java
new file mode 100644
index 0000000000..e607012b78
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/AdderImpl.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package test;
+
+public class AdderImpl {
+
+ public Double add(Double x, Double y) {
+ return x + y;
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/CalcImpl.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/CalcImpl.java
new file mode 100644
index 0000000000..5bea01a43f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/CalcImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.Service;
+
+public class CalcImpl {
+
+ public Double add(final Double x, final Double y, final Adder adder) {
+ return adder.add(x, y);
+ }
+
+ public Double addEval(final Double x, final Double y, final Service adder) {
+ return adder.eval("add", x, y);
+ }
+
+ public Double mult(final Double x, final Double y) {
+ return x * y;
+ }
+
+ public Boolean even(final Double x) {
+ return (double)((int)(double)x / 2 * 2) == (double)x;
+ }
+
+ public Iterable<Double> square(final Iterable<Double> l) {
+ final List<Double> r = new ArrayList<Double>();
+ for(final Double x : l)
+ r.add(x * x);
+ return r;
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/Client.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/Client.java
new file mode 100644
index 0000000000..c3bd875fcc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/Client.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package test;
+
+public interface Client {
+
+ String echo(String x);
+
+ Iterable<?> get(Iterable<String> id);
+
+ Iterable<String> post(Iterable<String> collection, Iterable<?> item);
+
+ Boolean put(Iterable<String> id, Iterable<?> item);
+
+ Boolean delete(Iterable<String> id);
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/ClientImpl.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/ClientImpl.java
new file mode 100644
index 0000000000..ade2ba302e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/ClientImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package test;
+
+public class ClientImpl {
+
+ public String echo(String x, Server server) {
+ return server.echo(x);
+ }
+
+ public Iterable<?> get(Iterable<String> id, Server server) {
+ return server.get(id);
+ }
+
+ public Iterable<String> post(Iterable<String> collection, Iterable<?> item, Server server) {
+ return server.post(collection, item);
+ }
+
+ public Boolean put(Iterable<String> id, Iterable<?> item, Server server) {
+ return server.put(id, item);
+ }
+
+ public Boolean delete(Iterable<String> id, Server server) {
+ return server.delete(id);
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/Server.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/Server.java
new file mode 100644
index 0000000000..3dfe3c84ef
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/Server.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package test;
+
+public interface Server {
+
+ String echo(String x);
+
+ Iterable<?> get(Iterable<String> id);
+
+ Iterable<String> post(Iterable<String> collection, Iterable<?> item);
+
+ Boolean put(Iterable<String> id, Iterable<?> item);
+
+ Boolean delete(Iterable<String> id);
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/test/ServerImpl.java b/sandbox/sebastien/cpp/apr-2/modules/java/test/ServerImpl.java
new file mode 100644
index 0000000000..9de68fdb75
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/test/ServerImpl.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package test;
+
+import static org.apache.tuscany.IterableUtil.*;
+
+public class ServerImpl {
+
+ public String echo(final String x) {
+ return x;
+ }
+
+ public Iterable<?> get(final Iterable<String> id) {
+ if (isNil(id))
+ return list("Sample Feed", "123456789",
+ list("Item", "111", list(list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99))),
+ list("Item", "222", list(list("'name", "Orange"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 3.55))),
+ list("Item", "333", list(list("'name", "Pear"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 1.55))));
+ final Iterable<?> entry = list(list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99));
+ return list("Item", car(id), entry);
+ }
+
+ public Iterable<String> post(final Iterable<String> collection, final Iterable<?> item) {
+ return list("123456789");
+ }
+
+ public Boolean put(final Iterable<String> id, final Iterable<?> item) {
+ return true;
+ }
+
+ public Boolean delete(final Iterable<String> id) {
+ return true;
+ }
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/java/wiring-test b/sandbox/sebastien/cpp/apr-2/modules/java/wiring-test
new file mode 100755
index 0000000000..fb2ad48efc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/java/wiring-test
@@ -0,0 +1,80 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+
+# Setup
+../http/httpd-conf tmp localhost 8090 ../server/htdocs
+../server/server-conf tmp
+./java-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+export CLASSPATH="`pwd`/libmod-tuscany-java-1.0.jar:`pwd`"
+
+../http/httpd-start tmp
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html ../server/htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml ../server/htdocs/test/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml ../server/htdocs/test/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @../server/htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @../server/htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @../server/htdocs/test/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt ../server/htdocs/test/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am
new file mode 100644
index 0000000000..8c88f32c0f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am
@@ -0,0 +1,29 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/js
+
+moddir = $(prefix)/modules/js
+nobase_dist_mod_DATA = htdocs/*.js htdocs/*.css
+EXTRA_DIST = htdocs/*.js htdocs/*.css
+
+js_test_SOURCES = js-test.cpp
+js_test_LDFLAGS = -lmozjs
+
+noinst_PROGRAMS = js-test
+TESTS = js-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp b/sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp
new file mode 100644
index 0000000000..b7c69a1a0c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_js_hpp
+#define tuscany_js_hpp
+
+/**
+ * Javascript evaluation functions.
+ */
+
+#define XP_UNIX
+#include <jsapi.h>
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace js {
+
+/**
+ * Report Javascript errors.
+ */
+void reportError(unused ::JSContext *cx, const char *message, JSErrorReport *report) {
+#ifdef WANT_MAINTAINER_MODE
+ cdebug << (const char*)(report->filename? report->filename : "<no filename>") << ":"
+ << (int)report->lineno << ":" << message << endl;
+#endif
+}
+
+/**
+ * Encapsulates a JavaScript runtime. Shared by multiple threads in
+ * a process.
+ */
+class JSRuntime {
+public:
+ JSRuntime() {
+ // Create JS runtime
+ rt = JS_NewRuntime(8L * 1024L * 1024L);
+ if(rt == NULL)
+ cleanup();
+ }
+
+ operator ::JSRuntime*() const {
+ return rt;
+ }
+private:
+ bool cleanup() {
+ if(rt != NULL) {
+ JS_DestroyRuntime(rt);
+ rt = NULL;
+ }
+ JS_ShutDown();
+ return true;
+ }
+
+ ::JSRuntime* rt;
+} jsRuntime;
+
+JSClass jsGlobalClass = { "global", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS};
+
+/**
+ * Represents a JavaScript context. Create one per thread.
+ */
+class JSContext {
+public:
+ JSContext() {
+ // Create JS context
+ cx = JS_NewContext(jsRuntime, 8192);
+ if(cx == NULL)
+ return;
+ JS_SetOptions(cx, JSOPTION_VAROBJFIX);
+ JS_SetVersion(cx, JSVERSION_DEFAULT);
+ JS_SetErrorReporter(cx, reportError);
+
+ // Create global JS object
+ global = JS_NewObject(cx, &jsGlobalClass, NULL, NULL);
+ if(global == NULL) {
+ cleanup();
+ return;
+ }
+
+ // Populate global object with the standard globals, like Object and Array
+ if(!JS_InitStandardClasses(cx, global)) {
+ cleanup();
+ return;
+ }
+ }
+
+ ~JSContext() {
+ cleanup();
+ }
+
+ operator ::JSContext*() const {
+ return cx;
+ }
+
+ JSObject* getGlobal() const {
+ return global;
+ }
+
+private:
+ bool cleanup() {
+ if(cx != NULL) {
+ JS_DestroyContext(cx);
+ cx = NULL;
+ }
+ return true;
+ }
+
+ ::JSContext* cx;
+ JSObject* global;
+};
+
+/**
+ * Returns true if a list represents a JS array.
+ */
+const bool isJSArray(const list<value>& l) {
+ if(isNil(l))
+ return true;
+ const value v = car(l);
+ if (isSymbol(v))
+ return false;
+ if(isList(v)) {
+ if(!isNil((list<value>)v) && isSymbol(car<value>(v)))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Converts JS properties to values.
+ */
+const list<value> jsPropertiesToValues(const list<value>& propertiesSoFar, JSObject* o, JSObject* i, const js::JSContext& cx) {
+
+ const value jsValToValue(const jsval& jsv, const js::JSContext& cx);
+
+ jsid id;
+ if(!JS_NextProperty(cx, i, &id) || id == JSVAL_VOID)
+ return propertiesSoFar;
+ jsval jsv;
+ if(!JS_GetPropertyById(cx, o, id, &jsv))
+ return propertiesSoFar;
+ const value val = jsValToValue(jsv, cx);
+
+ jsval idv;
+ JS_IdToValue(cx, id, &idv);
+ if(JSVAL_IS_STRING(idv)) {
+ if (isNil(val) && !isList(val))
+ return jsPropertiesToValues(propertiesSoFar, o, i, cx);
+ const string name = JS_GetStringBytes(JSVAL_TO_STRING(idv));
+ if (substr(name, 0, 1) == atsign)
+ return jsPropertiesToValues(cons<value>(mklist<value>(attribute, c_str(substr(name, 1)), val), propertiesSoFar), o, i, cx);
+ if (isList(val) && !isJSArray(val))
+ return jsPropertiesToValues(cons<value>(cons<value>(element, cons<value>(c_str(name), list<value>(val))), propertiesSoFar), o, i, cx);
+ return jsPropertiesToValues(cons<value> (mklist<value> (element, c_str(name), val), propertiesSoFar), o, i, cx);
+ }
+ return jsPropertiesToValues(cons(val, propertiesSoFar), o, i, cx);
+}
+
+/**
+ * Converts a JS val to a value.
+ */
+const value jsValToValue(const jsval& jsv, const js::JSContext& cx) {
+ switch(JS_TypeOfValue(cx, jsv)) {
+ case JSTYPE_STRING: {
+ return value(string(JS_GetStringBytes(JSVAL_TO_STRING(jsv))));
+ }
+ case JSTYPE_BOOLEAN: {
+ return value((bool)JSVAL_TO_BOOLEAN(jsv));
+ }
+ case JSTYPE_NUMBER: {
+ jsdouble jsd;
+ JS_ValueToNumber(cx, jsv, &jsd);
+ return value((double)jsd);
+ }
+ case JSTYPE_OBJECT: {
+ JSObject* o = JSVAL_TO_OBJECT(jsv);
+ if (o == NULL)
+ return value();
+ JSObject* i = JS_NewPropertyIterator(cx, o);
+ if(i == NULL)
+ return value(list<value> ());
+ const value pv = jsPropertiesToValues(list<value> (), o, i, cx);
+ return pv;
+ }
+ default: {
+ return value();
+ }
+ }
+}
+
+/**
+ * Converts a list of values to JS array elements.
+ */
+JSObject* valuesToJSElements(JSObject* a, const list<value>& l, int i, const js::JSContext& cx) {
+ const jsval valueToJSVal(const value& val, const js::JSContext& cx);
+ if (isNil(l))
+ return a;
+ jsval pv = valueToJSVal(car(l), cx);
+ JS_SetElement(cx, a, i, &pv);
+ return valuesToJSElements(a, cdr(l), ++i, cx);
+}
+
+/**
+ * Converts a value to a JS val.
+ */
+const jsval valueToJSVal(const value& val, const js::JSContext& cx) {
+ JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const js::JSContext& cx);
+
+ switch(type(val)) {
+ case value::String: {
+ return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, c_str((string)val)));
+ }
+ case value::Symbol: {
+ return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, c_str((string)val)));
+ }
+ case value::Bool: {
+ return BOOLEAN_TO_JSVAL((bool)val);
+ }
+ case value::Number: {
+ return DOUBLE_TO_JSVAL(JS_NewDouble(cx, (double)val));
+ }
+ case value::List: {
+ if (isJSArray(val))
+ return OBJECT_TO_JSVAL(valuesToJSElements(JS_NewArrayObject(cx, 0, NULL), val, 0, cx));
+ return OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), val, cx));
+ }
+ default: {
+ return JSVAL_VOID;
+ }
+ }
+}
+
+/**
+ * Converts a list of values to JS properties.
+ */
+JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const js::JSContext& cx) {
+ if (isNil(l))
+ return o;
+
+ // Write an attribute
+ const value token(car(l));
+
+ if (isTaggedList(token, attribute)) {
+ jsval pv = valueToJSVal(attributeValue(token), cx);
+ JS_SetProperty(cx, o, c_str(atsign + string(attributeName(token))), &pv);
+
+ } else if (isTaggedList(token, element)) {
+
+ // Write the value of an element
+ if (elementHasValue(token)) {
+ jsval pv = valueToJSVal(elementValue(token), cx);
+ JS_SetProperty(cx, o, c_str(string(elementName(token))), &pv);
+
+ } else {
+
+ // Write a parent element
+ JSObject* child = JS_NewObject(cx, NULL, NULL, NULL);
+ jsval pv = OBJECT_TO_JSVAL(child);
+ JS_SetProperty(cx, o, c_str(string(elementName(token))), &pv);
+
+ // Write its children
+ valuesToJSProperties(child, elementChildren(token), cx);
+ }
+ }
+
+ // Go on
+ return valuesToJSProperties(o, cdr(l), cx);
+}
+
+/**
+ * Evaluate a script provided as a string.
+ */
+const failable<value> evalScript(const string& s) {
+ js::JSContext cx;
+ jsval rval;
+ JSBool rc = JS_EvaluateScript(cx, cx.getGlobal(), c_str(s), (uintN)length(s), "eval.js", 1, &rval);
+ if (rc != JS_TRUE) {
+ return mkfailure<value>("Couldn't evaluate Javascript script.");
+ }
+ return jsValToValue(rval, cx);
+}
+
+}
+}
+
+#endif /* tuscany_js_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js
new file mode 100644
index 0000000000..6b998dceda
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+/**
+ * ATOM data conversion functions.
+ */
+var atom = new Object();
+
+/**
+ * Convert a list of elements to a list of values representing an ATOM entry.
+ */
+atom.entryElementsToValues = function(e) {
+ var lt = filter(selector(mklist(element, "'title")), e);
+ var t = isNil(lt)? '' : elementValue(car(lt));
+ var li = filter(selector(mklist(element, "'id")), e);
+ var i = isNil(li)? '' : elementValue(car(li));
+ var lc = filter(selector(mklist(element, "'content")), e);
+ return mklist(t, i, elementValue(car(lc)));
+};
+
+/**
+ * Convert a list of elements to a list of values representing ATOM entries.
+ */
+atom.entriesElementsToValues = function(e) {
+ if (isNil(e))
+ return e;
+ return cons(atom.entryElementsToValues(car(e)), atom.entriesElementsToValues(cdr(e)));
+};
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM entry.
+ */
+atom.readATOMEntry = function(l) {
+ var e = readXML(l);
+ if (isNil(e))
+ return mklist();
+ return atom.entryElementsToValues(car(e));
+};
+
+/**
+ * Convert a list of values representy an ATOM entry to a value.
+ */
+atom.entryValue = function(e) {
+ var v = elementsToValues(mklist(caddr(e)));
+ return cons(car(e), (cadr(e), cdr(car(v))));
+};
+
+/**
+ * Return true if a list of strings represents an ATOM feed.
+ */
+atom.isATOMFeed = function(l) {
+ if (!isXML(l))
+ return false;
+ return car(l).match('<feed') != null && car(l).match('="http://www.w3.org/2005/Atom"') != null;
+};
+
+/**
+ * Convert a DOM document to a list of values representing an ATOM feed.
+ */
+atom.readATOMFeedDocument = function(doc) {
+ var f = readXMLDocument(doc);
+ if (isNil(f))
+ return mklist();
+ var t = filter(selector(mklist(element, "'title")), car(f));
+ var i = filter(selector(mklist(element, "'id")), car(f));
+ var e = filter(selector(mklist(element, "'entry")), car(f));
+ if (isNil(e))
+ return mklist(elementValue(car(t)), elementValue(car(i)));
+ return cons(elementValue(car(t)), cons(elementValue(car(i)), atom.entriesElementsToValues(e)));
+};
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM feed.
+ */
+atom.readATOMFeed = function(l) {
+ return atom.readAtomFeedDocument(parseXML(l));
+};
+
+/**
+ * Convert an ATOM feed containing elements to an ATOM feed containing values.
+ */
+atom.feedValues = function(e) {
+ function feedValuesLoop(e) {
+ if (isNil(e))
+ return e;
+ return cons(entryValue(car(e)), feedValuesLoop(cdr(e)));
+ }
+
+ return cons(car(e), cons(cadr(e), feedValuesLoop(cddr(e))));
+};
+
+/**
+ * Convert a list of values representy an ATOM entry to a list of elements.
+ */
+atom.entryElement = function(l) {
+ return mklist(element, "'entry", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ mklist(element, "'title", mklist(attribute, "'type", "text"), car(l)),
+ mklist(element, "'id", cadr(l)),
+ mklist(element, "'content", mklist(attribute, "'type", (isList(caddr(l))? "application/xml" : "text")), caddr(l)),
+ mklist(element, "'link", mklist(attribute, "'href", cadr(l))));
+};
+
+/**
+ * Convert a list of values representing ATOM entries to a list of elements.
+ */
+atom.entriesElements = function(l) {
+ if (isNil(l))
+ return l;
+ return cons(atom.entryElement(car(l)), atom.entriesElements(cdr(l)));
+};
+
+/**
+ * Convert a list of values representing an ATOM entry to an ATOM entry.
+ */
+atom.writeATOMEntry = function(l) {
+ return writeXML(mklist(atom.entryElement(l)), true);
+};
+
+/**
+ * Convert a list of values representing an ATOM feed to an ATOM feed.
+ */
+atom.writeATOMFeed = function(l) {
+ var f = mklist(element, "'feed", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ mklist(element, "'title", mklist(attribute, "'type", "text"), car(l)),
+ mklist(element, "'id", cadr(l)));
+ if (isNil(cddr(l)))
+ return writeXML(mklist(f), true);
+ var fe = append(f, atom.entriesElements(cddr(l)));
+ return writeXML(mklist(fe), true);
+};
+
+/**
+ * Convert an ATOM entry containing a value to an ATOM entry containing an item element.
+ */
+atom.entryValuesToElements = function(v) {
+ if (isList(caddr(v)))
+ return cons(car(v), cons(cadr(v), valuesToElements(mklist(cons("'item", caddr(v))))));
+ return cons(car(v), cons(cadr(v), valuesToElements(mklist(mklist("'item", caddr(v))))));
+};
+
+/**
+ * Convert an ATOM feed containing values to an ATOM feed containing elements.
+ */
+atom.feedValuesToElements = function(v) {
+ function feedValuesToElementsLoop(v) {
+ if (isNil(v))
+ return v;
+ return cons(atom.entryValuesToElements(car(v)), feedValuesToElementsLoop(cdr(v)));
+ }
+
+ return cons(car(v), cons(cadr(v), feedValuesToElementsLoop(cddr(v))));
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js
new file mode 100644
index 0000000000..9ce6aa86e5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js
@@ -0,0 +1,561 @@
+/*
+ * 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.
+ *
+ * The JSON-RPC client code is based on Jan-Klaas' JavaScript
+ * o lait library (jsolait).
+ *
+ * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $
+ *
+ * Copyright (c) 2003-2004 Jan-Klaas Kollhof
+ * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ */
+
+/**
+ * Client component wiring API, supporting JSON and ATOM bindings.
+ */
+
+/**
+ * Escape a character.
+ */
+var JSONClient = new Object();
+
+JSONClient.escapeJSONChar = function(c) {
+ if(c == "\"" || c == "\\") return "\\" + c;
+ else if (c == "\b") return "\\b";
+ else if (c == "\f") return "\\f";
+ else if (c == "\n") return "\\n";
+ else if (c == "\r") return "\\r";
+ else if (c == "\t") return "\\t";
+ var hex = c.charCodeAt(0).toString(16);
+ if(hex.length == 1) return "\\u000" + hex;
+ else if(hex.length == 2) return "\\u00" + hex;
+ else if(hex.length == 3) return "\\u0" + hex;
+ else return "\\u" + hex;
+};
+
+/**
+ * Encode a string into JSON format.
+ */
+JSONClient.escapeJSONString = function(s) {
+ /* The following should suffice but Safari's regex is broken
+ (doesn't support callback substitutions)
+ return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g,
+ JSONClient.escapeJSONChar) + "\"";
+ */
+
+ /* Rather inefficient way to do it */
+ var parts = s.split("");
+ for(var i = 0; i < parts.length; i++) {
+ var c = parts[i];
+ if(c == '"' ||
+ c == '\\' ||
+ c.charCodeAt(0) < 32 ||
+ c.charCodeAt(0) >= 128)
+ parts[i] = JSONClient.escapeJSONChar(parts[i]);
+ }
+ return "\"" + parts.join("") + "\"";
+};
+
+/**
+ * Marshall objects to JSON format.
+ */
+JSONClient.toJSON = function(o) {
+ if(o == null) {
+ return "null";
+ } else if(o.constructor == String) {
+ return JSONClient.escapeJSONString(o);
+ } else if(o.constructor == Number) {
+ return o.toString();
+ } else if(o.constructor == Boolean) {
+ return o.toString();
+ } else if(o.constructor == Date) {
+ return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
+ } else if(o.constructor == Array) {
+ var v = [];
+ for(var i = 0; i < o.length; i++) v.push(JSONClient.toJSON(o[i]));
+ return "[" + v.join(", ") + "]";
+ } else {
+ var v = [];
+ for(attr in o) {
+ if(o[attr] == null) v.push("\"" + attr + "\": null");
+ else if(typeof o[attr] == "function"); /* skip */
+ else v.push(JSONClient.escapeJSONString(attr) + ": " + JSONClient.toJSON(o[attr]));
+ }
+ return "{" + v.join(", ") + "}";
+ }
+};
+
+/**
+ * Construct an HTTPBindingClient.
+ */
+function HTTPBindingClient(cname, uri, objectID) {
+ this.uri = "/references/" + cname + "/" + uri;
+ this.objectID = objectID;
+ this.apply = this._createApplyMethod();
+
+ if (typeof DOMParser == "undefined") {
+ DOMParser = function () {}
+
+ DOMParser.prototype.parseFromString = function (str, contentType) {
+ if (typeof ActiveXObject != "undefined") {
+ var d = new ActiveXObject("MSXML.DomDocument");
+ d.loadXML(str);
+ return d;
+ } else if (typeof XMLHttpRequest != "undefined") {
+ var req = new XMLHttpRequest;
+ req.open("GET", "data:" + (contentType || "application/xml") +
+ ";charset=utf-8," + encodeURIComponent(str), false);
+ if (req.overrideMimeType) {
+ req.overrideMimeType(contentType);
+ }
+ req.send(null);
+ return req.responseXML;
+ }
+ }
+ }
+}
+
+/**
+ * HTTPBindingClient.Exception.
+ */
+HTTPBindingClient.Exception = function(code, message, javaStack) {
+ this.code = code;
+ var name;
+ if(javaStack) {
+ this.javaStack = javaStack;
+ var m = javaStack.match(/^([^:]*)/);
+ if(m) name = m[0];
+ }
+ if(name) this.name = name;
+ else this.name = "HTTPBindingClientException";
+ this.message = message;
+};
+
+HTTPBindingClient.Exception.CODE_REMOTE_EXCEPTION = 490;
+HTTPBindingClient.Exception.CODE_ERR_CLIENT = 550;
+HTTPBindingClient.Exception.CODE_ERR_PARSE = 590;
+HTTPBindingClient.Exception.CODE_ERR_NOMETHOD = 591;
+HTTPBindingClient.Exception.CODE_ERR_UNMARSHALL = 592;
+HTTPBindingClient.Exception.CODE_ERR_MARSHALL = 593;
+
+HTTPBindingClient.Exception.prototype = new Error();
+HTTPBindingClient.Exception.prototype.toString = function(code, msg) {
+ return this.name + ": " + this.message;
+};
+
+/**
+ * Default top level exception handler.
+ */
+HTTPBindingClient.default_ex_handler = function(e) {
+ alert(e);
+};
+
+/**
+ * Client settable variables
+ */
+HTTPBindingClient.toplevel_ex_handler = HTTPBindingClient.default_ex_handler;
+HTTPBindingClient.profile_async = false;
+HTTPBindingClient.max_req_active = 1;
+HTTPBindingClient.requestId = 1;
+
+/**
+ * HTTPBindingClient implementation
+ */
+HTTPBindingClient.prototype._createApplyMethod = function() {
+ var fn = function() {
+ var args = [];
+ var callback = null;
+ var methodName = arguments[0];
+ for(var i = 1; i < arguments.length; i++) args.push(arguments[i]);
+
+ if(typeof args[args.length - 1] == "function") callback = args.pop();
+
+ var req = fn.client._makeRequest.call(fn.client, methodName, args, callback);
+ if(callback == null) {
+ return fn.client._sendRequest.call(fn.client, req);
+ } else {
+ HTTPBindingClient.async_requests.push(req);
+ HTTPBindingClient.kick_async();
+ return req.requestId;
+ }
+ };
+ fn.client = this;
+ return fn;
+};
+
+HTTPBindingClient._getCharsetFromHeaders = function(http) {
+ try {
+ var contentType = http.getResponseHeader("Content-type");
+ var parts = contentType.split(/\s*;\s*/);
+ for(var i = 0; i < parts.length; i++) {
+ if(parts[i].substring(0, 8) == "charset=")
+ return parts[i].substring(8, parts[i].length);
+ }
+ } catch (e) {}
+ return "UTF-8";
+};
+
+/**
+ * Async queue globals
+ */
+HTTPBindingClient.async_requests = [];
+HTTPBindingClient.async_inflight = {};
+HTTPBindingClient.async_responses = [];
+HTTPBindingClient.async_timeout = null;
+HTTPBindingClient.num_req_active = 0;
+
+HTTPBindingClient._async_handler = function() {
+ HTTPBindingClient.async_timeout = null;
+
+ while(HTTPBindingClient.async_responses.length > 0) {
+ var res = HTTPBindingClient.async_responses.shift();
+ if(res.canceled) continue;
+ if(res.profile) res.profile.dispatch = new Date();
+ try {
+ res.cb(res.result, res.ex, res.profile);
+ } catch(e) {
+ HTTPBindingClient.toplevel_ex_handler(e);
+ }
+ }
+
+ while(HTTPBindingClient.async_requests.length > 0 && HTTPBindingClient.num_req_active < HTTPBindingClient.max_req_active) {
+ var req = HTTPBindingClient.async_requests.shift();
+ if(req.canceled) continue;
+ req.client._sendRequest.call(req.client, req);
+ }
+};
+
+HTTPBindingClient.kick_async = function() {
+ if(HTTPBindingClient.async_timeout == null)
+ HTTPBindingClient.async_timeout = setTimeout(HTTPBindingClient._async_handler, 0);
+};
+
+HTTPBindingClient.cancelRequest = function(requestId) {
+ /* If it is in flight then mark it as canceled in the inflight map
+ and the XMLHttpRequest callback will discard the reply. */
+ if(HTTPBindingClient.async_inflight[requestId]) {
+ HTTPBindingClient.async_inflight[requestId].canceled = true;
+ return true;
+ }
+
+ /* If its not in flight yet then we can just mark it as canceled in
+ the the request queue and it will get discarded before being sent. */
+ for(var i in HTTPBindingClient.async_requests) {
+ if(HTTPBindingClient.async_requests[i].requestId == requestId) {
+ HTTPBindingClient.async_requests[i].canceled = true;
+ return true;
+ }
+ }
+
+ /* It may have returned from the network and be waiting for its callback
+ to be dispatched, so mark it as canceled in the response queue
+ and the response will get discarded before calling the callback. */
+ for(var i in HTTPBindingClient.async_responses) {
+ if(HTTPBindingClient.async_responses[i].requestId == requestId) {
+ HTTPBindingClient.async_responses[i].canceled = true;
+ return true;
+ }
+ }
+
+ return false;
+};
+
+HTTPBindingClient.prototype._makeRequest = function(methodName, args, cb) {
+ var req = {};
+ req.client = this;
+ req.requestId = HTTPBindingClient.requestId++;
+
+ var obj = {};
+ obj.id = req.requestId;
+ if (this.objectID)
+ obj.method = ".obj#" + this.objectID + "." + methodName;
+ else
+ obj.method = methodName;
+ obj.params = args;
+
+ if (cb) req.cb = cb;
+ if (HTTPBindingClient.profile_async)
+ req.profile = { "submit": new Date() };
+ req.data = JSONClient.toJSON(obj);
+
+ return req;
+};
+
+HTTPBindingClient.prototype._sendRequest = function(req) {
+ if(req.profile) req.profile.start = new Date();
+
+ /* Get free http object from the pool */
+ var http = HTTPBindingClient.poolGetHTTPRequest();
+ HTTPBindingClient.num_req_active++;
+
+ /* Send the request */
+ http.open("POST", this.uri, (req.cb != null));
+ http.setRequestHeader("Content-type", "application/json-rpc");
+
+ /* Construct call back if we have one */
+ if(req.cb) {
+ var self = this;
+ http.onreadystatechange = function() {
+ if(http.readyState == 4) {
+ http.onreadystatechange = function () {};
+ var res = { "cb": req.cb, "result": null, "ex": null};
+ if (req.profile) {
+ res.profile = req.profile;
+ res.profile.end = new Date();
+ }
+ try { res.result = self._handleResponse(http); }
+ catch(e) { res.ex = e; }
+ if(!HTTPBindingClient.async_inflight[req.requestId].canceled)
+ HTTPBindingClient.async_responses.push(res);
+ delete HTTPBindingClient.async_inflight[req.requestId];
+ HTTPBindingClient.kick_async();
+ }
+ };
+ } else {
+ http.onreadystatechange = function() {};
+ }
+
+ HTTPBindingClient.async_inflight[req.requestId] = req;
+
+ try {
+ http.send(req.data);
+ } catch(e) {
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+ throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed");
+ }
+
+ if(!req.cb) return this._handleResponse(http);
+};
+
+HTTPBindingClient.prototype._handleResponse = function(http) {
+ /* Get the charset */
+ if(!this.charset) {
+ this.charset = HTTPBindingClient._getCharsetFromHeaders(http);
+ }
+
+ /* Get request results */
+ var status, statusText, data;
+ try {
+ status = http.status;
+ statusText = http.statusText;
+ data = http.responseText;
+ } catch(e) {
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+ HTTPBindingClient.kick_async();
+ throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed");
+ }
+
+ /* Return http object to the pool; */
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+
+ /* Unmarshall the response */
+ if(status != 200) {
+ throw new HTTPBindingClient.Exception(status, statusText);
+ }
+ var obj;
+ try {
+ eval("obj = " + data);
+ } catch(e) {
+ throw new HTTPBindingClient.Exception(550, "error parsing result");
+ }
+ if(obj.error)
+ throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg, obj.error.trace);
+ var res = obj.result;
+
+ /* Handle CallableProxy */
+ if(res && res.objectID && res.JSONRPCType == "CallableReference")
+ return new HTTPBindingClient(this.uri, res.objectID);
+
+ return res;
+};
+
+
+/**
+ * XMLHttpRequest wrapper code
+ */
+HTTPBindingClient.http_spare = [];
+HTTPBindingClient.http_max_spare = 8;
+
+HTTPBindingClient.poolGetHTTPRequest = function() {
+ if(HTTPBindingClient.http_spare.length > 0) {
+ return HTTPBindingClient.http_spare.pop();
+ }
+ return HTTPBindingClient.getHTTPRequest();
+};
+
+HTTPBindingClient.poolReturnHTTPRequest = function(http) {
+ if(HTTPBindingClient.http_spare.length >= HTTPBindingClient.http_max_spare)
+ delete http;
+ else
+ HTTPBindingClient.http_spare.push(http);
+};
+
+HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0",
+ "MSXML2.XMLHTTP.4.0",
+ "MSXML2.XMLHTTP.3.0",
+ "MSXML2.XMLHTTP",
+ "Microsoft.XMLHTTP" ];
+
+HTTPBindingClient.getHTTPRequest = function() {
+ /* Mozilla XMLHttpRequest */
+ try {
+ HTTPBindingClient.httpObjectName = "XMLHttpRequest";
+ return new XMLHttpRequest();
+ } catch(e) {}
+
+ /* Microsoft MSXML ActiveX */
+ for (var i=0; i < HTTPBindingClient.msxmlNames.length; i++) {
+ try {
+ HTTPBindingClient.httpObjectName = HTTPBindingClient.msxmlNames[i];
+ return new ActiveXObject(HTTPBindingClient.msxmlNames[i]);
+ } catch (e) {}
+ }
+
+ /* None found */
+ HTTPBindingClient.httpObjectName = null;
+ throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object");
+};
+
+
+HTTPBindingClient.prototype.get = function(id, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("get - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("GET", this.uri + '/' + id, true);
+ xhr.send(null);
+};
+
+HTTPBindingClient.prototype.post = function (entry, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 201) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("post - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("POST", this.uri, true);
+ xhr.setRequestHeader("Content-Type", "application/atom+xml;type=entry");
+ xhr.send(entry);
+};
+
+HTTPBindingClient.prototype.put = function (id, entry, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("put - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("PUT", this.uri + '/' + id, true);
+ xhr.setRequestHeader("Content-Type", "application/atom+xml;type=entry");
+ xhr.send(entry);
+};
+
+HTTPBindingClient.prototype.del = function (id, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ if (responseFunction != null) responseFunction();
+ } else {
+ alert("delete - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("DELETE", this.uri + '/' + id, true);
+ xhr.send(null);
+};
+
+/**
+ * Public API.
+ */
+
+var sca = new Object();
+
+/**
+ * Return a component.
+ */
+sca.component = function(name) {
+ function ClientComponent(name) {
+ this.name = name;
+ }
+
+ return new ClientComponent(name);
+};
+
+/**
+ * Return a reference proxy.
+ */
+sca.reference = function(comp, name) {
+ return new HTTPBindingClient(comp.name, name);
+};
+
+/**
+ * Add proxy functions to a reference proxy.
+ */
+sca.defun = function(ref) {
+ function defapply(name) {
+ return function() {
+ var args = new Array();
+ args[0] = name;
+ for (i = 0, n = arguments.length; i < n; i++)
+ args[i + 1] = arguments[i];
+ return this.apply.apply(this, args);
+ };
+ }
+
+ for (f = 1; f < arguments.length; f++) {
+ var fn = arguments[f];
+ ref[fn]= defapply(fn);
+ }
+ return ref;
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js
new file mode 100644
index 0000000000..00baab06c8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+/**
+ * Functions to help represent data as lists of elements and attributes.
+ */
+
+var element = "'element"
+var attribute = "'attribute"
+var atsign = "'@"
+
+/**
+ * Return true if a value is an element.
+ */
+function isElement(v) {
+ if (!isList(v) || isNil(v) || car(v) != element)
+ return false;
+ return true;
+}
+
+/**
+ * Return true if a value is an attribute.
+ */
+function isAttribute(v) {
+ if (!isList(v) || isNil(v) || car(v) != attribute)
+ return false;
+ return true;
+}
+
+/**
+ * Return the name of an attribute.
+ */
+function attributeName(l) {
+ return cadr(l);
+}
+
+/**
+ * Return the value of an attribute.
+ */
+function attributeValue(l) {
+ return caddr(l);
+}
+
+/**
+ * Return the name of an element.
+ */
+function elementName(l) {
+ return cadr(l);
+}
+
+/**
+ * Return true if an element has children.
+ */
+function elementHasChildren(l) {
+ return !isNil(cddr(l));
+}
+
+/**
+ * Return the children of an element.
+ */
+function elementChildren(l) {
+ return cddr(l);
+}
+
+
+/**
+ * Return true if an element has a value.
+ */
+function elementHasValue(l) {
+ r = reverse(l);
+ if (isSymbol(car(r)))
+ return false;
+ if (isList(car(r)) && !isNil(car(r)) && isSymbol(car(car(r))))
+ return false;
+ return true;
+}
+
+/**
+ * Return the value of an element.
+ */
+function elementValue(l) {
+ return car(reverse(l));
+}
+
+/**
+ * Convert an element to a value.
+ */
+function elementToValueIsList(v) {
+ if (!isList(v))
+ return false;
+ return isNil(v) || !isSymbol(car(v));
+}
+
+function elementToValue(t) {
+ if (isTaggedList(t, attribute))
+ return mklist(atsign + attributeName(t).substring(1), attributeValue(t));
+ if (isTaggedList(t, element)) {
+ if (elementHasValue(t)) {
+ if (!elementToValueIsList(elementValue(t)))
+ return mklist(elementName(t), elementValue(t));
+ return cons(elementName(t), mklist(elementsToValues(elementValue(t))));
+ }
+ return cons(elementName(t), elementsToValues(elementChildren(t)));
+ }
+ if (!isList(t))
+ return t;
+ return elementsToValues(t);
+}
+
+/**
+ * Convert a list of elements to a list of values.
+ */
+function elementToValueIsSymbol(v) {
+ if (!isList(v))
+ return false;
+ if (isNil(v))
+ return false;
+ if (!isSymbol(car(v)))
+ return false;
+ return true;
+}
+
+function elementToValueGroupValues(v, l) {
+ if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l)))
+ return cons(v, l);
+ if (car(car(l)) != car(v))
+ return cons(v, l);
+ if (!elementToValueIsList(cadr(car(l)))) {
+ var g = mklist(car(v), mklist(cdr(v), cdr(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+ }
+ var g = mklist(car(v), cons(cdr(v), cadr(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+}
+
+function elementsToValues(e) {
+ if (isNil(e))
+ return e;
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)));
+}
+
+/**
+ * Convert a value to an element.
+ */
+function valueToElement(t) {
+ if (isList(t) && !isNil(t) && isSymbol(car(t))) {
+ var n = car(t);
+ var v = isNil(cdr(t))? mklist() : cadr(t);
+ if (!isList(v)) {
+ if (n.substring(0, 2) == atsign)
+ return mklist(attribute, n.substring(1), v);
+ return mklist(element, n, v);
+ }
+ if (isNil(v) || !isSymbol(car(v)))
+ return cons(element, cons(n, mklist(valuesToElements(v))));
+ return cons(element, cons(n, valuesToElements(cdr(t))));
+ }
+ if (!isList(t))
+ return t;
+ return valuesToElements(t);
+}
+
+/**
+ * Convert a list of values to a list of elements.
+ */
+function valuesToElements(l) {
+ if (isNil(l))
+ return l;
+ return cons(valueToElement(car(l)), valuesToElements(cdr(l)));
+}
+
+/**
+ * Return a selector lambda function which can be used to filter elements.
+ */
+function selector(s) {
+ function evalSelect(s, v) {
+ if (isNil(s))
+ return true;
+ if (isNil(v))
+ return false;
+ if (car(s) != car(v))
+ return false;
+ return evalSelect(cdr(s), cdr(v));
+ }
+
+ return function(v) { return evalSelect(s, v); };
+}
+
+/**
+ * Return the value of the attribute with the given name.
+ */
+function namedAttributeValue(name, l) {
+ var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l);
+ if (isNil(f))
+ return null;
+ return caddr(car(f));
+}
+
+/**
+ * Return child elements with the given name.
+ */
+function namedElementChildren(name, l) {
+ return filter(function(v) { return isElement(v) && elementName(v) == name; }, l);
+}
+
+/**
+ * Return the child element with the given name.
+ */
+function namedElementChild(name, l) {
+ var f = namedElementChildren(name, l);
+ if (isNil(f))
+ return null;
+ return car(f);
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js
new file mode 100644
index 0000000000..883b3aa801
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js
@@ -0,0 +1,638 @@
+/*
+ * 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.
+ */
+
+/**
+ * SVG and VML component rendering functions.
+ */
+
+var graph = new Object();
+
+/**
+ * Detect browser VML support.
+ */
+graph.supportsVML = function() {
+ if (typeof graph.supportsVML.supported != 'undefined')
+ return graph.supportsVML.supported;
+ graph.supportsVML.supported = navigator.appName == 'Microsoft Internet Explorer';
+ return graph.supportsVML.supported;
+};
+
+/**
+ * Detect browser SVG support.
+ */
+graph.supportsSVG = function() {
+ if (typeof graph.supportsSVG.supported != 'undefined')
+ return graph.supportsSVG.supported;
+ graph.supportsSVG.supported = navigator.appName != 'Microsoft Internet Explorer';
+ return graph.supportsSVG.supported;
+};
+
+/**
+ * Basic colors
+ */
+graph.red = 'red';
+graph.green = 'green';
+graph.blue = 'blue';
+graph.yellow = 'yellow';
+graph.orange = '#ffa500';
+graph.gray = 'gray'
+
+/**
+ * Base path class.
+ */
+graph.BasePath = function() {
+ this.path = '';
+ this.x = 0;
+ this.y = 0;
+
+ this.pos = function(x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ };
+
+ this.xpos = function() {
+ return this.x;
+ };
+
+ this.ypos = function() {
+ return this.y;
+ };
+
+ this.rmove = function(x, y) {
+ return this.move(this.x + x, this.y + y);
+ };
+
+ this.rline = function(x, y) {
+ return this.line(this.x + x, this.y + y);
+ };
+
+ this.rcurve = function(x1, y1, x, y) {
+ return this.curve(this.x + x1, this.y + y1, this.x + x1 + x, this.y + y1 + y);
+ };
+
+ this.str = function() {
+ return this.path;
+ };
+};
+
+/**
+ * Rendering functions that work both with VML and SVG.
+ */
+var graph;
+
+/**
+ * VML rendering.
+ */
+if (graph.supportsVML()) {
+
+ graph.vmlns='urn:schemas-microsoft-com:vml';
+ document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />');
+
+ /**
+ * Make a graph.
+ */
+ graph.mkgraph = function() {
+ var div = document.createElement('div');
+ div.id = 'vmldiv';
+ document.body.appendChild(div);
+
+ var vmlg = document.createElement('v:group');
+ vmlg.style.width = 500;
+ vmlg.style.height = 500;
+ vmlg.coordsize = '500,500';
+ div.appendChild(vmlg);
+
+ graph.dragging = null;
+
+ function draggable(n) {
+ if (n == vmlg)
+ return null;
+ if (n.nodeName == 'group')
+ return n;
+ return draggable(n.parentNode);
+ }
+
+ vmlg.onmousedown = function() {
+ window.event.returnValue = false;
+ graph.dragging = draggable(window.event.srcElement);
+ if (graph.dragging == null)
+ return false;
+ graph.dragging.parentNode.appendChild(graph.dragging);
+ graph.dragX = window.event.clientX;
+ graph.dragY = window.event.clientY;
+ vmlg.setCapture();
+ return false;
+ };
+
+ vmlg.onmouseup = function() {
+ if (graph.dragging == null)
+ return false;
+ graph.dragging = null;
+ vmlg.releaseCapture();
+ return false;
+ };
+
+ vmlg.onmousemove = function() {
+ if (graph.dragging == null)
+ return false;
+ var origX = graph.dragging.coordorigin.X;
+ var origY = graph.dragging.coordorigin.Y;
+ var newX = origX - (window.event.clientX - graph.dragX);
+ var newY = origY - (window.event.clientY - graph.dragY);
+ graph.dragX = window.event.clientX;
+ graph.dragY = window.event.clientY;
+ graph.dragging.setAttribute('coordorigin', newX + ' ' + newY);
+ return false;
+ };
+
+ graph.textWidthDiv = document.createElement('span');
+ graph.textWidthDiv.style.visibility = 'hidden'
+ div.appendChild(graph.textWidthDiv);
+
+ return vmlg;
+ };
+
+ /**
+ * Make a shape path.
+ */
+ graph.mkpath = function() {
+ function Path() {
+ this.BasePath = graph.BasePath;
+ this.BasePath();
+
+ this.move = function(x, y) {
+ this.path += 'M ' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.line = function(x, y) {
+ this.path += 'L ' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.curve = function(x1, y1, x, y) {
+ this.path += 'QB ' + x1 + ',' + y1 + ',' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.end = function() {
+ this.path += 'X E';
+ return this;
+ };
+ }
+
+ return new Path();
+ };
+
+ /**
+ * Make a title element.
+ */
+ graph.mktitle = function(t) {
+ var title = document.createElement('v:textbox');
+ title.style.left = '25';
+ title.style.top = '5';
+ title.style.position = 'absolute';
+ var tnode = document.createTextNode(t);
+ title.appendChild(tnode);
+ return title;
+ };
+
+ /**
+ * Return the width of a title.
+ */
+ graph.titlewidth = function(t) {
+ graph.textWidthDiv.innerHTML = t;
+ var twidth = graph.textWidthDiv.offsetWidth;
+ graph.textWidthDiv.innerHTML = '';
+ return twidth;
+ };
+
+ /**
+ * Make a component shape.
+ */
+ graph.mkcompshape = function(comp, cassoc) {
+ var name = scdl.name(comp);
+ var title = graph.mktitle(name);
+
+ var d = graph.mkcomppath(comp, cassoc).str();
+
+ var shape = document.createElement('v:shape');
+ shape.style.width = 500;
+ shape.style.height = 500;
+ shape.coordsize = '500,500';
+ shape.path = d;
+ shape.fillcolor = graph.color(comp);
+ shape.stroked = 'false';
+
+ var contour = document.createElement('v:shape');
+ contour.style.width = 500;
+ contour.style.height = 500;
+ contour.coordsize = '500,500';
+ contour.setAttribute('path', d);
+ contour.filled = 'false';
+ contour.strokecolor = graph.gray;
+ contour.strokeweight = '3';
+ contour.style.top = 1;
+ contour.style.left = 1;
+ var stroke = document.createElement('v:stroke');
+ stroke.opacity = '20%';
+ contour.appendChild(stroke);
+
+ var g = document.createElement('v:group');
+ g.style.width = 500;
+ g.style.height = 500;
+ g.coordsize = '500,500';
+ g.appendChild(shape);
+ g.appendChild(contour);
+ g.appendChild(title);
+ return g;
+ };
+}
+
+/**
+ * SVG rendering.
+ */
+if (graph.supportsSVG()) {
+
+ graph.svgns='http://www.w3.org/2000/svg';
+
+ /**
+ * Make a graph.
+ */
+ graph.mkgraph = function() {
+ var div = document.createElement('div');
+ div.id = 'svgdiv';
+ document.body.appendChild(div);
+
+ var svg = document.createElementNS(graph.svgns, 'svg');
+ svg.style.height = '100%';
+ svg.style.width = '100%';
+ div.appendChild(svg);
+
+ graph.dragging = null;
+
+ function draggable(n) {
+ if (n == svg)
+ return null;
+ if (n.nodeName == 'g')
+ return n;
+ return draggable(n.parentNode);
+ }
+
+ svg.onmousedown = function(e) {
+ if (e.preventDefault)
+ e.preventDefault();
+ else
+ e.returnValue= false;
+ graph.dragging = draggable(e.target);
+ if (graph.dragging == null)
+ return false;
+ graph.dragging.parentNode.appendChild(graph.dragging);
+ var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
+ graph.dragX = pos.clientX;
+ graph.dragY = pos.clientY;
+ return false;
+ };
+
+ svg.ontouchstart = svg.onmousedown;
+
+ svg.onmouseup = function(e) {
+ if (graph.dragging == null)
+ return false;
+ graph.dragging = null;
+ return false;
+ };
+
+ svg.ontouchend = svg.onmouseup;
+
+ svg.onmousemove = function(e) {
+ if (graph.dragging == null)
+ return false;
+ var matrix = graph.dragging.getCTM();
+ var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
+ var newX = Number(matrix.e) + (pos.clientX - graph.dragX);
+ var newY = Number(matrix.f) + (pos.clientY - graph.dragY);
+ graph.dragX = pos.clientX;
+ graph.dragY = pos.clientY;
+ graph.dragging.setAttribute('transform', 'translate(' + newX + ',' + newY + ')');
+ return false;
+ };
+
+ svg.ontouchmove = svg.onmousemove;
+
+ graph.textWidthSvg = document.createElementNS(graph.svgns, 'svg');
+ graph.textWidthSvg.style.visibility = 'hidden';
+ graph.textWidthSvg.style.height = '0px';
+ graph.textWidthSvg.style.width = '0px';
+ div.appendChild(graph.textWidthSvg);
+
+ return svg;
+ };
+
+ /**
+ * Make a shape path.
+ */
+ graph.mkpath = function() {
+ function Path() {
+ this.BasePath = graph.BasePath;
+ this.BasePath();
+
+ this.move = function(x, y) {
+ this.path += 'M' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.line = function(x, y) {
+ this.path += 'L' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.curve = function(x1, y1, x, y) {
+ this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.end = function() {
+ this.path += 'Z';
+ return this;
+ };
+ }
+
+ return new Path();
+ };
+
+ /**
+ * Make a title element.
+ */
+ graph.mktitle = function(t) {
+ var title = document.createElementNS(graph.svgns, 'text');
+ title.setAttribute('text-anchor', 'start');
+ title.setAttribute('x', 5);
+ title.setAttribute('y', 15);
+ title.appendChild(document.createTextNode(t));
+ graph.textWidthSvg.appendChild(title);
+ return title;
+ };
+
+ /**
+ * Return a width of a title.
+ */
+ graph.titlewidth = function(t) {
+ var title = graph.mktitle(t);
+ var width = title.getBBox().width;
+ graph.textWidthSvg.removeChild(title);
+ return width;
+ };
+
+ /**
+ * Make a component shape.
+ */
+ graph.mkcompshape = function(comp, cassoc) {
+ var name = scdl.name(comp);
+ var title = graph.mktitle(name);
+
+ var d = graph.mkcomppath(comp, cassoc).str();
+
+ var shape = document.createElementNS(graph.svgns, 'path');
+ shape.setAttribute('d', d);
+ shape.setAttribute('fill', graph.color(comp));
+
+ var contour = document.createElementNS(graph.svgns, 'path');
+ contour.setAttribute('d', d);
+ contour.setAttribute('fill', 'none');
+ contour.setAttribute('stroke', graph.gray);
+ contour.setAttribute('stroke-width', '4');
+ contour.setAttribute('stroke-opacity', '0.20');
+ contour.setAttribute('transform', 'translate(1,1)');
+
+ var g = document.createElementNS(graph.svgns, 'g');
+ g.appendChild(shape);
+ g.appendChild(contour);
+ g.appendChild(title);
+ return g;
+ };
+}
+
+/**
+ * Make a reference shape path, positioned to the right of a component shape.
+ */
+graph.mkrrefpath = function(ref, cassoc, path) {
+ var height = graph.refheight(ref, cassoc);
+ var ypos = path.ypos();
+ return path.rline(0,10).rline(0,10).rcurve(0,5,-5,0).rcurve(-5,0,0,-5).rcurve(0,-5,-5,0).rcurve(-5,0,0,5).rline(0,20).rcurve(0,5,5,0).rcurve(5,0,0,-5).rcurve(0,-5,5,0).rcurve(5,0,0,5).line(path.xpos(),ypos + height);
+};
+
+/**
+ * Make a reference shape path, positioned at the bottom of a component shape.
+ */
+graph.mkbrefpath = function(ref, cassoc, path) {
+ var width = graph.refwidth(ref, cassoc);
+ var xpos = path.xpos();
+ return path.line(xpos - width + 60,path.ypos()).rline(-10,0).rline(-10,0).rcurve(-5,0,0,-5).rcurve(0,-5,5,0).rcurve(5,0,0,-5).rcurve(0,-5,-5,0).rline(-20,0).rcurve(-5,0,0,5).rcurve(0,5,5,0).rcurve(5,0,0,5).rcurve(0,5,-5,0).line(xpos - width,path.ypos());
+};
+
+/**
+ * Make a service shape path, positioned to the left of a component shape.
+ */
+graph.mklsvcpath = function(svc, path) {
+ var height = 60;
+ var ypos = path.ypos();
+ return path.rline(0,-10).rline(0, -10).rcurve(0,-5,-5,0).rcurve(-5,0,0,5).rcurve(0,5,-5,0).rcurve(-5,0,0,-5).rline(0,-20).rcurve(0,-5,5,0).rcurve(5,0,0,5).rcurve(0,5,5,0).rcurve(5,0,0,-5).line(path.xpos(), ypos - height);
+};
+
+/**
+ * Make a service shape path, positioned at the top of a component shape.
+ */
+graph.mktsvcpath = function(svc, path) {
+ var width = 60;
+ var xpos = path.xpos();
+ return path.rline(10,0).rline(10,0).rcurve(5,0,0,-5).rcurve(0,-5,-5,0).rcurve(-5,0,0,-5).rcurve(0,-5,5,0).rline(20,0).rcurve(5,0,0,5).rcurve(0,5,-5,0).rcurve(-5,0,0,5).rcurve(0,5,5,0).line(xpos + width,path.ypos());
+};
+
+
+/**
+ * Return the services and references of a component.
+ */
+graph.tsvcs = function(comp) {
+ return filter(function(s) { return scdl.align(s) == 'top'; }, scdl.services(comp));
+};
+
+graph.lsvcs = function(comp) {
+ return filter(function(s) { var a = scdl.align(s); return a == null || a == 'left'; }, scdl.services(comp));
+};
+
+graph.brefs = function(comp) {
+ return filter(function(r) { return scdl.align(r) == 'bottom'; }, scdl.references(comp));
+};
+
+graph.rrefs = function(comp) {
+ return filter(function(r) { var a = scdl.align(r); return a == null || a == 'right'; }, scdl.references(comp));
+};
+
+/**
+ * Return the color of a component.
+ */
+graph.color = function(comp) {
+ var c = scdl.color(comp);
+ return c == null? graph.blue : c;
+}
+
+/**
+ * Return the height of a reference.
+ */
+graph.refheight = function(ref, cassoc) {
+ var target = assoc(scdl.target(ref), cassoc);
+ if (isNil(target))
+ return 60;
+ return graph.compheight(cadr(target), cassoc);
+}
+
+/**
+ * Return the total height of a list of references.
+ */
+graph.refsheight = function(refs, cassoc) {
+ if (isNil(refs))
+ return 0;
+ return graph.refheight(car(refs), cassoc) + graph.refsheight(cdr(refs), cassoc);
+}
+
+/**
+ * Return the height of a component.
+ */
+graph.compheight = function(comp, cassoc) {
+ var lsvcs = graph.lsvcs(comp);
+ var lsvcsh = Math.max(1, length(lsvcs)) * 60 + 20;
+ var rrefs = graph.rrefs(comp);
+ var rrefsh = graph.refsheight(rrefs, cassoc) + 20;
+ var height = Math.max(lsvcsh, rrefsh);
+ return height;
+};
+
+/**
+ * Return the width of a reference.
+ */
+graph.refwidth = function(ref, cassoc) {
+ var target = assoc(scdl.target(ref), cassoc);
+ if (isNil(target))
+ return 60;
+ return graph.compwidth(cadr(target), cassoc);
+}
+
+/**
+ * Return the total width of a list of references.
+ */
+graph.refswidth = function(refs, cassoc) {
+ if (isNil(refs))
+ return 0;
+ return graph.refwidth(car(refs), cassoc) + graph.refswidth(cdr(refs), cassoc);
+}
+
+/**
+ * Return the width of a component.
+ */
+graph.compwidth = function(comp, cassoc) {
+ var twidth = graph.titlewidth(scdl.name(comp)) + 20;
+ var tsvcs = graph.tsvcs(comp);
+ var tsvcsw = Math.max(1, length(tsvcs)) * 60 + 20;
+ var brefs = graph.brefs(comp);
+ var brefsw = graph.refswidth(brefs, cassoc) + 20;
+ var width = Math.max(twidth, Math.max(tsvcsw, brefsw));
+ return width;
+};
+
+/**
+* Make a component shape path.
+*/
+graph.mkcomppath = function(comp, cassoc) {
+ var tsvcs = graph.tsvcs(comp);
+ var lsvcs = graph.lsvcs(comp);
+ var brefs = graph.brefs(comp);
+ var rrefs = graph.rrefs(comp);
+
+ var height = graph.compheight(comp, cassoc);
+ var width = graph.compwidth(comp, cassoc);
+
+ var path = graph.mkpath().move(10,0);
+ for (var s = 0; s < length(tsvcs); s++)
+ path = graph.mktsvcpath(tsvcs[s], path);
+
+ path = path.line(width - 10,path.ypos()).rcurve(10,0,0,10);
+ for (var r = 0; r < length(rrefs); r++)
+ path = graph.mkrrefpath(rrefs[r], cassoc, path);
+
+ var boffset = 10 + graph.refswidth(brefs, cassoc);
+ path = path.line(path.xpos(),height - 10).rcurve(0,10,-10,0).line(boffset, path.ypos());
+ for (var r = 0; r < length(brefs); r++)
+ path = graph.mkbrefpath(brefs[r], cassoc, path);
+
+ var loffset = 10 + (length(lsvcs) * 60);
+ path = path.line(10,path.ypos()).rcurve(-10,0,0,-10).line(path.xpos(), loffset);
+ for (var s = 0; s < length(lsvcs); s++)
+ path = graph.mklsvcpath(lsvcs[s], path);
+
+ path = path.line(0,10).rcurve(0,-10,10,0);
+ return path.end();
+};
+
+/**
+ * Render a component.
+ */
+graph.component = function(comp, cassoc) {
+ return graph.mkcompshape(comp, cassoc);
+};
+
+/**
+ * Render a composite.
+ */
+graph.composite = function(compos) {
+ var name = scdl.name(compos);
+ var comps = scdl.components(compos);
+ var cassoc = scdl.nameToElementAssoc(comps);
+
+ function renderReference(ref, cassoc) {
+ var target = assoc(scdl.target(ref), cassoc);
+ if (isNil(target))
+ return mklist();
+ return renderComponent(cadr(target), cassoc);
+ }
+
+ function renderReferences(refs, cassoc) {
+ if (isNil(refs))
+ return mklist();
+ var rref = renderReference(car(refs), cassoc);
+ if (isNil(rref))
+ return renderReferences(cdr(refs), cassoc);
+ return append(rref, renderReferences(cdr(refs), cassoc));
+ }
+
+ function renderComponent(comp, cassoc) {
+ return append(renderReferences(scdl.references(comp), cassoc), mklist(graph.component(comp, cassoc)));
+ }
+
+ function renderComponents(comps, cassoc) {
+ if (isNil(comps))
+ return mklist();
+ return append(renderComponent(car(comps), cassoc), renderComponents(cdr(comps), cassoc));
+ }
+
+ var rcomps = renderComponents(comps, cassoc);
+ return rcomps;
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js
new file mode 100644
index 0000000000..baba0078fe
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+/**
+ * SCDL parsing functions.
+ */
+var scdl = new Object();
+
+/**
+ * Returns a list of components in a composite.
+ */
+scdl.components = function(l) {
+ var cs = namedElementChildren("'composite", l);
+ if (isNil(cs))
+ return cs;
+ return namedElementChildren("'component", car(cs));
+};
+
+/**
+ * Returns the name of a component, service or reference.
+ */
+scdl.name = function(l) {
+ return namedAttributeValue("'name", l);
+};
+
+/**
+ * Returns the color of a component.
+ */
+scdl.color = function(l) {
+ return namedAttributeValue("'color", l);
+};
+
+/**
+ * Returns the implementation of a component.
+ */
+scdl.implementation = function(l) {
+ function filterImplementation(v) {
+ return isElement(v) && cadr(v).match("implementation.") != null;
+ }
+
+ var n = filter(filterImplementation, l);
+ if (isNil(n))
+ return null;
+ return car(n);
+};
+
+/**
+ * Returns the type of an implementation.
+ */
+scdl.implementationType = function(l) {
+ return elementName(l).substring(1);
+};
+
+/**
+ * Returns the URI of a service, reference or implementation.
+ */
+scdl.uri = function(l) {
+ return namedAttributeValue("'uri", l);
+};
+
+/**
+ * Returns the align attribute of a service or reference.
+ */
+scdl.align = function(l) {
+ return namedAttributeValue("'align", l);
+};
+
+/**
+ * Returns a list of services in a component.
+ */
+scdl.services = function(l) {
+ return namedElementChildren("'service", l);
+};
+
+/**
+ * Returns a list of references in a component.
+ */
+scdl.references = function(l) {
+ return namedElementChildren("'reference", l);
+};
+
+/**
+ * Returns a list of bindings in a service or reference.
+ */
+scdl.bindings = function(l) {
+ function filterBinding(v) {
+ return isElement(v) && cadr(v).match("binding.") != null;
+ }
+
+ return filter(filterBinding, l);
+};
+
+/**
+ * Returns the type of a binding.
+ */
+scdl.bindingType = function(l) {
+ return elementName(l).substring(1);
+};
+
+/**
+ * Returns the target of a reference.
+ */
+scdl.target = function(l) {
+ function targetURI() {
+ function bindingsTarget(l) {
+ if (isNil(l))
+ return null;
+ var u = uri(car(l));
+ if (!isNil(u))
+ return u;
+ return bindingsTarget(cdr(l));
+ }
+
+ var t = namedAttributeValue("'target", l);
+ if (!isNil(t))
+ return t;
+ return bindingsTarget(scdl.bindings(l));
+ }
+ var turi = targetURI();
+ if (isNil(turi))
+ return turi;
+ return car(tokens(turi));
+};
+
+/**
+ * Returns a list of properties in a component.
+ */
+scdl.properties = function(l) {
+ return namedElementChildren("'property", l);
+};
+
+/**
+ * Returns the value of a property.
+ */
+scdl.propertyValue = function(l) {
+ return elementValue(l);
+};
+
+/**
+ * Convert a list of elements to a name -> element assoc list.
+ */
+scdl.nameToElementAssoc = function(l) {
+ if (isNil(l))
+ return l;
+ return cons(mklist(scdl.name(car(l)), car(l)), scdl.nameToElementAssoc(cdr(l)));
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css
new file mode 100644
index 0000000000..d1413018a0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+body {
+white-space: margin: 0px;
+font-family: arial,sans-serif; font-style: normal; font-variant: normal; font-size: 13px;
+}
+
+table {
+border: 1px; border-collapse: separate;
+font-family: arial,sans-serif; font-style: normal; font-variant: normal; font-size: 13px;
+}
+
+th {
+font-weight: bold; background-color: #e5ecf9; color: #598edd;
+text-align: left; padding-left: 2px; padding-right: 8px; padding-top: 2px; padding-bottom: 2px; vertical-align: text-top;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4;
+}
+
+td {
+padding-left: 2px; padding-top: 2px; padding-right: 8px; vertical-align: text-top;
+}
+
+iframe {
+visibility: hidden; width: 0px; height: 0px;
+}
+
+input {
+vertical-align: middle;
+-webkit-text-size-adjust: 140%;
+}
+
+a:link {
+color: blue;
+}
+
+a:visited {
+color: blue;
+}
+
+.tdw {
+padding-left: 2px; padding-top: 2px; padding-right: 8px; white-space: normal; vertical-align: text-top;
+}
+
+.hd1 {
+font-size: 150%; font-weight: bold;
+}
+
+.hd2 {
+font-weight: bold;
+}
+
+.imgbutton {
+width: 142px; height: 64px; margin-left: 20px; margin-right: 20px; padding: 0px; border: 1px;
+cursor: pointer; cursor: hand;
+}
+
+.tbar {
+margin: 0px;
+padding-top: 0px; padding-left: 0px; padding-right: 0px; padding-bottom: 3px;
+border-bottom: 1px solid #a2bae7;
+}
+
+.ltbar {
+padding-left: 0px; padding-top: 0px; padding-right: 8px; white-space: nowrap; vertical-align: top;
+}
+
+.rtbar {
+padding-left: 8px; padding-right: 0px; padding-top: 0px; white-space: nowrap; vertical-align: top;
+text-align: right;
+}
+
+.suggest {
+background-color: #e5ecf9; color: #598edd;
+border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px;
+border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4;
+border-left-color: #d1d3d4; border-right-color: #d1d3d4;
+position: absolute;
+overflow: auto; overflow-x: hidden;
+cursor: default;
+padding: 0px; margin: 0px;
+}
+
+.suggestTable {
+border: 0px; border-collapse: separate;
+padding-left: 5px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px;
+margin: 0px;
+}
+
+.suggestItem {
+padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: text-top;
+background-color: #e5ecf9; color: #598edd;
+}
+
+.suggestHilighted {
+padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: text-top;
+background-color: #598edd; color: #e5ecf9;
+}
+
+v\: * {
+behavior:url(#default#VML);
+display:inline-block;
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js
new file mode 100644
index 0000000000..fcd61571d1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+/**
+ * UI utility functions.
+ */
+
+var ui = new Object();
+
+/**
+ * Build a menu bar.
+ */
+ui.menu = function(name, href) {
+ function Menu(n, h) {
+ this.name = n;
+ this.href = h;
+
+ this.content = function() {
+ function complete(uri) {
+ if (uri.match('.*\.html$'))
+ return uri;
+ if (uri.match('.*/$'))
+ return uri + 'index.html';
+ return uri + '/index.html';
+ }
+
+ if (complete(this.href) != complete(window.top.location.pathname))
+ return '<a href="' + this.href + '" target="_parent">' + this.name + '</a>';
+ return '<span><b>' + this.name + '</b></span>';
+ };
+ }
+ return new Menu(name, href);
+};
+
+ui.menubar = function(left, right) {
+ var bar = '<table cellpadding="0" cellspacing="0" width="100%" class=tbar><tr>' +
+ '<td class=ltbar><table border="0" cellspacing="0" cellpadding="0"><tr>';
+ for (i in left)
+ bar = bar + '<td class=ltbar>' + left[i].content() + '</td>'
+
+ bar = bar + '</tr></table></td>' +
+ '<td class=rtbar><table border="0" cellpadding="0" cellspacing="0" align="right"><tr>';
+ for (i in right)
+ bar = bar + '<td class=rtbar>' + right[i].content() + '</td>'
+
+ bar = bar + '</tr></table></td></tr></table>';
+ return bar;
+};
+
+/**
+ * Autocomplete / suggest support for input fields
+ * To use it declare a 'suggest' function as follows:
+ * function suggestItems() {
+ * return new Array('abc', 'def', 'ghi');
+ * }
+ * then hook it to an input field as follows:
+ * suggest(document.yourForm.yourInputField, suggestItems);
+ */
+ui.selectSuggestion = function(node, value) {
+ for (;;) {
+ node = node.parentNode;
+ if (node.tagName.toLowerCase() == 'div')
+ break;
+ }
+ node.selectSuggestion(value);
+};
+
+ui.hilightSuggestion = function(node, over) {
+ if (over)
+ node.className = 'suggestHilighted';
+ node.className = 'suggestItem';
+};
+
+ui.suggest = function(input, suggestFunction) {
+ input.suggest = suggestFunction;
+
+ input.selectSuggestion = function(value) {
+ this.hideSuggestDiv();
+ this.value = value;
+ }
+
+ input.hideSuggestDiv = function() {
+ if (this.suggestDiv != null) {
+ this.suggestDiv.style.visibility = 'hidden';
+ }
+ }
+
+ input.showSuggestDiv = function() {
+ if (this.suggestDiv == null) {
+ this.suggestDiv = document.createElement('div');
+ this.suggestDiv.input = this;
+ this.suggestDiv.className = 'suggest';
+ input.parentNode.insertBefore(this.suggestDiv, input);
+ this.suggestDiv.style.visibility = 'hidden';
+ this.suggestDiv.style.zIndex = '99';
+
+ this.suggestDiv.selectSuggestion = function(value) {
+ this.input.selectSuggestion(value);
+ }
+ }
+
+ var values = this.suggest();
+ var items = '';
+ for (var i = 0; i < values.length; i++) {
+ if (values[i].indexOf(this.value) == -1)
+ continue;
+ if (items.length == 0)
+ items += '<table class=suggestTable>';
+ items += '<tr><td class="suggestItem" ' +
+ 'onmouseover="ui.hilightSuggestion(this, true)" onmouseout="ui.hilightSuggestion(this, false)" ' +
+ 'onmousedown="ui.selectSuggestion(this, \'' + values[i] + '\')">' + values[i] + '</td></tr>';
+ }
+ if (items.length != 0)
+ items += '</table>';
+ this.suggestDiv.innerHTML = items;
+
+ if (items.length != 0) {
+ var node = input;
+ var left = 0;
+ var top = 0;
+ for (;;) {
+ left += node.offsetLeft;
+ top += node.offsetTop;
+ node = node.offsetParent;
+ if (node.tagName.toLowerCase() == 'body')
+ break;
+ }
+ this.suggestDiv.style.left = left;
+ this.suggestDiv.style.top = top + input.offsetHeight;
+ this.suggestDiv.style.visibility = 'visible';
+ } else
+ this.suggestDiv.style.visibility = 'hidden';
+ }
+
+ input.onkeydown = function(event) {
+ this.showSuggestDiv();
+ };
+
+ input.onkeyup = function(event) {
+ this.showSuggestDiv();
+ };
+
+ input.onmousedown = function(event) {
+ this.showSuggestDiv();
+ };
+
+ input.onblur = function(event) {
+ setTimeout(function() { input.hideSuggestDiv(); }, 50);
+ };
+};
+
+/**
+ * Return the content document of a window.
+ */
+ui.content = function(win) {
+ if (!isNil(win.document))
+ return win.document;
+ if (!isNil(win.contentDocument))
+ return win.contentDocument;
+ return null;
+};
+
+/**
+ * Return a child element of a node with the given id.
+ */
+ui.elementByID = function(node, id) {
+ for (var i in node.childNodes) {
+ var child = node.childNodes[i];
+ if (child.id == id)
+ return child;
+ var gchild = ui.elementByID(child, id);
+ if (gchild != null)
+ return gchild;
+ }
+ return null;
+};
+
+/**
+ * Return the current document, or a child element with the given id.
+ */
+function $(id) {
+ if (id == document) {
+ if (!isNil(document.widget))
+ return widget;
+ return document;
+ }
+ return ui.elementByID($(document), id);
+};
+
+/**
+ * Initialize a widget.
+ */
+ui.onloadwidget = function() {
+ if (isNil(window.parent) || isNil(window.parent.ui) || isNil(window.parent.ui.widgets))
+ return true;
+ var pdoc = ui.content(window.parent);
+ for (w in window.parent.ui.widgets) {
+ var ww = ui.elementByID(pdoc, w).contentWindow;
+ if (ww == window) {
+ document.widget = ui.elementByID(pdoc, window.parent.ui.widgets[w]);
+ document.widget.innerHTML = document.body.innerHTML;
+ return true;
+ }
+ }
+ return true;
+};
+
+/**
+ * Load a widget into an element.
+ */
+ui.widgets = new Array();
+
+ui.bindwidget = function(f, el) {
+ window.ui.widgets[f] = el;
+ return f;
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js
new file mode 100644
index 0000000000..0f966b180e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+/**
+ * Simple utility functions.
+ */
+
+/**
+ * Scheme-like lists.
+ */
+function cons(car, cdr) {
+ return new Array(car).concat(cdr);
+}
+
+function car(l) {
+ return l[0];
+}
+
+function first(l) {
+ return car(l);
+}
+
+function cdr(l) {
+ return l.slice(1);
+}
+
+function rest(l) {
+ return cdr(l);
+}
+
+function cadr(l) {
+ return car(cdr(l));
+}
+
+function cddr(l) {
+ return cdr(cdr(l));
+}
+
+function caddr(l) {
+ return car(cddr(l));
+}
+
+function append(a, b) {
+ return a.concat(b);
+}
+
+function reverse(l) {
+ return l.slice(0).reverse();
+}
+
+function isNil(v) {
+ if (v == null)
+ return true;
+ if ('' + v == 'undefined')
+ return true;
+ try {
+ if (isList(v) && v.length == 0)
+ return true;
+ } catch (e) {}
+ return false;
+}
+
+function isSymbol(v) {
+ if (typeof v == 'string' && v.slice(0, 1) == "'")
+ return true;
+ return false;
+}
+
+function isString(v) {
+ if (typeof v == 'string')
+ return true;
+ return false;
+}
+
+function isList(v) {
+ try {
+ if (v.constructor == Array)
+ return true;
+ } catch (e) {}
+ return false;
+}
+
+function isTaggedList(v, t) {
+ if (isList(v) && !isNil(v) && car(v) == t)
+ return true;
+ return false;
+}
+
+function mklist() {
+ var a = new Array();
+ for (i = 0; i < arguments.length; i++)
+ a[i] = arguments[i];
+ return a;
+}
+
+function length(l) {
+ return l.length;
+}
+
+/**
+ * Scheme-like associations.
+ */
+function assoc(k, l) {
+ if (isNil(l))
+ return mklist();
+ if (k == car(car(l)))
+ return car(l);
+ return assoc(k, cdr(l));
+}
+
+/**
+ * Map and filter functions.
+ */
+function map(f, l) {
+ if (isNil(l))
+ return l;
+ return cons(f(car(l)), map(f, cdr(l)));
+}
+
+function filter(f, l) {
+ if (isNil(l))
+ return l;
+ if (f(car(l)))
+ return cons(car(l), filter(f, cdr(l)));
+ return filter(f, cdr(l));
+}
+
+/**
+ * Split a path into a list of segments.
+ */
+function tokens(path) {
+ return filter(function(s) { return length(s) != 0; }, path.split("/"));
+}
+
+/**
+ * Log a value.
+ */
+function log(v) {
+ try {
+ console.log(v);
+ } catch (e) {}
+ return true;
+}
+
+/**
+ * Dump an object to the debug console.
+ */
+function debug(o) {
+ try {
+ for (f in o) {
+ try {
+ console.log(f + '=' + o[f]);
+ } catch (e) {}
+ }
+ } catch (e) {}
+ return true;
+}
+
+/**
+ * Write a list of strings.
+ */
+function writeStrings(l) {
+ if (isNil(l))
+ return '';
+ return car(l) + writeStrings(cdr(l));
+}
+
+/**
+ * Write a value using a Scheme-like syntax.
+ */
+function writeValue(v) {
+ function writePrimitive(p) {
+ if (isSymbol(p))
+ return '' + p.substring(1);
+ if (isString(p))
+ return '"' + p + '"';
+ return '' + p;
+ }
+
+ function writeList(l) {
+ if (isNil(l))
+ return '';
+ return ' ' + writeValue(car(l)) + writeList(cdr(l));
+ }
+
+ if (!isList(v))
+ return writePrimitive(v);
+ if (isNil(v))
+ return '()';
+ return '(' + writeValue(car(v)) + writeList(cdr(v)) + ')';
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js
new file mode 100644
index 0000000000..1bec45f9b9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+/**
+ * XML handling functions.
+ */
+
+/**
+ * Convert a DOM node list to a regular list.
+ */
+function nodeList(n) {
+ var l = new Array();
+ if (isNil(n))
+ return l;
+ for (var i = 0; i < n.length; i++)
+ l[i] = n[i];
+ return l;
+}
+
+/**
+ * Return the child attributes of an element.
+ */
+function childAttributes(e) {
+ return filter(function(n) { return n.nodeType == 2; }, nodeList(e.attributes));
+}
+
+/**
+ * Return the child elements of an element.
+ */
+function childElements(e) {
+ return filter(function(n) { return n.nodeType == 1; }, nodeList(e.childNodes));
+}
+
+/**
+ * Return the child text nodes of an element.
+ */
+function childText(e) {
+ return filter(function(n) { return n.nodeType == 3; }, nodeList(e.childNodes));
+}
+
+/**
+ * Read a list of XML attributes.
+ */
+function readAttributes(a) {
+ if (isNil(a))
+ return a;
+ return cons(mklist(attribute, "'" + car(a).nodeName, car(a).nodeValue), readAttributes(cdr(a)));
+}
+
+/**
+ * Read an XML element.
+ */
+function readElement(e) {
+ var l = append(append(mklist(element, "'" + e.nodeName), readAttributes(childAttributes(e))), readElements(childElements(e)));
+ var t = childText(e);
+ if (isNil(t))
+ return l;
+ return append(l, mklist(car(t).nodeValue));
+}
+
+/**
+ * Read a list of XML elements.
+ */
+function readElements(l) {
+ if (isNil(l))
+ return l;
+ return cons(readElement(car(l)), readElements(cdr(l)));
+}
+
+/**
+ * Return true if a list of strings contains an XML document.
+ */
+function isXML(l) {
+ if (isNil(l))
+ return false;
+ return car(l).substring(0, 5) == '<?xml';
+}
+
+/**
+ * Parse a list of strings representing an XML document.
+ */
+function parseXML(l) {
+ var s = writeStrings(l);
+ if (window.DOMParser) {
+ var p =new DOMParser();
+ return p.parseFromString(s, "text/xml");
+ }
+ var doc;
+ try {
+ doc = new ActiveXObject("MSXML2.DOMDocument");
+ } catch (e) {
+ doc = new ActiveXObject("Microsoft.XMLDOM");
+ }
+ doc.async = 'false';
+ doc.loadXML(s);
+ return doc;
+}
+
+/**
+ * Read a list of values from an XML document.
+ */
+function readXMLDocument(doc) {
+ var root = childElements(doc);
+ if (isNil(root))
+ return mklist();
+ return mklist(readElement(car(root)));
+}
+
+/**
+ * Read a list of values from a list of strings representing an XML document.
+ */
+function readXML(l) {
+ return readXMLDocument(parseXML(l));
+}
+
+/**
+ * Make an XML document.
+ */
+/**
+ * Return a list of strings representing an XML document.
+ */
+function writeXMLDocument(doc) {
+ if (typeof(XMLSerializer) != 'undefined')
+ return mklist(new XMLSerializer().serializeToString(doc));
+ return mklist(doc.xml);
+}
+
+/**
+ * Write a list of XML element and attribute tokens.
+ */
+function expandElementValues(n, l) {
+ if (isNil(l))
+ return l;
+ return cons(cons(element, cons(n, car(l))), expandElementValues(n, cdr(l)));
+}
+
+function writeList(l, node, doc) {
+ if (isNil(l))
+ return node;
+ var token = car(l);
+ if (isTaggedList(token, attribute)) {
+ node.setAttribute(attributeName(token).substring(1), '' + attributeValue(token));
+ } else if (isTaggedList(token, element)) {
+ if (elementHasValue(token)) {
+ var v = elementValue(token);
+ if (isList(v)) {
+ var e = expandElementValues(elementName(token), v);
+ writeList(e, node, doc);
+ } else {
+ var child = doc.createElement(elementName(token).substring(1));
+ writeList(elementChildren(token), child, doc);
+ node.appendChild(child);
+ }
+ } else {
+ var child = doc.createElement(elementName(token).substring(1));
+ writeList(elementChildren(token), child, doc);
+ node.appendChild(child);
+ }
+ } else
+ node.appendChild(doc.createTextNode('' + token));
+ writeList(cdr(l), node, doc);
+ return node;
+}
+
+/**
+ * Convert a list of values to a list of strings representing an XML document.
+ */
+function writeXML(l, xmlTag) {
+ function mkdoc() {
+ if (document.implementation && document.implementation.createDocument)
+ return document.implementation.createDocument('', '', null);
+ return new ActiveXObject("MSXML2.DOMDocument");
+ }
+
+ var doc = mkdoc();
+ writeList(l, doc, doc);
+ if (!xmlTag)
+ return writeXMLDocument(doc);
+ return mklist('<?xml version="1.0" encoding="UTF-8"?>\n' + writeXMLDocument(doc) + '\n');
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp
new file mode 100644
index 0000000000..9cbf000ac3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test JavaScript evaluation functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace js {
+
+bool testJSEval() {
+ failable<value> v = evalScript("(function testJSON(n){ return JSON.parse(JSON.stringify(n)) })(5)");
+ assert(hasContent(v));
+ assert(content(v) == value(5));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::js::testJSEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/json/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/json/Makefile.am
new file mode 100644
index 0000000000..7b5b3878db
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/json/Makefile.am
@@ -0,0 +1,25 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/json
+
+json_test_SOURCES = json-test.cpp
+json_test_LDFLAGS = -lmozjs
+
+noinst_PROGRAMS = json-test
+TESTS = json-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/json/json-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/json/json-test.cpp
new file mode 100644
index 0000000000..6666b3f479
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/json/json-test.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test JSON data conversion functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "json.hpp"
+
+namespace tuscany {
+namespace json {
+
+ostream* jsonWriter(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+bool testJSON() {
+ const js::JSContext cx;
+
+ {
+ const list<value> ad = mklist<value>(mklist<value>(attribute, "city", string("san francisco")), mklist<value>(attribute, "state", string("ca")));
+ const list<value> ac = mklist<value>(mklist<value>(element, "id", string("1234")), mklist<value>(attribute, "balance", 1000));
+ const list<value> cr = mklist<value>(mklist<value> (attribute, "name", string("jdoe")), cons<value>(element, cons<value>("address", ad)), cons<value>(element, cons<value>("account", ac)));
+ const list<value> c = mklist<value>(cons<value>(element, cons<value>("customer", cr)));
+
+ ostringstream os;
+ writeJSON<ostream*>(jsonWriter, &os, c, cx);
+ assert(str(os) == "{\"customer\":{\"@name\":\"jdoe\",\"address\":{\"@city\":\"san francisco\",\"@state\":\"ca\"},\"account\":{\"id\":\"1234\",\"@balance\":1000}}}");
+ }
+ {
+ const list<value> phones = mklist<value> (string("408-1234"), string("650-1234"));
+ const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (element, "lastName", string("test\ttab")), mklist<value> (attribute, "firstName", string("test1")));
+
+ ostringstream os;
+ writeJSON<ostream*>(jsonWriter, &os, l, cx);
+ assert(str(os) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"@firstName\":\"test1\"}");
+
+ istringstream is(str(os));
+ const list<string> il = streamList(is);
+ const list<value> r = content(readJSON(il, cx));
+ assert(r == l);
+
+ ostringstream wos;
+ write(content(writeJSON(r, cx)), wos);
+ assert(str(wos) == str(os));
+ }
+ {
+ const list<value> l = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
+ ostringstream wos;
+ write(content(writeJSON(valuesToElements(l), cx)), wos);
+ assert(str(wos) == "{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}");
+
+ istringstream is(str(wos));
+ const list<string> il = streamList(is);
+ const list<value> r = elementsToValues(content(readJSON(il, cx)));
+ assert(r == l);
+ }
+ return true;
+}
+
+bool testJSONRPC() {
+ js::JSContext cx;
+ {
+ const string lm("{\"id\": 1, \"method\": \"test\", \"params\": []}");
+ const list<value> e = content(readJSON(mklist(lm), cx));
+ const list<value> v = elementsToValues(e);
+ assert(assoc<value>("id", v) == mklist<value>("id", 1));
+ assert(assoc<value>("method", v) == mklist<value>("method", string("test")));
+ assert(assoc<value>("params", v) == mklist<value>("params", list<value>()));
+ }
+ {
+ const string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
+ const list<value> e = content(readJSON(mklist(i), cx));
+ const string i2("{\"id\":3,\"result\":{\"0\":{\"price\":\"$2.99\",\"name\":\"Apple\"},\"1\":{\"price\":\"$3.55\",\"name\":\"Orange\"},\"2\":{\"price\":\"$1.55\",\"name\":\"Pear\"}}}");
+ const list<value> e2 = content(readJSON(mklist(i), cx));
+ assert(e == e2);
+ }
+ {
+ const string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
+ const list<value> e = content(readJSON(mklist(i), cx));
+ ostringstream os;
+ write(content(writeJSON(e, cx)), os);
+ assert(str(os) == i);
+ const list<value> v = elementsToValues(e);
+ const list<value> r = valuesToElements(v);
+ assert(r == e);
+ }
+ {
+ const list<value> r = mklist<value>(mklist<value>("id", 1), mklist<value>("result", mklist<value>(string("Service.get"), string("Service.getTotal"))));
+ const list<value> e = valuesToElements(r);
+ ostringstream os;
+ write(content(writeJSON(e, cx)), os);
+ assert(str(os) == "{\"id\":1,\"result\":[\"Service.get\",\"Service.getTotal\"]}");
+ }
+ {
+ const string f("{\"id\":1,\"result\":[\"Sample Feed\",\"123456789\",[\"Item\",\"111\",{\"name\":\"Apple\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":2.99}],[\"Item\",\"222\",{\"name\":\"Orange\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":3.55}],[\"Item\",\"333\",{\"name\":\"Pear\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":1.55}]]}");
+ const list<value> r = content(readJSON(mklist(f), cx));
+ const list<value> v = elementsToValues(r);
+ const list<value> e = valuesToElements(v);
+ ostringstream os;
+ write(content(writeJSON(e, cx)), os);
+ assert(str(os) == f);
+ }
+ {
+ const list<value> arg = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
+ const failable<list<string> > r = jsonRequest(1, "echo", mklist<value>(arg), cx);
+ ostringstream os;
+ write(content(r), os);
+ assert(str(os) == "{\"id\":1,\"method\":\"echo\",\"params\":[{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}]}");
+
+ istringstream is(str(os));
+ const list<string> il = streamList(is);
+ const list<value> ir = elementsToValues(content(readJSON(il, cx)));
+ assert(car<value>(cadr<value>(caddr<value>(ir))) == arg);
+ }
+ {
+ const list<value> res = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples")) + (list<value>() + "text" + string("Hello World!")));
+ const failable<list<string> > r = jsonResult(1, res, cx);
+ ostringstream os;
+ write(content(r), os);
+ assert(str(os) == "{\"id\":1,\"result\":{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/c/samples\",\"text\":\"Hello World!\"}}}");
+
+ istringstream is(str(os));
+ const list<string> il = streamList(is);
+ const list<value> ir = elementsToValues(content(readJSON(il, cx)));
+ assert(cdr<value>(cadr<value>(ir)) == res);
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::json::testJSON();
+ tuscany::json::testJSONRPC();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/json/json.hpp b/sandbox/sebastien/cpp/apr-2/modules/json/json.hpp
new file mode 100644
index 0000000000..df82fddbb5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/json/json.hpp
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_json_hpp
+#define tuscany_json_hpp
+
+/**
+ * JSON data conversion functions.
+ */
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "../js/eval.hpp"
+
+namespace tuscany {
+namespace json {
+
+/**
+ * Return true if a list of strings contains a JSON document.
+ */
+const bool isJSON(const list<string>& ls) {
+ if (isNil(ls))
+ return false;
+ const string s = substr(car(ls), 0, 1);
+ return s == "[" || s == "{";
+}
+
+/**
+ * Consumes JSON strings and populates a JS object.
+ */
+failable<bool> consume(JSONParser* parser, const list<string>& ilist, const js::JSContext& cx) {
+ if (isNil(ilist))
+ return true;
+ JSString* jstr = JS_NewStringCopyZ(cx, c_str(car(ilist)));
+ if(!JS_ConsumeJSONText(cx, parser, JS_GetStringChars(jstr), (uint32)JS_GetStringLength(jstr)))
+ return mkfailure<bool>("JS_ConsumeJSONText failed");
+ return consume(parser, cdr(ilist), cx);
+}
+
+/**
+ * Convert a list of strings representing a JSON document to a list of values.
+ */
+const failable<list<value> > readJSON(const list<string>& ilist, const js::JSContext& cx) {
+ jsval val;
+ JSONParser* parser = JS_BeginJSONParse(cx, &val);
+ if(parser == NULL)
+ return mkfailure<list<value> >("JS_BeginJSONParse failed");
+
+ const failable<bool> consumed = consume(parser, ilist, cx);
+
+ if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL))
+ return mkfailure<list<value> >("JS_FinishJSONParse failed");
+ if(!hasContent(consumed))
+ return mkfailure<list<value> >(reason(consumed));
+
+ return list<value>(js::jsValToValue(val, cx));
+}
+
+/**
+ * Context passed to the JSON write callback function.
+ */
+template<typename R> class WriteContext {
+public:
+ WriteContext(const lambda<R(const string&, const R)>& reduce, const R& accum, const js::JSContext& cx) : cx(cx), reduce(reduce), accum(accum) {
+ }
+ const js::JSContext& cx;
+ const lambda<R(const string&, const R)> reduce;
+ R accum;
+};
+
+/**
+ * Called by JS_Stringify to write JSON out.
+ */
+template<typename R> JSBool writeCallback(const jschar *buf, uint32 len, void *data) {
+ WriteContext<R>& wcx = *(static_cast<WriteContext<R>*> (data));
+ JSString* jstr = JS_NewUCStringCopyN(wcx.cx, buf, len);
+ wcx.accum = wcx.reduce(string(JS_GetStringBytes(jstr), JS_GetStringLength(jstr)), wcx.accum);
+ return JS_TRUE;
+}
+
+/**
+ * Convert a list of values to a JSON document.
+ */
+template<typename R> const failable<R> writeJSON(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const js::JSContext& cx) {
+ jsval val;
+ if (js::isJSArray(l))
+ val = OBJECT_TO_JSVAL(valuesToJSElements(JS_NewArrayObject(cx, 0, NULL), l, 0, cx));
+ else
+ val = OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), l, cx));
+
+ WriteContext<R> wcx(reduce, initial, cx);
+ if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx))
+ return mkfailure<R>("JS_Stringify failed");
+ return wcx.accum;
+}
+
+/**
+ * Convert a list of values to a list of strings representing a JSON document.
+ */
+const failable<list<string> > writeJSON(const list<value>& l, const js::JSContext& cx) {
+ const failable<list<string> > ls = writeJSON<list<string>>(rcons<string>, list<string>(), l, cx);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert a list of function + params to a JSON-RPC request.
+ */
+const failable<list<string> > jsonRequest(const value& id, const value& func, const value& params, js::JSContext& cx) {
+ const list<value> r = mklist<value>(mklist<value>("id", id), mklist<value>("method", string(func)), mklist<value>("params", params));
+ return writeJSON(valuesToElements(r), cx);
+}
+
+/**
+ * Convert a value to a JSON-RPC result.
+ */
+const failable<list<string> > jsonResult(const value& id, const value& val, js::JSContext& cx) {
+ return writeJSON(valuesToElements(mklist<value>(mklist<value>("id", id), mklist<value>("result", val))), cx);
+}
+
+/**
+ * Convert a JSON-RPC result to a value.
+ */
+const failable<value> jsonResultValue(const list<string>& s, js::JSContext& cx) {
+ const failable<list<value> > jsres = json::readJSON(s, cx);
+ if (!hasContent(jsres))
+ return mkfailure<value>(reason(jsres));
+ const list<value> rval(cadr<value>(elementsToValues(content(jsres))));
+ const value val = cadr(rval);
+ if (isList(val) && !js::isJSArray(val))
+ return value(mklist<value>(val));
+ return val;
+}
+
+/**
+ * Convert a JSON payload to a list of values.
+ */
+const list<value> jsonValues(const list<value>& e) {
+ return elementsToValues(e);
+}
+
+/**
+ * Return a portable function name from a JSON-RPC function name.
+ * Strip the ".", "system." and "Service." prefixes added by some JSON-RPC clients.
+ */
+const string funcName(const string& f) {
+ if (length(f) > 1 && find(f, ".", 0) == 0)
+ return c_str(f) + 1;
+ if (length(f) > 7 && find(f, "system.", 0) == 0)
+ return c_str(f) + 7;
+ if (length(f) > 8 && find(f, "Service.", 0) == 0)
+ return c_str(f) + 8;
+ return f;
+}
+
+/**
+ * Returns a list of param values other than the id and method args from a list
+ * of key value pairs.
+ */
+const list<value> queryParams(const list<list<value> >& a) {
+ if (isNil(a))
+ return list<value>();
+ const list<value> p = car(a);
+ if (car(p) == value("id") || car(p) == value("method"))
+ return queryParams(cdr(a));
+ return cons(cadr(p), queryParams(cdr(a)));
+}
+
+}
+}
+
+#endif /* tuscany_json_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am
new file mode 100644
index 0000000000..6c0cd2bc57
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am
@@ -0,0 +1,42 @@
+# 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.
+
+if WANT_OAUTH
+
+INCLUDES = -I${HTTPD_INCLUDE} -I${LIBOAUTH_INCLUDE}
+
+dist_mod_SCRIPTS = oauth-conf oauth-memcached-conf oauth1-appkey-conf oauth2-appkey-conf
+moddir=$(prefix)/modules/oauth
+
+mod_LTLIBRARIES = libmod_tuscany_oauth1.la libmod_tuscany_oauth2.la
+noinst_DATA = libmod_tuscany_oauth1.so libmod_tuscany_oauth2.so
+
+libmod_tuscany_oauth1_la_SOURCES = mod-oauth1.cpp
+libmod_tuscany_oauth1_la_LDFLAGS = -L${LIBOAUTH_LIB} -R${LIBOAUTH_LIB} -loauth -lxml2 -lcurl -lmozjs
+libmod_tuscany_oauth1.so:
+ ln -s .libs/libmod_tuscany_oauth1.so
+
+libmod_tuscany_oauth2_la_SOURCES = mod-oauth2.cpp
+libmod_tuscany_oauth2_la_LDFLAGS = -lxml2 -lcurl -lmozjs
+libmod_tuscany_oauth2.so:
+ ln -s .libs/libmod_tuscany_oauth2.so
+
+EXTRA_DIST = oauth.composite user-info.scm htdocs/index.html htdocs/login/index.html htdocs/logout/index.html htdocs/public/index.html
+
+dist_noinst_SCRIPTS = start-test stop-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html
new file mode 100644
index 0000000000..7d26567214
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html
@@ -0,0 +1,58 @@
+<!--
+ 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.
+-->
+
+<html>
+<head>
+<script type="text/javascript" src="/component.js"></script>
+<script type="text/javascript">
+var protected = sca.component("Protected");
+var userInfo = sca.defun(sca.reference(protected, "userInfo"), "getuser", "getemail", "getnickname", "getfullname", "getfirstname", "getlastname", "getrealm");
+var user = userInfo.getuser();
+var email = userInfo.apply("getemail");
+var nickname = userInfo.apply("getnickname");
+var fullname = userInfo.apply("getfullname");
+var firstname = userInfo.apply("getfirstname");
+var lastname = userInfo.apply("getlastname");
+var realm = userInfo.apply("getrealm");
+</script>
+</head>
+<body>
+<h1>Protected area - It works!</h1>
+<p>The following info is returned by a JSONRPC service:</p>
+<div>User: <span id="user"></span></div>
+<div>Email: <span id="email"></span></div>
+<div>Nickname: <span id="nickname"></span></div>
+<div>Fullname: <span id="fullname"></span></div>
+<div>Firstname: <span id="firstname"></span></div>
+<div>Lastname: <span id="lastname"></span></div>
+<div>Realm: <span id="realm"></span></div>
+<script type="text/javascript">
+document.getElementById('user').innerHTML=user;
+document.getElementById('email').innerHTML=email;
+document.getElementById('nickname').innerHTML=nickname;
+document.getElementById('fullname').innerHTML=fullname;
+document.getElementById('firstname').innerHTML=firstname;
+document.getElementById('lastname').innerHTML=lastname;
+document.getElementById('realm').innerHTML=realm;
+</script>
+<p><a href="info">User info</a></p>
+<p><a href="login">Sign in</a></p>
+<p><a href="logout">Sign out</a></p>
+<p><a href="public">Public area</a></p>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html
new file mode 100644
index 0000000000..c41c334b76
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html
@@ -0,0 +1,116 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with an OAuth provider</h1>
+
+<script type="text/javascript">
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function oauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(oauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitSignin2(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signin2.mod_oauth2_authorize.value = parms[0];
+ document.signin2.mod_oauth2_access_token.value = parms[1];
+ document.signin2.mod_oauth2_client_id.value = parms[2];
+ document.signin2.mod_oauth2_info.value = parms[3];
+ document.signin2.action = oauthReferrer();
+ document.signin2.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'github.com', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitSignin1(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signin1.mod_oauth1_request_token.value = parms[0];
+ document.signin1.mod_oauth1_authorize.value = parms[1];
+ document.signin1.mod_oauth1_access_token.value = parms[2];
+ document.signin1.mod_oauth1_client_id.value = parms[3];
+ document.signin1.mod_oauth1_info.value = parms[4];
+ document.signin1.action = oauthReferrer();
+ document.signin1.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'linkedin.com', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'twitter.com', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="fields">
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitSignin2(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitSignin2(withGithub)" value="Sign in"/></p>
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitSignin1(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitSignin1(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="signin2" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="signin1" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html
new file mode 100644
index 0000000000..54673e01ee
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html
@@ -0,0 +1,211 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with a Form, an OpenID provider or an OAuth provider</h1>
+
+<script type="text/javascript">
+function submitFormSignin() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.formSignin.httpd_location.value = '/';
+ document.formSignin.submit();
+}
+
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function openauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(openauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitOpenIDSignin(w) {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.openIDSignin.openid_identifier.value = w();
+ document.openIDSignin.action = openauthReferrer();
+ document.openIDSignin.submit();
+}
+
+function withGoogle() {
+ return 'https://www.google.com/accounts/o8/id';
+}
+
+function withYahoo() {
+ return 'https://me.yahoo.com/';
+}
+
+function withMyOpenID() {
+ return 'http://www.myopenid.com/xrds';
+}
+
+function withVerisign() {
+ return 'https://pip.verisignlabs.com/';
+}
+
+function withMySpace() {
+ return 'https://api.myspace.com/openid';
+}
+
+function withGoogleApps() {
+ return 'https://www.google.com/accounts/o8/site-xrds?ns=2&hd=' + document.fields.domain.value;
+}
+
+function withLivejournal() {
+ return 'http://' + document.fields.ljuser.value + '.livejournal.com';
+}
+
+function withBlogspot() {
+ return 'http://' + document.fields.bsuser.value + '.blogspot.com';
+}
+
+function withBlogger() {
+ return 'http://' + document.fields.bguser.value + '.blogger.com';
+}
+
+function withXRDSEndpoint() {
+ return document.fields.endpoint.value;
+}
+
+function submitOAuth2Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
+ document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
+ document.oauth2Signin.mod_oauth2_client_id.value = parms[2];
+ document.oauth2Signin.mod_oauth2_info.value = parms[3];
+ document.oauth2Signin.action = openauthReferrer();
+ document.oauth2Signin.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'github.com', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitOAuth1Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth1Signin.mod_oauth1_request_token.value = parms[0];
+ document.oauth1Signin.mod_oauth1_authorize.value = parms[1];
+ document.oauth1Signin.mod_oauth1_access_token.value = parms[2];
+ document.oauth1Signin.mod_oauth1_client_id.value = parms[3];
+ document.oauth1Signin.mod_oauth1_info.value = parms[4];
+ document.oauth1Signin.action = openauthReferrer();
+ document.oauth1Signin.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'linkedin.com', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'twitter.com', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="formSignin" method="POST" action="/login/dologin">
+<p>Sign in with your user id and password<br/>
+<table border="0">
+<tr><td>Username:</td><td><input type="text" name="httpd_username" value=""/></td></tr>
+<tr><td>Password:</td><td><input type="password" name="httpd_password" value=""/></td></tr>
+<tr><td><input type="button" onclick="submitFormSignin()" value="Sign in"/></td><td></td></tr>
+</table>
+</p>
+<input type="hidden" name="httpd_location" value="/"/>
+</form>
+
+<form name="fields">
+<p>Sign in with your Google account<br/><input type="button" onclick="submitOpenIDSignin(withGoogle)" value="Sign in"/></p>
+<p>Sign in with your Yahoo account<br/><input type="button" onclick="submitOpenIDSignin(withYahoo)" value="Sign in"/></p>
+<p>Sign in with your MyOpenID account<br/><input type="button" onclick="submitOpenIDSignin(withMyOpenID)" value="Sign in"/></p>
+<p>Sign in with your Verisign account<br/><input type="button" onclick="submitOpenIDSignin(withVerisign)" value="Sign in"/></p>
+<p>Sign in with your MySpace account<br/><input type="button" onclick="submitOpenIDSignin(withMySpace)" value="Sign in"/></p>
+
+<p>Sign in with a Google apps domain<br/>
+<input type="text" size="20" name="domain" value="example.com"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withGoogleApps)" value="Sign in"/></p>
+
+<p>Sign in with your Livejournal account<br/>
+<input type="text" size="10" name="ljuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withLivejournal)" value="Sign in"/></p>
+
+<p>Sign in with your Blogspot account<br/>
+<input type="text" size="10" name="bsuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogspot)" value="Sign in"/></p>
+
+<p>Sign in with your Blogger account<br/>
+<input type="text" size="10" name="bguser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogger)" value="Sign in"/></p>
+
+<p>Sign in with an OpenID endpoint<br/>
+<input type="text" size="50" name="endpoint" value="https://www.google.com/accounts/o8/id"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withXRDSEndpoint)" value="Sign in"/></p>
+
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitOAuth2Signin(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitOAuth2Signin(withGithub)" value="Sign in"/></p>
+
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitOAuth1Signin(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitOAuth1Signin(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="openIDSignin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value=""/>
+</form>
+
+<form name="oauth2Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="oauth1Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html
new file mode 100644
index 0000000000..02a92d1b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html
new file mode 100644
index 0000000000..af2cd7ca19
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+
+<html>
+<body>
+<h1>Unprotected area - It works!</h1>
+<p><a href="/info">User info</a></p>
+<p><a href="/login">Sign in</a></p>
+<p><a href="/logout">Sign out</a></p>
+<p><a href="/">Protected area</a></p>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp
new file mode 100644
index 0000000000..0f190127db
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp
@@ -0,0 +1,580 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module for OAuth 1.0 authentication.
+ */
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+extern "C" {
+#include <oauth.h>
+}
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../json/json.hpp"
+#include "../http/httpd.hpp"
+#include "../http/http.hpp"
+#include "../http/openauth.hpp"
+#include "../../components/cache/memcache.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth1;
+}
+
+namespace tuscany {
+namespace oauth1 {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ string ca;
+ string cert;
+ string key;
+ list<list<value> > appkeys;
+ list<string> mcaddrs;
+ memcache::MemCached mc;
+ http::CURLSession cs;
+};
+
+/**
+ * Directory configuration.
+ */
+class DirConf {
+public:
+ DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") {
+ }
+
+ const gc_pool p;
+ const char* dir;
+ bool enabled;
+ string login;
+};
+
+/**
+ * Return the user info for a session.
+ */
+const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) {
+ return memcache::get(mklist<value>("tuscanyOpenAuth", sid), mc);
+}
+
+/**
+ * Handle an authenticated request.
+ */
+const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+ debug(info, "modoauth1::authenticated::info");
+
+ // Store user info in the request
+ const list<value> realm = assoc<value>("realm", info);
+ if (isNil(realm) || isNil(cdr(realm)))
+ return mkfailure<int>("Couldn't retrieve realm");
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
+
+ const list<value> id = assoc<value>("id", info);
+ if (isNil(id) || isNil(cdr(id)))
+ return mkfailure<int>("Couldn't retrieve user id");
+ r->user = apr_pstrdup(r->pool, c_str(cadr(id)));
+
+ const list<value> email = assoc<value>("email", info);
+ if (!isNil(email) && !isNil(cdr(email)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "EMAIL"), apr_pstrdup(r->pool, c_str(cadr(email))));
+
+ const list<value> screenname = assoc<value>("screen_name", info);
+ if (!isNil(screenname) && !isNil(cdr(screenname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(screenname))));
+
+ const list<value> name = assoc<value>("name", info);
+ if (!isNil(name) && !isNil(cdr(name)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(name))));
+
+ const list<value> firstname = assoc<value>("first-name", info);
+ if (!isNil(firstname) && !isNil(cdr(firstname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FIRSTNAME"), apr_pstrdup(r->pool, c_str(cadr(firstname))));
+
+ const list<value> lastname = assoc<value>("last-name", info);
+ if (!isNil(lastname) && !isNil(cdr(lastname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname))));
+ return OK;
+}
+
+/**
+ * Convert a query string containing oauth args to an authorization header.
+ */
+const string header(const string& qs, const string& redir, const string& verif) {
+ const list<list<value> > args = httpd::queryArgs(qs);
+ ostringstream hdr;
+ hdr << "Authorization: OAuth "
+ << "oauth_nonce=\"" << string(cadr(assoc<value>("oauth_nonce", args))) << "\", ";
+
+ if (length(redir) != 0)
+ hdr << "oauth_callback=\"" << httpd::escape(redir) << "\", ";
+
+ hdr << "oauth_signature_method=\"" << string(cadr(assoc<value>("oauth_signature_method", args))) << "\", "
+ << "oauth_timestamp=\"" << string(cadr(assoc<value>("oauth_timestamp", args))) << "\", "
+ << "oauth_consumer_key=\"" << string(cadr(assoc<value>("oauth_consumer_key", args))) << "\", ";
+
+ const list<value> atok = assoc<value>("oauth_token", args);
+ if (!isNil(atok) && !isNil(cdr(atok)))
+ hdr << "oauth_token=\"" << string(cadr(atok)) << "\", ";
+
+ if (length(verif) != 0)
+ hdr << "oauth_verifier=\"" << verif << "\", ";
+
+ hdr << "oauth_signature=\"" << string(cadr(assoc<value>("oauth_signature", args))) << "\", "
+ << "oauth_version=\"" << string(cadr(assoc<value>("oauth_version", args))) << "\"";
+ debug(str(hdr), "modoauth1::authheader");
+ return str(hdr);
+}
+
+
+/**
+ * Sign a request.
+ */
+const list<string> sign(const string& verb, const string& uri, const list<value> appkey, const string& tok, const string& sec) {
+ char* qs = NULL;
+ char* suri = oauth_sign_url2(c_str(uri), &qs, OA_HMAC, c_str(verb), c_str(car(appkey)), c_str(cadr(appkey)), length(tok) != 0? c_str(tok) : NULL, length(sec) != 0? c_str(sec) : NULL);
+ const list<string> res = mklist<string>(suri, qs);
+ free(suri);
+ free(qs);
+ return res;
+}
+
+/**
+ * Handle an authorize request.
+ */
+const failable<int> authorize(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract authorize, access_token, client ID and info URIs
+ const list<value> req = assoc<value>("mod_oauth1_request_token", args);
+ if (isNil(req) || isNil(cdr(req)))
+ return mkfailure<int>("Missing mod_oauth1_request_token parameter");
+ const list<value> auth = assoc<value>("mod_oauth1_authorize", args);
+ if (isNil(auth) || isNil(cdr(auth)))
+ return mkfailure<int>("Missing mod_oauth1_authorize parameter");
+ const list<value> tok = assoc<value>("mod_oauth1_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth1_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth1_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth1_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth1_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth1_info parameter");
+
+ // Build the redirect URI
+ const list<list<value> > redirargs = mklist<list<value> >(mklist<value>("mod_oauth1_step", "access_token"), tok, cid, info);
+ const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(redirargs);
+ debug(redir, "modoauth1::authorize::redir");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Build and sign the request token URI
+ const string requri = httpd::unescape(cadr(req)) + string("&") + httpd::queryString(mklist<list<value> >(mklist<value>("oauth_callback", httpd::escape(redir))));
+ const list<string> srequri = sign("POST", requri, appkey, "", "");
+ debug(srequri, "modoauth1::authorize::srequri");
+
+ // Put the args into an oauth header
+ const string reqhdr = header(cadr(srequri), redir, "");
+
+ // Send the request token request
+ char* pres = oauth_http_post2(c_str(car(srequri)), "", c_str(reqhdr));
+ if (pres == NULL)
+ return mkfailure<int>("Couldn't send request token request");
+ const string res(pres);
+ free(pres);
+ debug(res, "modoauth1::authorize::res");
+ const list<list<value> > resargs = httpd::queryArgs(res);
+
+ // Retrieve the request token
+ const list<value> conf = assoc<value>("oauth_callback_confirmed", resargs);
+ if (isNil(conf) || isNil(cdr(conf)) || cadr(conf) != "true")
+ return mkfailure<int>("Couldn't confirm oauth_callback");
+ const list<value> tv = assoc<value>("oauth_token", resargs);
+ if (isNil(tv) || isNil(cdr(tv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token");
+ const list<value> sv = assoc<value>("oauth_token_secret", resargs);
+ if (isNil(sv) || isNil(cdr(sv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token_secret");
+
+ // Store the request token in memcached
+ const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth1Token", cadr(tv)), cadr(sv), sc.mc);
+ if (!hasContent(prc))
+ return mkfailure<int>(reason(prc));
+
+ // Redirect to the authorize URI
+ const string authuri = httpd::unescape(cadr(auth)) + string("?") + httpd::queryString(mklist<list<value> >(tv));
+ debug(authuri, "modoauth1::authorize::authuri");
+ return httpd::externalRedirect(authuri, r);
+}
+
+/**
+ * Extract user info from a profile/info response.
+ * TODO This currently only works for Twitter, Foursquare and LinkedIn.
+ * User profile parsing needs to be made configurable.
+ */
+const failable<list<value> > profileUserInfo(const value& cid, const string& info) {
+ string b = substr(info, 0, 1);
+ if (b == "[") {
+ // Twitter JSON profile
+ js::JSContext cx;
+ const list<value> infov(json::jsonValues(content(json::readJSON(mklist<string>(info), cx))));
+ if (isNil(infov))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ debug(infov, "modoauth1::access_token::info");
+ const list<value> uv = assoc<value>("user", car(infov));
+ debug(uv, "modoauth1::access_token::userInfo");
+ if (isNil(uv) || isNil(cdr(uv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(uv);
+ return cons<value>(mklist<value>("realm", cid), iv);
+ }
+ if (b == "{") {
+ // Foursquare JSON profile
+ js::JSContext cx;
+ const list<value> infov(json::jsonValues(content(json::readJSON(mklist<string>(info), cx))));
+ if (isNil(infov))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ debug(infov, "modoauth1::access_token::info");
+ const list<value> uv = assoc<value>("user", infov);
+ debug(uv, "modoauth1::access_token::userInfo");
+ if (isNil(uv) || isNil(cdr(uv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(uv);
+ return cons<value>(mklist<value>("realm", cid), iv);
+ }
+ if (b == "<") {
+ // XML profile
+ const list<value> infov = elementsToValues(readXML(mklist<string>(info)));
+ if (isNil(infov))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ debug(infov, "modoauth1::access_token::info");
+ const list<value> pv = car(infov);
+ debug(pv, "modoauth1::access_token::userInfo");
+ if (isNil(pv) || isNil(cdr(pv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(pv);
+ return cons<value>(mklist<value>("realm", cid), iv);
+ }
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+}
+
+/**
+ * Handle an access_token request.
+ */
+const failable<int> access_token(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract access_token URI, client ID and verification code
+ const list<value> tok = assoc<value>("mod_oauth1_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth1_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth1_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth1_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth1_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth1_info parameter");
+ const list<value> tv = assoc<value>("oauth_token", args);
+ if (isNil(tv) || isNil(cdr(tv)))
+ return mkfailure<int>("Missing oauth_token parameter");
+ const list<value> vv = assoc<value>("oauth_verifier", args);
+ if (isNil(vv) || isNil(cdr(vv)))
+ return mkfailure<int>("Missing oauth_verifier parameter");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Retrieve the request token from memcached
+ const failable<value> sv = memcache::get(mklist<value>("tuscanyOAuth1Token", cadr(tv)), sc.mc);
+ if (!hasContent(sv))
+ return mkfailure<int>(reason(sv));
+
+ // Build and sign access token request URI
+ const string tokuri = httpd::unescape(cadr(tok)) + string("?") + httpd::queryString(mklist<list<value> >(vv));
+ const list<string> stokuri = sign("POST", tokuri, appkey, cadr(tv), content(sv));
+ debug(stokuri, "modoauth1::access_token::stokuri");
+
+ // Put the args into an oauth header
+ string tokhdr = header(cadr(stokuri), "", cadr(vv));
+
+ // Send the access token request
+ char* ptokres = oauth_http_post2(c_str(car(stokuri)), "", c_str(tokhdr));
+ if (ptokres == NULL)
+ return mkfailure<int>("Couldn't post access_token request");
+ const string tokres(ptokres);
+ free(ptokres);
+ debug(tokres, "modoauth1::access_token::res");
+ const list<list<value> > tokresargs = httpd::queryArgs(tokres);
+
+ // Retrieve the access token
+ const list<value> atv = assoc<value>("oauth_token", tokresargs);
+ if (isNil(atv) || isNil(cdr(atv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token");
+ const list<value> asv = assoc<value>("oauth_token_secret", tokresargs);
+ if (isNil(asv) || isNil(cdr(asv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token_secret");
+ debug(atv, "modoauth1::access_token::token");
+
+ // Build and sign user profile request URI
+ const string profuri = httpd::unescape(cadr(info));
+ const list<string> sprofuri = sign("GET", profuri, appkey, cadr(atv), cadr(asv));
+ debug(sprofuri, "modoauth1::access_token::sprofuri");
+
+ // Put the args into an oauth header
+ string profhdr = header(cadr(sprofuri), "", "");
+
+ // Send the user profile request
+ char* pprofres = oauth_http_get2(c_str(car(sprofuri)), NULL, c_str(profhdr));
+ if (pprofres == NULL)
+ return mkfailure<int>("Couldn't get user info");
+ const string profres(pprofres);
+ free(pprofres);
+ debug(profres, "modoauth1::access_token::profres");
+
+ // Retrieve the user info from the profile
+ const failable<list<value> > iv = profileUserInfo(cadr(cid), profres);
+ if (!hasContent(iv))
+ return mkfailure<int>(reason(iv));
+
+ // Store user info in memcached keyed by session ID
+ const value sid = string("OAuth1_") + mkrand();
+ const failable<bool> prc = memcache::put(mklist<value>("tuscanyOpenAuth", sid), content(iv), sc.mc);
+ if (!hasContent(prc))
+ return mkfailure<int>(reason(prc));
+
+ // Send session ID to the client in a cookie
+ apr_table_set(r->err_headers_out, "Set-Cookie", c_str(openauth::cookie(sid)));
+ return httpd::externalRedirect(httpd::url(r->uri, r), r);
+}
+
+/**
+ * Check user authentication.
+ */
+static int checkAuthn(request_rec *r) {
+ // Decline if we're not enabled or AuthType is not set to Open
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth1);
+ if (!dc.enabled)
+ return DECLINED;
+ const char* atype = ap_auth_type(r);
+ if (atype == NULL || strcasecmp(atype, "Open"))
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modoauth1::checkAuthn::input");
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth1);
+
+ // Get session id from the request
+ const maybe<string> sid = openauth::sessionID(r);
+ if (hasContent(sid)) {
+ // Decline if the session id was not created by this module
+ if (substr(content(sid), 0, 7) != "OAuth1_")
+ return DECLINED;
+
+ // If we're authenticated store the user info in the request
+ const failable<value> info = userInfo(content(sid), sc.mc);
+ if (hasContent(info)) {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authenticated(content(info), r));
+ }
+ }
+
+ // Get the request args
+ const list<list<value> > args = httpd::queryArgs(r);
+
+ // Decline if the request is for another authentication provider
+ if (!isNil(assoc<value>("openid_identifier", args)))
+ return DECLINED;
+ if (!isNil(assoc<value>("mod_oauth2_step", args)))
+ return DECLINED;
+
+ // Determine the OAuth protocol flow step, conveniently passed
+ // around in a request arg
+ const list<value> sl = assoc<value>("mod_oauth1_step", args);
+ const value step = !isNil(sl) && !isNil(cdr(sl))? cadr(sl) : "";
+
+ // Handle OAuth authorize request step
+ if (step == "authorize") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authorize(args, r, sc));
+ }
+
+ // Handle OAuth access_token request step
+ if (step == "access_token") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(access_token(args, r, sc));
+ }
+
+ // Redirect to the login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(openauth::login(dc.login, r));
+}
+
+/**
+ * Process the module configuration.
+ */
+int postConfigMerge(ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth1);
+ debug(httpd::serverName(s), "modoauth1::postConfigMerge::serverName");
+
+ // Merge configuration from main server
+ if (isNil(sc.appkeys))
+ sc.appkeys = mainsc.appkeys;
+ sc.mc = mainsc.mc;
+ sc.cs = mainsc.cs;
+
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth1);
+ debug(httpd::serverName(s), "modoauth1::postConfig::serverName");
+
+ // Merge server configurations
+ return postConfigMerge(sc, s);
+}
+
+/**
+ * Child process initialization.
+ */
+void childInit(apr_pool_t* p, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_oauth1);
+ if(psc == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_oauth1 loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+ ServerConf& sc = *psc;
+
+ // Connect to Memcached
+ if (isNil(sc.mcaddrs))
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached("localhost", 11211));
+ else
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(sc.mcaddrs));
+
+ // Setup a CURL session
+ sc.cs = *(new (gc_new<http::CURLSession>()) http::CURLSession(sc.ca, sc.cert, sc.key));
+
+ // Merge the updated configuration into the virtual hosts
+ postConfigMerge(sc, s->next);
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confAppKey(cmd_parms *cmd, unused void *c, const char *arg1, const char* arg2, const char* arg3) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.appkeys = cons<list<value> >(mklist<value>(arg1, mklist<value>(arg2, arg3)), sc.appkeys);
+ return NULL;
+}
+const char* confMemcached(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.mcaddrs = cons<string>(arg, sc.mcaddrs);
+ return NULL;
+}
+const char* confEnabled(cmd_parms *cmd, void *c, const int arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.enabled = (bool)arg;
+ return NULL;
+}
+const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.login = arg;
+ return NULL;
+}
+const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.ca = arg;
+ return NULL;
+}
+const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.cert = arg;
+ return NULL;
+}
+const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.key = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_TAKE3("AddAuthOAuth1AppKey", (const char*(*)())confAppKey, NULL, RSRC_CONF, "OAuth 2.0 name app-id app-key"),
+ AP_INIT_ITERATE("AddAuthOAuthMemcached", (const char*(*)())confMemcached, NULL, RSRC_CONF, "Memcached server host:port"),
+ AP_INIT_FLAG("AuthOAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "OAuth 2.0 authentication On | Off"),
+ AP_INIT_TAKE1("AuthOAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "OAuth 2.0 login page"),
+ AP_INIT_TAKE1("AuthOAuthSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "OAUth 2.0 SSL CA certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate key file"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+void registerHooks(unused apr_pool_t *p) {
+ ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_check_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
+}
+
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_oauth1 = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::oauth1::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::oauth1::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::oauth1::commands, tuscany::oauth1::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp
new file mode 100644
index 0000000000..b52967977e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module for OAuth 2.0 authentication.
+ */
+
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../http/httpd.hpp"
+#include "../http/http.hpp"
+#include "../http/openauth.hpp"
+#include "../../components/cache/memcache.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2;
+}
+
+namespace tuscany {
+namespace oauth2 {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ string ca;
+ string cert;
+ string key;
+ list<list<value> > appkeys;
+ list<string> mcaddrs;
+ memcache::MemCached mc;
+ http::CURLSession cs;
+};
+
+/**
+ * Directory configuration.
+ */
+class DirConf {
+public:
+ DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") {
+ }
+
+ const gc_pool p;
+ const char* dir;
+ bool enabled;
+ string login;
+};
+
+/**
+ * Return the user info for a session.
+ */
+const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) {
+ return memcache::get(mklist<value>("tuscanyOpenAuth", sid), mc);
+}
+
+/**
+ * Handle an authenticated request.
+ */
+const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+ debug(info, "modoauth2::authenticated::info");
+
+ // Store user info in the request
+ const list<value> realm = assoc<value>("realm", info);
+ if (isNil(realm) || isNil(cdr(realm)))
+ return mkfailure<int>("Couldn't retrieve realm");
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
+
+ const list<value> id = assoc<value>("id", info);
+ if (isNil(id) || isNil(cdr(id)))
+ return mkfailure<int>("Couldn't retrieve user id");
+ r->user = apr_pstrdup(r->pool, c_str(cadr(id)));
+
+ const list<value> email = assoc<value>("email", info);
+ if (!isNil(email) && !isNil(cdr(email)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "EMAIL"), apr_pstrdup(r->pool, c_str(cadr(email))));
+
+ const list<value> fullname = assoc<value>("name", info);
+ if (!isNil(fullname) && !isNil(cdr(fullname))) {
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname))));
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname))));
+ }
+
+ const list<value> firstname = assoc<value>("first_name", info);
+ if (!isNil(firstname) && !isNil(cdr(firstname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FIRSTNAME"), apr_pstrdup(r->pool, c_str(cadr(firstname))));
+
+ const list<value> lastname = assoc<value>("last_name", info);
+ if (!isNil(lastname) && !isNil(cdr(lastname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname))));
+
+ return OK;
+}
+
+/**
+ * Handle an authorize request.
+ */
+const failable<int> authorize(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract authorize, access_token, client ID and info URIs
+ const list<value> auth = assoc<value>("mod_oauth2_authorize", args);
+ if (isNil(auth) || isNil(cdr(auth)))
+ return mkfailure<int>("Missing mod_oauth2_authorize parameter");
+ const list<value> tok = assoc<value>("mod_oauth2_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth2_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth2_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth2_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth2_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth2_info parameter");
+
+ // Build the redirect URI
+ const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
+ const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(rargs);
+ debug(redir, "modoauth2::authorize::redir");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Redirect to the authorize URI
+ const list<list<value> > aargs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("scope", "email"), mklist<value>("redirect_uri", httpd::escape(redir)));
+ const string uri = httpd::unescape(cadr(auth)) + string("?") + httpd::queryString(aargs);
+ debug(uri, "modoauth2::authorize::uri");
+ return httpd::externalRedirect(uri, r);
+}
+
+/**
+ * Extract user info from a profile/info response.
+ * TODO This currently only works for Facebook and Gowalla.
+ * User profile parsing needs to be made configurable.
+ */
+const failable<list<value> > profileUserInfo(const value& cid, const list<value>& info) {
+ return cons<value>(mklist<value>("realm", cid), info);
+}
+
+/**
+ * Handle an access_token request.
+ */
+const failable<int> access_token(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract access_token URI, client ID and authorization code
+ const list<value> tok = assoc<value>("mod_oauth2_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth2_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth2_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth2_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth2_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth2_info parameter");
+ const list<value> code = assoc<value>("code", args);
+ if (isNil(code) || isNil(cdr(code)))
+ return mkfailure<int>("Missing code parameter");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Build the redirect URI
+ const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
+ const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(rargs);
+ debug(redir, "modoauth2::access_token::redir");
+
+ // Request access token
+ const list<list<value> > targs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("redirect_uri", httpd::escape(redir)), mklist<value>("client_secret", cadr(appkey)), code);
+ const string turi = httpd::unescape(cadr(tok)) + string("?") + httpd::queryString(targs);
+ debug(turi, "modoauth2::access_token::tokenuri");
+ const failable<value> tr = http::get(turi, sc.cs);
+ if (!hasContent(tr))
+ return mkfailure<int>(reason(tr));
+ debug(tr, "modoauth2::access_token::response");
+ const list<value> tv = assoc<value>("access_token", httpd::queryArgs(join("", convertValues<string>(content(tr)))));
+ if (isNil(tv) || isNil(cdr(tv)))
+ return mkfailure<int>("Couldn't retrieve access_token");
+ debug(tv, "modoauth2::access_token::token");
+
+ // Request user info
+ // TODO Make this step configurable
+ const list<list<value> > iargs = mklist<list<value> >(tv);
+ const string iuri = httpd::unescape(cadr(info)) + string("?") + httpd::queryString(iargs);
+ debug(iuri, "modoauth2::access_token::infouri");
+ const failable<value> profres = http::get(iuri, sc.cs);
+ if (!hasContent(profres))
+ return mkfailure<int>("Couldn't retrieve user info");
+ debug(content(profres), "modoauth2::access_token::info");
+
+ // Retrieve the user info from the profile
+ const failable<list<value> > iv = profileUserInfo(cadr(cid), content(profres));
+ if (!hasContent(iv))
+ return mkfailure<int>(reason(iv));
+
+ // Store user info in memcached keyed by session ID
+ const value sid = string("OAuth2_") + mkrand();
+ const failable<bool> prc = memcache::put(mklist<value>("tuscanyOpenAuth", sid), content(iv), sc.mc);
+ if (!hasContent(prc))
+ return mkfailure<int>(reason(prc));
+
+ // Send session ID to the client in a cookie
+ apr_table_set(r->err_headers_out, "Set-Cookie", c_str(openauth::cookie(sid)));
+ return httpd::externalRedirect(httpd::url(r->uri, r), r);
+}
+
+/**
+ * Check user authentication.
+ */
+static int checkAuthn(request_rec *r) {
+ // Decline if we're not enabled or AuthType is not set to Open
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth2);
+ if (!dc.enabled)
+ return DECLINED;
+ const char* atype = ap_auth_type(r);
+ if (atype == NULL || strcasecmp(atype, "Open"))
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modoauth2::checkAuthn::input");
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth2);
+
+ // Get session id from the request
+ const maybe<string> sid = openauth::sessionID(r);
+ if (hasContent(sid)) {
+ // Decline if the session id was not created by this module
+ if (substr(content(sid), 0, 7) != "OAuth2_")
+ return DECLINED;
+
+ // If we're authenticated store the user info in the request
+ const failable<value> info = userInfo(content(sid), sc.mc);
+ if (hasContent(info)) {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authenticated(content(info), r));
+ }
+ }
+
+ // Get the request args
+ const list<list<value> > args = httpd::queryArgs(r);
+
+ // Decline if the request is for another authentication provider
+ if (!isNil(assoc<value>("openid_identifier", args)))
+ return DECLINED;
+ if (!isNil(assoc<value>("mod_oauth1_step", args)))
+ return DECLINED;
+
+ // Determine the OAuth protocol flow step, conveniently passed
+ // around in a request arg
+ const list<value> sl = assoc<value>("mod_oauth2_step", args);
+ const value step = !isNil(sl) && !isNil(cdr(sl))? cadr(sl) : "";
+
+ // Handle OAuth authorize request step
+ if (step == "authorize") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authorize(args, r, sc));
+ }
+
+ // Handle OAuth access_token request step
+ if (step == "access_token") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(access_token(args, r, sc));
+ }
+
+ // Redirect to the login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(openauth::login(dc.login, r));
+}
+
+/**
+ * Process the module configuration.
+ */
+int postConfigMerge(ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
+ debug(httpd::serverName(s), "modoauth2::postConfigMerge::serverName");
+
+ // Merge configuration from main server
+ if (isNil(sc.appkeys))
+ sc.appkeys = mainsc.appkeys;
+ sc.mc = mainsc.mc;
+ sc.cs = mainsc.cs;
+
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
+ debug(httpd::serverName(s), "modoauth2::postConfig::serverName");
+
+ // Merge server configurations
+ return postConfigMerge(sc, s);
+}
+
+/**
+ * Child process initialization.
+ */
+void childInit(apr_pool_t* p, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_oauth2);
+ if(psc == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_oauth2 loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+ ServerConf& sc = *psc;
+
+ // Connect to Memcached
+ if (isNil(sc.mcaddrs))
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached("localhost", 11211));
+ else
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(sc.mcaddrs));
+
+ // Setup a CURL session
+ sc.cs = *(new (gc_new<http::CURLSession>()) http::CURLSession(sc.ca, sc.cert, sc.key));
+
+ // Merge the updated configuration into the virtual hosts
+ postConfigMerge(sc, s->next);
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confAppKey(cmd_parms *cmd, unused void *c, const char *arg1, const char* arg2, const char* arg3) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.appkeys = cons<list<value> >(mklist<value>(arg1, mklist<value>(arg2, arg3)), sc.appkeys);
+ return NULL;
+}
+const char* confMemcached(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.mcaddrs = cons<string>(arg, sc.mcaddrs);
+ return NULL;
+}
+const char* confEnabled(cmd_parms *cmd, void *c, const int arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.enabled = (bool)arg;
+ return NULL;
+}
+const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.login = arg;
+ return NULL;
+}
+const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.ca = arg;
+ return NULL;
+}
+const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.cert = arg;
+ return NULL;
+}
+const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.key = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_TAKE3("AddAuthOAuth2AppKey", (const char*(*)())confAppKey, NULL, RSRC_CONF, "OAuth 2.0 name app-id app-key"),
+ AP_INIT_ITERATE("AddAuthOAuthMemcached", (const char*(*)())confMemcached, NULL, RSRC_CONF, "Memcached server host:port"),
+ AP_INIT_FLAG("AuthOAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "OAuth 2.0 authentication On | Off"),
+ AP_INIT_TAKE1("AuthOAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "OAuth 2.0 login page"),
+ AP_INIT_TAKE1("AuthOAuthSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "OAUth 2.0 SSL CA certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate key file"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+void registerHooks(unused apr_pool_t *p) {
+ ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_check_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
+}
+
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2 = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::oauth2::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::oauth2::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::oauth2::commands, tuscany::oauth2::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf
new file mode 100755
index 0000000000..dc3a6ebc9d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf
@@ -0,0 +1,59 @@
+#!/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
+# 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.
+
+# Generate an OAuth server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Configure HTTPD mod_tuscany_oauth module
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: oauth-conf $*
+# Load support for OAuth authentication
+LoadModule mod_tuscany_oauth1 $here/libmod_tuscany_oauth1.so
+LoadModule mod_tuscany_oauth2 $here/libmod_tuscany_oauth2.so
+
+EOF
+
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: oauth-conf $*
+# Enable OAuth authentication
+<Location />
+AuthType Open
+AuthName "$host"
+AuthOAuth On
+AuthOAuthLoginPage /login
+Require valid-user
+</Location>
+
+# Configure OAuth App keys
+Include $root/cert/oauth-keys.conf
+Include $HOME/.oauth/*-key.conf
+
+EOF
+
+cat >$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth-conf $*
+# OAuth App keys
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf
new file mode 100755
index 0000000000..23a82a0486
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf
@@ -0,0 +1,32 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+host=$2
+port=$3
+
+# Configure HTTPD mod_tuscany_oauth module cache
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: oauth-memcached-conf $*
+AddAuthOAuthMemcached $host:$port
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite
new file mode 100644
index 0000000000..c2025493c8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="oauth">
+
+ <component name="Protected">
+ <t:implementation.widget location="protected/index.html"/>
+ <reference name="userInfo" target="UserInfo"/>
+ </component>
+
+ <component name="UserInfo">
+ <t:implementation.scheme script="user-info.scm"/>
+ <service name="info">
+ <t:binding.jsonrpc uri="info"/>
+ </service>
+ <property name="user">?</property>
+ <property name="email">?</property>
+ <property name="nickname">?</property>
+ <property name="fullname">?</property>
+ <property name="firstname">?</property>
+ <property name="lastname">?</property>
+ <property name="realm">?</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf
new file mode 100755
index 0000000000..fca7d4e8f3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+name=$2
+id=$3
+secret=$4
+
+# Configure an OAuth 1.0 app key
+mkdir -p $root/cert
+umask 0007
+
+cat >>$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth1-appkey-conf $*
+AddAuthOAuth1AppKey $name $id $secret
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf
new file mode 100755
index 0000000000..0a7986f07e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+name=$2
+id=$3
+secret=$4
+
+# Configure an OAuth 2.0 app key
+mkdir -p $root/cert
+umask 0007
+
+cat >>$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth2-appkey-conf $*
+AddAuthOAuth2AppKey $name $id $secret
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test
new file mode 100755
index 0000000000..bfd7667ce4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test
@@ -0,0 +1,67 @@
+#!/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
+# 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 supporting both OpenID and OAuth in the same app
+here=`readlink -f $0`; here=`dirname $here`
+
+# Setup
+../../components/cache/memcached-start 11212
+../../components/cache/memcached-start 11213
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+
+./oauth-conf tmp
+./oauth-memcached-conf tmp localhost 11212
+./oauth-memcached-conf tmp localhost 11213
+
+# Configure your app keys here
+./oauth1-appkey-conf tmp twitter.com app2345 secret7890
+./oauth1-appkey-conf tmp linkedin.com app3456 secret4567
+./oauth2-appkey-conf tmp facebook.com app1234 secret6789
+./oauth2-appkey-conf tmp github.com app5678 secret8901
+
+../openid/openid-conf tmp
+../openid/openid-step2-conf tmp
+../openid/openid-memcached-conf tmp localhost 11212
+../openid/openid-memcached-conf tmp localhost 11213
+
+../http/open-auth-conf tmp
+../http/passwd-auth-conf tmp foo foo
+
+# For this test to work you need to add your form, oauth and open id ids
+# to the authorized user group
+../../modules/http/group-auth-conf tmp foo
+../../modules/http/group-auth-conf tmp 123456
+../../modules/http/group-auth-conf tmp https://www.google.com/accounts/o8/id?id=12345678
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite oauth.composite
+
+Alias /login/index.html $here/htdocs/login/mixed.html
+
+EOF
+
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/start-test b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-test
new file mode 100755
index 0000000000..0e859ce6e6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-test
@@ -0,0 +1,54 @@
+#!/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
+# 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.
+
+# Setup
+../../ubuntu/ip-redirect-all 80 8090
+../../ubuntu/ip-redirect-all 443 8453
+
+../../components/cache/memcached-start 11212
+../../components/cache/memcached-start 11213
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090/80 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453/443
+
+./oauth-conf tmp
+./oauth-memcached-conf tmp localhost 11212
+./oauth-memcached-conf tmp localhost 11213
+
+# Configure your app keys here
+./oauth1-appkey-conf tmp twitter.com app2345 secret7890
+./oauth1-appkey-conf tmp linkedin.com app3456 secret4567
+./oauth2-appkey-conf tmp facebook.com app1234 secret6789
+./oauth2-appkey-conf tmp github.com app5678 secret8901
+
+# For this test to work you need to add your oauth user id to the
+# authorized user group
+../../modules/http/group-auth-conf tmp 123456
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite oauth.composite
+EOF
+
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/stop-test b/sandbox/sebastien/cpp/apr-2/modules/oauth/stop-test
new file mode 100755
index 0000000000..a0587f8cb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/stop-test
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+
+../../components/cache/memcached-stop 11212
+../../components/cache/memcached-stop 11213
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm b/sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm
new file mode 100644
index 0000000000..4960a0a455
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm
@@ -0,0 +1,36 @@
+; 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.
+
+; OAuth support test case
+
+(define (get id user email nickname fullname firstname lastname realm) (list "text/html" (list
+ "<html><body><p>The following info is generated on the server:</p><div>User: " (user) "</div><div>Email: " (email) "</div><div>Nickname: " (nickname) "</div><div>Fullname: " (fullname) "</div><div>Firstname: " (firstname) "</div><div>Lastname: " (lastname) "</div><div>Realm: " (realm) "</div></body></html>")))
+
+(define (getuser user email nickname fullname firstname lastname realm) (user))
+
+(define (getemail user email nickname fullname firstname lastname realm) (email))
+
+(define (getnickname user email nickname fullname firstname lastname realm) (nickname))
+
+(define (getfullname user email nickname fullname firstname lastname realm) (fullname))
+
+(define (getfirstname user email nickname fullname firstname lastname realm) (firstname))
+
+(define (getlastname user email nickname fullname firstname lastname realm) (lastname))
+
+(define (getrealm user email nickname fullname firstname lastname realm) (realm))
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/openid/Makefile.am
new file mode 100644
index 0000000000..a46dd56743
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/Makefile.am
@@ -0,0 +1,32 @@
+# 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.
+
+
+if WANT_OPENID
+
+dist_mod_SCRIPTS = openid-conf openid-step2-conf openid-memcached-conf
+moddir = $(prefix)/modules/openid
+
+mod_DATA = openid.prefix
+openid.prefix: $(top_builddir)/config.status
+ echo ${MODAUTHOPENID_PREFIX} >openid.prefix
+
+EXTRA_DIST = openid.composite user-info.scm htdocs/index.html htdocs/login/index.html htdocs/logout/index.html htdocs/public/index.html
+
+dist_noinst_SCRIPTS = start-test stop-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/index.html
new file mode 100644
index 0000000000..98bbac0c57
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/index.html
@@ -0,0 +1,46 @@
+<!--
+ 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.
+-->
+
+<html>
+<head>
+<script type="text/javascript" src="/component.js"></script>
+<script type="text/javascript">
+var protected = sca.component("Protected");
+var userInfo = sca.defun(sca.reference(protected, "userInfo"), "getuser", "getemail", "getrealm");
+var user = userInfo.getuser();
+var email = userInfo.getemail();
+var realm = userInfo.getrealm();
+</script>
+</head>
+<body>
+<h1>Protected area - It works!</h1>
+<p>The following info is returned by a JSONRPC service:</p>
+<div id="user"></div>
+<div id="email"></div>
+<div id="realm"></div>
+<script type="text/javascript">
+document.getElementById('user').innerHTML="User: " + user;
+document.getElementById('email').innerHTML="Email: " + email;
+document.getElementById('realm').innerHTML="Realm: " + realm;
+</script>
+<p><a href="info">User info</a></p>
+<p><a href="login">Sign in</a></p>
+<p><a href="logout">Sign out</a></p>
+<p><a href="public">Public area</a></p>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/login/index.html b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/login/index.html
new file mode 100644
index 0000000000..493227addc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/login/index.html
@@ -0,0 +1,129 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with an OpenID provider</h1>
+
+<script type="text/javascript">
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function openidReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(openidReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitSignin(w) {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signin.openid_identifier.value = w();
+ document.signin.action = openidReferrer();
+ document.signin.submit();
+}
+
+
+function withGoogle() {
+ return 'https://www.google.com/accounts/o8/id';
+}
+
+function withYahoo() {
+ return 'https://me.yahoo.com/';
+}
+
+function withMyOpenID() {
+ return 'http://www.myopenid.com/xrds';
+}
+
+function withVerisign() {
+ return 'https://pip.verisignlabs.com/';
+}
+
+function withMySpace() {
+ return 'https://api.myspace.com/openid';
+}
+
+function withGoogleApps() {
+ return 'https://www.google.com/accounts/o8/site-xrds?ns=2&hd=' + document.fields.domain.value;
+}
+
+function withLivejournal() {
+ return 'http://' + document.fields.ljuser.value + '.livejournal.com';
+}
+
+function withBlogspot() {
+ return 'http://' + document.fields.bsuser.value + '.blogspot.com';
+}
+
+function withBlogger() {
+ return 'http://' + document.fields.bguser.value + '.blogger.com';
+}
+
+function withXRDSEndpoint() {
+ return document.fields.endpoint.value;
+}
+</script>
+
+<form name="signin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value="https://www.google.com/accounts/o8/id"/>
+</form>
+
+<form name="fields">
+<p>Sign in with your Google account<br/><input type="button" onclick="submitSignin(withGoogle)" value="Sign in"/></p>
+<p>Sign in with your Yahoo account<br/><input type="button" onclick="submitSignin(withYahoo)" value="Sign in"/></p>
+<p>Sign in with your MyOpenID account<br/><input type="button" onclick="submitSignin(withMyOpenID)" value="Sign in"/></p>
+<p>Sign in with your Verisign account<br/><input type="button" onclick="submitSignin(withVerisign)" value="Sign in"/></p>
+<p>Sign in with your MySpace account<br/><input type="button" onclick="submitSignin(withMySpace)" value="Sign in"/></p>
+
+<p>Sign in with a Google apps domain<br/>
+<input type="text" size="20" name="domain" value="example.com"/><br/>
+<input type="button" onclick="submitSignin(withGoogleApps)" value="Sign in"/></p>
+
+<p>Sign in with your Livejournal account<br/>
+<input type="text" size="10" name="ljuser" value=""/><br/>
+<input type="button" onclick="submitSignin(withLivejournal)" value="Sign in"/></p>
+
+<p>Sign in with your Blogspot account<br/>
+<input type="text" size="10" name="bsuser" value=""/><br/>
+<input type="button" onclick="submitSignin(withBlogspot)" value="Sign in"/></p>
+
+<p>Sign in with your Blogger account<br/>
+<input type="text" size="10" name="bguser" value=""/><br/>
+<input type="button" onclick="submitSignin(withBlogger)" value="Sign in"/></p>
+
+<p>Sign in with an OpenID endpoint<br/>
+<input type="text" size="50" name="endpoint" value="https://www.google.com/accounts/o8/id"/><br/>
+<input type="button" onclick="submitSignin(withXRDSEndpoint)" value="Sign in"/></p>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/logout/index.html b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/logout/index.html
new file mode 100644
index 0000000000..02a92d1b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/public/index.html b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/public/index.html
new file mode 100644
index 0000000000..af2cd7ca19
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/htdocs/public/index.html
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+
+<html>
+<body>
+<h1>Unprotected area - It works!</h1>
+<p><a href="/info">User info</a></p>
+<p><a href="/login">Sign in</a></p>
+<p><a href="/logout">Sign out</a></p>
+<p><a href="/">Protected area</a></p>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/openid-conf b/sandbox/sebastien/cpp/apr-2/modules/openid/openid-conf
new file mode 100755
index 0000000000..797f8b0607
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/openid-conf
@@ -0,0 +1,67 @@
+#!/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
+# 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.
+
+# Generate an OpenID server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+openid_prefix=`cat $here/openid.prefix`
+
+# Configure OpenID authentication
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: openid-conf $*
+# Load support for OpenID authentication
+LoadModule authopenid_module $openid_prefix/modules/mod_auth_openid.so
+
+EOF
+
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: openid-conf $*
+# Enable OpenID authentication
+<Location />
+AuthType Open
+AuthName "$host"
+Require valid-user
+AuthOpenIDEnabled On
+AuthOpenIDCookiePath /
+AuthOpenIDCookieName TuscanyOpenAuth
+AuthOpenIDSecureCookie On
+AuthOpenIDLoginPage /login
+AuthOpenIDAXAdd EMAIL http://axschema.org/contact/email
+AuthOpenIDAXAdd FULLNAME http://axschema.org/namePerson
+AuthOpenIDAXAdd NICKNAME http://axschema.org/namePerson/friendly
+AuthOpenIDAXAdd FIRSTNAME http://axschema.org/namePerson/first
+AuthOpenIDAXAdd LASTNAME http://axschema.org/namePerson/last
+</Location>
+
+EOF
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: openid-conf $*
+# Allow access to /openid location
+<Location /openid>
+AuthType None
+Require all granted
+</Location>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/openid-memcached-conf b/sandbox/sebastien/cpp/apr-2/modules/openid/openid-memcached-conf
new file mode 100755
index 0000000000..1717b3ce92
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/openid-memcached-conf
@@ -0,0 +1,32 @@
+#!/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
+# 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.
+
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+host=$2
+port=$3
+
+# Configure HTTPD mod_auth_openid module cache
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: openid-cache-conf $*
+AddAuthOpenIDMemcached $host:$port
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/openid-step2-conf b/sandbox/sebastien/cpp/apr-2/modules/openid/openid-step2-conf
new file mode 100755
index 0000000000..559a62d20b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/openid-step2-conf
@@ -0,0 +1,78 @@
+#!/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
+# 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.
+
+# Generate an OpenID Step2 server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Configure HTTPD to serve OpenID XRDS and LRDD documents
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: openid-step2-conf $*
+# Serve OpenID XRDS document
+Alias /openid $root/conf/openid.xrds
+<Location /openid>
+ForceType application/xrds+xml
+</Location>
+
+# Serve OpenID LRDD document
+Alias /.well-known/host-meta $root/conf/openid.lrdd
+<Location /.well-known/host-meta>
+ForceType text/plain
+</Location>
+
+EOF
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: openid-conf $*
+# Allow access to /.well-known/host-meta location
+<Location /.well-known/host-meta>
+AuthType None
+Require all granted
+</Location>
+
+EOF
+
+# Generate OpenID XRDS document
+cat >$root/conf/openid.xrds <<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<xrds:XRDS xmlns:xrds="xri://\$xrds" xmlns="xri://\$xrd*(\$v*2.0)">
+<XRD>
+<CanonicalID>$host</CanonicalID>
+<Service priority="0">
+<Type>http://specs.openid.net/auth/2.0/server</Type>
+<Type>http://specs.openid.net/auth/2.0/signon</Type>
+<Type>http://openid.net/srv/ax/1.0</Type>
+<Type>http://specs.openid.net/extensions/ui/1.0/mode/popup</Type>
+<Type>http://specs.openid.net/extensions/ui/1.0/icon</Type>
+<Type>http://specs.openid.net/extensions/pape/1.0</Type>
+<URI>https://www.google.com/a/$host/o8/ud?be=o8</URI>
+</Service>
+</XRD>
+</xrds:XRDS>
+EOF
+
+# Generate OpenID LRDD document
+cat >$root/conf/openid.lrdd <<EOF
+Link: <https://www.google.com/accounts/o8/site-xrds?hd=$host>; rel="describedby http://reltype.google.com/openid/xrd-op"; type="application/xrds+xml"
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/openid.composite b/sandbox/sebastien/cpp/apr-2/modules/openid/openid.composite
new file mode 100644
index 0000000000..08bb74b7c7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/openid.composite
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="openid">
+
+ <component name="Protected">
+ <t:implementation.widget location="protected/index.html"/>
+ <reference name="userInfo" target="UserInfo"/>
+ </component>
+
+ <component name="UserInfo">
+ <t:implementation.scheme script="user-info.scm"/>
+ <service name="info">
+ <t:binding.jsonrpc uri="info"/>
+ </service>
+ <property name="user">anonymous</property>
+ <property name="email">anonymous@example.com</property>
+ <property name="realm">example.com</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/start-test b/sandbox/sebastien/cpp/apr-2/modules/openid/start-test
new file mode 100755
index 0000000000..7ae27c57cd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/start-test
@@ -0,0 +1,46 @@
+#!/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
+# 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.
+
+# Setup
+../../components/cache/memcached-start 11212
+../../components/cache/memcached-start 11213
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+
+./openid-conf tmp
+./openid-memcached-conf tmp localhost 11212
+./openid-memcached-conf tmp localhost 11213
+./openid-step2-conf tmp
+
+# For this test to work you need to add your openid to the
+# the authorized user group
+../../modules/http/group-auth-conf tmp https://www.google.com/accounts/o8/id?id=1234567
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite openid.composite
+EOF
+
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/stop-test b/sandbox/sebastien/cpp/apr-2/modules/openid/stop-test
new file mode 100755
index 0000000000..a0587f8cb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/stop-test
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+
+../../components/cache/memcached-stop 11212
+../../components/cache/memcached-stop 11213
diff --git a/sandbox/sebastien/cpp/apr-2/modules/openid/user-info.scm b/sandbox/sebastien/cpp/apr-2/modules/openid/user-info.scm
new file mode 100644
index 0000000000..b1ef74c6bd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/openid/user-info.scm
@@ -0,0 +1,28 @@
+; 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.
+
+; OpenID support test case
+
+(define (get id user email realm) (list "text/html" (list
+ "<html><body><p>The following info is generated on the server:</p><div>User: " (user) "</div><div>Email: " (email) "</div><div>Realm: " (realm) "</div></body></html>")))
+
+(define (getuser user email realm) (user))
+
+(define (getemail user email realm) (email))
+
+(define (getrealm user email realm) (realm))
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/python/Makefile.am
new file mode 100644
index 0000000000..2f56b9a1db
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/Makefile.am
@@ -0,0 +1,56 @@
+# 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.
+
+
+if WANT_PYTHON
+
+INCLUDES = -I${PYTHON_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/python
+
+dist_mod_SCRIPTS = python-conf
+moddir = $(prefix)/modules/python
+
+prefix_DATA = python.prefix
+prefixdir = $(prefix)/modules/python
+python.prefix: $(top_builddir)/config.status
+ echo ${PYTHON_PREFIX} >python.prefix
+
+EXTRA_DIST = domain-test.composite client-test.py server-test.py
+
+mod_LTLIBRARIES = libmod_tuscany_python.la
+libmod_tuscany_python_la_SOURCES = mod-python.cpp
+libmod_tuscany_python_la_LDFLAGS = -lxml2 -lcurl -lmozjs -L${PYTHON_LIB} -R${PYTHON_LIB} -lpython2.6
+noinst_DATA = libmod_tuscany_python.so
+libmod_tuscany_python.so:
+ ln -s .libs/libmod_tuscany_python.so
+
+python_test_SOURCES = python-test.cpp
+python_test_LDFLAGS = -L${PYTHON_LIB} -R${PYTHON_LIB} -lpython2.6
+
+python_shell_SOURCES = python-shell.cpp
+python_shell_LDFLAGS = -L${PYTHON_LIB} -R${PYTHON_LIB} -lpython2.6
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = server-test wiring-test
+noinst_PROGRAMS = python-test python-shell client-test
+TESTS = python-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/client-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/python/client-test.cpp
new file mode 100644
index 0000000000..21fda53e05
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/client-test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "../server/client-test.hpp"
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ tuscany::server::testURI = "http://localhost:8090/python";
+
+ tuscany::server::testServer();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/client-test.py b/sandbox/sebastien/cpp/apr-2/modules/python/client-test.py
new file mode 100644
index 0000000000..3c7183e865
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/client-test.py
@@ -0,0 +1,40 @@
+# 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.
+
+import unittest
+
+# JSON-RPC test case
+
+def echo(x, ref):
+ e1 = ref("echo", x)
+ e2 = ref.echo(x)
+ assert e1 == e2
+ return e1
+
+# ATOMPub test case
+
+def get(id, ref):
+ return ref.get(id);
+
+def post(collection, item, ref):
+ return ref.post(collection, item)
+
+def put(id, item, ref):
+ return ref.put(id, item)
+
+def delete(id, ref):
+ return ref.delete(id)
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/domain-test.composite b/sandbox/sebastien/cpp/apr-2/modules/python/domain-test.composite
new file mode 100644
index 0000000000..c8e92b286e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/domain-test.composite
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://domain/test"
+ name="domain-test">
+
+ <component name="python-test">
+ <t:implementation.python script="server-test.py"/>
+ <service name="test">
+ <t:binding.http uri="python"/>
+ </service>
+ </component>
+
+ <component name="client-test">
+ <t:implementation.python script="client-test.py"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="ref" target="python-test">
+ <t:binding.http/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/driver.hpp b/sandbox/sebastien/cpp/apr-2/modules/python/driver.hpp
new file mode 100644
index 0000000000..79897b0c5e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/driver.hpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_python_driver_hpp
+#define tuscany_python_driver_hpp
+
+/**
+ * Python evaluator main driver loop.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "monad.hpp"
+#include "../scheme/driver.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace python {
+
+const value evalDriverLoop(PyObject* script, istream& in, ostream& out) {
+ scheme::promptForInput(scheme::evalInputPrompt, out);
+ value input = scheme::readValue(in);
+ if (isNil(input))
+ return input;
+ const failable<value> output = evalScript(input, script);
+ scheme::announceOutput(scheme::evalOutputPrompt, out);
+ scheme::userPrint(content(output), out);
+ return evalDriverLoop(script, in, out);
+}
+
+const bool evalDriverRun(const char* path, istream& in, ostream& out) {
+ PythonRuntime py;
+ scheme::setupDisplay(out);
+ ifstream is(path);
+ failable<PyObject*> script = readScript(moduleName(path), path, is);
+ if (!hasContent(script))
+ return true;
+ evalDriverLoop(content(script), in, out);
+ Py_DECREF(content(script));
+ return true;
+}
+
+}
+}
+#endif /* tuscany_python_driver_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/eval.hpp b/sandbox/sebastien/cpp/apr-2/modules/python/eval.hpp
new file mode 100644
index 0000000000..2dd4b8ba33
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/eval.hpp
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_python_eval_hpp
+#define tuscany_python_eval_hpp
+
+/**
+ * Python script evaluation logic.
+ */
+#include <python2.6/Python.h>
+
+#include "list.hpp"
+#include "value.hpp"
+
+namespace tuscany {
+namespace python {
+
+/**
+ * Represent a Python runtime.
+ */
+class PythonRuntime {
+public:
+ PythonRuntime() {
+ if (Py_IsInitialized())
+ return;
+ Py_InitializeEx(0);
+ const char* arg0 = "";
+ PySys_SetArgv(0, const_cast<char**>(&arg0));
+ }
+};
+
+/**
+ * Return the last python error.
+ */
+const string lastError() {
+ if(PyErr_Occurred()) {
+ PyObject* type;
+ PyObject* val;
+ PyObject* trace;
+ PyErr_Fetch(&type, &val, &trace);
+ if (type != NULL && val != NULL) {
+ PyObject* stype = PyObject_Str(type);
+ PyObject* sval = PyObject_Str(val);
+ string msg = string() + PyString_AsString(stype) + " : " + PyString_AsString(sval);
+ Py_DECREF(stype);
+ Py_DECREF(sval);
+ Py_DECREF(type);
+ Py_DECREF(val);
+ Py_XDECREF(trace);
+ PyErr_Print();
+ return msg;
+ }
+ PyErr_Print();
+ Py_XDECREF(type);
+ Py_XDECREF(val);
+ Py_XDECREF(trace);
+ PyErr_Print();
+ return "Unknown Python error";
+ }
+ return "";
+}
+
+/**
+ * Declare conversion functions.
+ */
+PyObject* valueToPyObject(const value& v);
+const value pyObjectToValue(PyObject *o);
+PyObject* valuesToPyTuple(const list<value>& v);
+const list<value> pyTupleToValues(PyObject* o);
+
+/**
+ * Callable python type used to represent a lambda expression.
+ */
+typedef struct {
+ PyObject_HEAD
+ lambda<value(const list<value>&)> func;
+} pyLambda;
+
+PyObject *mkPyLambda(const lambda<value(const list<value>&)>& l);
+
+void pyLambda_dealloc(PyObject* self) {
+ PyMem_DEL(self);
+}
+
+const string pyRepr(PyObject * o) {
+ return PyString_AsString(PyObject_Repr(o));
+}
+
+PyObject* pyLambda_call(PyObject* self, PyObject* args, unused PyObject* kwds) {
+ debug("python::call");
+ const pyLambda* pyl = (pyLambda*)self;
+ const value result = pyl->func(pyTupleToValues(args));
+ debug(result, "python::call::result");
+ Py_DECREF(args);
+ PyObject *pyr = valueToPyObject(result);
+ Py_INCREF(pyr);
+ return pyr;
+}
+
+struct pyProxy {
+ const value name;
+ const lambda<value(const list<value>&)> func;
+
+ pyProxy(const value& name, const lambda<value(const list<value>&)>& func) : name(name), func(func) {
+ }
+
+ const value operator()(const list<value>& args) const {
+ debug(name, "python::proxy::name");
+ const value result = func(cons<value>(name, args));
+ debug(result, "python::proxy::result");
+ return result;
+ }
+};
+
+PyObject* pyLambda_getattr(PyObject *self, PyObject *attrname) {
+ const string name = PyString_AsString(attrname);
+ if (substr(name, 0, 1) == "_")
+ return PyObject_GenericGetAttr(self, attrname);
+
+ if (name == "eval") {
+ Py_INCREF(self);
+ return self;
+ }
+
+ const pyLambda* pyl = (pyLambda*)self;
+ debug(name, "python::getattr::name");
+ PyObject* pyr = mkPyLambda(pyProxy(name, pyl->func));
+ Py_INCREF(pyr);
+ return pyr;
+}
+
+PyTypeObject pyLambda_type = {
+ PyObject_HEAD_INIT(0)
+ 0,
+ "lambda",
+ sizeof(pyLambda),
+ 0,
+ (destructor)pyLambda_dealloc,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ (ternaryfunc)pyLambda_call,
+ 0,
+ (binaryfunc)pyLambda_getattr,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
+
+/**
+ * Create a new python object representing a lambda expression.
+ */
+PyObject *mkPyLambda(const lambda<value(const list<value>&)>& l) {
+ pyLambda* pyl = NULL;
+ pyl = PyObject_NEW(pyLambda, &pyLambda_type);
+ if (pyl != NULL)
+ pyl->func = l;
+ return (PyObject *)pyl;
+}
+
+/**
+ * Convert a list of values to a python list.
+ */
+PyObject* valuesToPyListHelper(PyObject* l, const list<value>& v) {
+ if (isNil(v))
+ return l;
+ PyList_Append(l, valueToPyObject(car(v)));
+ return valuesToPyListHelper(l, cdr(v));
+}
+
+PyObject* valuesToPyTuple(const list<value>& v) {
+ return PyList_AsTuple(valuesToPyListHelper(PyList_New(0), v));
+}
+
+/**
+ * Convert a value to a python object.
+ */
+PyObject* valueToPyObject(const value& v) {
+ switch (type(v)) {
+ case value::List:
+ return valuesToPyTuple(v);
+ case value::Lambda:
+ return mkPyLambda(v);
+ case value::Symbol:
+ return PyString_FromString(c_str(string("'") + v));
+ case value::String:
+ return PyString_FromString(c_str(v));
+ case value::Number:
+ return PyFloat_FromDouble((double)v);
+ case value::Bool:
+ return (bool)v? Py_True : Py_False;
+ default:
+ return Py_None;
+ }
+}
+
+/**
+ * Convert a python tuple to a list of values.
+ */
+
+const list<value> pyTupleToValuesHelper(PyObject* o, const size_t i, const size_t size) {
+ if (i == size)
+ return list<value>();
+ return cons(pyObjectToValue(PyTuple_GetItem(o, i)), pyTupleToValuesHelper(o, i + 1, size));
+}
+
+const list<value> pyTupleToValues(PyObject* o) {
+ return pyTupleToValuesHelper(o, 0, PyTuple_Size(o));
+}
+
+/**
+ * Lambda function used to represent a python callable object.
+ */
+struct pyCallable {
+ PyObject* func;
+
+ pyCallable(PyObject* func) : func(func) {
+ Py_INCREF(func);
+ }
+
+ ~pyCallable() {
+ Py_DECREF(func);
+ }
+
+ const value operator()(const list<value>& args) const {
+ PyObject* pyargs = valuesToPyTuple(args);
+ PyObject* result = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ const value v = pyObjectToValue(result);
+ Py_DECREF(result);
+ return v;
+ }
+};
+
+/**
+ * Convert a python object to a value.
+ */
+const value pyObjectToValue(PyObject *o) {
+ if (PyString_Check(o)) {
+ const char* s = PyString_AsString(o);
+ if (*s == '\'')
+ return value(s + 1);
+ return value(string(s));
+ }
+ if (PyBool_Check(o))
+ return value(o == Py_True);
+ if (PyInt_Check(o))
+ return value((double)PyInt_AsLong(o));
+ if (PyLong_Check(o))
+ return value((double)PyLong_AsLong(o));
+ if (PyFloat_Check(o))
+ return value((double)PyFloat_AsDouble(o));
+ if (PyTuple_Check(o))
+ return pyTupleToValues(o);
+ if (PyCallable_Check(o))
+ return lambda<value(const list<value>&)>(pyCallable(o));
+ return value();
+}
+
+/**
+ * Convert a python script path to a module name.
+ */
+const string moduleName(const string& path) {
+ return join(".", tokenize("/", substr(path, 0, length(path) -3)));
+}
+
+/**
+ * Evaluate an expression against a script provided as a python object.
+ */
+const failable<value> evalScript(const value& expr, PyObject* script) {
+
+ // Get the requested function
+ PyObject* func = PyObject_GetAttrString(script, c_str(car<value>(expr)));
+ if (func == NULL) {
+
+ // The start, stop, and restart functions are optional
+ const value fn = car<value>(expr);
+ if (fn == "start" || fn == "stop") {
+ PyErr_Clear();
+ return value(lambda<value(const list<value>&)>());
+ }
+
+ return mkfailure<value>(string("Couldn't find function: ") + car<value>(expr) + " : " + lastError());
+ }
+ if (!PyCallable_Check(func)) {
+ Py_DECREF(func);
+ return mkfailure<value>(string("Couldn't find callable function: ") + car<value>(expr));
+ }
+
+ // Convert args to python objects
+ PyObject* args = valuesToPyTuple(cdr<value>(expr));
+
+ // Call the function
+ PyObject* result = PyObject_CallObject(func, args);
+ Py_DECREF(args);
+ Py_DECREF(func);
+ if (result == NULL)
+ return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastError());
+
+ // Convert python result to a value
+ const value v = pyObjectToValue(result);
+ Py_DECREF(result);
+ return v;
+}
+
+/**
+ * Read a python script from an input stream.
+ */
+const failable<PyObject*> readScript(const string& name, const string& path, istream& is) {
+ const list<string> ls = streamList(is);
+ ostringstream os;
+ write(ls, os);
+ PyObject* code = Py_CompileStringFlags(c_str(str(os)), c_str(path), Py_file_input, NULL);
+ if (code == NULL)
+ return mkfailure<PyObject*>(string("Couldn't compile script: ") + path + " : " + lastError());
+ PyObject* mod = PyImport_ExecCodeModuleEx(const_cast<char*>(c_str(name)), code, const_cast<char*>(c_str(path)));
+ if (mod == NULL)
+ return mkfailure<PyObject*>(string("Couldn't import module: ") + path + " : " + lastError());
+ return mod;
+}
+
+/**
+ * Evaluate an expression against a script provided as an input stream.
+ */
+const failable<value> evalScript(const value& expr, istream& is) {
+ failable<PyObject*> script = readScript("script", "script.py", is);
+ if (!hasContent(script))
+ return mkfailure<value>(reason(script));
+ return evalScript(expr, content(script));
+}
+
+}
+}
+#endif /* tuscany_python_eval_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/mod-python.cpp b/sandbox/sebastien/cpp/apr-2/modules/python/mod-python.cpp
new file mode 100644
index 0000000000..8561a1fbf4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/mod-python.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module used to eval Python component implementations.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../server/mod-cpp.hpp"
+#include "../server/mod-eval.hpp"
+#include "mod-python.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+
+/**
+ * Apply a lifecycle start or restart event.
+ */
+const value applyLifecycle(unused const list<value>& params) {
+
+ // Create a Python runtime
+ new (gc_new<python::PythonRuntime>()) python::PythonRuntime();
+
+ // Return a nil function as we don't need to handle the stop event
+ return failable<value>(lambda<value(const list<value>&)>());
+}
+
+/**
+ * Evaluate a Python component implementation and convert it to an applicable
+ * lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, unused const lambda<value(const list<value>&)>& lifecycle) {
+ const string itype(elementName(impl));
+ if (contains(itype, ".python"))
+ return modpython::evalImplementation(path, impl, px);
+ if (contains(itype, ".cpp"))
+ return modcpp::evalImplementation(path, impl, px);
+ return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype);
+}
+
+}
+}
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/mod-python.hpp b/sandbox/sebastien/cpp/apr-2/modules/python/mod-python.hpp
new file mode 100644
index 0000000000..0121779530
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/mod-python.hpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_modpython_hpp
+#define tuscany_modpython_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate Python
+ * component implementations.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modpython {
+
+/**
+ * Apply a Python component implementation function.
+ */
+struct applyImplementation {
+ PyObject* impl;
+ const list<value> px;
+ applyImplementation(PyObject* impl, const list<value>& px) : impl(impl), px(px) {
+ }
+ const value operator()(const list<value>& params) const {
+ const value expr = append<value>(params, px);
+ debug(expr, "modeval::python::applyImplementation::input");
+ const failable<value> res = python::evalScript(expr, impl);
+ const value val = !hasContent(res)? mklist<value>(value(), reason(res)) : mklist<value>(content(res));
+ debug(val, "modeval::python::applyImplementation::result");
+ return val;
+ }
+};
+
+/**
+ * Evaluate a Python component implementation and convert it to an applicable
+ * lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) {
+ const string spath(attributeValue("script", impl));
+ const string fpath(path + spath);
+ ifstream is(fpath);
+ if (fail(is))
+ return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath);
+ const failable<PyObject*> script = python::readScript(python::moduleName(spath), fpath, is);
+ if (!hasContent(script))
+ return mkfailure<lambda<value(const list<value>&)> >(reason(script));
+ return lambda<value(const list<value>&)>(applyImplementation(content(script), px));
+}
+
+}
+}
+}
+
+#endif /* tuscany_modpython_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/python-conf b/sandbox/sebastien/cpp/apr-2/modules/python/python-conf
new file mode 100755
index 0000000000..a5b45357fc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/python-conf
@@ -0,0 +1,30 @@
+#!/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
+# 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.
+
+# Generate a Python server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: python-conf $*
+# Support for Python SCA components
+LoadModule mod_tuscany_eval $here/libmod_tuscany_python.so
+
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/python-shell.cpp b/sandbox/sebastien/cpp/apr-2/modules/python/python-shell.cpp
new file mode 100644
index 0000000000..89b47b8d44
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/python-shell.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Python script evaluator shell, used for interactive testing of scripts.
+ */
+
+#include <assert.h>
+#include "gc.hpp"
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+int main(const int argc, char** argv) {
+ tuscany::gc_scoped_pool pool;
+ if (argc != 2) {
+ tuscany::cerr << "Usage: python-shell <script.py>" << tuscany::endl;
+ return 1;
+ }
+ tuscany::python::evalDriverRun(argv[1], tuscany::cin, tuscany::cout);
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/python-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/python/python-test.cpp
new file mode 100644
index 0000000000..41889e6d0e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/python-test.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Python script evaluator.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+namespace tuscany {
+namespace python {
+
+const string testPythonAdd =
+ "def add(x, y):\n"
+ " return x + y\n";
+
+bool testEvalExpr() {
+ gc_scoped_pool pool;
+ PythonRuntime py;
+
+ istringstream is(testPythonAdd);
+ failable<PyObject*> script = readScript("script", "script.py", is);
+ assert(hasContent(script));
+
+ const value exp = mklist<value>("add", 2, 3);
+ const failable<value> r = evalScript(exp, content(script));
+ assert(hasContent(r));
+ assert(content(r) == value(5));
+
+ return true;
+}
+
+const value mult(const list<value>& args) {
+ const double x = car(args);
+ const double y = cadr(args);
+ return x * y;
+}
+
+const string testReturnLambda(
+ "def mul(x, y):\n"
+ " return x * y\n"
+ "\n"
+ "def testReturnLambda():\n"
+ " return mul\n");
+
+const string testCallLambda(
+ "def testCallLambda(l, x, y):\n"
+ " return l(x, y)\n");
+
+bool testEvalLambda() {
+ gc_scoped_pool pool;
+ PythonRuntime py;
+
+ const value trl = mklist<value>("testReturnLambda");
+ istringstream trlis(testReturnLambda);
+ const failable<value> trlv = evalScript(trl, trlis);
+
+ assert(hasContent(trlv));
+ assert(isLambda(content(trlv)));
+ const lambda<value(const list<value>&)> trll(content(trlv));
+ assert(trll(mklist<value>(2, 3)) == value(6));
+
+ istringstream tclis(testCallLambda);
+ const value tcl = mklist<value>("testCallLambda", content(trlv), 2, 3);
+ const failable<value> tclv = evalScript(tcl, tclis);
+ assert(hasContent(tclv));
+ assert(content(tclv) == value(6));
+
+ istringstream tcelis(testCallLambda);
+ const value tcel = mklist<value>("testCallLambda", lambda<value(const list<value>&)>(mult), 3, 4);
+ const failable<value> tcelv = evalScript(tcel, tcelis);
+ assert(hasContent(tcelv));
+ assert(content(tcelv) == value(12));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::python::testEvalExpr();
+ tuscany::python::testEvalLambda();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/server-test b/sandbox/sebastien/cpp/apr-2/modules/python/server-test
new file mode 100755
index 0000000000..b01f5f501d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/server-test
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+# Setup
+../http/httpd-conf tmp localhost 8090 ../server/htdocs
+../server/server-conf tmp
+./python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+../http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/server-test.py b/sandbox/sebastien/cpp/apr-2/modules/python/server-test.py
new file mode 100644
index 0000000000..29404c3753
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/server-test.py
@@ -0,0 +1,42 @@
+# 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.
+
+# JSON-RPC test case
+
+def echo(x):
+ return x
+
+# ATOMPub test case
+
+def get(id):
+ if id == ():
+ return ("Sample Feed", "123456789",
+ ("Item", "111", (("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99))),
+ ("Item", "222", (("'name", "Orange"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 3.55))),
+ ("Item", "333", (("'name", "Pear"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 1.55))))
+
+ entry = (("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99))
+ return ("Item", id[0], entry)
+
+def post(collection, item):
+ return ("123456789",)
+
+def put(id, item):
+ return True
+
+def delete(id):
+ return True
diff --git a/sandbox/sebastien/cpp/apr-2/modules/python/wiring-test b/sandbox/sebastien/cpp/apr-2/modules/python/wiring-test
new file mode 100755
index 0000000000..c571981bbd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/python/wiring-test
@@ -0,0 +1,78 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+
+# Setup
+../http/httpd-conf tmp localhost 8090 ../server/htdocs
+../server/server-conf tmp
+./python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+../http/httpd-start tmp
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html ../server/htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml ../server/htdocs/test/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml ../server/htdocs/test/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @../server/htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @../server/htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @../server/htdocs/test/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt ../server/htdocs/test/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/rss/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/rss/Makefile.am
new file mode 100644
index 0000000000..06a67f3c3f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/rss/Makefile.am
@@ -0,0 +1,25 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/rss
+
+rss_test_SOURCES = rss-test.cpp
+rss_test_LDFLAGS = -lxml2
+
+noinst_PROGRAMS = rss-test
+TESTS = rss-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/rss/rss-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/rss/rss-test.cpp
new file mode 100644
index 0000000000..9bfd620835
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/rss/rss-test.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test RSS data conversion functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "rss.hpp"
+
+namespace tuscany {
+namespace rss {
+
+ostream* writer(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
+ "<description>"
+ "<item>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</item>"
+ "</description>"
+ "</item>\n");
+
+string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
+ "<description>Apple</description>"
+ "</item>\n");
+
+string incompleteEntry("<item>"
+ "<title>fruit</title><description>"
+ "<Item xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</Item>"
+ "</description>"
+ "</item>");
+
+string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<item>"
+ "<title>fruit</title>"
+ "<link></link>"
+ "<description>"
+ "<Item xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</Item>"
+ "</description>"
+ "</item>\n");
+
+bool testEntry() {
+ {
+ const list<value> i = list<value>() + element + value("item")
+ + value(list<value>() + element + value("name") + value(string("Apple")))
+ + value(list<value>() + element + value("price") + value(string("$2.99")));
+ const list<value> a = mklist<value>(string("fruit"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemEntry);
+ }
+ {
+ const list<value> a = mklist<value>(string("fruit"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), "Apple");
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemTextEntry);
+ }
+ {
+ const list<value> a = content(readRSSEntry(mklist(itemEntry)));
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemEntry);
+ }
+ {
+ const list<value> a = content(readRSSEntry(mklist(itemTextEntry)));
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemTextEntry);
+ }
+ {
+ const list<value> a = content(readRSSEntry(mklist(incompleteEntry)));
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == completedEntry);
+ }
+ return true;
+}
+
+string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<rss version=\"2.0\">"
+ "<channel>"
+ "<title>Feed</title>"
+ "<link>1234</link>"
+ "<description>Feed</description>"
+ "</channel>"
+ "</rss>\n");
+
+string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<rss version=\"2.0\">"
+ "<channel>"
+ "<title>Feed</title>"
+ "<link>1234</link>"
+ "<description>Feed</description>"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
+ "<description>"
+ "<item>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</item>"
+ "</description>"
+ "</item>"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</link>"
+ "<description>"
+ "<item>"
+ "<name>Orange</name><price>$3.55</price>"
+ "</item>"
+ "</description>"
+ "</item>"
+ "</channel>"
+ "</rss>\n");
+
+bool testFeed() {
+ {
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, mklist<value>("Feed", "1234"));
+ assert(str(os) == emptyFeed);
+ }
+ {
+ const list<value> a = content(readRSSFeed(mklist(emptyFeed)));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == emptyFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + (list<value>() + element + "item"
+ + (list<value>() + element + "name" + "Apple")
+ + (list<value>() + element + "price" + "$2.99")))
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + (list<value>() + element + "item"
+ + (list<value>() + element + "name" + "Orange")
+ + (list<value>() + element + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + valueToElement(list<value>() + "item"
+ + (list<value>() + "name" + "Apple")
+ + (list<value>() + "price" + "$2.99")))
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + valueToElement(list<value>() + "item"
+ + (list<value>() + "name" + "Orange")
+ + (list<value>() + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ {
+ const list<value> a = content(readRSSFeed(mklist(itemFeed)));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::rss::testEntry();
+ tuscany::rss::testFeed();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/rss/rss.hpp b/sandbox/sebastien/cpp/apr-2/modules/rss/rss.hpp
new file mode 100644
index 0000000000..506d1f4a6d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/rss/rss.hpp
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_rss_hpp
+#define tuscany_rss_hpp
+
+/**
+ * RSS data conversion functions.
+ */
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+namespace rss {
+
+/**
+ * Convert a list of elements to a list of values representing an RSS entry.
+ */
+const list<value> entryElementsToValues(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> li = filter<value>(selector(mklist<value>(element, "link")), e);
+ const value i = isNil(li)? value(emptyString) : elementValue(car(li));
+ const list<value> ld = filter<value>(selector(mklist<value>(element, "description")), e);
+ return mklist<value>(t, i, elementValue(car(ld)));
+}
+
+/**
+ * Convert a list of elements to a list of values representing RSS entries.
+ */
+const list<value> entriesElementsToValues(const list<value>& e) {
+ if (isNil(e))
+ return e;
+ return cons<value>(entryElementsToValues(car(e)), entriesElementsToValues(cdr(e)));
+}
+
+/**
+ * Return true if a list of strings contains an RSS feed.
+ */
+const bool isRSSFeed(const list<string>& ls) {
+ if (!isXML(ls))
+ return false;
+ return contains(car(ls), "<rss");
+}
+
+/**
+ * Convert a list of strings to a list of values representing an RSS entry.
+ */
+const failable<list<value> > readRSSEntry(const list<string>& ilist) {
+ const list<value> e = readXML(ilist);
+ if (isNil(e))
+ return mkfailure<list<value> >("Empty entry");
+ return entryElementsToValues(car(e));
+}
+
+/**
+ * Convert a list of values representing an RSS entry to a value.
+ */
+const value entryValue(const list<value>& e) {
+ const list<value> v = elementsToValues(mklist<value>(caddr(e)));
+ return cons(car(e), mklist<value>(cadr(e), isList(car(v))? (value)cdr<value>(car(v)) : car(v)));
+}
+
+/**
+ * Convert a list of strings to a list of values representing an RSS feed.
+ */
+const failable<list<value> > readRSSFeed(const list<string>& ilist) {
+ const list<value> f = readXML(ilist);
+ if (isNil(f))
+ return mkfailure<list<value> >("Empty feed");
+ const list<value> c = filter<value>(selector(mklist<value>(element, "channel")), car(f));
+ const list<value> t = filter<value>(selector(mklist<value>(element, "title")), car(c));
+ const list<value> i = filter<value>(selector(mklist<value>(element, "link")), car(c));
+ const list<value> e = filter<value>(selector(mklist<value>(element, "item")), car(c));
+ if (isNil(e))
+ return mklist<value>(elementValue(car(t)), elementValue(car(i)));
+ return cons<value>(elementValue(car(t)), cons(elementValue(car(i)), entriesElementsToValues(e)));
+}
+
+/**
+ * Convert an RSS feed containing elements to an RSS feed containing values.
+ */
+const list<value> feedValuesLoop(const list<value> e) {
+ if (isNil(e))
+ return e;
+ return cons<value>(entryValue(car(e)), feedValuesLoop(cdr(e)));
+}
+
+const list<value> feedValues(const list<value>& e) {
+ return cons(car<value>(e), cons<value>(cadr<value>(e), feedValuesLoop(cddr<value>(e))));
+}
+
+/**
+ * Convert a list of values representing an RSS entry to a list of elements.
+ * The first two values in the list are the entry title and id.
+ */
+const list<value> entryElement(const list<value>& l) {
+ return list<value>()
+ + element + "item"
+ + (list<value>() + element + "title" + car(l))
+ + (list<value>() + element + "link" + cadr(l))
+ + (list<value>() + element + "description" + caddr(l));
+}
+
+/**
+ * Convert a list of values representing RSS entries to a list of elements.
+ */
+const list<value> entriesElements(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(entryElement(car(l)), entriesElements(cdr(l)));
+}
+
+/**
+ * Convert a list of values representing an RSS entry to an RSS entry.
+ * The first two values in the list are the entry id and title.
+ */
+template<typename R> const failable<R> writeRSSEntry(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML<R>(reduce, initial, mklist<value>(entryElement(l)));
+}
+
+const failable<list<string> > writeRSSEntry(const list<value>& l) {
+ const failable<list<string> > ls = writeRSSEntry<list<string> >(rcons<string>, list<string>(), l);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert a list of values representing an RSS feed to an RSS feed.
+ * The first two values in the list are the feed id and title.
+ */
+template<typename R> const failable<R> writeRSSFeed(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ const list<value> c = list<value>()
+ + (list<value>() + element + "title" + car(l))
+ + (list<value>() + element + "link" + cadr(l))
+ + (list<value>() + element + "description" + car(l));
+ const list<value> ce = isNil(cddr(l))? c : append(c, entriesElements(cddr(l)));
+ const list<value> fe = list<value>()
+ + element + "rss" + (list<value>() + attribute + "version" + "2.0")
+ + append(list<value>() + element + "channel", ce);
+ return writeXML<R>(reduce, initial, mklist<value>(fe));
+}
+
+/**
+ * Convert a list of values representing an RSS feed to a list of strings.
+ * The first two values in the list are the feed id and title.
+ */
+const failable<list<string> > writeRSSFeed(const list<value>& l) {
+ const failable<list<string> > ls = writeRSSFeed<list<string>>(rcons<string>, list<string>(), l);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert an RSS entry containing a value to an RSS entry containing an item element.
+ */
+const list<value> entryValuesToElements(const list<value> val) {
+ return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(cons<value>("item", (list<value>)caddr(val))))));
+}
+
+/**
+ * Convert an RSS feed containing values to an RSS feed containing elements.
+ */
+const list<value> feedValuesToElementsLoop(const list<value> val) {
+ if (isNil(val))
+ return val;
+ return cons<value>(entryValuesToElements(car(val)), feedValuesToElementsLoop(cdr(val)));
+}
+
+const list<value> feedValuesToElements(const list<value>& val) {
+ return cons(car<value>(val), cons<value>(cadr<value>(val), feedValuesToElementsLoop(cddr<value>(val))));
+}
+
+}
+}
+
+#endif /* tuscany_rss_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scdl/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/scdl/Makefile.am
new file mode 100644
index 0000000000..09cbd35ec0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scdl/Makefile.am
@@ -0,0 +1,27 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/scdl
+
+scdl_test_SOURCES = scdl-test.cpp
+scdl_test_LDFLAGS = -lxml2
+
+EXTRA_DIST = test.composite
+
+noinst_PROGRAMS = scdl-test
+TESTS = scdl-test validate-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scdl/scdl-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/scdl/scdl-test.cpp
new file mode 100644
index 0000000000..e8ee77eb4e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scdl/scdl-test.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test SCDL read functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "scdl.hpp"
+
+namespace tuscany {
+namespace scdl {
+
+bool testComposite() {
+ ifstream is("test.composite");
+ const list<value> c = readXML(streamList(is));
+ return true;
+}
+
+bool testComponents() {
+ ifstream is("test.composite");
+ const list<value> c = components(readXML(streamList(is)));
+ assert(length(c) == 4);
+
+ const value store = car(c);
+ assert(name(store) == string("Store"));
+ const value impl = implementation(store);
+ assert(uri(impl) == string("store.html"));
+ assert(implementationType(impl) == "t:implementation.scheme");
+
+ const value catalog = named(string("Catalog"), c);
+ assert(name(catalog) == string("Catalog"));
+
+ const list<value> t = mkbtree(sort(nameToElementAssoc(c)));
+ assert(assoctree<value>("Catalog", t) == mklist<value>("Catalog" , cadr(c)));
+ return true;
+}
+
+bool testServices() {
+ ifstream is("test.composite");
+ const list<value> c = components(readXML(streamList(is)));
+ const value store = car(c);
+
+ assert(length(services(store)) == 1);
+ const value widget = car(services(store));
+ assert(name(widget) == string("Widget"));
+
+ assert(length(bindings(widget)) == 1);
+ const value binding = car(bindings(widget));
+ assert(uri(binding) == string("/store"));
+ assert(bindingType(binding) == "t:binding.http");
+ return true;
+}
+
+bool testReferences() {
+ ifstream is("test.composite");
+ const list<value> c = components(readXML(streamList(is)));
+ const value store = car(c);
+
+ assert(length(references(store)) == 3);
+ const value catalog = car(references(store));
+ assert(name(catalog) == string("catalog"));
+ assert(target(catalog) == string("Catalog"));
+
+ assert(length(bindings(catalog)) == 1);
+ const value binding = car(bindings(catalog));
+ assert(uri(binding) == value());
+ assert(bindingType(binding) == "t:binding.jsonrpc");
+
+ const list<value> t = mkbtree(sort(referenceToTargetAssoc(references(store))));
+ assert(assoctree<value>("shoppingCart", t) == mklist<value>(string("shoppingCart"), string("ShoppingCart/Cart")));
+ return true;
+}
+
+bool testProperties() {
+ ifstream is("test.composite");
+ const list<value> c = components(readXML(streamList(is)));
+ const value catalog = named(string("Catalog"), c);
+
+ assert(length(properties(catalog)) == 1);
+ const value currencyCode = car(properties(catalog));
+ assert(name(currencyCode) == string("currencyCode"));
+ assert(propertyValue(currencyCode) == string("USD"));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::scdl::testComposite();
+ tuscany::scdl::testComponents();
+ tuscany::scdl::testServices();
+ tuscany::scdl::testReferences();
+ tuscany::scdl::testProperties();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scdl/scdl.hpp b/sandbox/sebastien/cpp/apr-2/modules/scdl/scdl.hpp
new file mode 100644
index 0000000000..0f008dc3a8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scdl/scdl.hpp
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scdl_hpp
+#define tuscany_scdl_hpp
+
+/**
+ * SCDL read functions.
+ */
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+namespace scdl {
+
+/**
+ * Returns a list of components in a composite.
+ */
+const list<value> components(const value& l) {
+ const list<value> cs = elementChildren("composite", l);
+ if (isNil(cs))
+ return cs;
+ return elementChildren("component", car(cs));
+}
+
+/**
+ * Returns the name of a component, service or reference.
+ */
+const value name(const value& l) {
+ return attributeValue("name", l);
+}
+
+/**
+ * Convert a list of elements to a name -> element assoc list.
+ */
+const list<value> nameToElementAssoc(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ const value e(car(l));
+ return cons<value>(mklist<value>(name(e), e), nameToElementAssoc(cdr(l)));
+}
+
+/**
+ * Returns the scdl declaration with the given name.
+ */
+struct filterName {
+ const value n;
+ filterName(const value& n) : n(n) {
+ }
+ const bool operator()(const value& v) const {
+ return name(v) == n;
+ }
+};
+
+const value named(const value& name, const value& l) {
+ const list<value> c = filter<value>(filterName(name), l);
+ if (isNil(c))
+ return value();
+ return car(c);
+}
+
+/**
+ * Returns the implementation of a component.
+ */
+const bool filterImplementation(const value& v) {
+ return isElement(v) && contains(string(cadr<value>(v)), "implementation.");
+}
+
+const value implementation(const value& l) {
+ const list<value> n = filter<value>(filterImplementation, l);
+ if (isNil(n))
+ return value();
+ return car(n);
+}
+
+/**
+ * Returns the URI of a service, reference or implementation.
+ */
+const value uri(const value& l) {
+ return attributeValue("uri", l);
+}
+
+/**
+ * Returns a list of services in a component.
+ */
+const list<value> services(const value& l) {
+ return elementChildren("service", l);
+}
+
+/**
+ * Returns a list of references in a component.
+ */
+const list<value> references(const value& l) {
+ return elementChildren("reference", l);
+}
+
+/**
+ * Returns a list of bindings in a service or reference.
+ */
+const bool filterBinding(const value& v) {
+ return isElement(v) && contains(string(cadr<value>(v)), "binding.");
+}
+
+const list<value> bindings(const value& l) {
+ return filter<value>(filterBinding, l);
+}
+
+/**
+ * Returns the target of a reference.
+ */
+const value bindingsTarget(const list<value>& l) {
+ if (isNil(l))
+ return value();
+ const value u = uri(car(l));
+ if (!isNil(u))
+ return u;
+ return bindingsTarget(cdr(l));
+}
+
+const value target(const value& l) {
+ const value target = attributeValue("target", l);
+ if (!isNil(target))
+ return target;
+ return bindingsTarget(bindings(l));
+}
+
+/**
+ * Convert a list of references to a reference name -> target assoc list.
+ */
+const list<value> referenceToTargetAssoc(const list<value>& r) {
+ if (isNil(r))
+ return r;
+ const value ref(car(r));
+ return cons<value>(mklist<value>(scdl::name(ref), scdl::target(ref)), referenceToTargetAssoc(cdr(r)));
+}
+
+/**
+ * Returns a list of properties in a component.
+ */
+const list<value> properties(const value& l) {
+ return elementChildren("property", l);
+}
+
+/**
+ * Returns the type of an implementation.
+ */
+const value implementationType(const value& l) {
+ return elementName(l);
+}
+
+/**
+ * Returns the type of a binding.
+ */
+const value bindingType(const value& l) {
+ return elementName(l);
+}
+
+/**
+ * Returns the value of a property.
+ */
+const value propertyValue(const value& l) {
+ return elementValue(l);
+}
+
+}
+}
+
+#endif /* tuscany_scdl_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scdl/test.composite b/sandbox/sebastien/cpp/apr-2/modules/scdl/test.composite
new file mode 100644
index 0000000000..f6fdba7f5f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scdl/test.composite
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.scheme script="store.scm"/>
+ <service name="Widget">
+ <t:binding.http uri="/store"/>
+ </service>
+ <reference name="catalog" target="Catalog">
+ <t:binding.jsonrpc/>
+ </reference>
+ <reference name="shoppingCart" target="ShoppingCart/Cart">
+ <t:binding.atom/>
+ </reference>
+ <reference name="shoppingTotal" target="ShoppingCart/Total">
+ <t:binding.jsonrpc/>
+ </reference>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.scheme script="fruits-catalog.scm"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.scheme script="shopping-cart.scm"/>
+ <service name="Cart">
+ <t:binding.atom uri="/ShoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc/>
+ </service>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.scheme script="currency-converter.scm"/>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scdl/validate-test b/sandbox/sebastien/cpp/apr-2/modules/scdl/validate-test
new file mode 100755
index 0000000000..e70fe67aa0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scdl/validate-test
@@ -0,0 +1,23 @@
+#!/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
+# 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.
+
+# Validate test composite
+../../kernel/xsd-test ../../xsd/tuscany-sca-1.1.xsd test.composite 2>/dev/null
+rc=$?
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/scheme/Makefile.am
new file mode 100644
index 0000000000..8e2141e724
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/Makefile.am
@@ -0,0 +1,44 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/scheme
+
+eval_test_SOURCES = eval-test.cpp
+
+eval_shell_SOURCES = eval-shell.cpp
+
+value_element_SOURCES = value-element.cpp
+value_element_LDFLAGS =
+
+element_value_SOURCES = element-value.cpp
+element_value_LDFLAGS =
+
+xml_value_SOURCES = xml-value.cpp
+xml_value_LDFLAGS = -lxml2
+
+value_xml_SOURCES = value-xml.cpp
+value_xml_LDFLAGS = -lxml2
+
+json_value_SOURCES = json-value.cpp
+json_value_LDFLAGS = -lmozjs
+
+value_json_SOURCES = value-json.cpp
+value_json_LDFLAGS = -lmozjs
+
+noinst_PROGRAMS = eval-test eval-shell element-value value-element xml-value value-xml json-value value-json
+TESTS = eval-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/driver.hpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/driver.hpp
new file mode 100644
index 0000000000..112c226ed1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/driver.hpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scheme_driver_hpp
+#define tuscany_scheme_driver_hpp
+
+/**
+ * Script evaluator main driver loop.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+const string evalOutputPrompt("; ");
+const string evalInputPrompt("=> ");
+
+const bool promptForInput(const string& str, ostream& out) {
+ out << endl << endl << str;
+ return true;
+}
+
+const bool announceOutput(const string str, ostream& out) {
+ out << endl << str;
+ return true;
+}
+
+const bool userPrint(const value val, ostream& out) {
+ if(isCompoundProcedure(val))
+ writeValue(mklist<value>(compoundProcedureSymbol, procedureParameters(val), procedureBody(val), "<procedure-env>"), out);
+ writeValue(val, out);
+ return true;
+}
+
+const value evalDriverLoop(istream& in, ostream& out, Env& env) {
+ promptForInput(evalInputPrompt, out);
+ value input = readValue(in);
+ if (isNil(input))
+ return input;
+ const value output = evalExpr(input, env);
+ announceOutput(evalOutputPrompt, out);
+ userPrint(output, out);
+ return evalDriverLoop(in, out, env);
+}
+
+const bool evalDriverRun(istream& in, ostream& out) {
+ setupDisplay(out);
+ Env env = setupEnvironment();
+ evalDriverLoop(in, out, env);
+ return true;
+}
+
+}
+}
+#endif /* tuscany_scheme_driver_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/element-value.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/element-value.cpp
new file mode 100644
index 0000000000..8a443dbdb2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/element-value.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Convert a scheme value representing an element to a value.
+ */
+
+#include "fstream.hpp"
+#include "string.hpp"
+#include "element.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+int elementValue() {
+ const value v = elementsToValues(readValue(cin));
+ cout << writeValue(v);
+ return 0;
+}
+
+}
+}
+
+int main() {
+ return tuscany::scheme::elementValue();
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/environment.hpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/environment.hpp
new file mode 100644
index 0000000000..bfb415a978
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/environment.hpp
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scheme_environment_hpp
+#define tuscany_scheme_environment_hpp
+
+/**
+ * Script evaluator environment implementation.
+ */
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "primitive.hpp"
+#include <string>
+
+namespace tuscany {
+namespace scheme {
+
+typedef value Frame;
+typedef list<value> Env;
+
+const value trueSymbol("true");
+const value falseSymbol("false");
+const value defineSymbol("define");
+const value setSymbol("set!");
+const value dotSymbol(".");
+
+const Env theEmptyEnvironment() {
+ return list<value>();
+}
+
+const bool isDefinition(const value& exp) {
+ return isTaggedList(exp, defineSymbol);
+}
+
+const bool isAssignment(const value& exp) {
+ return isTaggedList(exp, setSymbol);
+}
+
+const bool isVariable(const value& exp) {
+ return isSymbol(exp);
+}
+
+const Env enclosingEnvironment(const Env& env) {
+ return cdr(env);
+}
+
+const gc_ptr<Frame> firstFrame(const Env& env) {
+ return car(env);
+}
+
+list<value> frameVariables(const Frame& frame) {
+ return car((list<value> )frame);
+}
+
+list<value> frameValues(const Frame& frame) {
+ return cdr((list<value> )frame);
+}
+
+const bool isDotVariable(const value& var) {
+ return var == dotSymbol;
+}
+
+const Frame makeBinding(const Frame& frameSoFar, const list<value>& variables, const list<value> values) {
+ if (isNil(variables)) {
+ if (!isNil(values))
+ logStream() << "Too many arguments supplied " << values << endl;
+ return frameSoFar;
+ }
+ if (isDotVariable(car(variables)))
+ return makeBinding(frameSoFar, cdr(variables), mklist<value>(values));
+
+ if (isNil(values)) {
+ if (!isNil(variables))
+ logStream() << "Too few arguments supplied " << variables << endl;
+ return frameSoFar;
+ }
+
+ const list<value> vars = cons(car(variables), frameVariables(frameSoFar));
+ const list<value> vals = cons(car(values), frameValues(frameSoFar));
+ const Frame newFrame = cons(value(vars), vals);
+
+ return makeBinding(newFrame, cdr(variables), cdr(values));
+}
+
+const gc_ptr<Frame> makeFrame(const list<value>& variables, const list<value> values) {
+ gc_ptr<Frame> frame = new (gc_new<Frame>()) Frame();
+ *frame = value(makeBinding(cons(value(list<value>()), list<value>()), variables, values));
+ return frame;
+}
+
+const value definitionVariable(const value& exp) {
+ const list<value> exps(exp);
+ if(isSymbol(car(cdr(exps))))
+ return car(cdr(exps));
+ const list<value> lexps(car(cdr(exps)));
+ return car(lexps);
+}
+
+const value definitionValue(const value& exp) {
+ const list<value> exps(exp);
+ if(isSymbol(car(cdr(exps))))
+ return car(cdr(cdr(exps)));
+ const list<value> lexps(car(cdr(exps)));
+ return makeLambda(cdr(lexps), cdr(cdr(exps)));
+}
+
+const value assignmentVariable(const value& exp) {
+ return car(cdr((list<value> )exp));
+}
+
+const value assignmentValue(const value& exp) {
+ return car(cdr(cdr((list<value> )exp)));
+}
+
+const Frame addBindingToFrame(const value& var, const value& val, const Frame& frame) {
+ return cons(value(cons(var, frameVariables(frame))), cons(val, frameValues(frame)));
+}
+
+const bool defineVariable(const value& var, const value& val, Env& env) {
+ *firstFrame(env) = addBindingToFrame(var, val, *firstFrame(env));
+ return true;
+}
+
+const Env extendEnvironment(const list<value>& vars, const list<value>& vals, const Env& baseEnv) {
+ return cons<value>(makeFrame(vars, vals), baseEnv);
+}
+
+const Env setupEnvironment() {
+ Env env = extendEnvironment(primitiveProcedureNames(), primitiveProcedureObjects(), theEmptyEnvironment());
+ defineVariable(trueSymbol, true, env);
+ defineVariable(falseSymbol, false, env);
+ return env;
+}
+
+const value lookupEnvLoop(const value& var, const Env& env);
+
+const value lookupEnvScan(const value& var, const list<value>& vars, const list<value>& vals, const Env& env) {
+ if(isNil(vars))
+ return lookupEnvLoop(var, enclosingEnvironment(env));
+ if(var == car(vars))
+ return car(vals);
+ return lookupEnvScan(var, cdr(vars), cdr(vals), env);
+}
+
+const value lookupEnvLoop(const value& var, const Env& env) {
+ if(env == theEmptyEnvironment()) {
+ logStream() << "Unbound variable " << var << endl;
+ return value();
+ }
+ return lookupEnvScan(var, frameVariables(*firstFrame(env)), frameValues(*firstFrame(env)), env);
+}
+
+const value lookupVariableValue(const value& var, const Env& env) {
+ return lookupEnvLoop(var, env);
+}
+
+}
+}
+#endif /* tuscany_scheme_environment_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/eval-shell.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/eval-shell.cpp
new file mode 100644
index 0000000000..4aa67c2375
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/eval-shell.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Script evaluator shell, used for interactive testing of scripts.
+ */
+
+#include <assert.h>
+#include "gc.hpp"
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+int main() {
+ tuscany::gc_scoped_pool pool;
+ tuscany::scheme::evalDriverRun(tuscany::cin, tuscany::cout);
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/eval-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/eval-test.cpp
new file mode 100644
index 0000000000..7c4c0c69c4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/eval-test.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test script evaluator.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+bool testEnv() {
+ gc_scoped_pool pool;
+ Env globalEnv = list<value>();
+ Env env = extendEnvironment(mklist<value>("a"), mklist<value>(1), globalEnv);
+ defineVariable("x", env, env);
+ assert(lookupVariableValue(value("x"), env) == env);
+ assert(lookupVariableValue("a", env) == value(1));
+ return true;
+}
+
+bool testEnvGC() {
+ resetLambdaCounters();
+ resetListCounters();
+ resetValueCounters();
+ testEnv();
+ assert(checkValueCounters());
+ assert(checkLambdaCounters());
+ assert(checkListCounters());
+ return true;
+}
+
+bool testRead() {
+ istringstream is("abcd");
+ assert(readValue(is) == "abcd");
+
+ istringstream is2("123");
+ assert(readValue(is2) == value(123));
+
+ istringstream is3("(abcd)");
+ assert(readValue(is3) == mklist(value("abcd")));
+
+ istringstream is4("(abcd xyz)");
+ assert(readValue(is4) == mklist<value>("abcd", "xyz"));
+
+ istringstream is5("(abcd (xyz tuv))");
+ assert(readValue(is5) == mklist<value>("abcd", mklist<value>("xyz", "tuv")));
+
+ return true;
+}
+
+bool testWrite() {
+ const list<value> i = list<value>()
+ + (list<value>() + "item" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + (list<value>() + "item"
+ + (list<value>() + "name" + "Apple")
+ + (list<value>() + "price" + "$2.99")))
+ + (list<value>() + "item" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + (list<value>() + "item"
+ + (list<value>() + "name" + "Orange")
+ + (list<value>() + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("feed-1234", i));
+ ostringstream os;
+ writeValue(a, os);
+ istringstream is(str(os));
+ assert(readValue(is) == a);
+ return true;
+}
+
+const string testSchemeNumber(
+ "(define (testNumber) (if (= 1 1) (display \"testNumber ok\") (error \"testNumber\"))) "
+ "(testNumber)");
+
+const string testSchemeString(
+ "(define (testString) (if (= \"abc\" \"abc\") (display \"testString ok\") (error \"testString\"))) "
+ "(testString)");
+
+const string testSchemeDefinition(
+ "(define a \"abc\") (define (testDefinition) (if (= a \"abc\") (display \"testDefinition ok\") (error \"testDefinition\"))) "
+ "(testDefinition)");
+
+const string testSchemeIf(
+ "(define (testIf) (if (= \"abc\" \"abc\") (if (= \"xyz\" \"xyz\") (display \"testIf ok\") (error \"testNestedIf\")) (error \"testIf\"))) "
+ "(testIf)");
+
+const string testSchemeCond(
+ "(define (testCond) (cond ((= \"abc\" \"abc\") (display \"testCond ok\")) (else (error \"testIf\"))))"
+ "(testCond)");
+
+const string testSchemeBegin(
+ "(define (testBegin) "
+ "(begin "
+ "(define a \"abc\") "
+ "(if (= a \"abc\") (display \"testBegin1 ok\") (error \"testBegin\")) "
+ "(define x \"xyz\") "
+ "(if (= x \"xyz\") (display \"testBegin2 ok\") (error \"testBegin\")) "
+ ") "
+ ") "
+ "(testBegin)");
+
+const string testSchemeLambda(
+ "(define sqrt (lambda (x) (* x x))) "
+ "(define (testLambda) (if (= 4 (sqrt 2)) (display \"testLambda ok\") (error \"testLambda\"))) "
+ "(testLambda)");
+
+const string testSchemeForward(
+ "(define (testLambda) (if (= 4 (sqrt 2)) (display \"testForward ok\") (error \"testForward\"))) "
+ "(define sqrt (lambda (x) (* x x))) "
+ "(testLambda)");
+
+const string evalOutput(const string& scm) {
+ istringstream is(scm);
+ ostringstream os;
+ evalDriverRun(is, os);
+ return str(os);
+}
+
+bool testEval() {
+ gc_scoped_pool pool;
+ assert(contains(evalOutput(testSchemeNumber), "testNumber ok"));
+ assert(contains(evalOutput(testSchemeString), "testString ok"));
+ assert(contains(evalOutput(testSchemeDefinition), "testDefinition ok"));
+ assert(contains(evalOutput(testSchemeIf), "testIf ok"));
+ assert(contains(evalOutput(testSchemeCond), "testCond ok"));
+ assert(contains(evalOutput(testSchemeBegin), "testBegin1 ok"));
+ assert(contains(evalOutput(testSchemeBegin), "testBegin2 ok"));
+ assert(contains(evalOutput(testSchemeLambda), "testLambda ok"));
+ assert(contains(evalOutput(testSchemeForward), "testForward ok"));
+ return true;
+}
+
+bool testEvalExpr() {
+ gc_scoped_pool pool;
+ const value exp = mklist<value>("+", 2, 3);
+ Env env = setupEnvironment();
+ const value r = evalExpr(exp, env);
+ assert(r == value(5));
+ return true;
+}
+
+bool testEvalRun() {
+ gc_scoped_pool pool;
+ evalDriverRun(cin, cout);
+ return true;
+}
+
+const value mult(const list<value>& args) {
+ const double x = car(args);
+ const double y = cadr(args);
+ return x * y;
+}
+
+const string testReturnLambda(
+ "(define (testReturnLambda) * )");
+
+const string testCallLambda(
+ "(define (testCallLambda l x y) (l x y))");
+
+bool testEvalLambda() {
+ gc_scoped_pool pool;
+ Env env = setupEnvironment();
+
+ const value trl = mklist<value>("testReturnLambda");
+ istringstream trlis(testReturnLambda);
+ const value trlv = evalScript(trl, trlis, env);
+
+ istringstream tclis(testCallLambda);
+ const value tcl = cons<value>("testCallLambda", quotedParameters(mklist<value>(trlv, 2, 3)));
+ const value tclv = evalScript(tcl, tclis, env);
+ assert(tclv == value(6));
+
+ istringstream tcelis(testCallLambda);
+ const value tcel = cons<value>("testCallLambda", quotedParameters(mklist<value>(primitiveProcedure(mult), 3, 4)));
+ const value tcelv = evalScript(tcel, tcelis, env);
+ assert(tcelv == value(12));
+ return true;
+}
+
+bool testEvalGC() {
+ resetLambdaCounters();
+ resetListCounters();
+ resetValueCounters();
+ testEval();
+ testEvalExpr();
+ testEvalLambda();
+ assert(checkValueCounters());
+ assert(checkLambdaCounters());
+ assert(checkListCounters());
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::scheme::testEnv();
+ tuscany::scheme::testEnvGC();
+ tuscany::scheme::testRead();
+ tuscany::scheme::testWrite();
+ tuscany::scheme::testEval();
+ tuscany::scheme::testEvalExpr();
+ tuscany::scheme::testEvalLambda();
+ tuscany::scheme::testEvalGC();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/eval.hpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/eval.hpp
new file mode 100644
index 0000000000..34d1a7bc17
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/eval.hpp
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scheme_eval_hpp
+#define tuscany_scheme_eval_hpp
+
+/**
+ * Core script evaluation logic.
+ */
+
+#include <string.h>
+#include "list.hpp"
+#include "value.hpp"
+#include "primitive.hpp"
+#include "io.hpp"
+#include "environment.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+const value evalExpr(const value& exp, Env& env);
+
+const value compoundProcedureSymbol("compound-procedure");
+const value procedureSymbol("procedure");
+const value applySymbol("apply");
+const value beginSymbol("begin");
+const value condSymbol("cond");
+const value elseSymbol("else");
+const value ifSymbol("if");
+
+const bool isBegin(const value& exp) {
+ return isTaggedList(exp, beginSymbol);
+}
+
+const list<value> beginActions(const value& exp) {
+ return cdr((list<value> )exp);
+}
+
+const bool isLambdaExpr(const value& exp) {
+ return isTaggedList(exp, lambdaSymbol);
+}
+
+const list<value> lambdaParameters(const value& exp) {
+ return car(cdr((list<value> )exp));
+}
+
+static list<value> lambdaBody(const value& exp) {
+ return cdr(cdr((list<value> )exp));
+}
+
+const value makeProcedure(const list<value>& parameters, const value& body, const Env& env) {
+ return mklist<value>(procedureSymbol, parameters, body, env);
+}
+
+const bool isApply(const value& exp) {
+ return isTaggedList(exp, applySymbol);
+}
+
+const bool isApplication(const value& exp) {
+ return isList(exp);
+}
+
+const value operat(const value& exp) {
+ return car((list<value> )exp);
+}
+
+const list<value> operands(const value& exp) {
+ return cdr((list<value> )exp);
+}
+
+const list<value> listOfValues(const list<value> exps, Env& env) {
+ if(isNil(exps))
+ return list<value> ();
+ return cons(evalExpr(car(exps), env), listOfValues(cdr(exps), env));
+}
+
+const value applyOperat(const value& exp) {
+ return cadr((list<value> )exp);
+}
+
+const value applyOperand(const value& exp) {
+ return caddr((list<value> )exp);
+}
+
+const bool isCompoundProcedure(const value& procedure) {
+ return isTaggedList(procedure, procedureSymbol);
+}
+
+const list<value> procedureParameters(const value& exp) {
+ return car(cdr((list<value> )exp));
+}
+
+const value procedureBody(const value& exp) {
+ return car(cdr(cdr((list<value> )exp)));
+}
+
+const Env procedureEnvironment(const value& exp) {
+ return (Env)car(cdr(cdr(cdr((list<value> )exp))));
+}
+
+const bool isLastExp(const list<value>& seq) {
+ return isNil(cdr(seq));
+}
+
+const value firstExp(const list<value>& seq) {
+ return car(seq);
+}
+
+const list<value> restExp(const list<value>& seq) {
+ return cdr(seq);
+}
+
+const value makeBegin(const list<value> seq) {
+ return cons(beginSymbol, seq);
+}
+
+const value evalSequence(const list<value>& exps, Env& env) {
+ if(isLastExp(exps))
+ return evalExpr(firstExp(exps), env);
+ evalExpr(firstExp(exps), env);
+ return evalSequence(restExp(exps), env);
+}
+
+const value applyProcedure(const value& procedure, list<value>& arguments) {
+ if(isPrimitiveProcedure(procedure))
+ return applyPrimitiveProcedure(procedure, arguments);
+ if(isCompoundProcedure(procedure)) {
+ Env env = extendEnvironment(procedureParameters(procedure), arguments, procedureEnvironment(procedure));
+ return evalSequence(procedureBody(procedure), env);
+ }
+ logStream() << "Unknown procedure type " << procedure << endl;
+ return value();
+}
+
+const value sequenceToExp(const list<value> exps) {
+ if(isNil(exps))
+ return exps;
+ if(isLastExp(exps))
+ return firstExp(exps);
+ return makeBegin(exps);
+}
+
+const list<value> condClauses(const value& exp) {
+ return cdr((list<value> )exp);
+}
+
+const value condPredicate(const value& clause) {
+ return car((list<value> )clause);
+}
+
+const list<value> condActions(const value& clause) {
+ return cdr((list<value> )clause);
+}
+
+const value ifPredicate(const value& exp) {
+ return car(cdr((list<value> )exp));
+}
+
+const value ifConsequent(const value& exp) {
+ return car(cdr(cdr((list<value> )exp)));
+}
+
+const value ifAlternative(const value& exp) {
+ if(!isNil(cdr(cdr(cdr((list<value> )exp)))))
+ return car(cdr(cdr(cdr((list<value> )exp))));
+ return false;
+}
+
+const bool isCond(const value& exp) {
+ return isTaggedList(exp, condSymbol);
+}
+
+const bool isCondElseClause(const value& clause) {
+ return condPredicate(clause) == elseSymbol;
+}
+
+const bool isIf(const value& exp) {
+ return isTaggedList(exp, ifSymbol);
+}
+
+const value makeIf(value predicate, value consequent, value alternative) {
+ return mklist(ifSymbol, predicate, consequent, alternative);
+}
+
+const value expandClauses(const list<value>& clauses) {
+ if(isNil(clauses))
+ return false;
+ const value first = car(clauses);
+ const list<value> rest = cdr(clauses);
+ if(isCondElseClause(first)) {
+ if(isNil(rest))
+ return sequenceToExp(condActions(first));
+ logStream() << "else clause isn't last " << clauses << endl;
+ return value();
+ }
+ return makeIf(condPredicate(first), sequenceToExp(condActions(first)), expandClauses(rest));
+}
+
+value condToIf(const value& exp) {
+ return expandClauses(condClauses(exp));
+}
+
+value evalIf(const value& exp, Env& env) {
+ if(isTrue(evalExpr(ifPredicate(exp), env)))
+ return evalExpr(ifConsequent(exp), env);
+ return evalExpr(ifAlternative(exp), env);
+}
+
+const value evalDefinition(const value& exp, Env& env) {
+ defineVariable(definitionVariable(exp), evalExpr(definitionValue(exp), env), env);
+ return definitionVariable(exp);
+}
+
+const value evalExpr(const value& exp, Env& env) {
+ if(isSelfEvaluating(exp))
+ return exp;
+ if(isQuoted(exp))
+ return textOfQuotation(exp);
+ if(isDefinition(exp))
+ return evalDefinition(exp, env);
+ if(isIf(exp))
+ return evalIf(exp, env);
+ if(isBegin(exp))
+ return evalSequence(beginActions(exp), env);
+ if(isCond(exp))
+ return evalExpr(condToIf(exp), env);
+ if(isLambdaExpr(exp))
+ return makeProcedure(lambdaParameters(exp), lambdaBody(exp), env);
+ if(isVariable(exp))
+ return lookupVariableValue(exp, env);
+ if(isApply(exp)) {
+ list<value> applyOperandValues = evalExpr(applyOperand(exp), env);
+ return applyProcedure(evalExpr(applyOperat(exp), env), applyOperandValues);
+ }
+ if(isApplication(exp)) {
+ list<value> operandValues = listOfValues(operands(exp), env);
+ return applyProcedure(evalExpr(operat(exp), env), operandValues);
+ }
+ logStream() << "Unknown expression type " << exp << endl;
+ return value();
+}
+
+const list<value> quotedParameters(const list<value>& p) {
+ if (isNil(p))
+ return p;
+ return cons<value>(mklist<value>(quoteSymbol, car(p)), quotedParameters(cdr(p)));
+}
+
+/**
+ * Evaluate an expression against a script provided as a list of values.
+ */
+const value evalScriptLoop(const value& expr, const list<value>& script, scheme::Env& env) {
+ if (isNil(script))
+ return scheme::evalExpr(expr, env);
+ scheme::evalExpr(car(script), env);
+ return evalScriptLoop(expr, cdr(script), env);
+}
+
+const value evalScript(const value& expr, const value& script, Env& env) {
+ return evalScriptLoop(expr, script, env);
+}
+
+/**
+ * Evaluate an expression against a script provided as an input stream.
+ */
+const value evalScript(const value& expr, istream& is, Env& env) {
+ return evalScript(expr, readScript(is), env);
+}
+
+}
+}
+#endif /* tuscany_scheme_eval_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/io.hpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/io.hpp
new file mode 100644
index 0000000000..6928739d17
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/io.hpp
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scheme_io_hpp
+#define tuscany_scheme_io_hpp
+
+/**
+ * Script evaluator IO functions.
+ */
+
+#include <ctype.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "primitive.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+const value rightParenthesis(mklist<value>(")"));
+const value leftParenthesis(mklist<value>("("));
+const value comment(mklist<value>(";"));
+
+const double stringToNumber(const string& str) {
+ return atof(c_str(str));
+}
+
+const bool isWhitespace(const char ch) {
+ return ch != -1 && isspace(ch);
+}
+
+const bool isIdentifierStart(const char ch) {
+ return ch != -1 && !isspace(ch) && !isdigit(ch);
+}
+
+const bool isIdentifierPart(const char ch) {
+ return ch != -1 && !isspace(ch) && ch != '(' && ch != ')';
+}
+
+const bool isDigit(const char ch) {
+ return isdigit(ch) || ch == '.';
+}
+
+const bool isLeftParenthesis(const value& token) {
+ return leftParenthesis == token;
+}
+
+const bool isRightParenthesis(const value& token) {
+ return rightParenthesis == token;
+}
+
+const char readChar(istream& in) {
+ if(in.eof()) {
+ return -1;
+ }
+ char c = (char)get(in);
+ return c;
+}
+
+const char peekChar(istream& in) {
+ if(eof(in))
+ return -1;
+ char c = (char)peek(in);
+ return c;
+}
+
+const bool isQuote(const value& token) {
+ return token == quoteSymbol;
+}
+
+const value skipComment(istream& in);
+const value readQuoted(istream& in);
+const value readIdentifier(const char chr, istream& in);
+const value readString(istream& in);
+const value readNumber(const char chr, istream& in);
+const value readValue(istream& in);
+
+const value readToken(istream& in) {
+ const char firstChar = readChar(in);
+ if(isWhitespace(firstChar))
+ return readToken(in);
+ if(firstChar == ';')
+ return skipComment(in);
+ if(firstChar == '\'')
+ return readQuoted(in);
+ if(firstChar == '(')
+ return leftParenthesis;
+ if(firstChar == ')')
+ return rightParenthesis;
+ if(firstChar == '"')
+ return readString(in);
+ if(isIdentifierStart(firstChar))
+ return readIdentifier(firstChar, in);
+ if(isDigit(firstChar))
+ return readNumber(firstChar, in);
+ if(firstChar == -1)
+ return value();
+ logStream() << "Illegal lexical syntax '" << firstChar << "'" << endl;
+ return readToken(in);
+}
+
+const value skipComment(istream& in) {
+ const char nextChar = readChar(in);
+ if (nextChar == '\n')
+ return readToken(in);
+ return skipComment(in);
+}
+
+const value readQuoted(istream& in) {
+ return mklist(quoteSymbol, readValue(in));
+}
+
+const list<value> readList(const list<value>& listSoFar, istream& in) {
+ const value token = readToken(in);
+ if(isNil(token) || isRightParenthesis(token))
+ return reverse(listSoFar);
+ if(isLeftParenthesis(token))
+ return readList(cons(value(readList(list<value> (), in)), listSoFar), in);
+ return readList(cons(token, listSoFar), in);
+}
+
+const string listToString(const list<char>& l) {
+ if(isNil(l))
+ return "";
+ const char buf[1] = { car(l) };
+ return string(buf, 1) + listToString(cdr(l));
+}
+
+const list<char> readIdentifierHelper(const list<char>& listSoFar, istream& in) {
+ const char nextChar = peekChar(in);
+ if(isIdentifierPart(nextChar))
+ return readIdentifierHelper(cons(readChar(in), listSoFar), in);
+ return reverse(listSoFar);
+}
+
+const value readIdentifier(const char chr, istream& in) {
+ const value val = c_str(listToString(readIdentifierHelper(mklist(chr), in)));
+ if (val == "false")
+ return value((bool)false);
+ if (val == "true")
+ return value((bool)true);
+ return val;
+}
+
+const list<char> readStringHelper(const list<char>& listSoFar, istream& in) {
+ const char nextChar = readChar(in);
+ if(nextChar != -1 && nextChar != '"')
+ return readStringHelper(cons(nextChar, listSoFar), in);
+ return reverse(listSoFar);
+}
+
+const value readString(istream& in) {
+ return listToString(readStringHelper(list<char>(), in));
+}
+
+const list<char> readNumberHelper(const list<char>& listSoFar, istream& in) {
+ const char nextChar = peekChar(in);
+ if(isDigit(nextChar))
+ return readNumberHelper(cons(readChar(in), listSoFar), in);
+ return reverse(listSoFar);
+}
+
+const value readNumber(const char chr, istream& in) {
+ return stringToNumber(listToString(readNumberHelper(mklist(chr), in)));
+}
+
+const value readValue(istream& in) {
+ const value nextToken = readToken(in);
+ if(isLeftParenthesis(nextToken))
+ return readList(list<value> (), in);
+ return nextToken;
+}
+
+const value readValue(const string s) {
+ istringstream in(s);
+ const value nextToken = readToken(in);
+ if(isLeftParenthesis(nextToken))
+ return readList(list<value> (), in);
+ return nextToken;
+}
+
+const bool writeValue(const value& val, ostream& out) {
+ out << val;
+ return true;
+}
+
+const string writeValue(const value& val) {
+ ostringstream out;
+ out << val;
+ return str(out);
+}
+
+const value readScript(istream& in) {
+ const value val = readValue(in);
+ if (isNil(val))
+ return list<value>();
+ return cons(val, (list<value>)readScript(in));
+}
+
+}
+}
+#endif /* tuscany_scheme_io_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/json-value.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/json-value.cpp
new file mode 100644
index 0000000000..0ab9c85854
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/json-value.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Convert a JSON document to a scheme value.
+ */
+
+#include "fstream.hpp"
+#include "string.hpp"
+#include "../json/json.hpp"
+#include "element.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+int jsonValue() {
+ const js::JSContext cx;
+ const failable<list<value> > lv = json::readJSON(streamList(cin), cx);
+ if (!hasContent(lv)) {
+ cerr << reason(lv);
+ return 1;
+ }
+ const value v = elementsToValues(content(lv));
+ cout << writeValue(v);
+ return 0;
+}
+
+}
+}
+
+int main() {
+ return tuscany::scheme::jsonValue();
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/primitive.hpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/primitive.hpp
new file mode 100644
index 0000000000..6f3f71f4cd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/primitive.hpp
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scheme_primitive_hpp
+#define tuscany_scheme_primitive_hpp
+
+/**
+ * Script evaluator primitive functions.
+ */
+
+#include "stream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+const value primitiveSymbol("primitive");
+const value quoteSymbol("'");
+const value lambdaSymbol("lambda");
+
+#ifdef WANT_THREADS
+__thread
+#endif
+ostream* displayOutStream = NULL;
+
+#ifdef WANT_THREADS
+__thread
+#endif
+ostream* logOutStream = NULL;
+
+const bool setupDisplay(ostream& out) {
+ displayOutStream = &out;
+ return true;
+}
+
+ostream& displayStream() {
+ if (displayOutStream == NULL)
+ return cout;
+ return *displayOutStream;
+}
+
+const bool setupLog(ostream& out) {
+ logOutStream = &out;
+ return true;
+}
+
+ostream& logStream() {
+ if (logOutStream == NULL)
+ return cerr;
+ return *logOutStream;
+}
+
+const value carProc(const list<value>& args) {
+ return car((list<value> )car(args));
+}
+
+const value cdrProc(const list<value>& args) {
+ return cdr((list<value> )car(args));
+}
+
+const value consProc(const list<value>& args) {
+ return cons(car(args), (list<value> )cadr(args));
+}
+
+const value listProc(const list<value>& args) {
+ return args;
+}
+
+const value assocProc(const list<value>& args) {
+ return assoc(car(args), (list<list<value> >)cadr(args));
+}
+
+const value nulProc(const list<value>& args) {
+ const value v(car(args));
+ if (isNil(v))
+ return true;
+ if (isList(v))
+ return isNil(list<value>(v));
+ return false;
+}
+
+const value equalProc(const list<value>& args) {
+ return (bool)(car(args) == cadr(args));
+}
+
+const value addProc(const list<value>& args) {
+ if (isNil(cdr(args)))
+ return (double)car(args);
+ return (double)car(args) + (double)cadr(args);
+}
+
+const value subProc(const list<value>& args) {
+ if (isNil(cdr(args)))
+ return (double)0 - (double)car(args);
+ return (double)car(args) - (double)cadr(args);
+}
+
+const value mulProc(const list<value>& args) {
+ return (double)car(args) * (double)cadr(args);
+}
+
+const value divProc(const list<value>& args) {
+ return (double)car(args) / (double)cadr(args);
+}
+
+const value displayProc(const list<value>& args) {
+ if (isNil(args)) {
+ displayStream() << endl;
+ return true;
+ }
+ displayStream() << car(args);
+ return displayProc(cdr(args));
+}
+
+const value logProc(const list<value>& args) {
+ if (isNil(args)) {
+ logStream() << endl;
+ return true;
+ }
+ logStream() << car(args);
+ return logProc(cdr(args));
+}
+
+const value uuidProc(unused const list<value>& args) {
+ return mkuuid();
+}
+
+const value cadrProc(unused const list<value>& args) {
+ return cadr((list<value> )car(args));
+}
+
+const value caddrProc(unused const list<value>& args) {
+ return caddr((list<value> )car(args));
+}
+
+const value cadddrProc(unused const list<value>& args) {
+ return cadddr((list<value> )car(args));
+}
+
+const value cddrProc(unused const list<value>& args) {
+ return cddr((list<value> )car(args));
+}
+
+const value cdddrProc(unused const list<value>& args) {
+ return cdddr((list<value> )car(args));
+}
+
+const value startProc(unused const list<value>& args) {
+ return lambda<value(const list<value>&)>();
+}
+
+const value stopProc(unused const list<value>& args) {
+ return lambda<value(const list<value>&)>();
+}
+
+const value applyPrimitiveProcedure(const value& proc, list<value>& args) {
+ const lambda<value(const list<value>&)> func(cadr((list<value>)proc));
+ return func(args);
+}
+
+const bool isPrimitiveProcedure(const value& proc) {
+ return isTaggedList(proc, primitiveSymbol);
+}
+
+const bool isSelfEvaluating(const value& exp) {
+ if(isNil(exp))
+ return true;
+ if(isNumber(exp))
+ return true;
+ if(isString(exp))
+ return true;
+ if(isBool(exp))
+ return true;
+ if(isLambda(exp))
+ return true;
+ return false;
+}
+
+const value primitiveImplementation(const list<value>& proc) {
+ return car(cdr(proc));
+}
+
+template<typename F> const value primitiveProcedure(const F& f) {
+ return mklist<value>(primitiveSymbol, (lambda<value(const list<value>&)>)f);
+}
+
+const list<value> primitiveProcedureNames() {
+ return mklist<value>("car")
+ + "cdr"
+ + "cons"
+ + "list"
+ + "nul"
+ + "="
+ + "equal?"
+ + "+"
+ + "-"
+ + "*"
+ + "/"
+ + "assoc"
+ + "cadr"
+ + "caddr"
+ + "cadddr"
+ + "cddr"
+ + "cdddr"
+ + "display"
+ + "log"
+ + "uuid"
+ + "start"
+ + "stop";
+}
+
+const list<value> primitiveProcedureObjects() {
+ return mklist(primitiveProcedure(carProc))
+ + primitiveProcedure(cdrProc)
+ + primitiveProcedure(consProc)
+ + primitiveProcedure(listProc)
+ + primitiveProcedure(nulProc)
+ + primitiveProcedure(equalProc)
+ + primitiveProcedure(equalProc)
+ + primitiveProcedure(addProc)
+ + primitiveProcedure(subProc)
+ + primitiveProcedure(mulProc)
+ + primitiveProcedure(divProc)
+ + primitiveProcedure(assocProc)
+ + primitiveProcedure(cadrProc)
+ + primitiveProcedure(caddrProc)
+ + primitiveProcedure(cadddrProc)
+ + primitiveProcedure(cddrProc)
+ + primitiveProcedure(cdddrProc)
+ + primitiveProcedure(displayProc)
+ + primitiveProcedure(logProc)
+ + primitiveProcedure(uuidProc)
+ + primitiveProcedure(startProc)
+ + primitiveProcedure(stopProc);
+}
+
+const bool isFalse(const value& exp) {
+ return (bool)exp == false;
+}
+
+const bool isTrue(const value& exp) {
+ return (bool)exp == true;
+}
+
+const bool isQuoted(const value& exp) {
+ return isTaggedList(exp, quoteSymbol);
+}
+
+const value textOfQuotation(const value& exp) {
+ return car(cdr((list<value> )exp));
+}
+
+const value makeLambda(const list<value>& parameters, const list<value>& body) {
+ return cons(lambdaSymbol, cons<value>(parameters, body));
+}
+
+}
+}
+#endif /* tuscany_scheme_primitive_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/value-element.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/value-element.cpp
new file mode 100644
index 0000000000..a4acdaf2d7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/value-element.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Convert a scheme value to a value representing an element.
+ */
+
+#include "fstream.hpp"
+#include "string.hpp"
+#include "element.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+int valueElement() {
+ const value v = valuesToElements(readValue(cin));
+ cout << writeValue(v);
+ return 0;
+}
+
+}
+}
+
+int main() {
+ return tuscany::scheme::valueElement();
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/value-json.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/value-json.cpp
new file mode 100644
index 0000000000..40cc8891dd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/value-json.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Convert a scheme value to a JSON document.
+ */
+
+#include "fstream.hpp"
+#include "string.hpp"
+#include "../json/json.hpp"
+#include "element.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+int valueJSON() {
+ const js::JSContext cx;
+ failable<list<string> > s = json::writeJSON(valuesToElements(readValue(cin)), cx);
+ if (!hasContent(s)) {
+ cerr << reason(s);
+ return 1;
+ }
+ write(content(s), cout);
+ return 0;
+}
+
+}
+}
+
+int main() {
+ return tuscany::scheme::valueJSON();
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/value-xml.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/value-xml.cpp
new file mode 100644
index 0000000000..1508f7b516
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/value-xml.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Convert a scheme value to an XML document.
+ */
+
+#include "fstream.hpp"
+#include "string.hpp"
+#include "xml.hpp"
+#include "element.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+int valueXML() {
+ failable<list<string> > s = writeXML(valuesToElements(readValue(cin)));
+ if (!hasContent(s)) {
+ cerr << reason(s);
+ return 1;
+ }
+ write(content(s), cout);
+ return 0;
+}
+
+}
+}
+
+int main() {
+ return tuscany::scheme::valueXML();
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/scheme/xml-value.cpp b/sandbox/sebastien/cpp/apr-2/modules/scheme/xml-value.cpp
new file mode 100644
index 0000000000..0b95174e33
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/scheme/xml-value.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Convert an XML document to a scheme value.
+ */
+
+#include "fstream.hpp"
+#include "string.hpp"
+#include "xml.hpp"
+#include "element.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace scheme {
+
+int xmlValue() {
+ const value v = elementsToValues(readXML(streamList(cin)));
+ cout << writeValue(v);
+ return 0;
+}
+
+}
+}
+
+int main() {
+ return tuscany::scheme::xmlValue();
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/server/Makefile.am
new file mode 100644
index 0000000000..30c89da85d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/Makefile.am
@@ -0,0 +1,55 @@
+# 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.
+
+INCLUDES = -I${HTTPD_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/server
+
+dist_mod_SCRIPTS = cpp-conf scheme-conf server-conf
+moddir = $(prefix)/modules/server
+
+EXTRA_DIST = domain-test.composite client-test.scm server-test.scm htdocs/*.xml htdocs/*.txt htdocs/*.html
+
+mod_LTLIBRARIES = libmod_tuscany_eval.la libmod_tuscany_wiring.la
+noinst_DATA = libmod_tuscany_eval.so libmod_tuscany_wiring.so
+
+libmod_tuscany_eval_la_SOURCES = mod-eval.cpp
+libmod_tuscany_eval_la_LDFLAGS = -lxml2 -lcurl -lmozjs
+libmod_tuscany_eval.so:
+ ln -s .libs/libmod_tuscany_eval.so
+
+libmod_tuscany_wiring_la_SOURCES = mod-wiring.cpp
+libmod_tuscany_wiring_la_LDFLAGS = -lxml2 -lcurl -lmozjs
+libmod_tuscany_wiring.so:
+ ln -s .libs/libmod_tuscany_wiring.so
+
+noinst_test_LTLIBRARIES = libimpl-test.la
+noinst_testdir = `pwd`/tmp
+noinst_DATA += libimpl-test.so
+
+libimpl_test_la_SOURCES = impl-test.cpp
+libimpl-test.so:
+ ln -s .libs/libimpl-test.so
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = httpd-test server-test wiring-test
+noinst_PROGRAMS = client-test
+TESTS = httpd-test server-test wiring-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/client-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/server/client-test.cpp
new file mode 100644
index 0000000000..5de7ab6e7b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/client-test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "client-test.hpp"
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ tuscany::server::testURI = "http://localhost:8090/test";
+
+ tuscany::server::testServer();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/client-test.hpp b/sandbox/sebastien/cpp/apr-2/modules/server/client-test.hpp
new file mode 100644
index 0000000000..c17f012012
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/client-test.hpp
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "parallel.hpp"
+#include "perf.hpp"
+#include "../http/http.hpp"
+
+namespace tuscany {
+namespace server {
+
+string testURI = "http://localhost:8090/test";
+bool testBlobs = true;
+
+ostream* curlWriter(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+const bool testGet() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ {
+ ostringstream os;
+ const failable<list<ostream*> > r = http::get<ostream*>(curlWriter, &os, "http://localhost:8090/index.html", ch);
+ assert(hasContent(r));
+ assert(contains(str(os), "HTTP/1.1 200") || contains(str(os), "HTTP/1.0 200"));
+ assert(contains(str(os), "It works"));
+ }
+ {
+ const failable<value> r = http::getcontent("http://localhost:8090/index.html", ch);
+ assert(hasContent(r));
+ assert(contains(car(reverse(list<value>(content(r)))), "It works"));
+ }
+ return true;
+}
+
+struct getLoop {
+ http::CURLSession ch;
+ getLoop(http::CURLSession& ch) : ch(ch) {
+ }
+ const bool operator()() const {
+ const failable<value> r = http::getcontent("http://localhost:8090/index.html", ch);
+ assert(hasContent(r));
+ assert(contains(car(reverse(list<value>(content(r)))), "It works"));
+ return true;
+ }
+};
+
+const bool testGetPerf() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const lambda<bool()> gl = getLoop(ch);
+ cout << "Static GET test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+const bool testEval() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const value val = content(http::evalExpr(mklist<value>(string("echo"), string("Hello")), testURI, ch));
+ assert(val == string("Hello"));
+ return true;
+}
+
+struct evalLoop {
+ const string uri;
+ http::CURLSession ch;
+ evalLoop(const string& uri, http::CURLSession& ch) : uri(uri), ch(ch) {
+ }
+ const bool operator()() const {
+ const value val = content(http::evalExpr(mklist<value>(string("echo"), string("Hello")), uri, ch));
+ assert(val == string("Hello"));
+ return true;
+ }
+};
+
+const value blob(string(2048, 'A'));
+const list<value> blobs = mklist(blob, blob);
+
+struct blobEvalLoop {
+ const string uri;
+ http::CURLSession ch;
+ blobEvalLoop(const string& uri, http::CURLSession& ch) : uri(uri), ch(ch) {
+ }
+ const bool operator()() const {
+ const value val = content(http::evalExpr(mklist<value>(string("echo"), blobs), uri, ch));
+ assert(val == blobs);
+ return true;
+ }
+};
+
+const bool testEvalPerf() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const lambda<bool()> el = evalLoop(testURI, ch);
+ cout << "JSON-RPC eval echo test " << time(el, 5, 200) << " ms" << endl;
+
+ if (testBlobs) {
+ const lambda<bool()> bel = blobEvalLoop(testURI, ch);
+ cout << "JSON-RPC eval blob test " << time(bel, 5, 200) << " ms" << endl;
+ }
+ return true;
+}
+
+bool testPost() {
+ gc_scoped_pool pool;
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ http::CURLSession ch("", "", "");
+ const failable<value> id = http::post(a, testURI, ch);
+ assert(hasContent(id));
+ return true;
+}
+
+struct postLoop {
+ const string uri;
+ const value val;
+ http::CURLSession ch;
+ postLoop(const string& uri, const value& val, http::CURLSession& ch) : uri(uri), val(val), ch(ch) {
+ }
+ const bool operator()() const {
+ const failable<value> id = http::post(val, uri, ch);
+ assert(hasContent(id));
+ return true;
+ }
+};
+
+struct postBlobLoop {
+ const string uri;
+ const value val;
+ http::CURLSession ch;
+ postBlobLoop(const string& uri, const value& val, http::CURLSession& ch) : uri(uri), val(val), ch(ch) {
+ }
+ const bool operator()() const {
+ gc_scoped_pool pool;
+ const failable<value> id = http::post(val, uri, ch);
+ assert(hasContent(id));
+ return true;
+ }
+};
+
+const bool testPostPerf() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ const lambda<bool()> pl = postLoop(testURI, val, ch);
+ cout << "ATOMPub POST small test " << time(pl, 5, 200) << " ms" << endl;
+ }
+ if (testBlobs) {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "blob1" + blob)
+ + (list<value>() + "blob2" + blob)
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ const lambda<bool()> pl = postBlobLoop(testURI, val, ch);
+ cout << "ATOMPub POST blob test " << time(pl, 5, 200) << " ms" << endl;
+ }
+ return true;
+}
+
+#ifdef WANT_THREADS
+
+const bool postThread(const string& uri, const int count, const value& val) {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const lambda<bool()> pl = postLoop(uri, val, ch);
+ time(pl, 0, count);
+ return true;
+}
+
+const list<future<bool> > startPost(worker& w, const int threads, const lambda<bool()>& l) {
+ if (threads == 0)
+ return list<future<bool> >();
+ return cons(submit(w, l), startPost(w, threads - 1, l));
+}
+
+const bool checkPost(const list<future<bool> >& r) {
+ if (isNil(r))
+ return true;
+ assert(car(r) == true);
+ return checkPost(cdr(r));
+}
+
+struct postThreadLoop {
+ const lambda<bool()> l;
+ const int threads;
+ const gc_ptr<worker> w;
+ postThreadLoop(const lambda<bool()>& l, const int threads) : l(l), threads(threads), w(new (gc_new<worker>()) worker(threads)) {
+ }
+ const bool operator()() const {
+ list<future<bool> > r = startPost(*w, threads, l);
+ checkPost(r);
+ return true;
+ }
+};
+
+const bool testPostThreadPerf() {
+ gc_scoped_pool pool;
+ const int count = 50;
+ const int threads = 10;
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const value val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const lambda<bool()> pl= curry(lambda<bool(const string, const int, const value)>(postThread), testURI, count, val);
+ const lambda<bool()> ptl = postThreadLoop(pl, threads);
+ double t = time(ptl, 0, 1) / (threads * count);
+ cout << "ATOMPub POST thread test " << t << " ms" << endl;
+
+ return true;
+}
+
+#else
+
+const bool postProc(const string& uri, const int count, const value& val) {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const lambda<bool()> pl = postLoop(uri, val, ch);
+ time(pl, 0, count);
+ return true;
+}
+
+const list<pid_t> startPost(const int procs, const lambda<bool()>& l) {
+ if (procs == 0)
+ return list<pid_t>();
+ pid_t pid = fork();
+ if (pid == 0) {
+ assert(l() == true);
+ exit(0);
+ }
+ return cons(pid, startPost(procs - 1, l));
+}
+
+const bool checkPost(const list<pid_t>& r) {
+ if (isNil(r))
+ return true;
+ int status;
+ waitpid(car(r), &status, 0);
+ assert(status == 0);
+ return checkPost(cdr(r));
+}
+
+struct postForkLoop {
+ const lambda<bool()> l;
+ const int procs;
+ postForkLoop(const lambda<bool()>& l, const int procs) : l(l), procs(procs) {
+ }
+ const bool operator()() const {
+ list<pid_t> r = startPost(procs, l);
+ checkPost(r);
+ return true;
+ }
+};
+
+const bool testPostForkPerf() {
+ gc_scoped_pool pool;
+ const int count = 50;
+ const int procs = 10;
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const value val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const lambda<bool()> pl= curry(lambda<bool(const string, const int, const value)>(postProc), testURI, count, val);
+ const lambda<bool()> ptl = postForkLoop(pl, procs);
+ double t = time(ptl, 0, 1) / (procs * count);
+ cout << "ATOMPub POST fork test " << t << " ms" << endl;
+
+ return true;
+}
+
+#endif
+
+const bool testPut() {
+ gc_scoped_pool pool;
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ http::CURLSession ch("", "", "");
+ value rc = content(http::put(a, testURI + "/111", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+const bool testDel() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ value rc = content(http::del(testURI + "/111", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+const bool testServer() {
+ tuscany::server::testGet();
+ tuscany::server::testPost();
+ tuscany::server::testPut();
+ tuscany::server::testDel();
+ tuscany::server::testEval();
+ tuscany::server::testGetPerf();
+ tuscany::server::testPostPerf();
+#ifdef WANT_THREADS
+ tuscany::server::testPostThreadPerf();
+#else
+ tuscany::server::testPostForkPerf();
+#endif
+ tuscany::server::testEvalPerf();
+ return true;
+}
+
+}
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/client-test.scm b/sandbox/sebastien/cpp/apr-2/modules/server/client-test.scm
new file mode 100644
index 0000000000..47b799d390
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/client-test.scm
@@ -0,0 +1,38 @@
+; 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.
+
+; JSON-RPC test case
+
+(define (echo x ref) (ref "echo" x))
+
+; ATOMPub test case
+
+(define (get id ref)
+ (ref "get" id)
+)
+
+(define (post coll entry ref)
+ (ref "post" coll entry)
+)
+
+(define (put id entry ref)
+ (ref "put" id entry)
+)
+
+(define (delete id ref)
+ (ref "delete" id)
+)
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/cpp-conf b/sandbox/sebastien/cpp/apr-2/modules/server/cpp-conf
new file mode 100755
index 0000000000..086bb49d38
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/cpp-conf
@@ -0,0 +1,30 @@
+#!/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
+# 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.
+
+# Generate a C++ server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: cpp-conf $*
+# Support for C++ SCA components
+LoadModule mod_tuscany_eval $here/libmod_tuscany_eval.so
+
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/domain-test.composite b/sandbox/sebastien/cpp/apr-2/modules/server/domain-test.composite
new file mode 100644
index 0000000000..048c451ef6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/domain-test.composite
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://domain/test"
+ name="domain-test">
+
+ <component name="scheme-test">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="test">
+ <t:binding.http uri="test"/>
+ </service>
+ </component>
+
+ <component name="cpp-test">
+ <implementation.cpp path="." library="libimpl-test"/>
+ <service name="cpp">
+ <t:binding.http uri="cpp"/>
+ </service>
+ </component>
+
+ <component name="client-test">
+ <t:implementation.scheme script="client-test.scm"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="ref" target="scheme-test">
+ <t:binding.http/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/index.html
new file mode 100644
index 0000000000..1bfb3e30c2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/index.html
@@ -0,0 +1,21 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>It works!</h1></body></html>
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/entry.xml b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/entry.xml
new file mode 100644
index 0000000000..6528c793e3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/entry.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111"/></entry>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/feed.xml b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/feed.xml
new file mode 100644
index 0000000000..bcb304f9c2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/feed.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Sample Feed</title><id>123456789</id><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111"/></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>222</id><content type="application/xml"><item><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content><link href="222"/></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>333</id><content type="application/xml"><item><name>Pear</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>1.55</price></item></content><link href="333"/></entry></feed>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-request.txt b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-request.txt
new file mode 100644
index 0000000000..b4bd07fc46
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-request.txt
@@ -0,0 +1 @@
+{"id":1,"method":"echo","params":["Hello"]}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-result.txt b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-result.txt
new file mode 100644
index 0000000000..121bf74902
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/test/json-result.txt
@@ -0,0 +1 @@
+{"id":1,"result":"Hello"} \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/wiring/ref.js b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/wiring/ref.js
new file mode 100644
index 0000000000..95a84c01a5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/htdocs/wiring/ref.js
@@ -0,0 +1,574 @@
+/*
+ * 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.
+ *
+ * The JSON-RPC client code is based on Jan-Klaas' JavaScript
+ * o lait library (jsolait).
+ *
+ * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $
+ *
+ * Copyright (c) 2003-2004 Jan-Klaas Kollhof
+ * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ */
+
+/**
+ * Escape a character.
+ */
+var JSONClient = new Object();
+
+JSONClient.escapeJSONChar = function(c) {
+ if(c == "\"" || c == "\\") return "\\" + c;
+ else if (c == "\b") return "\\b";
+ else if (c == "\f") return "\\f";
+ else if (c == "\n") return "\\n";
+ else if (c == "\r") return "\\r";
+ else if (c == "\t") return "\\t";
+ var hex = c.charCodeAt(0).toString(16);
+ if(hex.length == 1) return "\\u000" + hex;
+ else if(hex.length == 2) return "\\u00" + hex;
+ else if(hex.length == 3) return "\\u0" + hex;
+ else return "\\u" + hex;
+};
+
+/**
+ * Encode a string into JSON format.
+ */
+JSONClient.escapeJSONString = function(s) {
+ /* The following should suffice but Safari's regex is broken
+ (doesn't support callback substitutions)
+ return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g,
+ JSONClient.escapeJSONChar) + "\"";
+ */
+
+ /* Rather inefficient way to do it */
+ var parts = s.split("");
+ for(var i = 0; i < parts.length; i++) {
+ var c = parts[i];
+ if(c == '"' ||
+ c == '\\' ||
+ c.charCodeAt(0) < 32 ||
+ c.charCodeAt(0) >= 128)
+ parts[i] = JSONClient.escapeJSONChar(parts[i]);
+ }
+ return "\"" + parts.join("") + "\"";
+};
+
+/**
+ * Marshall objects to JSON format.
+ */
+JSONClient.toJSON = function(o) {
+ if(o == null) {
+ return "null";
+ } else if(o.constructor == String) {
+ return JSONClient.escapeJSONString(o);
+ } else if(o.constructor == Number) {
+ return o.toString();
+ } else if(o.constructor == Boolean) {
+ return o.toString();
+ } else if(o.constructor == Date) {
+ return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
+ } else if(o.constructor == Array) {
+ var v = [];
+ for(var i = 0; i < o.length; i++) v.push(JSONClient.toJSON(o[i]));
+ return "[" + v.join(", ") + "]";
+ } else {
+ var v = [];
+ for(attr in o) {
+ if(o[attr] == null) v.push("\"" + attr + "\": null");
+ else if(typeof o[attr] == "function"); /* skip */
+ else v.push(JSONClient.escapeJSONString(attr) + ": " + JSONClient.toJSON(o[attr]));
+ }
+ return "{" + v.join(", ") + "}";
+ }
+};
+
+/**
+ * HTTPBindingClient.Exception.
+ */
+HTTPBindingClient.Exception = function(code, message, javaStack) {
+ this.code = code;
+ var name;
+ if(javaStack) {
+ this.javaStack = javaStack;
+ var m = javaStack.match(/^([^:]*)/);
+ if(m) name = m[0];
+ }
+ if(name) this.name = name;
+ else this.name = "HTTPBindingClientException";
+ this.message = message;
+};
+
+HTTPBindingClient.Exception.CODE_REMOTE_EXCEPTION = 490;
+HTTPBindingClient.Exception.CODE_ERR_CLIENT = 550;
+HTTPBindingClient.Exception.CODE_ERR_PARSE = 590;
+HTTPBindingClient.Exception.CODE_ERR_NOMETHOD = 591;
+HTTPBindingClient.Exception.CODE_ERR_UNMARSHALL = 592;
+HTTPBindingClient.Exception.CODE_ERR_MARSHALL = 593;
+
+HTTPBindingClient.Exception.prototype = new Error();
+HTTPBindingClient.Exception.prototype.toString = function(code, msg) {
+ return this.name + ": " + this.message;
+};
+
+/**
+ * Default top level exception handler.
+ */
+HTTPBindingClient.default_ex_handler = function(e) {
+ alert(e);
+};
+
+/**
+ * Client settable variables
+ */
+HTTPBindingClient.toplevel_ex_handler = HTTPBindingClient.default_ex_handler;
+HTTPBindingClient.profile_async = false;
+HTTPBindingClient.max_req_active = 1;
+HTTPBindingClient.requestId = 1;
+
+/**
+ * HTTPBindingClient implementation
+ */
+HTTPBindingClient.prototype._createApplyMethod = function() {
+ var fn = function() {
+ var args = [];
+ var callback = null;
+ var methodName = arguments[0];
+ for(var i = 1; i < arguments.length; i++) args.push(arguments[i]);
+
+ if(typeof args[args.length - 1] == "function") callback = args.pop();
+
+ var req = fn.client._makeRequest.call(fn.client, methodName, args, callback);
+ if(callback == null) {
+ return fn.client._sendRequest.call(fn.client, req);
+ } else {
+ HTTPBindingClient.async_requests.push(req);
+ HTTPBindingClient.kick_async();
+ return req.requestId;
+ }
+ };
+ fn.client = this;
+ return fn;
+};
+
+HTTPBindingClient._getCharsetFromHeaders = function(http) {
+ try {
+ var contentType = http.getResponseHeader("Content-type");
+ var parts = contentType.split(/\s*;\s*/);
+ for(var i = 0; i < parts.length; i++) {
+ if(parts[i].substring(0, 8) == "charset=")
+ return parts[i].substring(8, parts[i].length);
+ }
+ } catch (e) {}
+ return "UTF-8";
+};
+
+/**
+ * Async queue globals
+ */
+HTTPBindingClient.async_requests = [];
+HTTPBindingClient.async_inflight = {};
+HTTPBindingClient.async_responses = [];
+HTTPBindingClient.async_timeout = null;
+HTTPBindingClient.num_req_active = 0;
+
+HTTPBindingClient._async_handler = function() {
+ HTTPBindingClient.async_timeout = null;
+
+ while(HTTPBindingClient.async_responses.length > 0) {
+ var res = HTTPBindingClient.async_responses.shift();
+ if(res.canceled) continue;
+ if(res.profile) res.profile.dispatch = new Date();
+ try {
+ res.cb(res.result, res.ex, res.profile);
+ } catch(e) {
+ HTTPBindingClient.toplevel_ex_handler(e);
+ }
+ }
+
+ while(HTTPBindingClient.async_requests.length > 0 && HTTPBindingClient.num_req_active < HTTPBindingClient.max_req_active) {
+ var req = HTTPBindingClient.async_requests.shift();
+ if(req.canceled) continue;
+ req.client._sendRequest.call(req.client, req);
+ }
+};
+
+HTTPBindingClient.kick_async = function() {
+ if(HTTPBindingClient.async_timeout == null)
+ HTTPBindingClient.async_timeout = setTimeout(HTTPBindingClient._async_handler, 0);
+};
+
+HTTPBindingClient.cancelRequest = function(requestId) {
+ /* If it is in flight then mark it as canceled in the inflight map
+ and the XMLHttpRequest callback will discard the reply. */
+ if(HTTPBindingClient.async_inflight[requestId]) {
+ HTTPBindingClient.async_inflight[requestId].canceled = true;
+ return true;
+ }
+
+ /* If its not in flight yet then we can just mark it as canceled in
+ the the request queue and it will get discarded before being sent. */
+ for(var i in HTTPBindingClient.async_requests) {
+ if(HTTPBindingClient.async_requests[i].requestId == requestId) {
+ HTTPBindingClient.async_requests[i].canceled = true;
+ return true;
+ }
+ }
+
+ /* It may have returned from the network and be waiting for its callback
+ to be dispatched, so mark it as canceled in the response queue
+ and the response will get discarded before calling the callback. */
+ for(var i in HTTPBindingClient.async_responses) {
+ if(HTTPBindingClient.async_responses[i].requestId == requestId) {
+ HTTPBindingClient.async_responses[i].canceled = true;
+ return true;
+ }
+ }
+
+ return false;
+};
+
+HTTPBindingClient.prototype._makeRequest = function(methodName, args, cb) {
+ var req = {};
+ req.client = this;
+ req.requestId = HTTPBindingClient.requestId++;
+
+ var obj = {};
+ obj.id = req.requestId;
+ if (this.objectID)
+ obj.method = ".obj#" + this.objectID + "." + methodName;
+ else
+ obj.method = methodName;
+ obj.params = args;
+
+ if (cb) req.cb = cb;
+ if (HTTPBindingClient.profile_async)
+ req.profile = { "submit": new Date() };
+ req.data = JSONClient.toJSON(obj);
+
+ return req;
+};
+
+HTTPBindingClient.prototype._sendRequest = function(req) {
+ if(req.profile) req.profile.start = new Date();
+
+ /* Get free http object from the pool */
+ var http = HTTPBindingClient.poolGetHTTPRequest();
+ HTTPBindingClient.num_req_active++;
+
+ /* Send the request */
+ http.open("POST", this.uri, (req.cb != null));
+
+ /* setRequestHeader is missing in Opera 8 Beta */
+ try {
+ http.setRequestHeader("Content-type", "text/plain");
+ } catch(e) {}
+
+ /* Construct call back if we have one */
+ if(req.cb) {
+ var self = this;
+ http.onreadystatechange = function() {
+ if(http.readyState == 4) {
+ http.onreadystatechange = function () {};
+ var res = { "cb": req.cb, "result": null, "ex": null};
+ if (req.profile) {
+ res.profile = req.profile;
+ res.profile.end = new Date();
+ }
+ try { res.result = self._handleResponse(http); }
+ catch(e) { res.ex = e; }
+ if(!HTTPBindingClient.async_inflight[req.requestId].canceled)
+ HTTPBindingClient.async_responses.push(res);
+ delete HTTPBindingClient.async_inflight[req.requestId];
+ HTTPBindingClient.kick_async();
+ }
+ };
+ } else {
+ http.onreadystatechange = function() {};
+ }
+
+ HTTPBindingClient.async_inflight[req.requestId] = req;
+
+ try {
+ http.send(req.data);
+ } catch(e) {
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+ throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed");
+ }
+
+ if(!req.cb) return this._handleResponse(http);
+};
+
+HTTPBindingClient.prototype._handleResponse = function(http) {
+ /* Get the charset */
+ if(!this.charset) {
+ this.charset = HTTPBindingClient._getCharsetFromHeaders(http);
+ }
+
+ /* Get request results */
+ var status, statusText, data;
+ try {
+ status = http.status;
+ statusText = http.statusText;
+ data = http.responseText;
+ } catch(e) {
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+ HTTPBindingClient.kick_async();
+ throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed");
+ }
+
+ /* Return http object to the pool; */
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+
+ /* Unmarshall the response */
+ if(status != 200) {
+ throw new HTTPBindingClient.Exception(status, statusText);
+ }
+ var obj;
+ try {
+ eval("obj = " + data);
+ } catch(e) {
+ throw new HTTPBindingClient.Exception(550, "error parsing result");
+ }
+ if(obj.error)
+ throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg, obj.error.trace);
+ var res = obj.result;
+
+ /* Handle CallableProxy */
+ if(res && res.objectID && res.JSONRPCType == "CallableReference")
+ return new HTTPBindingClient(this.uri, res.objectID);
+
+ return res;
+};
+
+
+/**
+ * XMLHttpRequest wrapper code
+ */
+HTTPBindingClient.http_spare = [];
+HTTPBindingClient.http_max_spare = 8;
+
+HTTPBindingClient.poolGetHTTPRequest = function() {
+ if(HTTPBindingClient.http_spare.length > 0) {
+ return HTTPBindingClient.http_spare.pop();
+ }
+ return HTTPBindingClient.getHTTPRequest();
+};
+
+HTTPBindingClient.poolReturnHTTPRequest = function(http) {
+ if(HTTPBindingClient.http_spare.length >= HTTPBindingClient.http_max_spare)
+ delete http;
+ else
+ HTTPBindingClient.http_spare.push(http);
+};
+
+HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0",
+ "MSXML2.XMLHTTP.4.0",
+ "MSXML2.XMLHTTP.3.0",
+ "MSXML2.XMLHTTP",
+ "Microsoft.XMLHTTP" ];
+
+HTTPBindingClient.getHTTPRequest = function() {
+ /* Mozilla XMLHttpRequest */
+ try {
+ HTTPBindingClient.httpObjectName = "XMLHttpRequest";
+ return new XMLHttpRequest();
+ } catch(e) {}
+
+ /* Microsoft MSXML ActiveX */
+ for (var i=0; i < HTTPBindingClient.msxmlNames.length; i++) {
+ try {
+ HTTPBindingClient.httpObjectName = HTTPBindingClient.msxmlNames[i];
+ return new ActiveXObject(HTTPBindingClient.msxmlNames[i]);
+ } catch (e) {}
+ }
+
+ /* None found */
+ HTTPBindingClient.httpObjectName = null;
+ throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object");
+};
+
+
+HTTPBindingClient.prototype.get = function(id, responseFunction) {
+ var xhr = this.createXMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("get - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("GET", this.uri + '/' + id, true);
+ xhr.send(null);
+};
+
+HTTPBindingClient.prototype.post = function (entry, responseFunction) {
+ var xhr = this.createXMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 201) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("post - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("POST", this.uri, true);
+ xhr.setRequestHeader("Content-Type", "application/atom+xml");
+ xhr.send(entry);
+};
+
+HTTPBindingClient.prototype.put = function (id, entry, responseFunction) {
+ var xhr = this.createXMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("put - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("PUT", this.uri + '/' + id, true);
+ xhr.setRequestHeader("Content-Type", "application/atom+xml");
+ xhr.send(entry);
+};
+
+HTTPBindingClient.prototype.del = function (id, responseFunction) {
+ var xhr = this.createXMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ if (responseFunction != null) responseFunction();
+ } else {
+ alert("delete - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("DELETE", this.uri + '/' + id, true);
+ xhr.send(null);
+};
+
+HTTPBindingClient.prototype.createXMLHttpRequest = function () {
+ /* Mozilla XMLHttpRequest */
+ try { return new XMLHttpRequest(); } catch(e) {}
+
+ /* Microsoft MSXML ActiveX */
+ for (var i = 0; i < HTTPBindingClient.msxmlNames.length; i++) {
+ try { return new ActiveXObject(HTTPBindingClient.msxmlNames[i]); } catch (e) {}
+ }
+ alert("XML http request not supported");
+ return null;
+}
+
+/**
+ * Construct an HTTPBindingClient.
+ */
+function HTTPBindingClient(cname, uri, objectID) {
+ this.uri = "/references/" + cname + "/" + uri;
+ this.objectID = objectID;
+ this.apply = this._createApplyMethod();
+
+ if (typeof DOMParser == "undefined") {
+ DOMParser = function () {}
+
+ DOMParser.prototype.parseFromString = function (str, contentType) {
+ if (typeof ActiveXObject != "undefined") {
+ var d = new ActiveXObject("MSXML.DomDocument");
+ d.loadXML(str);
+ return d;
+ } else if (typeof XMLHttpRequest != "undefined") {
+ var req = new XMLHttpRequest;
+ req.open("GET", "data:" + (contentType || "application/xml") +
+ ";charset=utf-8," + encodeURIComponent(str), false);
+ if (req.overrideMimeType) {
+ req.overrideMimeType(contentType);
+ }
+ req.send(null);
+ return req.responseXML;
+ }
+ }
+ }
+};
+
+/**
+ * Construct a component.
+ */
+function ClientComponent(name) {
+ this.name = name;
+}
+
+/**
+ * Public API.
+ */
+
+/**
+ * Return a component.
+ */
+function component(name) {
+ return new ClientComponent(name);
+}
+
+/**
+ * Return a reference proxy.
+ */
+function reference(comp, name) {
+ return new HTTPBindingClient(comp.name, name);
+};
+
+/**
+ * Add proxy functions to a reference proxy.
+ */
+function defun(ref) {
+ function defapply(name) {
+ return function() {
+ var args = new Array();
+ args[0] = name;
+ for (i = 0, n = arguments.length; i < n; i++)
+ args[i + 1] = arguments[i];
+ return this.apply.apply(this, args);
+ };
+ }
+
+ for (f = 1; f < arguments.length; f++) {
+ var fn = arguments[f];
+ ref[fn]= defapply(fn);
+ }
+ return ref;
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/httpd-test b/sandbox/sebastien/cpp/apr-2/modules/server/httpd-test
new file mode 100755
index 0000000000..050becdb24
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/httpd-test
@@ -0,0 +1,78 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+
+# Setup
+../http/httpd-conf tmp localhost 8090 htdocs
+./server-conf tmp
+./scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+../http/httpd-start tmp
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/test/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/test/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/test/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/test/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/test/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/test/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/test/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/test/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/test/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt htdocs/test/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/impl-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/server/impl-test.cpp
new file mode 100644
index 0000000000..1bd0843745
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/impl-test.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test component implementation.
+ */
+
+#include "string.hpp"
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace server {
+
+const failable<value> get(unused const list<value>& params) {
+ return value(mklist<value>("text/html", mklist<value>("Hey")));
+}
+
+const failable<value> post(unused const list<value>& params) {
+ return value(mklist<value>(string("123456789")));
+}
+
+const failable<value> put(unused const list<value>& params) {
+ return value(true);
+}
+
+const failable<value> del(unused const list<value>& params) {
+ return value(true);
+}
+
+const failable<value> echo(const list<value>& params) {
+ return value(car(params));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "get")
+ return tuscany::server::get(cdr(params));
+ if (func == "post")
+ return tuscany::server::post(cdr(params));
+ if (func == "put")
+ return tuscany::server::put(cdr(params));
+ if (func == "delete")
+ return tuscany::server::del(cdr(params));
+ if (func == "echo")
+ return tuscany::server::echo(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/mod-cpp.hpp b/sandbox/sebastien/cpp/apr-2/modules/server/mod-cpp.hpp
new file mode 100644
index 0000000000..8cae35e493
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/mod-cpp.hpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_modcpp_hpp
+#define tuscany_modcpp_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate C++
+ * component implementations.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+
+#include "function.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "dynlib.hpp"
+#include "../scheme/driver.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modcpp {
+
+/**
+ * Apply a C++ component implementation function.
+ */
+const list<value> failableResult(const value& func, const list<value>& v) {
+ if (isNil(cdr(v)))
+ return v;
+
+ // Report a failure with an empty reason as 'function not supported'
+ // Except for the start, and stop functions, which are optional
+ const value reason = cadr(v);
+ if (length(reason) == 0) {
+ if (func == "start" || func == "stop")
+ return mklist<value>(lambda<value(const list<value>&)>());
+ return mklist<value>(value(), string("Function not supported: ") + func);
+ }
+ return v;
+}
+
+struct applyImplementation {
+ const lib ilib;
+ const lambda<value(const list<value>&)> impl;
+ const list<value> px;
+
+ applyImplementation(const lib& ilib, const lambda<value(const list<value>&)>& impl, const list<value>& px) : ilib(ilib), impl(impl), px(px) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ debug(params, "modeval::cpp::applyImplementation::input");
+
+ // Apply the component implementation function
+ const value val = failableResult(car(params), impl(append(params, px)));
+
+ debug(val, "modeval::cpp::applyImplementation::result");
+ return val;
+ }
+};
+
+/**
+ * Evaluate a C++ component implementation and convert it to
+ * an applicable lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) {
+
+ // Configure the implementation's lambda function
+ const value ipath(attributeValue("path", impl));
+ const value iname(attributeValue("library", impl));
+ const string fpath(isNil(ipath)? path + iname : path + ipath + "/" + iname);
+ const lib ilib(*(new (gc_new<lib>()) lib(fpath + dynlibExt)));
+ const failable<lambda<value(const list<value>&)> > evalf(dynlambda<value(const list<value>&)>("apply", ilib));
+ if (!hasContent(evalf))
+ return evalf;
+ const lambda<value(const list<value>&)> l(applyImplementation(ilib, content(evalf), px));
+ return l;
+}
+
+}
+}
+}
+
+#endif /* tuscany_modcpp_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.cpp b/sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.cpp
new file mode 100644
index 0000000000..a94ccf5bbe
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module used to eval C++ and Scheme component implementations.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "mod-eval.hpp"
+#include "mod-scheme.hpp"
+#include "mod-cpp.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+
+/**
+ * Apply a lifecycle start or restart event.
+ */
+const value applyLifecycle(unused const list<value>& params) {
+ // Return a nil function as we don't need to handle any subsequent events
+ return failable<value>(lambda<value(const list<value>&)>());
+}
+
+/**
+ * Evaluate a Scheme or C++ component implementation and convert it to an
+ * applicable lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, unused const lambda<value(const list<value>&)>& lifecycle) {
+ const string itype(elementName(impl));
+ if (contains(itype, ".scheme"))
+ return modscheme::evalImplementation(path, impl, px);
+ if (contains(itype, ".cpp"))
+ return modcpp::evalImplementation(path, impl, px);
+ return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype);
+}
+
+}
+}
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.hpp b/sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.hpp
new file mode 100644
index 0000000000..b8d3147459
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/mod-eval.hpp
@@ -0,0 +1,896 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_modeval_hpp
+#define tuscany_modeval_hpp
+
+/**
+ * HTTPD module used to eval component implementations.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "../atom/atom.hpp"
+#include "../json/json.hpp"
+#include "../scdl/scdl.hpp"
+#include "../http/http.hpp"
+#include "../http/httpd.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval;
+}
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s), wiringServerName(""), contributionPath(""), compositeName(""), virtualHostContributionPath(""), virtualHostCompositeName(""), ca(""), cert(""), key("") {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ lambda<value(const list<value>&)> lifecycle;
+ string wiringServerName;
+ string contributionPath;
+ string compositeName;
+ string virtualHostContributionPath;
+ string virtualHostCompositeName;
+ string ca;
+ string cert;
+ string key;
+ list<value> implementations;
+ list<value> implTree;
+};
+
+/**
+ * Return true if a server contains a composite configuration.
+ */
+const bool hasCompositeConf(const ServerConf& sc) {
+ return sc.contributionPath != "" && sc.compositeName != "";
+}
+
+/**
+ * Return true if a server contains a virtual host composite configuration.
+ */
+const bool hasVirtualCompositeConf(const ServerConf& sc) {
+ return sc.virtualHostContributionPath != "" && sc.virtualHostCompositeName != "";
+}
+
+/**
+ * Convert a result represented as a content + failure pair to a
+ * failable monad.
+ */
+const failable<value> failableResult(const list<value>& v) {
+ if (isNil(cdr(v)))
+ return car(v);
+ return mkfailure<value>(string(cadr(v)));
+}
+
+/**
+ * Handle an HTTP GET.
+ */
+const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>& impl) {
+ debug(r->uri, "modeval::get::uri");
+
+ // Inspect the query string
+ const list<list<value> > args = httpd::queryArgs(r);
+ const list<value> ia = assoc(value("id"), args);
+ const list<value> ma = assoc(value("method"), args);
+
+ // Evaluate a JSON-RPC request and return a JSON result
+ if (!isNil(ia) && !isNil(ma)) {
+
+ // Extract the request id, method and params
+ const value id = cadr(ia);
+ const value func = c_str(json::funcName(string(cadr(ma))));
+
+ // Apply the requested function
+ const failable<value> val = failableResult(impl(cons(func, json::queryParams(args))));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+
+ // Return JSON result
+ js::JSContext cx;
+ return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r);
+ }
+
+ // Evaluate the GET expression
+ const list<value> path(pathValues(r->uri));
+ const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(cddr(path)))));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+ const value c = content(val);
+
+ // Write content-type / content-list pair
+ if (isString(car<value>(c)) && isList(cadr<value>(c)))
+ return httpd::writeResult(convertValues<string>(cadr<value>(c)), car<value>(c), r);
+
+ // Write ATOM feed or entry
+ if (isString(car<value>(c)) && isString(cadr<value>(c))) {
+ if (isNil(cddr(path)))
+ return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(c)), "application/atom+xml;type=feed", r);
+ else
+ return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(c)), "application/atom+xml;type=entry", r);
+ }
+
+ // Write JSON value
+ js::JSContext cx;
+ return httpd::writeResult(json::writeJSON(valuesToElements(c), cx), "application/json", r);
+}
+
+/**
+ * Handle an HTTP POST.
+ */
+const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>& impl) {
+ debug(r->uri, "modeval::post::url");
+
+ // Evaluate a JSON-RPC request and return a JSON result
+ const string ct = httpd::contentType(r);
+ if (contains(ct, "application/json-rpc") || contains(ct, "text/plain") || contains(ct, "application/x-www-form-urlencoded")) {
+
+ // Read the JSON request
+ const int rc = httpd::setupReadPolicy(r);
+ if(rc != OK)
+ return rc;
+ const list<string> ls = httpd::read(r);
+ debug(ls, "modeval::post::input");
+ js::JSContext cx;
+ const list<value> json = elementsToValues(content(json::readJSON(ls, cx)));
+ const list<list<value> > args = httpd::postArgs(json);
+
+ // Extract the request id, method and params
+ const value id = cadr(assoc(value("id"), args));
+ const value func = c_str(json::funcName(cadr(assoc(value("method"), args))));
+ const list<value> params = (list<value>)cadr(assoc(value("params"), args));
+
+ // Evaluate the request expression
+ const failable<value> val = failableResult(impl(cons<value>(func, params)));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+
+ // Return JSON result
+ return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r);
+ }
+
+ // Evaluate an ATOM POST request and return the location of the corresponding created resource
+ if (contains(ct, "application/atom+xml")) {
+
+ // Read the ATOM entry
+ const list<value> path(pathValues(r->uri));
+ const int rc = httpd::setupReadPolicy(r);
+ if(rc != OK)
+ return rc;
+ const list<string> ls = httpd::read(r);
+ debug(ls, "modeval::post::input");
+ const value entry = atom::entryValue(content(atom::readATOMEntry(ls)));
+
+ // Evaluate the POST expression
+ const failable<value> val = failableResult(impl(cons<value>("post", mklist<value>(cddr(path), entry))));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+
+ // Return the created resource location
+ debug(content(val), "modeval::post::location");
+ apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, c_str(httpd::url(r->uri, content(val), r))));
+ r->status = HTTP_CREATED;
+ return OK;
+ }
+
+ // Unknown content type, wrap the HTTP request struct in a value and pass it to
+ // the component implementation function
+ const failable<value> val = failableResult(impl(cons<value>("handle", mklist<value>(httpd::requestValue(r)))));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+ return (int)content(val);
+}
+
+/**
+ * Handle an HTTP PUT.
+ */
+const failable<int> put(request_rec* r, const lambda<value(const list<value>&)>& impl) {
+ debug(r->uri, "modeval::put::url");
+
+ // Read the ATOM entry
+ const list<value> path(pathValues(r->uri));
+ const int rc = httpd::setupReadPolicy(r);
+ if(rc != OK)
+ return rc;
+ const list<string> ls = httpd::read(r);
+ debug(ls, "modeval::put::input");
+ const value entry = atom::entryValue(content(atom::readATOMEntry(ls)));
+
+ // Evaluate the PUT expression and update the corresponding resource
+ const failable<value> val = failableResult(impl(cons<value>("put", mklist<value>(cddr(path), entry))));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+ if (val == value(false))
+ return HTTP_NOT_FOUND;
+ return OK;
+}
+
+/**
+ * Handle an HTTP DELETE.
+ */
+const failable<int> del(request_rec* r, const lambda<value(const list<value>&)>& impl) {
+ debug(r->uri, "modeval::delete::url");
+
+ // Evaluate an ATOM delete request
+ const list<value> path(pathValues(r->uri));
+ const failable<value> val = failableResult(impl(cons<value>("delete", mklist<value>(cddr(path)))));
+ if (!hasContent(val))
+ return mkfailure<int>(reason(val));
+ if (val == value(false))
+ return HTTP_NOT_FOUND;
+ return OK;
+}
+
+/**
+ * Translate a component request.
+ */
+int translate(request_rec *r) {
+ if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE)
+ return DECLINED;
+ if (strncmp(r->uri, "/components/", 12) != 0)
+ return DECLINED;
+ r->handler = "mod_tuscany_eval";
+ return OK;
+}
+
+/**
+ * Make an HTTP proxy lambda.
+ */
+const value mkhttpProxy(const ServerConf& sc, const string& ref, const string& base) {
+ const string uri = base + ref;
+ debug(uri, "modeval::mkhttpProxy::uri");
+ return lambda<value(const list<value>&)>(http::proxy(uri, sc.ca, sc.cert, sc.key, sc.p));
+}
+
+/**
+ * Return a component implementation proxy lambda.
+ */
+class implProxy {
+public:
+ implProxy(const ServerConf& sc, const value& name) : sc(sc), name(name) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ debug(params, "modeval::implProxy::input");
+
+ // Lookup the component implementation
+ const list<value> impl(assoctree<value>(name, sc.implTree));
+ if (isNil(impl))
+ return mkfailure<value>(string("Couldn't find component implementation: ") + name);
+
+ // Call its lambda function
+ const lambda<value(const list<value>&)> l(cadr<value>(impl));
+ const value func = c_str(car(params));
+ const failable<value> val = failableResult(l(cons(func, cdr(params))));
+ debug(val, "modeval::implProxy::result");
+ if (!hasContent(val))
+ return value();
+ return content(val);
+ }
+
+private:
+ const ServerConf& sc;
+ const value name;
+};
+
+const value mkimplProxy(const ServerConf& sc, const value& name) {
+ debug(name, "modeval::implProxy::impl");
+ return lambda<value(const list<value>&)>(implProxy(sc, name));
+}
+
+/**
+ * Convert a list of component references to a list of proxy lambdas.
+ */
+const value mkrefProxy(const ServerConf& sc, const value& ref, const string& base) {
+ const value target = scdl::target(ref);
+ debug(ref, "modeval::mkrefProxy::ref");
+ debug(target, "modeval::mkrefProxy::target");
+
+ // Use an HTTP proxy or an internal proxy to the component implementation
+ if (isNil(target) || httpd::isAbsolute(target))
+ return mkhttpProxy(sc, scdl::name(ref), base);
+ return mkimplProxy(sc, car(pathValues(target)));
+}
+
+const list<value> refProxies(const ServerConf& sc, const list<value>& refs, const string& base) {
+ if (isNil(refs))
+ return refs;
+ return cons(mkrefProxy(sc, car(refs), base), refProxies(sc, cdr(refs), base));
+}
+
+/**
+ * Store current HTTP request for access from property lambda functions.
+ */
+#ifdef WANT_THREADS
+__thread
+#endif
+request_rec* currentRequest = NULL;
+
+class ScopedRequest {
+public:
+ ScopedRequest(request_rec* r) {
+ currentRequest = r;
+ }
+
+ ~ScopedRequest() {
+ currentRequest = NULL;
+ }
+};
+
+/**
+ * Convert a list of component properties to a list of lambda functions that just return
+ * the property value. The host, user and email properties are configured with the values
+ * from the HTTP request, if any.
+ */
+struct propProxy {
+ const value v;
+ propProxy(const value& v) : v(v) {
+ }
+ const value operator()(unused const list<value>& params) const {
+ return v;
+ }
+};
+
+struct hostPropProxy {
+ const value v;
+ hostPropProxy(const value& v) : v(v) {
+ }
+ const value operator()(unused const list<value>& params) const {
+ return httpd::hostName(currentRequest, v);
+ }
+};
+
+struct envPropProxy {
+ const string name;
+ const value v;
+ envPropProxy(const string& name, const value& v) : name(name), v(v) {
+ }
+ const value operator()(unused const list<value>& params) const {
+ const char* env = apr_table_get(currentRequest->subprocess_env, c_str(name));
+ if (env == NULL || *env == '\0')
+ return v;
+ return string(env);
+ }
+};
+
+struct userPropProxy {
+ const value v;
+ userPropProxy(const value& v) : v(v) {
+ }
+ const value operator()(unused const list<value>& params) const {
+ if (currentRequest->user == NULL)
+ return v;
+ return string(currentRequest->user);
+ }
+};
+
+const value mkpropProxy(const value& prop) {
+ if (scdl::name(prop) == "host")
+ return lambda<value(const list<value>&)>(hostPropProxy(elementValue(prop)));
+ if (scdl::name(prop) == "user")
+ return lambda<value(const list<value>&)>(userPropProxy(elementValue(prop)));
+ if (scdl::name(prop) == "realm")
+ return lambda<value(const list<value>&)>(envPropProxy("REALM", elementValue(prop)));
+ if (scdl::name(prop) == "email")
+ return lambda<value(const list<value>&)>(envPropProxy("EMAIL", elementValue(prop)));
+ if (scdl::name(prop) == "nickname")
+ return lambda<value(const list<value>&)>(envPropProxy("NICKNAME", elementValue(prop)));
+ if (scdl::name(prop) == "fullname")
+ return lambda<value(const list<value>&)>(envPropProxy("FULLNAME", elementValue(prop)));
+ if (scdl::name(prop) == "firstname")
+ return lambda<value(const list<value>&)>(envPropProxy("FIRSTNAME", elementValue(prop)));
+ if (scdl::name(prop) == "lastname")
+ return lambda<value(const list<value>&)>(envPropProxy("LASTNAME", elementValue(prop)));
+ return lambda<value(const list<value>&)>(propProxy(elementValue(prop)));
+}
+
+const list<value> propProxies(const list<value>& props) {
+ if (isNil(props))
+ return props;
+ return cons(mkpropProxy(car(props)), propProxies(cdr(props)));
+}
+
+/**
+ * Evaluate a component and convert it to an applicable lambda function.
+ */
+struct implementationFailure {
+ const value reason;
+ implementationFailure(const value& r) : reason(r) {
+ }
+
+ // Default implementation representing an implementation that
+ // couldn't be evaluated. Report the evaluation error on all
+ // subsequent calls expect start/stop.
+ const value operator()(unused const list<value>& params) const {
+ const value func = car(params);
+ if (func == "start" || func == "stop")
+ return mklist<value>(lambda<value(const list<value>&)>());
+ return mklist<value>(value(), reason);
+ }
+};
+
+const value evalComponent(ServerConf& sc, const value& comp) {
+ extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px, const lambda<value(const list<value>&)>& lifecycle);
+
+ const value impl = scdl::implementation(comp);
+ debug(comp, "modeval::evalComponent::comp");
+ debug(impl, "modeval::evalComponent::impl");
+
+ // Convert component references to configured proxy lambdas
+ ostringstream base;
+ base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/";
+ const list<value> rpx(refProxies(sc, scdl::references(comp), str(base)));
+
+ // Convert component proxies to configured proxy lambdas
+ const list<value> ppx(propProxies(scdl::properties(comp)));
+
+ // Evaluate the component implementation and convert it to an applicable lambda function
+ const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(sc.contributionPath, impl, append(rpx, ppx), sc.lifecycle));
+ if (!hasContent(cimpl))
+ return lambda<value(const list<value>&)>(implementationFailure(reason(cimpl)));
+ return content(cimpl);
+}
+
+/**
+ * Return a list of component-name + configured-implementation pairs.
+ */
+const list<value> componentToImplementationAssoc(ServerConf& sc, const list<value>& c) {
+ if (isNil(c))
+ return c;
+ return cons<value>(mklist<value>(scdl::name(car(c)), evalComponent(sc, car(c))), componentToImplementationAssoc(sc, cdr(c)));
+}
+
+/**
+ * Read the components declared in a composite.
+ */
+const failable<list<value> > readComponents(const string& path) {
+ ifstream is(path);
+ if (fail(is))
+ return mkfailure<list<value> >(string("Could not read composite: ") + path);
+ return scdl::components(readXML(streamList(is)));
+}
+
+/**
+ * Apply a list of component implementations to a start or restart lifecycle expression.
+ * Return the functions returned by the component implementations.
+ */
+const failable<list<value> > applyLifecycleExpr(const list<value>& impls, const list<value>& expr) {
+ if (isNil(impls))
+ return list<value>();
+
+ // Evaluate lifecycle expression against a component implementation lambda
+ const lambda<value(const list<value>&)> l = cadr<value>(car(impls));
+ const failable<value> r = failableResult(l(expr));
+ if (!hasContent(r))
+ return mkfailure<list<value> >(reason(r));
+ const lambda<value(const list<value>&)> rl = content(r);
+
+ // Use the returned lambda function, if any, from now on
+ const lambda<value(const list<value>&)> al = isNil(rl)? l : rl;
+
+ // Continue with the rest of the list
+ const failable<list<value> > nr = applyLifecycleExpr(cdr(impls), expr);
+ if (!hasContent(nr))
+ return nr;
+ return cons<value>(mklist<value>(car<value>(car(impls)), value(al)), content(nr));
+}
+
+/**
+ * Configure the components declared in the deployed composite.
+ */
+const failable<bool> confComponents(ServerConf& sc) {
+ if (!hasCompositeConf(sc))
+ return false;
+ debug(sc.contributionPath, "modeval::confComponents::contributionPath");
+ debug(sc.compositeName, "modeval::confComponents::compositeName");
+ if (sc.ca != "") debug(sc.ca, "modeval::confComponents::sslCA");
+ if (sc.cert != "") debug(sc.cert, "modeval::confComponents::sslCert");
+ if (sc.key != "") debug(sc.key, "modeval::confComponents::sslKey");
+
+ // Read the components and get their implementation lambda functions
+ const failable<list<value> > comps = readComponents(sc.contributionPath + sc.compositeName);
+ if (!hasContent(comps))
+ return mkfailure<bool>(reason(comps));
+ sc.implementations = componentToImplementationAssoc(sc, content(comps));
+ debug(sc.implementations, "modeval::confComponents::implementations");
+ return true;
+}
+
+/**
+ * Start the components declared in the deployed composite.
+ */
+const failable<bool> startComponents(ServerConf& sc) {
+
+ // Start the components and record the returned implementation lambda functions
+ debug(sc.implementations, "modeval::startComponents::start");
+ const failable<list<value> > impls = applyLifecycleExpr(sc.implementations, mklist<value>("start"));
+ if (!hasContent(impls))
+ return mkfailure<bool>(reason(impls));
+ sc.implementations = content(impls);
+ debug(sc.implementations, "modeval::startComponents::implementations");
+ return true;
+}
+
+/**
+ * Virtual host scoped server configuration.
+ */
+class VirtualHostConf {
+public:
+ VirtualHostConf(const gc_pool& p, const ServerConf& sc) : sc(sc), vsc(pool(p), sc.server) {
+ vsc.virtualHostContributionPath = sc.virtualHostContributionPath;
+ vsc.virtualHostCompositeName = sc.virtualHostCompositeName;
+ vsc.ca = sc.ca;
+ vsc.cert = sc.cert;
+ vsc.key = sc.key;
+ }
+
+ ~VirtualHostConf() {
+ extern const failable<bool> virtualHostCleanup(const ServerConf& vsc, const ServerConf& sc);
+ virtualHostCleanup(vsc, sc);
+ }
+
+ const ServerConf& sc;
+ ServerConf vsc;
+};
+
+/**
+ * Configure and start the components deployed in a virtual host.
+ */
+const failable<bool> virtualHostConfig(ServerConf& vsc, const ServerConf& sc, request_rec* r) {
+
+ // Determine the server name and wiring server name
+ debug(httpd::serverName(vsc.server), "modeval::virtualHostConfig::serverName");
+ debug(httpd::serverName(r), "modeval::virtualHostConfig::virtualHostName");
+ vsc.wiringServerName = httpd::serverName(r);
+ debug(vsc.wiringServerName, "modeval::virtualHostConfig::wiringServerName");
+ debug(vsc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
+
+ // Resolve the configured virtual contribution under
+ // the virtual host's SCA contribution root
+ vsc.contributionPath = vsc.virtualHostContributionPath + httpd::subdomain(httpd::hostName(r)) + "/";
+ vsc.compositeName = vsc.virtualHostCompositeName;
+
+ // Chdir to the virtual host's contribution
+ if (chdir(c_str(sc.contributionPath)) != 0)
+ return mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + sc.contributionPath);
+
+ // Configure the deployed components
+ const failable<bool> cr = confComponents(vsc);
+ if (!hasContent(cr))
+ return cr;
+
+ // Start the configured components
+ const failable<bool> sr = startComponents(vsc);
+ if (!hasContent(sr))
+ return sr;
+
+ // Store the implementation lambda functions (from both the virtual host and the
+ // main server) in a tree for fast retrieval
+ vsc.implTree = mkbtree(sort(append(vsc.implementations, sc.implementations)));
+ return true;
+}
+
+/**
+ * Cleanup a virtual host.
+ */
+const failable<bool> virtualHostCleanup(const ServerConf& vsc, const ServerConf& sc) {
+ if (!hasCompositeConf(vsc))
+ return true;
+ debug("modeval::virtualHostCleanup");
+
+ // Stop the component implementations
+ applyLifecycleExpr(vsc.implementations, mklist<value>("stop"));
+
+ // Chdir back to the main server's contribution
+ if (chdir(c_str(sc.contributionPath)) != 0)
+ return mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + sc.contributionPath);
+ return true;
+}
+
+/**
+ * HTTP request handler.
+ */
+int handler(request_rec *r) {
+ if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE)
+ return DECLINED;
+ if(strcmp(r->handler, "mod_tuscany_eval"))
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ ScopedRequest sr(r);
+ httpdDebugRequest(r, "modeval::handler::input");
+
+ // Get the server configuration
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval);
+
+ // Process dynamic virtual host configuration, if any
+ VirtualHostConf vhc(gc_pool(r->pool), sc);
+ const bool usevh = hasVirtualCompositeConf(vhc.vsc) && httpd::isVirtualHostRequest(sc.server, r);
+ if (usevh) {
+ const failable<bool> cr = virtualHostConfig(vhc.vsc, sc, r);
+ if (!hasContent(cr))
+ return httpd::reportStatus(mkfailure<int>(reason(cr)));
+ }
+
+ // Get the component implementation lambda
+ const list<value> path(pathValues(r->uri));
+ const list<value> impl(assoctree<value>(cadr(path), usevh? vhc.vsc.implTree : sc.implTree));
+ if (isNil(impl))
+ return httpd::reportStatus(mkfailure<int>(string("Couldn't find component implementation: ") + cadr(path)));
+
+ // Handle HTTP method
+ const lambda<value(const list<value>&)> l(cadr<value>(impl));
+ if (r->header_only)
+ return OK;
+ if(r->method_number == M_GET)
+ return httpd::reportStatus(get(r, l));
+ if(r->method_number == M_POST)
+ return httpd::reportStatus(post(r, l));
+ if(r->method_number == M_PUT)
+ return httpd::reportStatus(put(r, l));
+ if(r->method_number == M_DELETE)
+ return httpd::reportStatus(del(r, l));
+ return HTTP_NOT_IMPLEMENTED;
+}
+
+/**
+ * Cleanup callback, called when the server is stopped or restarted.
+ */
+apr_status_t serverCleanup(void* v) {
+ gc_pool pool;
+ ServerConf& sc = *(ServerConf*)v;
+ debug("modeval::serverCleanup");
+
+ // Stop the component implementations
+ applyLifecycleExpr(sc.implementations, mklist<value>("stop"));
+
+ // Call the module lifecycle function
+ if (isNil(sc.lifecycle))
+ return APR_SUCCESS;
+ debug("modeval::serverCleanup::stop");
+ sc.lifecycle(mklist<value>("stop"));
+
+ return APR_SUCCESS;
+}
+
+/**
+ * Called after all the configuration commands have been run.
+ * Process the server configuration and configure the deployed components.
+ */
+const int postConfigMerge(const ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval);
+ debug(httpd::serverName(s), "modeval::postConfigMerge::serverName");
+ if (sc.wiringServerName == "")
+ sc.wiringServerName = mainsc.wiringServerName != ""? mainsc.wiringServerName : httpd::serverName(s);
+ debug(sc.wiringServerName, "modeval::postConfigMerge::wiringServerName");
+ sc.contributionPath = mainsc.contributionPath;
+ sc.compositeName = mainsc.compositeName;
+ sc.virtualHostContributionPath = mainsc.virtualHostContributionPath;
+ sc.virtualHostCompositeName = mainsc.virtualHostCompositeName;
+ if (sc.ca == "") sc.ca = mainsc.ca;
+ if (sc.cert == "") sc.cert = mainsc.cert;
+ if (sc.key == "") sc.key = mainsc.key;
+ sc.implementations = mainsc.implementations;
+ sc.implTree = mainsc.implTree;
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, server_rec *s) {
+ extern const value applyLifecycle(const list<value>&);
+
+ gc_scoped_pool pool(p);
+
+ // Get the server configuration and determine the wiring server name
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval);
+ debug(httpd::serverName(s), "modeval::postConfig::serverName");
+ if (sc.wiringServerName == "") sc.wiringServerName = httpd::serverName(s);
+ debug(sc.wiringServerName, "modeval::postConfig::wiringServerName");
+
+ // Count the calls to post config
+ const string k("tuscany::modeval::postConfig");
+ const long int count = (long int)httpd::userData(k, s);
+ httpd::putUserData(k, (void*)(count + 1), s);
+
+ // Count == 0, do nothing as post config is always called twice,
+ // count == 1 is the first start, count > 1 is a restart
+ if (count == 0)
+ return OK;
+
+ if (count == 1) {
+ // Chdir to the deployed contribution
+ if (chdir(c_str(sc.contributionPath)) != 0) {
+ mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + sc.contributionPath);
+ return -1;
+ }
+
+ debug("modeval::postConfig::start");
+ const failable<value> r = failableResult(applyLifecycle(mklist<value>("start")));
+ if (!hasContent(r))
+ return -1;
+ sc.lifecycle = content(r);
+ }
+ if (count > 1) {
+ debug("modeval::postConfig::restart");
+ const failable<value> r = failableResult(applyLifecycle(mklist<value>("restart")));
+ if (!hasContent(r))
+ return -1;
+ sc.lifecycle = content(r);
+ }
+
+ // Configure the deployed components
+ const failable<bool> res = confComponents(sc);
+ if (!hasContent(res)) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
+ return -1;
+ }
+
+ // Register a cleanup callback, called when the server is stopped or restarted
+ apr_pool_pre_cleanup_register(p, (void*)&sc, serverCleanup);
+
+ // Merge the configuration into the virtual hosts
+ return postConfigMerge(sc, s->next);
+}
+
+/**
+ * Child process initialization.
+ */
+void childInit(apr_pool_t* p, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_eval);
+ if(psc == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+ ServerConf& sc = *psc;
+
+ // Start the components in the child process
+ const failable<bool> res = startComponents(sc);
+ if (!hasContent(res)) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+
+ // Store the implementation lambda functions in a tree for fast retrieval
+ sc.implTree = mkbtree(sort(sc.implementations));
+
+ // Merge the updated configuration into the virtual hosts
+ postConfigMerge(sc, s->next);
+
+ // Register a cleanup callback, called when the child is stopped or restarted
+ apr_pool_pre_cleanup_register(p, (void*)psc, serverCleanup);
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.wiringServerName = arg;
+ return NULL;
+}
+const char* confContribution(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.contributionPath = arg;
+ return NULL;
+}
+const char* confComposite(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.compositeName = arg;
+ return NULL;
+}
+const char* confVirtualContribution(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.virtualHostContributionPath = arg;
+ return NULL;
+}
+const char* confVirtualComposite(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.virtualHostCompositeName = arg;
+ return NULL;
+}
+const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.ca = arg;
+ return NULL;
+}
+const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.cert = arg;
+ return NULL;
+}
+const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
+ sc.key = arg;
+ return NULL;
+}
+const char* confEnv(unused cmd_parms *cmd, unused void *c, const char *name, const char *value) {
+ gc_scoped_pool pool(cmd->pool);
+ setenv(name, value != NULL? value : "", 1);
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, RSRC_CONF, "SCA wiring server name"),
+ AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, RSRC_CONF, "SCA contribution location"),
+ AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"),
+ AP_INIT_TAKE1("SCAVirtualContribution", (const char*(*)())confVirtualContribution, NULL, RSRC_CONF, "SCA virtual host contribution location"),
+ AP_INIT_TAKE1("SCAVirtualComposite", (const char*(*)())confVirtualComposite, NULL, RSRC_CONF, "SCA virtual composite location"),
+ AP_INIT_TAKE12("SCASetEnv", (const char*(*)())confEnv, NULL, OR_FILEINFO, "Environment variable name and optional value"),
+ AP_INIT_TAKE1("SCAWiringSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "SCA wiring SSL CA certificate file"),
+ AP_INIT_TAKE1("SCAWiringSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "SCA wiring SSL certificate file"),
+ AP_INIT_TAKE1("SCAWiringSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "SCA wiring SSL certificate key file"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+
+void registerHooks(unused apr_pool_t *p) {
+ ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_translate_name(translate, NULL, NULL, APR_HOOK_FIRST);
+}
+
+}
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_eval = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ NULL, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::server::modeval::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::server::modeval::commands, tuscany::server::modeval::registerHooks
+};
+
+}
+
+#endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/mod-scheme.hpp b/sandbox/sebastien/cpp/apr-2/modules/server/mod-scheme.hpp
new file mode 100644
index 0000000000..43d7bf4041
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/mod-scheme.hpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_modscheme_hpp
+#define tuscany_modscheme_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate Scheme
+ * component implementations.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../scheme/eval.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modscheme {
+
+/**
+ * Convert proxy lambdas to evaluator primitive procedures.
+ */
+const list<value> primitiveProcedures(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(mklist<value>(scheme::primitiveSymbol, car(l)), primitiveProcedures(cdr(l)));
+}
+
+/**
+ * Apply a Scheme component implementation function.
+ */
+struct applyImplementation {
+ const value impl;
+ const list<value> px;
+
+ applyImplementation(const value& impl, const list<value>& px) : impl(impl), px(scheme::quotedParameters(primitiveProcedures(px))) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value expr = cons<value>(car(params), append(scheme::quotedParameters(cdr(params)), px));
+ debug(expr, "modeval::scheme::applyImplementation::input");
+ scheme::Env env = scheme::setupEnvironment();
+ const value res = scheme::evalScript(expr, impl, env);
+ const value val = isNil(res)? mklist<value>(value(), string("Could not evaluate expression")) : mklist<value>(res);
+ debug(val, "modeval::scheme::applyImplementation::result");
+ return val;
+ }
+};
+
+/**
+ * Evaluate a Scheme component implementation and convert it to an
+ * applicable lambda function.
+ */
+const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) {
+ const string fpath(path + attributeValue("script", impl));
+ ifstream is(fpath);
+ if (fail(is))
+ return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath);
+ const value script = scheme::readScript(is);
+ if (isNil(script))
+ return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath);
+ return lambda<value(const list<value>&)>(applyImplementation(script, px));
+}
+
+}
+}
+}
+
+#endif /* tuscany_modscheme_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/mod-wiring.cpp b/sandbox/sebastien/cpp/apr-2/modules/server/mod-wiring.cpp
new file mode 100644
index 0000000000..0ab61f5af8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/mod-wiring.cpp
@@ -0,0 +1,472 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module used to wire component references and route requests to
+ * target service components.
+ */
+
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../scdl/scdl.hpp"
+#include "../http/httpd.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_wiring;
+}
+
+namespace tuscany {
+namespace server {
+namespace modwiring {
+
+/**
+ * Set to true to wire using mod_proxy, false to wire using HTTP client redirects.
+ */
+const bool useModProxy = true;
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s), contributionPath(""), compositeName(""), virtualHostContributionPath(""), virtualHostCompositeName("") {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ string contributionPath;
+ string compositeName;
+ string virtualHostContributionPath;
+ string virtualHostCompositeName;
+ list<value> references;
+ list<value> services;
+};
+
+/**
+ * Return true if a server contains a composite configuration.
+ */
+const bool hasCompositeConf(const ServerConf& sc) {
+ return sc.contributionPath != "" && sc.compositeName != "";
+}
+
+/**
+ * Return true if a server contains a virtual host composite configuration.
+ */
+const bool hasVirtualCompositeConf(const ServerConf& sc) {
+ return sc.virtualHostContributionPath != "" && sc.virtualHostCompositeName != "";
+}
+
+/**
+ * Route a /references/component-name/reference-name request,
+ * to the target of the component reference.
+ */
+int translateReference(const ServerConf& sc, request_rec *r) {
+ httpdDebugRequest(r, "modwiring::translateReference::input");
+ debug(r->uri, "modwiring::translateReference::uri");
+
+ // Find the requested component
+ const list<value> rpath(pathValues(r->uri));
+ const list<value> comp(assoctree(cadr(rpath), sc.references));
+ if (isNil(comp))
+ return HTTP_NOT_FOUND;
+
+ // Find the requested reference and target configuration
+ const list<value> ref(assoctree<value>(caddr(rpath), cadr(comp)));
+ if (isNil(ref))
+ return HTTP_NOT_FOUND;
+ const string target(cadr(ref));
+ debug(target, "modwiring::translateReference::target");
+
+ // Route to an absolute target URI using mod_proxy or an HTTP client redirect
+ const list<value> pathInfo = cdddr(rpath);
+ if (httpd::isAbsolute(target)) {
+ if (useModProxy) {
+ // Build proxy URI
+ // current request's protocol scheme, reference target uri and request path info
+ string turi = httpd::scheme(r) + substr(target, find(target, "://")) + path(pathInfo);
+ r->filename = apr_pstrdup(r->pool, c_str(string("proxy:") + turi));
+ debug(r->filename, "modwiring::translateReference::filename");
+ r->proxyreq = PROXYREQ_REVERSE;
+ r->handler = "proxy-server";
+ apr_table_setn(r->notes, "proxy-nocanon", "1");
+ return OK;
+ }
+
+ debug(target, "modwiring::translateReference::location");
+ r->handler = "mod_tuscany_wiring";
+ return httpd::externalRedirect(target, r);
+ }
+
+ // Route to a relative target URI using a local internal redirect
+ // /components/, target component name and request path info
+ const value tname = substr(target, 0, find(target, '/'));
+ const string tpath = path(cons(tname, pathInfo));
+ r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/components") + tpath));
+ debug(r->filename, "modwiring::translateReference::filename");
+ r->handler = "mod_tuscany_wiring";
+ return OK;
+}
+
+/**
+ * Find a leaf matching a request path in a tree of URI paths.
+ */
+const int matchPath(const list<value>& k, const list<value>& p) {
+ if (isNil(p))
+ return true;
+ if (isNil(k))
+ return false;
+ if (car(k) != car(p))
+ return false;
+ return matchPath(cdr(k), cdr(p));
+}
+
+const list<value> assocPath(const value& k, const list<value>& tree) {
+ if (isNil(tree))
+ return tree;
+ if (matchPath(k, car<value>(car(tree))))
+ return car(tree);
+ if (k < car<value>(car(tree)))
+ return assocPath(k, cadr(tree));
+ return assocPath(k, caddr(tree));
+}
+
+/**
+ * Route a service request to the component providing the requested service.
+ */
+int translateService(const ServerConf& sc, request_rec *r) {
+ httpdDebugRequest(r, "modwiring::translateService::input");
+ debug(r->uri, "modwiring::translateService::uri");
+
+ // Find the requested component
+ debug(sc.services, "modwiring::translateService::services");
+ const list<value> p(pathValues(r->uri));
+ const list<value> svc(assocPath(p, sc.services));
+ if (isNil(svc))
+ return DECLINED;
+ debug(svc, "modwiring::translateService::service");
+
+ // Build a component-name + path-info URI
+ const list<value> target(cons<value>(cadr(svc), httpd::pathInfo(p, car(svc))));
+ debug(target, "modwiring::translateService::target");
+
+ // Dispatch to the target component using a local internal redirect
+ const string tp(path(target));
+ debug(tp, "modwiring::translateService::path");
+ const string redir(string("/redirect:/components") + tp);
+ debug(redir, "modwiring::translateService::redirect");
+ r->filename = apr_pstrdup(r->pool, c_str(redir));
+ r->handler = "mod_tuscany_wiring";
+ return OK;
+}
+
+/**
+ * Read the components declared in a composite.
+ */
+const failable<list<value> > readComponents(const string& path) {
+ ifstream is(path);
+ if (fail(is))
+ return mkfailure<list<value> >(string("Could not read composite: ") + path);
+ return scdl::components(readXML(streamList(is)));
+}
+
+/**
+ * Return a list of component-name + references pairs. The references are
+ * arranged in trees of reference-name + reference-target pairs.
+ */
+const list<value> componentReferenceToTargetTree(const value& c) {
+ return mklist<value>(scdl::name(c), mkbtree(sort(scdl::referenceToTargetAssoc(scdl::references(c)))));
+}
+
+const list<value> componentReferenceToTargetAssoc(const list<value>& c) {
+ if (isNil(c))
+ return c;
+ return cons<value>(componentReferenceToTargetTree(car(c)), componentReferenceToTargetAssoc(cdr(c)));
+}
+
+/**
+ * Return a list of service-URI-path + component-name pairs. Service-URI-paths are
+ * represented as lists of URI path fragments.
+ */
+const list<value> defaultBindingURI(const string& cn, const string& sn) {
+ return mklist<value>(cn, sn);
+}
+
+const list<value> bindingToComponentAssoc(const string& cn, const string& sn, const list<value>& b) {
+ if (isNil(b))
+ return b;
+ const value uri(scdl::uri(car(b)));
+ if (isNil(uri))
+ return cons<value>(mklist<value>(defaultBindingURI(cn, sn), cn), bindingToComponentAssoc(cn, sn, cdr(b)));
+ return cons<value>(mklist<value>(pathValues(c_str(string(uri))), cn), bindingToComponentAssoc(cn, sn, cdr(b)));
+}
+
+const list<value> serviceToComponentAssoc(const string& cn, const list<value>& s) {
+ if (isNil(s))
+ return s;
+ const string sn(scdl::name(car(s)));
+ const list<value> btoc(bindingToComponentAssoc(cn, sn, scdl::bindings(car(s))));
+ if (isNil(btoc))
+ return cons<value>(mklist<value>(defaultBindingURI(cn, sn), cn), serviceToComponentAssoc(cn, cdr(s)));
+ return append<value>(btoc, serviceToComponentAssoc(cn, cdr(s)));
+}
+
+const list<value> uriToComponentAssoc(const list<value>& c) {
+ if (isNil(c))
+ return c;
+ return append<value>(serviceToComponentAssoc(scdl::name(car(c)), scdl::services(car(c))), uriToComponentAssoc(cdr(c)));
+}
+
+/**
+ * Configure the components declared in the server's deployment composite.
+ */
+const bool confComponents(ServerConf& sc) {
+ if (!hasCompositeConf(sc))
+ return true;
+ debug(sc.contributionPath, "modwiring::confComponents::contributionPath");
+ debug(sc.compositeName, "modwiring::confComponents::compositeName");
+
+ // Read the component configuration and store the references and service URIs
+ // in trees for fast retrieval later
+ const failable<list<value> > comps = readComponents(sc.contributionPath + sc.compositeName);
+ if (!hasContent(comps))
+ return true;
+ const list<value> refs = componentReferenceToTargetAssoc(content(comps));
+ debug(refs, "modwiring::confComponents::references");
+ sc.references = mkbtree(sort(refs));
+
+ const list<value> svcs = uriToComponentAssoc(content(comps));
+ debug(svcs, "modwiring::confComponents::services");
+ sc.services = mkbtree(sort(svcs));
+ return true;
+}
+
+/**
+ * Virtual host scoped server configuration.
+ */
+class VirtualHostConf {
+public:
+ VirtualHostConf(const gc_pool& p, const ServerConf& ssc) : sc(pool(p), ssc.server) {
+ sc.virtualHostContributionPath = ssc.virtualHostContributionPath;
+ sc.virtualHostCompositeName = ssc.virtualHostCompositeName;
+ }
+
+ ~VirtualHostConf() {
+ }
+
+ ServerConf sc;
+};
+
+/**
+ * Configure and start the components deployed in a virtual host.
+ */
+const failable<bool> virtualHostConfig(ServerConf& sc, request_rec* r) {
+ debug(httpd::serverName(sc.server), "modwiring::virtualHostConfig::serverName");
+ debug(httpd::serverName(r), "modwiring::virtualHostConfig::virtualHostName");
+ debug(sc.virtualHostContributionPath, "modwiring::virtualHostConfig::virtualHostContributionPath");
+
+ // Resolve the configured virtual contribution under
+ // the virtual host's SCA contribution root
+ sc.contributionPath = sc.virtualHostContributionPath + httpd::subdomain(httpd::hostName(r)) + "/";
+ sc.compositeName = sc.virtualHostCompositeName;
+
+ // Configure the wiring for the deployed components
+ confComponents(sc);
+ return true;
+}
+
+/**
+ * Translate an HTTP service or reference request and route it
+ * to the target component.
+ */
+int translate(request_rec *r) {
+ if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE)
+ return DECLINED;
+
+ // No translation needed for a component or tunnel request
+ if (!strncmp(r->uri, "/components/", 12))
+ return DECLINED;
+
+ // Get the server configuration
+ gc_scoped_pool pool(r->pool);
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_wiring);
+
+ // Process dynamic virtual host configuration
+ VirtualHostConf vhc(gc_pool(r->pool), sc);
+ const bool usevh = hasVirtualCompositeConf(vhc.sc) && httpd::isVirtualHostRequest(sc.server, r);
+ if (usevh) {
+ const failable<bool> cr = virtualHostConfig(vhc.sc, r);
+ if (!hasContent(cr))
+ return -1;
+ }
+
+ // Translate a component reference request
+ if (!strncmp(r->uri, "/references/", 12))
+ return translateReference(usevh? vhc.sc: sc, r);
+
+ // Translate a service request
+ return translateService(usevh? vhc.sc : sc, r);
+}
+
+/**
+ * HTTP request handler, redirect to a target component.
+ */
+int handler(request_rec *r) {
+ if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE)
+ return DECLINED;
+ if(strcmp(r->handler, "mod_tuscany_wiring"))
+ return DECLINED;
+ if (r->filename == NULL || strncmp(r->filename, "/redirect:", 10) != 0)
+ return DECLINED;
+
+ // Nothing to do for an external redirect
+ if (r->status == HTTP_MOVED_TEMPORARILY)
+ return OK;
+
+ // Do an internal redirect
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modwiring::handler::input");
+
+ debug(r->uri, "modwiring::handler::uri");
+ debug(r->filename, "modwiring::handler::filename");
+ debug(r->path_info, "modwiring::handler::path info");
+ if (r->args == NULL)
+ return httpd::internalRedirect(httpd::redirectURI(string(r->filename + 10), string(r->path_info)), r);
+ return httpd::internalRedirect(httpd::redirectURI(string(r->filename + 10), string(r->path_info), string(r->args)), r);
+}
+
+/**
+ * Called after all the configuration commands have been run.
+ * Process the server configuration and configure the wiring for the deployed components.
+ */
+const int postConfigMerge(const ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ debug(httpd::serverName(s), "modwiring::postConfigMerge::serverName");
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_wiring);
+ sc.contributionPath = mainsc.contributionPath;
+ sc.compositeName = mainsc.compositeName;
+ sc.virtualHostContributionPath = mainsc.virtualHostContributionPath;
+ sc.virtualHostCompositeName = mainsc.virtualHostCompositeName;
+ sc.references = mainsc.references;
+ sc.services = mainsc.services;
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, server_rec *s) {
+ gc_scoped_pool pool(p);
+
+ // Count the calls to post config, skip the first one as
+ // postConfig is always called twice
+ const string k("tuscany::modwiring::postConfig");
+ const long int count = (long int)httpd::userData(k, s);
+ httpd::putUserData(k, (void*)(count + 1), s);
+ if (count == 0)
+ return OK;
+
+ // Configure the wiring for the deployed components
+ debug(httpd::serverName(s), "modwiring::postConfig::serverName");
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_wiring);
+ confComponents(sc);
+
+ // Merge the config into any virtual hosts
+ return postConfigMerge(sc, s->next);
+}
+
+/**
+ * Child process initialization.
+ */
+void childInit(apr_pool_t* p, server_rec* s) {
+ gc_scoped_pool pool(p);
+ if(ap_get_module_config(s->module_config, &mod_tuscany_wiring) == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_wiring loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+}
+
+/**
+ * Configuration commands.
+ */
+const char *confContribution(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring);
+ sc.contributionPath = arg;
+ return NULL;
+}
+const char *confComposite(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring);
+ sc.compositeName = arg;
+ return NULL;
+}
+const char *confVirtualContribution(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring);
+ sc.virtualHostContributionPath = arg;
+ return NULL;
+}
+const char *confVirtualComposite(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring);
+ sc.virtualHostCompositeName = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, RSRC_CONF, "SCA contribution location"),
+ AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"),
+ AP_INIT_TAKE1("SCAVirtualContribution", (const char*(*)())confVirtualContribution, NULL, RSRC_CONF, "SCA virtual host contribution location"),
+ AP_INIT_TAKE1("SCAVirtualComposite", (const char*(*)())confVirtualComposite, NULL, RSRC_CONF, "SCA virtual host composite location"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+void registerHooks(unused apr_pool_t *p) {
+ ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_translate_name(translate, NULL, NULL, APR_HOOK_FIRST);
+}
+
+}
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_wiring = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ NULL, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::server::modwiring::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::server::modwiring::commands, tuscany::server::modwiring::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/scheme-conf b/sandbox/sebastien/cpp/apr-2/modules/server/scheme-conf
new file mode 100755
index 0000000000..cd3c82b280
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/scheme-conf
@@ -0,0 +1,30 @@
+#!/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
+# 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.
+
+# Generate a Scheme server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: scheme-conf $*
+# Support for Scheme SCA components
+LoadModule mod_tuscany_eval $here/libmod_tuscany_eval.so
+
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/server-conf b/sandbox/sebastien/cpp/apr-2/modules/server/server-conf
new file mode 100755
index 0000000000..742d48d614
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/server-conf
@@ -0,0 +1,103 @@
+#!/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
+# 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.
+
+# Generate a server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+jsprefix=`readlink -f $here/../js`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+port=`echo $conf | awk '{ print $7 }' | awk -F "/" '{ print $1 }'`
+pport=`echo $conf | awk '{ print $7 }' | awk -F "/" '{ print $2 }'`
+if [ "$pport" = "" ]; then
+ pport=$port
+fi
+servername="http://$host:$pport"
+
+sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"`
+if [ "$sslconf" != "" ]; then
+ sslport=`echo $sslconf | awk '{ print $6 }' | awk -F "/" '{ print $1 }'`
+ sslpport=`echo $sslconf | awk '{ print $6 }' | awk -F "/" '{ print $2 }'`
+ if [ "$sslpport" = "" ]; then
+ sslpport=$sslport
+ fi
+ servername="https://$host:$sslpport"
+fi
+
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: server-conf $*
+# Support for SCA component wiring
+LoadModule mod_tuscany_wiring $here/libmod_tuscany_wiring.so
+
+EOF
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: server-conf $*
+# Route all wiring through the configured server name
+SCAWiringServerName $servername
+
+# Serve JavaScript client scripts
+Alias /component.js $jsprefix/htdocs/component.js
+Alias /util.js $jsprefix/htdocs/util.js
+Alias /elemutil.js $jsprefix/htdocs/elemutil.js
+Alias /xmlutil.js $jsprefix/htdocs/xmlutil.js
+Alias /atomutil.js $jsprefix/htdocs/atomutil.js
+Alias /ui.js $jsprefix/htdocs/ui.js
+Alias /ui.css $jsprefix/htdocs/ui.css
+Alias /scdl.js $jsprefix/htdocs/scdl.js
+Alias /graph.js $jsprefix/htdocs/graph.js
+
+<Location /component.js>
+AuthType None
+Require all granted
+</Location>
+<Location /scdl.js>
+AuthType None
+Require all granted
+</Location>
+<Location /util.js>
+AuthType None
+Require all granted
+</Location>
+<Location /ui.js>
+AuthType None
+Require all granted
+</Location>
+<Location /ui.css>
+AuthType None
+Require all granted
+</Location>
+
+EOF
+
+ssl=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"`
+if [ "$ssl" != "" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Configure SSL certificates
+SCAWiringSSLCACertificateFile "$root/cert/ca.crt"
+SCAWiringSSLCertificateFile "$root/cert/server.crt"
+SCAWiringSSLCertificateKeyFile "$root/cert/server.key"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/server-test b/sandbox/sebastien/cpp/apr-2/modules/server/server-test
new file mode 100755
index 0000000000..e53c7f5ef1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/server-test
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+# Setup
+../http/httpd-conf tmp localhost 8090 htdocs
+./server-conf tmp
+./scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+../http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/server-test.scm b/sandbox/sebastien/cpp/apr-2/modules/server/server-test.scm
new file mode 100644
index 0000000000..c23adb7f51
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/server-test.scm
@@ -0,0 +1,44 @@
+; 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.
+
+; JSON-RPC test case
+
+(define (echo x) x)
+
+; ATOMPub test case
+
+(define (get id)
+ (if (nul id)
+ '("Sample Feed" "123456789"
+ ("Item" "111" ((name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99)))
+ ("Item" "222" ((name "Orange") (currencyCode "USD") (currencySymbol "$") (price 3.55)))
+ ("Item" "333" ((name "Pear") (currencyCode "USD") (currencySymbol "$") (price 1.55))))
+
+ (list "Item" (car id) '((name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99))))
+)
+
+(define (post collection item)
+ '("123456789")
+)
+
+(define (put id item)
+ true
+)
+
+(define (delete id)
+ true
+)
diff --git a/sandbox/sebastien/cpp/apr-2/modules/server/wiring-test b/sandbox/sebastien/cpp/apr-2/modules/server/wiring-test
new file mode 100755
index 0000000000..e791ec555b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/server/wiring-test
@@ -0,0 +1,78 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+
+# Setup
+../http/httpd-conf tmp localhost 8090 htdocs
+./server-conf tmp
+./scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+EOF
+
+../http/httpd-start tmp
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/test/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/test/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/test/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt htdocs/test/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+../http/httpd-stop tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/wsgi/Makefile.am
new file mode 100644
index 0000000000..9f67ab37c0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/Makefile.am
@@ -0,0 +1,58 @@
+# 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.
+
+if WANT_PYTHON
+
+INCLUDES = -I${PYTHON_INCLUDE}
+
+dist_mod_SCRIPTS = composite.py wsgi-start wsgi-stop gae-start gae-stop
+moddir = $(prefix)/modules/wsgi
+
+dist_mod_DATA = app.yaml scdl.py util.py elemutil.py xmlutil.py atomutil.py jsonutil.py
+
+noinst_DATA = target.stamp
+
+target.stamp: app.yaml *.py *.composite htdocs/*
+ mkdir -p target
+ cp app.yaml *.py *.composite target
+ cp -R htdocs target/htdocs
+ touch target.stamp
+
+clean-local:
+ rm -rf target.stamp target
+
+prefix_DATA = gae.prefix
+prefixdir=$(prefix)/modules/wsgi
+gae.prefix: $(top_builddir)/config.status
+ echo ${GAE_PREFIX} >gae.prefix
+
+EXTRA_DIST = domain-test.composite *.py htdocs/*.xml htdocs/*.txt htdocs/*.html
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+noinst_PROGRAMS = client-test
+
+dist_noinst_SCRIPTS = util-test wsgi-test wiring-test http-test server-test
+TESTS = util-test wsgi-test wiring-test http-test server-test
+
+if WANT_GAE
+dist_noinst_SCRIPTS += gae-test
+TESTS += gae-test
+endif
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/app.yaml b/sandbox/sebastien/cpp/apr-2/modules/wsgi/app.yaml
new file mode 100644
index 0000000000..bc70aceced
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/app.yaml
@@ -0,0 +1,50 @@
+# 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.
+
+application: sca-wsgi
+version: 1
+runtime: python
+api_version: 1
+skip_files:
+- ^(.*/)?app\.yaml
+- ^(.*/)?app\.yml
+- ^(.*/)?index\.yaml
+- ^(.*/)?index\.yml
+- ^(.*/)?#.*#
+- ^(.*/)?.*~
+- ^(.*/)?.*\.py[co]
+- ^(.*/)?.*/RCS/.*
+- ^(.*/)?\..*
+- ^(.*/)?.*-test$
+- ^(.*/)?.*\.cpp$
+- ^(.*/)?.*\.o$
+- ^(.*/)?core$
+- ^(.*/)?.*\.out$
+- ^(.*/)?.*\.log$
+- ^(.*/)?Makefile.*
+- ^(.*/)?tmp/.*
+- ^(.*/)?wsgi-start
+- ^(.*/)?wsgi-stop
+
+handlers:
+- url: /(.*\.(html|js|png))
+ static_files: htdocs/\1
+ upload: htdocs/(.*\.(html|js|png))
+
+- url: /.*
+ script: composite.py
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/atom-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/atom-test.py
new file mode 100755
index 0000000000..81a6106519
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/atom-test.py
@@ -0,0 +1,168 @@
+#!/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 ATOM data conversion functions
+
+import unittest
+from elemutil import *
+from atomutil import *
+
+itemEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>" \
+ "<content type=\"application/xml\">" \
+ "<item>" \
+ "<name>Apple</name><price>$2.99</price>" \
+ "</item>" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\" />" \
+ "</entry>\n"
+
+textEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>" \
+ "<content type=\"text\">" \
+ "Apple" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\" />" \
+ "</entry>\n"
+
+incompleteEntry = \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title>item</title><content type=\"text/xml\">" \
+ "<Item xmlns=\"http://services/\">" \
+ "<name xmlns=\"\">Orange</name>" \
+ "<price xmlns=\"\">3.55</price>" \
+ "</Item>" \
+ "</content>" \
+ "</entry>"
+
+completedEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id />" \
+ "<content type=\"application/xml\">" \
+ "<Item xmlns=\"http://services/\">" \
+ "<name xmlns=\"\">Orange</name>" \
+ "<price xmlns=\"\">3.55</price>" \
+ "</Item>" \
+ "</content><link href=\"\" />" \
+ "</entry>\n"
+
+def testEntry():
+ i = (element, "'item", (element, "'name", "Apple"), (element, "'price", "$2.99"))
+ a = ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b", i)
+ s = writeATOMEntry(a);
+ assert car(s) == itemEntry
+
+ a2 = readATOMEntry((itemEntry,))
+ s2 = writeATOMEntry(a2)
+ assert car(s2) == itemEntry
+
+ a3 = readATOMEntry((textEntry,))
+ s3 = writeATOMEntry(a3)
+ assert car(s3) == textEntry
+
+ a4 = readATOMEntry((incompleteEntry,))
+ s4 = writeATOMEntry(a4)
+ assert car(s4) == completedEntry
+ return True
+
+emptyFeed = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">Feed</title>" \
+ "<id>1234</id>" \
+ "</feed>\n"
+
+itemFeed = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">Feed</title>" \
+ "<id>1234</id>" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>" \
+ "<content type=\"application/xml\">" \
+ "<item>" \
+ "<name>Apple</name><price>$2.99</price>" \
+ "</item>" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\" />" \
+ "</entry>" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>" \
+ "<content type=\"application/xml\">" \
+ "<item>" \
+ "<name>Orange</name><price>$3.55</price>" \
+ "</item>" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c\" />" \
+ "</entry>" \
+ "</feed>\n"
+
+def testFeed():
+ s = writeATOMFeed(("Feed", "1234"))
+ assert car(s) == emptyFeed
+
+ a2 = readATOMFeed((emptyFeed,))
+ s2 = writeATOMFeed(a2)
+ assert car(s2) == emptyFeed
+
+ i3 = (("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ (element, "'item", (element, "'name", "Apple"), (element, "'price", "$2.99"))),
+ ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ (element, "'item", (element, "'name", "Orange"), (element, "'price", "$3.55"))))
+ a3 = cons("Feed", cons("1234", i3))
+ s3 = writeATOMFeed(a3)
+ assert car(s3) == itemFeed
+
+ i4 = (("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ valueToElement(("'item", ("'name", "Apple"), ("'price", "$2.99")))),
+ ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ valueToElement(("'item", ("'name", "Orange"), ("'price", "$3.55")))))
+ a4 = cons("Feed", cons("1234", i4))
+ s4 = writeATOMFeed(a4)
+ assert car(s4) == itemFeed
+
+ a5 = readATOMFeed((itemFeed,));
+ s5 = writeATOMFeed(a5);
+ assert car(s5) == itemFeed
+
+ i6 = (("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ (("'name", "Apple"), ("'price", "$2.99"))),
+ ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ (("'name", "Orange"), ("'price", "$3.55"))))
+ a6 = cons("Feed", cons("1234", i6))
+ s6 = writeATOMFeed(feedValuesToElements(a6))
+ assert car(s6) == itemFeed
+
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testEntry()
+ testFeed()
+ print "OK"
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/atomutil.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/atomutil.py
new file mode 100644
index 0000000000..1e6a7c31b5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/atomutil.py
@@ -0,0 +1,120 @@
+# 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.
+
+# ATOM data conversion functions
+
+from util import *
+from elemutil import *
+from xmlutil import *
+
+# Convert a list of elements to a list of values representing an ATOM entry
+def entryElementsToValues(e):
+ lt = filter(selector((element, "'title")), e)
+ t = "" if isNil(lt) else elementValue(car(lt))
+ li = filter(selector((element, "'id")), e)
+ i = "" if isNil(li) else elementValue(car(li))
+ lc = filter(selector((element, "'content")), e)
+ return (t, i, elementValue(car(lc)))
+
+# Convert a list of elements to a list of values representing ATOM entries
+def entriesElementsToValues(e):
+ if isNil(e):
+ return e
+ return cons(entryElementsToValues(car(e)), entriesElementsToValues(cdr(e)))
+
+# Convert a list of strings to a list of values representing an ATOM entry
+def readATOMEntry(l):
+ e = readXML(l)
+ if isNil(e):
+ return ()
+ return entryElementsToValues(car(e))
+
+# Convert a list of values representy an ATOM entry to a value
+def entryValue(e):
+ v = elementsToValues((caddr(e),))
+ return cons(car(e), (cadr(e), cdr(car(v))))
+
+# Return true if a list of strings represents an ATOM feed
+def isATOMFeed(l):
+ if not isXML(l):
+ return False
+ return contains(car(l), "<feed") and contains(car(l), "=\"http://www.w3.org/2005/Atom\"")
+
+# Convert a list of strings to a list of values representing an ATOM feed
+def readATOMFeed(l):
+ f = readXML(l)
+ if isNil(f):
+ return ()
+ t = filter(selector((element, "'title")), car(f))
+ i = filter(selector((element, "'id")), car(f))
+ e = filter(selector((element, "'entry")), car(f))
+ if isNil(e):
+ return (elementValue(car(t)), elementValue(car(i)))
+ return cons(elementValue(car(t)), cons(elementValue(car(i)), entriesElementsToValues(e)))
+
+# Convert an ATOM feed containing elements to an ATOM feed containing values
+def feedValuesLoop(e):
+ if (isNil(e)):
+ return e
+ return cons(entryValue(car(e)), feedValuesLoop(cdr(e)))
+
+def feedValues(e):
+ return cons(car(e), cons(cadr(e), feedValuesLoop(cddr(e))))
+
+# Convert a list of values representy an ATOM entry to a list of elements
+def entryElement(l):
+ return (element, "'entry", (attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ (element, "'title", (attribute, "'type", "text"), car(l)),
+ (element, "'id", cadr(l)),
+ (element, "'content", (attribute, "'type", ("application/xml" if isList(caddr(l)) else "text")), caddr(l)),
+ (element, "'link", (attribute, "'href", cadr(l))))
+
+# Convert a list of values representing ATOM entries to a list of elements
+def entriesElements(l):
+ if isNil(l):
+ return l
+ return cons(entryElement(car(l)), entriesElements(cdr(l)))
+
+# Convert a list of values representing an ATOM entry to an ATOM entry
+def writeATOMEntry(l):
+ return writeXML((entryElement(l),), True)
+
+# Convert a list of values representing an ATOM feed to an ATOM feed
+def writeATOMFeed(l):
+ f = (element, "'feed", (attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ (element, "'title", (attribute, "'type", "text"), car(l)),
+ (element, "'id", cadr(l)))
+ if isNil(cddr(l)):
+ return writeXML((f,), True)
+ fe = append(f, entriesElements(cddr(l)))
+ return writeXML((fe,), True)
+
+# Convert an ATOM entry containing a value to an ATOM entry containing an item element
+def entryValuesToElements(v):
+ if isList(caddr(v)):
+ return cons(car(v), cons(cadr(v), valuesToElements((cons("'item", caddr(v)),))))
+ return cons(car(v), cons(cadr(v), valuesToElements((("'item", caddr(v)),))))
+
+# Convert an ATOM feed containing values to an ATOM feed containing elements
+def feedValuesToElementsLoop(v):
+ if isNil(v):
+ return v
+ return cons(entryValuesToElements(car(v)), feedValuesToElementsLoop(cdr(v)))
+
+def feedValuesToElements(v):
+ return cons(car(v), cons(cadr(v), feedValuesToElementsLoop(cddr(v))))
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.cpp
new file mode 100644
index 0000000000..da4fff973b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "../server/client-test.hpp"
+
+int main(const int argc, const char** argv) {
+ tuscany::cout << "Testing..." << tuscany::endl;
+ tuscany::server::testURI = argc < 2? "http://localhost:8090/wsgi" : argv[1];
+ tuscany::server::testBlobs = false;
+
+ tuscany::server::testServer();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.py
new file mode 100644
index 0000000000..867222e792
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/client-test.py
@@ -0,0 +1,40 @@
+# 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.
+
+import unittest
+
+# JSON-RPC test case
+
+def echo(x, ref):
+ e1 = ref("echo", x)
+ e2 = ref.echo(x)
+ assert e1 == e2
+ return e1
+
+# ATOMPub test case
+
+def get(id, ref):
+ return ref.get(id)
+
+def post(collection, item, ref):
+ return ref.post(collection, item)
+
+def put(id, item, ref):
+ return ref.put(id, item)
+
+def delete(id, ref):
+ return ref.delete(id)
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/composite.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/composite.py
new file mode 100755
index 0000000000..7044483f70
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/composite.py
@@ -0,0 +1,251 @@
+#!/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.
+
+# Composite deployment and integration with WSGI
+
+from wsgiref.simple_server import make_server
+from wsgiref.handlers import CGIHandler
+from wsgiref.util import request_uri
+from wsgiref.util import FileWrapper
+from os import environ
+import os.path
+import hashlib
+from sys import stderr, argv
+from util import *
+from scdl import *
+from atomutil import *
+from jsonutil import *
+
+# Cache the deployed components between requests
+comps = None
+
+# Return the path of an HTTP request
+def requestPath(e):
+ return e.get("PATH_INFO", "")
+
+# Return the method of an HTTP request
+def requestMethod(e):
+ return e.get("REQUEST_METHOD", "")
+
+# Return the method of an HTTP request
+def requestContentType(e):
+ return e.get("CONTENT_TYPE", "")
+
+# Return the request body input stream
+def requestBody(e):
+ i = e.get("wsgi.input", None)
+ if i == None:
+ return ()
+ l = int(e.get("CONTENT_LENGTH", "0"))
+ return (i.read(l),)
+
+def requestIfNoneMatch(e):
+ return e.get("HTTP_IF_NONE_MATCH", "");
+
+# Hash a list of strings into an MD5 signature
+def md5update(md, s):
+ if isNil(s):
+ return md.hexdigest()
+ md.update(car(s))
+ return md5update(md, cdr(s))
+
+def md5(s):
+ return md5update(hashlib.md5(), s)
+
+# Return an HTTP success result
+def result(e, r, st, h = (), b = None):
+ if st == 201:
+ r("201 Created", list(h))
+ return ()
+
+ if st == 200:
+ if b == None:
+ r("200 OK", list(h))
+ return ()
+
+ # Handle etags to minimize bandwidth usage
+ md = md5(b)
+ if (md == requestIfNoneMatch(e)):
+ r("304 Not Modified", list((("Etag", md), ("Expires", "Tue, 01 Jan 1980 00:00:00 GMT"))))
+ return ()
+ r("200 OK", list(h + (("Etag", md), ("Expires", "Tue, 01 Jan 1980 00:00:00 GMT"))))
+ return b
+
+ if st == 301:
+ r("301 Moved Permanently", list(h))
+
+ return failure(e, r, 500)
+
+# Return an HTTP failure result
+def failure(e, r, st):
+ s = "404 Not Found" if st == 404 else str(st) + " " + "Internal Server Error"
+ r(s, list((("Content-type", "text/html"),)))
+ return ("<html><head><title>"+ s + "</title></head><body><h1>" + s[4:] + "</h1></body></html>",)
+
+# Return a static file
+def fileresult(e, r, ct, f):
+
+ # Read the file, return a 404 if not found
+ p = "htdocs" + f
+ if not os.path.exists(p):
+ return failure(e, r, 404)
+ c = tuple(FileWrapper(open("htdocs" + f)))
+
+ # Handle etags to minimize bandwidth usage
+ md = md5(c)
+ r("200 OK", list((("Content-type", ct),("Etag", md))))
+ return c
+
+# Converts the args received in a POST to a list of key value pairs
+def postArgs(a):
+ if isNil(a):
+ return ((),)
+ l = car(a);
+ return cons(l, postArgs(cdr(a)))
+
+# Return the URL used to sign out
+def signout(ruri):
+ try:
+ from google.appengine.api import users
+ return users.create_logout_url(ruri)
+ except:
+ return None
+
+# Return the URL used to sign in
+def signin(ruri):
+ try:
+ from google.appengine.api import users
+ return users.create_login_url(ruri)
+ except:
+ return None
+
+# WSGI application function
+def application(e, r):
+ m = requestMethod(e)
+ fpath = requestPath(e)
+
+ # Serve static files
+ if m == "GET":
+ if fpath.endswith(".html"):
+ return fileresult(e, r, "text/html", fpath)
+ if fpath.endswith(".js"):
+ return fileresult(e, r, "application/x-javascript", fpath)
+ if fpath.endswith(".png"):
+ return fileresult(e, r, "image/png", fpath)
+ if fpath == "/":
+ return result(e, r, 301, (("Location", "/index.html"),))
+
+ # Debug hook
+ if fpath == "/debug":
+ return result(e, r, 200, (("Content-type", "text/plain"),), ("Debug",))
+
+ # Sign in and out
+ if fpath == "/login":
+ redir = signin("/")
+ if redir:
+ return result(e, r, 301, (("Location", redir),))
+ if fpath == "/logout":
+ redir = signout(signin("/"))
+ if redir:
+ return result(e, r, 301, (("Location", redir),))
+
+ # Find the requested component
+ path = tokens(fpath)
+ uc = uriToComponent(path, comps)
+ uri = car(uc)
+ if uri == None:
+ return failure(e, r, 404)
+ comp = cadr(uc)
+
+ # Call the requested component function
+ id = path[len(uri):]
+ if m == "GET":
+ v = comp("get", id)
+
+ # Write returned content-type / content pair
+ if not isinstance(cadr(v), basestring):
+ return result(e, r, 200, (("Content-type", car(v)),), cadr(v))
+
+ # Write an ATOM feed or entry
+ if isNil(id):
+ return result(e, r, 200, (("Content-type", "application/atom+xml;type=feed"),), writeATOMFeed(feedValuesToElements(v)))
+ return result(e, r, 200, (("Content-type", "application/atom+xml;type=entry"),), writeATOMEntry(entryValuesToElements(v)))
+
+ if m == "POST":
+ ct = requestContentType(e)
+
+ # Handle a JSON-RPC function call
+ if ct.find("application/json-rpc") != -1 or ct.find("text/plain") != -1 or ct.find("application/x-www-form-urlencoded") != -1:
+ json = elementsToValues(readJSON(requestBody(e)))
+ args = postArgs(json)
+ jid = cadr(assoc("'id", args))
+ func = funcName(cadr(assoc("'method", args)))
+ params = cadr(assoc("'params", args))
+ v = comp(func, *params)
+ return result(e, r, 200, (("Content-type", "application/json-rpc"),), jsonResult(jid, v))
+
+ # Handle an ATOM entry POST
+ if ct.find("application/atom+xml") != -1:
+ ae = entryValue(readATOMEntry(requestBody(e)))
+ v = comp("post", id, ae)
+ if isNil(v):
+ return failure(e, r, 500)
+ return result(e, r, 201, (("Location", request_uri(e) + "/" + "/".join(v)),))
+ return failure(e, r, 500)
+
+ if m == "PUT":
+ # Handle an ATOM entry PUT
+ ae = entryValue(readATOMEntry(requestBody(e)))
+ v = comp("put", id, ae)
+ if v == False:
+ return failure(e, r, 404)
+ return result(e, r, 200)
+
+ if m == "DELETE":
+ v = comp("delete", id)
+ if v == False:
+ return failure(e, r, 404)
+ return result(e, r, 200)
+
+ return failure(e, r, 500)
+
+# Return the WSGI server type
+def serverType(e):
+ return e.get("SERVER_SOFTWARE", "")
+
+def main():
+ # Read the deployed composite and evaluate the configured components
+ global comps
+ if comps == None:
+ domain = "domain.composite" if os.path.exists("domain.composite") else "domain-test.composite"
+ comps = evalComponents(components(parse(domain)))
+
+ # Handle the WSGI request with the WSGI runtime
+ st = serverType(environ)
+ if st.find("App Engine") != -1 or st.find("Development") != -1:
+ from google.appengine.ext.webapp.util import run_wsgi_app
+ run_wsgi_app(application)
+ elif st != "":
+ CGIHandler().run(application)
+ else:
+ make_server("", int(argv[1]), application).serve_forever()
+
+# Run the WSGI application
+if __name__ == "__main__":
+ main()
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/domain-test.composite b/sandbox/sebastien/cpp/apr-2/modules/wsgi/domain-test.composite
new file mode 100644
index 0000000000..9c44ebf5d8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/domain-test.composite
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://domain/test"
+ name="domain-test">
+
+ <component name="wsgi-test">
+ <t:implementation.python script="server-test.py"/>
+ <service name="test">
+ <t:binding.http uri="wsgi"/>
+ </service>
+ </component>
+
+ <component name="client-test">
+ <t:implementation.python script="client-test.py"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="ref" target="wsgi-test">
+ <t:binding.http/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/elemutil.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/elemutil.py
new file mode 100644
index 0000000000..b4b28d5110
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/elemutil.py
@@ -0,0 +1,168 @@
+# 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.
+
+# Functions to help represent data as lists of elements and attributes
+
+from util import *
+
+element = "'element"
+attribute = "'attribute"
+atsign = "'@"
+
+# Return true if a value is an element
+def isElement(v):
+ if not isList(v) or isNil(v) or v == None or car(v) != element:
+ return False
+ return True
+
+# Return true if a value is an attribute
+def isAttribute(v):
+ if not isList(v) or isNil(v) or v == None or car(v) != attribute:
+ return False
+ return True
+
+# Return the name of attribute
+def attributeName(l):
+ return cadr(l)
+
+# Return the value of attribute
+def attributeValue(l):
+ return caddr(l)
+
+# Return the name of an element
+def elementName(l):
+ return cadr(l)
+
+# Return true if an element has children
+def elementHasChildren(l):
+ return not isNil(cddr(l))
+
+# Return the children of an element
+def elementChildren(l):
+ return cddr(l)
+
+# Return true if an element has a value
+def elementHasValue(l):
+ r = reverse(l)
+ if isSymbol(car(r)):
+ return False
+ if isList(car(r)) and not isNil(car(r)) and isSymbol(car(car(r))):
+ return False
+ return True
+
+# Return the value of an element
+def elementValue(l):
+ return car(reverse(l))
+
+# Convert an element to a value
+def elementToValueIsList(v):
+ if not isList(v):
+ return False
+ return isNil(v) or not isSymbol(car(v))
+
+def elementToValue(t):
+ if isTaggedList(t, attribute):
+ return (atsign + attributeName(t)[1:], attributeValue(t))
+ if isTaggedList(t, element):
+ if elementHasValue(t):
+ if not elementToValueIsList(elementValue(t)):
+ return (elementName(t), elementValue(t))
+ return cons(elementName(t), (elementsToValues(elementValue(t)),))
+ return cons(elementName(t), elementsToValues(elementChildren(t)))
+ if not isList(t):
+ return t
+ return elementsToValues(t)
+
+# Convert a list of elements to a list of values
+def elementToValueIsSymbol(v):
+ if not isList(v):
+ return False
+ if (isNil(v)):
+ return False
+ if not isSymbol(car(v)):
+ return False
+ return True
+
+def elementToValueGroupValues(v, l):
+ if isNil(l) or not elementToValueIsSymbol(v) or not elementToValueIsSymbol(car(l)):
+ return cons(v, l)
+ if car(car(l)) != car(v):
+ return cons(v, l)
+ if not elementToValueIsList(cadr(car(l))):
+ g = (car(v), (cdr(v), cdr(car(l))))
+ return elementToValueGroupValues(g, cdr(l))
+ g = (car(v), cons(cdr(v), cadr(car(l))))
+ return elementToValueGroupValues(g, cdr(l))
+
+def elementsToValues(e):
+ if isNil(e):
+ return e
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)))
+
+# Convert a value to an element
+def valueToElement(t):
+ if isList(t) and not isNil(t) and isSymbol(car(t)):
+ n = car(t)
+ v = () if isNil(cdr(t)) else cadr(t)
+ if not isList(v):
+ if n[0:2] == atsign:
+ return (attribute, n[1:], v)
+ return (element, n, v)
+ if isNil(v) or not isSymbol(car(v)):
+ return cons(element, cons(n, (valuesToElements(v),)))
+ return cons(element, cons(n, valuesToElements(cdr(t))))
+ if not isList(t):
+ return t
+ return valuesToElements(t)
+
+# Convert a list of values to a list of elements
+def valuesToElements(l):
+ if isNil(l):
+ return l
+ return cons(valueToElement(car(l)), valuesToElements(cdr(l)))
+
+# Return a selector lambda function which can be used to filter elements
+def evalSelect(s, v):
+ if isNil(s):
+ return True
+ if isNil(v):
+ return False
+ if car(s) != car(v):
+ return False
+ return evalSelect(cdr(s), cdr(v))
+
+def selector(s):
+ return lambda v: evalSelect(s, v)
+
+# Return the value of the attribute with the given name
+def namedAttributeValue(name, l):
+ f = filter(lambda v: isAttribute(v) and attributeName(v) == name, l)
+ if isNil(f):
+ return None
+ return caddr(car(f))
+
+# Return child elements with the given name
+def namedElementChildren(name, l):
+ return filter(lambda v: isElement(v) and elementName(v) == name, l)
+
+# Return the child element with the given name
+def namedElementChild(name, l):
+ f = namedElementChildren(name, l)
+ if isNil(f):
+ return None
+ return car(f)
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-start b/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-start
new file mode 100755
index 0000000000..a3ee8765cb
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-start
@@ -0,0 +1,29 @@
+#!/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
+# 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.
+
+# Start Google AppEngine server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+port=$2
+
+python_prefix=`cat $here/../python/python.prefix`
+gae_prefix=`cat $here/gae.prefix`
+cd $root
+$python_prefix/bin/python $gae_prefix/dev_appserver.py -a 0.0.0.0 -p $port $root &
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-stop b/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-stop
new file mode 100755
index 0000000000..69de7f0c2b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-stop
@@ -0,0 +1,29 @@
+#!/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
+# 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.
+
+# Stop Google AppEngine server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+port=$2
+
+python_prefix=`cat $here/../python/python.prefix`
+gae_prefix=`cat $here/gae.prefix`
+py="$python_prefix/bin/python $gae_prefix/dev_appserver.py -a 0.0.0.0 -p $port $root"
+
+kill `ps -ef | grep -v grep | grep "${py}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-test b/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-test
new file mode 100755
index 0000000000..1791a830ca
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/gae-test
@@ -0,0 +1,30 @@
+#!/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
+# 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.
+
+# Setup
+./gae-start target 8090 2>/dev/null
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./gae-stop target 8090
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/index.html
new file mode 100644
index 0000000000..cd25bf17b3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/index.html
@@ -0,0 +1 @@
+<html><body><h1>It works!</h1></body></html> \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/entry.xml b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/entry.xml
new file mode 100644
index 0000000000..d26a46f25b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/entry.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111" /></entry>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/feed.xml b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/feed.xml
new file mode 100644
index 0000000000..0be99f6eaf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/feed.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Sample Feed</title><id>123456789</id><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111" /></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>222</id><content type="application/xml"><item><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content><link href="222" /></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>333</id><content type="application/xml"><item><name>Pear</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>1.55</price></item></content><link href="333" /></entry></feed>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-request.txt b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-request.txt
new file mode 100644
index 0000000000..b4bd07fc46
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-request.txt
@@ -0,0 +1 @@
+{"id":1,"method":"echo","params":["Hello"]}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-result.txt b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-result.txt
new file mode 100644
index 0000000000..121bf74902
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/htdocs/test/json-result.txt
@@ -0,0 +1 @@
+{"id":1,"result":"Hello"} \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/http-test b/sandbox/sebastien/cpp/apr-2/modules/wsgi/http-test
new file mode 100755
index 0000000000..6676f6514c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/http-test
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+uri=$1
+if [ "$uri" = "" ]; then
+ uri="http://localhost:8090"
+fi
+
+# Setup
+mkdir -p tmp
+./wsgi-start target 8090 2>/dev/null
+sleep 2
+
+# Test JSON-RPC
+here=`readlink -f $0`; here=`dirname $here`
+python_prefix=`cat $here/../python/python.prefix`
+$python_prefix/bin/python http-test.py
+rc=$?
+
+# Cleanup
+./wsgi-stop target 8090
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/http-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/http-test.py
new file mode 100755
index 0000000000..45a1ecd3cc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/http-test.py
@@ -0,0 +1,32 @@
+#!/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.
+
+# HTTP client proxy functions
+
+from httputil import *
+
+def testClient():
+ c = mkclient("http://localhost:8090/wsgi")
+ assert c.echo("Hey") == "Hey"
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testClient()
+ print "OK"
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/httputil.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/httputil.py
new file mode 100644
index 0000000000..723e1a7284
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/httputil.py
@@ -0,0 +1,93 @@
+#!/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.
+
+# HTTP client proxy functions
+
+from httplib import HTTPConnection, HTTPSConnection
+from urlparse import urlparse
+from StringIO import StringIO
+import os.path
+from string import strip
+from base64 import b64encode
+from sys import stderr
+from util import *
+from atomutil import *
+from jsonutil import *
+
+# JSON request id
+id = 1
+
+# Make a callable HTTP client
+class client:
+ def __init__(self, url):
+ self.url = urlparse(url)
+
+ def __call__(self, func, *args):
+
+ # Connect to the configured URL
+ print >> stderr, "Client POST", self.url.geturl()
+ c, headers = connect(self.url)
+
+ # POST a JSON-RPC request
+ global id
+ req = StringIO()
+ writeStrings(jsonRequest(id, func, args), req)
+ id = id + 1
+ headers["Content-type"] = "application/json-rpc"
+ c.request("POST", self.url.path, req.getvalue(), headers)
+ res = c.getresponse()
+ print >> stderr, "Client status", res.status
+ if res.status != 200:
+ return None
+ return jsonResultValue((res.read(),))
+
+ def __getattr__(self, name):
+ if name[0] == '_':
+ raise AttributeError()
+ if name == "eval":
+ return self
+ l = lambda *args: self.__call__(name, *args)
+ self.__dict__[name] = l
+ return l
+
+ def __repr__(self):
+ return repr((self.url,))
+
+def mkclient(url):
+ return client(url)
+
+# Connect to a URL, return a connection and any authorization headers
+def connect(url):
+ if url.scheme == "https":
+
+ # With HTTPS, use a cerficate or HTTP basic authentication
+ if os.path.exists("server.key"):
+ c = HTTPSConnection(url.hostname, 443 if url.port == None else url.port, "server.key", "server.crt")
+ return c, {}
+ else:
+ c = HTTPSConnection(url.hostname, 443 if url.port == None else url.port)
+
+ # For HTTP basic authentication the user and password are
+ # provided by htpasswd.py
+ import htpasswd
+ auth = 'Basic ' + b64encode(htpasswd.user + ':' + htpasswd.passwd)
+ return c, {"Authorization": auth}
+ else:
+ c = HTTPConnection(url.hostname, 80 if url.port == None else url.port)
+ return c, {}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/json-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/json-test.py
new file mode 100755
index 0000000000..2f2a755bff
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/json-test.py
@@ -0,0 +1,59 @@
+#!/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 JSON data conversion functions
+
+import unittest
+from elemutil import *
+from jsonutil import *
+
+def testJSON():
+ ad = ((attribute, "'city", "san francisco"), (attribute, "'state", "ca"))
+ ac = ((element, "'id", "1234"), (attribute, "'balance", 1000))
+ cr = ((attribute, "'name", "jdoe"), cons(element, cons("'address", ad)), cons(element, cons("'account", ac)))
+ c = (cons(element, cons("'customer", cr)),)
+ s = writeJSON(c);
+ assert car(s) == "{\"customer\":{\"account\":{\"@balance\":1000,\"id\":\"1234\"},\"@name\":\"jdoe\",\"address\":{\"@city\":\"san francisco\",\"@state\":\"ca\"}}}"
+
+ phones = ("408-1234", "650-1234")
+ l = ((element, "'phones", phones), (element, "'lastName", "test\ttab"), (attribute, "'firstName", "test1"))
+ s2 = writeJSON(l);
+ assert car(s2) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"@firstName\":\"test1\",\"lastName\":\"test\\ttab\"}"
+
+ r = readJSON(s2)
+ assert r == ((element, "'lastName", "test\ttab"), (attribute, "'firstName", "test1"), (element, "'phones", phones))
+ w = writeJSON(r)
+ assert car(w) == "{\"lastName\":\"test\\ttab\",\"@firstName\":\"test1\",\"phones\":[\"408-1234\",\"650-1234\"]}"
+
+ l4 = (("'ns1:echoString", ("'@xmlns:ns1", "http://ws.apache.org/axis2/services/echo"), ("'text", "Hello World!")),)
+ s4 = writeJSON(valuesToElements(l4))
+ assert car(s4) == "{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}"
+
+ r4 = elementsToValues(readJSON(s4))
+ assert r4 == (("'ns1:echoString", ("'text", 'Hello World!'), ("'@xmlns:ns1", 'http://ws.apache.org/axis2/services/echo')),)
+ return True
+
+def testJSONRPC():
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testJSON()
+ testJSONRPC()
+ print "OK"
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/jsonutil.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/jsonutil.py
new file mode 100644
index 0000000000..ad8f5fcc6b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/jsonutil.py
@@ -0,0 +1,152 @@
+# 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.
+
+# JSON data conversion functions
+
+try:
+ import json
+except:
+ from django.utils import simplejson as json
+
+from StringIO import StringIO
+from util import *
+from elemutil import *
+
+# Return true if a list represents a JS array
+def isJSArray(l):
+ if isNil(l):
+ return True
+ v = car(l)
+ if isSymbol(v):
+ return False
+ if isList(v):
+ if not isNil(v) and isSymbol(car(v)):
+ return False
+ return True
+
+# Converts JSON properties to values
+def jsPropertiesToValues(propertiesSoFar, o, i):
+ if isNil(i):
+ return propertiesSoFar
+ p = car(i)
+ jsv = o[p]
+ v = jsValToValue(jsv)
+
+ if isinstance(p, basestring):
+ n = str(p)
+ if n[0:1] == "@":
+ return jsPropertiesToValues(cons((attribute, "'" + n[1:], v), propertiesSoFar), o, cdr(i))
+ if isList(v) and not isJSArray(v):
+ return jsPropertiesToValues(cons(cons(element, cons("'" + n, v)), propertiesSoFar), o, cdr(i))
+ return jsPropertiesToValues(cons((element, "'" + n, v), propertiesSoFar), o, cdr(i))
+ return jsPropertiesToValues(cons(v, propertiesSoFar), o, cdr(i))
+
+# Converts a JSON val to a value
+def jsValToValue(jsv):
+ if isinstance(jsv, dict):
+ return jsPropertiesToValues((), jsv, tuple(jsv.keys()))
+ if isList(jsv):
+ return jsPropertiesToValues((), jsv, tuple(reversed(range(0, len(jsv)))))
+ if isinstance(jsv, basestring):
+ return str(jsv)
+ return jsv
+
+# Return true if a list of strings contains a JSON document
+def isJSON(l):
+ if isNil(l):
+ return False
+ s = car(l)[0:1]
+ return s == "[" or s == "{"
+
+# Convert a list of strings representing a JSON document to a list of values
+def readJSON(l):
+ s = StringIO()
+ writeStrings(l, s)
+ val = json.loads(s.getvalue())
+ return jsValToValue(val)
+
+# Convert a list of values to JSON array elements
+def valuesToJSElements(a, l, i):
+ if isNil(l):
+ return a
+ pv = valueToJSVal(car(l))
+ a[i] = pv
+ return valuesToJSElements(a, cdr(l), i + 1)
+
+# Convert a value to a JSON value
+def valueToJSVal(v):
+ if not isList(v):
+ return v
+ if isJSArray(v):
+ return valuesToJSElements(list(range(0, len(v))), v, 0)
+ return valuesToJSProperties({}, v)
+
+# Convert a list of values to JSON properties
+def valuesToJSProperties(o, l):
+ if isNil(l):
+ return o
+ token = car(l)
+ if isTaggedList(token, attribute):
+ pv = valueToJSVal(attributeValue(token))
+ o["@" + attributeName(token)[1:]] = pv
+ elif isTaggedList(token, element):
+ if elementHasValue(token):
+ pv = valueToJSVal(elementValue(token))
+ o[elementName(token)[1:]] = pv
+ else:
+ child = {}
+ o[elementName(token)[1:]] = child
+ valuesToJSProperties(child, elementChildren(token))
+ return valuesToJSProperties(o, cdr(l))
+
+# Convert a list of values to a list of strings representing a JSON document
+def writeJSON(l):
+ if isJSArray(l):
+ jsv = valuesToJSElements(list(range(0, len(l))), l, 0)
+ else:
+ jsv = valuesToJSProperties({}, l)
+ s = json.dumps(jsv, separators=(',',':'))
+ return (s,)
+
+# Convert a list + params to a JSON-RPC request
+def jsonRequest(id, func, params):
+ r = (("'id", id), ("'method", func), ("'params", params))
+ return writeJSON(valuesToElements(r))
+
+# Convert a value to a JSON-RPC result
+def jsonResult(id, val):
+ return writeJSON(valuesToElements((("'id", id), ("'result", val))))
+
+# Convert a JSON-RPC result to a value
+def jsonResultValue(s):
+ jsres = readJSON(s)
+ res = elementsToValues(jsres)
+ val = cadr(assoc("'result", res))
+ if isList(val) and not isJSArray(val):
+ return (val,)
+ return val
+
+# Return a portable function name from a JSON-RPC function name
+def funcName(f):
+ if f.startswith("."):
+ return f[1:]
+ if f.startswith("system."):
+ return f[7:]
+ if f.startswith("Service."):
+ return f[8:]
+ return f
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/rss-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/rss-test.py
new file mode 100755
index 0000000000..e8a094b7d8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/rss-test.py
@@ -0,0 +1,170 @@
+#!/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 RSS data conversion functions
+
+import unittest
+from elemutil import *
+from rssutil import *
+
+itemEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<item>" \
+ "<title>fruit</title>" \
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>" \
+ "<description>" \
+ "<item>" \
+ "<name>Apple</name><price>$2.99</price>" \
+ "</item>" \
+ "</description>" \
+ "</item>\n"
+
+textEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<item>" \
+ "<title>fruit</title>" \
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>" \
+ "<description>" \
+ "Apple" \
+ "</description>" \
+ "</item>\n"
+
+incompleteEntry = \
+ "<item>" \
+ "<title>fruit</title><description>" \
+ "<fruit xmlns=\"http://services/\">" \
+ "<name xmlns=\"\">Orange</name>" \
+ "<price xmlns=\"\">3.55</price>" \
+ "</fruit>" \
+ "</description>" \
+ "</item>"
+
+completedEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<item>" \
+ "<title>fruit</title>" \
+ "<link />" \
+ "<description>" \
+ "<fruit xmlns=\"http://services/\">" \
+ "<name xmlns=\"\">Orange</name>" \
+ "<price xmlns=\"\">3.55</price>" \
+ "</fruit>" \
+ "</description>" \
+ "</item>\n"
+
+def testEntry():
+ i = (element, "'item", (element, "'name", "Apple"), (element, "'price", "$2.99"))
+ a = ("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b", i)
+ s = writeRSSEntry(a);
+ assert car(s) == itemEntry
+
+ a2 = readRSSEntry((itemEntry,))
+ s2 = writeRSSEntry(a2)
+ assert car(s2) == itemEntry
+
+ a3 = readRSSEntry((textEntry,))
+ s3 = writeRSSEntry(a3)
+ assert car(s3) == textEntry
+
+ a4 = readRSSEntry((incompleteEntry,))
+ s4 = writeRSSEntry(a4)
+ assert car(s4) == completedEntry
+ return True
+
+emptyFeed = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<rss version=\"2.0\">" \
+ "<channel>" \
+ "<title>Feed</title>" \
+ "<link>1234</link>" \
+ "<description>Feed</description>" \
+ "</channel>" \
+ "</rss>\n"
+
+itemFeed = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<rss version=\"2.0\">" \
+ "<channel>" \
+ "<title>Feed</title>" \
+ "<link>1234</link>" \
+ "<description>Feed</description>" \
+ "<item>" \
+ "<title>fruit</title>" \
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>" \
+ "<description>" \
+ "<item>" \
+ "<name>Apple</name><price>$2.99</price>" \
+ "</item>" \
+ "</description>" \
+ "</item>" \
+ "<item>" \
+ "<title>fruit</title>" \
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</link>" \
+ "<description>" \
+ "<item>" \
+ "<name>Orange</name><price>$3.55</price>" \
+ "</item>" \
+ "</description>" \
+ "</item>" \
+ "</channel>" \
+ "</rss>\n"
+
+def testFeed():
+ s = writeRSSFeed(("Feed", "1234"))
+ assert car(s) == emptyFeed
+
+ a2 = readRSSFeed((emptyFeed,))
+ s2 = writeRSSFeed(a2)
+ assert car(s2) == emptyFeed
+
+ i3 = (("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ (element, "'item", (element, "'name", "Apple"), (element, "'price", "$2.99"))),
+ ("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ (element, "'item", (element, "'name", "Orange"), (element, "'price", "$3.55"))))
+ a3 = cons("Feed", cons("1234", i3))
+ s3 = writeRSSFeed(a3)
+ assert car(s3) == itemFeed
+
+ i4 = (("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ valueToElement(("'item", ("'name", "Apple"), ("'price", "$2.99")))),
+ ("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ valueToElement(("'item", ("'name", "Orange"), ("'price", "$3.55")))))
+ a4 = cons("Feed", cons("1234", i4))
+ s4 = writeRSSFeed(a4)
+ assert car(s4) == itemFeed
+
+ a5 = readRSSFeed((itemFeed,));
+ s5 = writeRSSFeed(a5);
+ assert car(s5) == itemFeed
+
+ i6 = (("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ (("'name", "Apple"), ("'price", "$2.99"))),
+ ("fruit", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ (("'name", "Orange"), ("'price", "$3.55"))))
+ a6 = cons("Feed", cons("1234", i6))
+ s6 = writeRSSFeed(feedValuesToElements(a6))
+ assert car(s6) == itemFeed
+
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testEntry()
+ testFeed()
+ print "OK"
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/rssutil.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/rssutil.py
new file mode 100644
index 0000000000..984d71b690
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/rssutil.py
@@ -0,0 +1,117 @@
+# 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.
+
+# RSS data conversion functions
+
+from util import *
+from elemutil import *
+from xmlutil import *
+
+# Convert a list of elements to a list of values representing an RSS entry
+def entryElementsToValues(e):
+ lt = filter(selector((element, "'title")), e)
+ t = "" if isNil(lt) else elementValue(car(lt))
+ li = filter(selector((element, "'link")), e)
+ i = "" if isNil(li) else elementValue(car(li))
+ lc = filter(selector((element, "'description")), e)
+ return (t, i, elementValue(car(lc)))
+
+# Convert a list of elements to a list of values representing RSS entries
+def entriesElementsToValues(e):
+ if isNil(e):
+ return e
+ return cons(entryElementsToValues(car(e)), entriesElementsToValues(cdr(e)))
+
+# Convert a list of strings to a list of values representing an RSS entry
+def readRSSEntry(l):
+ e = readXML(l)
+ if isNil(e):
+ return ()
+ return entryElementsToValues(car(e))
+
+# Convert a list of values representy an RSS entry to a value
+def entryValue(e):
+ v = elementsToValues((caddr(e),))
+ return cons(car(e), (cadr(e), cdr(car(v))))
+
+# Return true if a list of strings represents an RSS feed
+def isRSSFeed(l):
+ if not isXML(l):
+ return False
+ return contains(car(l), "<rss")
+
+# Convert a list of strings to a list of values representing an RSS feed
+def readRSSFeed(l):
+ f = readXML(l)
+ if isNil(f):
+ return ()
+ c = filter(selector((element, "'channel")), car(f))
+ t = filter(selector((element, "'title")), car(c))
+ i = filter(selector((element, "'link")), car(c))
+ e = filter(selector((element, "'item")), car(c))
+ if isNil(e):
+ return (elementValue(car(t)), elementValue(car(i)))
+ return cons(elementValue(car(t)), cons(elementValue(car(i)), entriesElementsToValues(e)))
+
+# Convert an RSS feed containing elements to an RSS feed containing values
+def feedValuesLoop(e):
+ if (isNil(e)):
+ return e
+ return cons(entryValue(car(e)), feedValuesLoop(cdr(e)))
+
+def feedValues(e):
+ return cons(car(e), cons(cadr(e), feedValuesLoop(cddr(e))))
+
+# Convert a list of values representy an RSS entry to a list of elements
+def entryElement(l):
+ return (element, "'item",
+ (element, "'title", car(l)),
+ (element, "'link", cadr(l)),
+ (element, "'description", caddr(l)))
+
+# Convert a list of values representing RSS entries to a list of elements
+def entriesElements(l):
+ if isNil(l):
+ return l
+ return cons(entryElement(car(l)), entriesElements(cdr(l)))
+
+# Convert a list of values representing an RSS entry to an RSS entry
+def writeRSSEntry(l):
+ return writeXML((entryElement(l),), True)
+
+# Convert a list of values representing an RSS feed to an RSS feed
+def writeRSSFeed(l):
+ c = ((element, "'title", car(l)),
+ (element, "'link", cadr(l)),
+ (element, "'description", car(l)))
+ ce = c if isNil(cddr(l)) else append(c, entriesElements(cddr(l)))
+ fe = (element, "'rss", (attribute, "'version", "2.0"), append((element, "'channel"), ce))
+ return writeXML((fe,), True)
+
+# Convert an RSS entry containing a value to an RSS entry containing an item element
+def entryValuesToElements(v):
+ return cons(car(v), cons(cadr(v), valuesToElements((cons("'item", caddr(v)),))))
+
+# Convert an RSS feed containing values to an RSS feed containing elements
+def feedValuesToElementsLoop(v):
+ if isNil(v):
+ return v
+ return cons(entryValuesToElements(car(v)), feedValuesToElementsLoop(cdr(v)))
+
+def feedValuesToElements(v):
+ return cons(car(v), cons(cadr(v), feedValuesToElementsLoop(cddr(v))))
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py
new file mode 100644
index 0000000000..97c2f7dd69
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py
@@ -0,0 +1,272 @@
+# 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.
+
+# SCDL parsing functions
+
+from xml.etree.cElementTree import iterparse
+from sys import stderr
+from os import environ
+from util import *
+from httputil import *
+
+# Element tree utility functions, used to parse SCDL documents
+def parse(file):
+ return map(lambda x: x, iterparse(file, events=("start", "end")))
+
+def evt(e):
+ return car(e)
+
+def elt(e):
+ return cadr(e)
+
+def att(e):
+ return elt(e).attrib
+
+def text(e):
+ return elt(e).text
+
+def match(e, ev, tag):
+ return evt(e) == ev and elt(e).tag.find("}" + tag) != -1
+
+# Make a callable component
+class component:
+ def __init__(self, name, impl, svcs, refs, props):
+ self.name = name
+ self.impl = impl
+ self.mod = None
+ self.svcs = svcs
+ self.refs = refs
+ self.props = props
+ self.proxies = ()
+
+ def __call__(self, func, *args):
+ return self.mod.__getattribute__(func)(*(args + self.proxies))
+
+ def __getattr__(self, name):
+ if name[0] == '_':
+ raise AttributeError()
+ if name == "eval":
+ return self
+ l = lambda *args: self.__call__(name, *args)
+ self.__dict__[name] = l
+ return l
+
+ def __repr__(self):
+ return repr((self.name, self.impl, self.mod, self.svcs, self.refs, self.props, self.proxies))
+
+def mkcomponent(name, impl, svcs, refs, props):
+ return component(name, impl, svcs, refs, props)
+
+# Return the Python module name of a component implementation
+def implementation(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ""
+ if match(car(e), "start", "implementation.python") == False:
+ return implementation(cdr(e))
+ if "script" in att(car(e)):
+ s = att(car(e))["script"]
+ return s[0:len(s) - 3]
+ return None
+
+# Return the URI of a binding under a SCDL service or reference element
+def binding(e):
+ if len(e) == 0 or match(car(e), "end", "reference") == True or match(car(e), "end", "service") == True:
+ return ()
+ if match(car(e), "start", "binding.") == False:
+ return binding(cdr(e))
+ return att(car(e))["uri"]
+
+# Return the list of references under a SCDL component element
+def references(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ()
+ if match(car(e), "start", "reference") == False:
+ return references(cdr(e))
+ if "target" in att(car(e)):
+ return cons((att(car(e))["name"], car(tokens(att(car(e))["target"]))), references(cdr(e)))
+ return cons((att(car(e))["name"], binding(e)), references(cdr(e)))
+
+# Return the list of properties under a SCDL component element
+def properties(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ()
+ if match(car(e), "start", "property") == False:
+ return properties(cdr(e))
+ return cons((att(car(e))["name"], text(car(e))), properties(cdr(e)))
+
+# Return the list of services under a SCDL component element
+def services(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ()
+ if match(car(e), "start", "service") == False:
+ return services(cdr(e))
+ return cons(tokens(binding(e)), services(cdr(e)))
+
+# Return the name attribute of a SCDL element
+def name(e):
+ return att(car(e))["name"]
+
+# Return the list of components under a SCDL composite element
+def components(e):
+ if len(e) == 0:
+ return ()
+ if match(car(e), "start", "component") == False:
+ return components(cdr(e))
+ n = name(e)
+ return cons(mkcomponent(n, implementation(e), services(e), references(e), properties(e)), components(cdr(e)))
+
+# Find a component with a given name
+def nameToComponent(name, comps):
+ if comps == ():
+ return None
+ if car(comps).name == name:
+ return car(comps)
+ return nameToComponent(name, cdr(comps))
+
+# Find the URI matching a given URI in a list of service URIs
+def matchingURI(u, svcs):
+ if svcs == ():
+ return None
+ if car(svcs) == u[0:len(car(svcs))]:
+ return car(svcs)
+ return matchingURI(u, cdr(svcs))
+
+# Return the (service URI, component) pair matching a given URI
+def uriToComponent(u, comps):
+ if car(u) == "components":
+ return componentURIToComponent(u, comps)
+ if car(u) == "references":
+ return referenceURIToComponent(u, comps)
+ return serviceURIToComponent(u, comps)
+
+def serviceURIToComponent(u, comps):
+ if comps == ():
+ return (None, None)
+ m = matchingURI(u, car(comps).svcs)
+ if m != None:
+ return (m, car(comps))
+ return serviceURIToComponent(u, cdr(comps))
+
+def componentURIToComponent(u, comps):
+ comp = nameToComponent(cadr(u), comps)
+ if comps == None:
+ return (None, None)
+ return (u[0:2], comp)
+
+def referenceURIToComponent(u, comps):
+ sc = nameToComponent(cadr(u), comps)
+ if sc == None:
+ return (None, None)
+
+ def referenceToComponent(r, refs):
+ if refs == ():
+ return None
+ if r == car(car(refs)):
+ return cadr(car(refs))
+ return referenceToComponent(r, cdr(refs))
+
+ tn = referenceToComponent(caddr(u), sc.refs)
+ if tn == None:
+ return (None, None)
+ tc = nameToComponent(tn, comps)
+ if tc == None:
+ return (None, None)
+ return (u[0:3], tc)
+
+# Evaluate a reference, return a proxy to the resolved component or an
+# HTTP client configured with the reference target uri
+def evalReference(r, comps):
+ t = cadr(r)
+ if t.startswith("http://") or t.startswith("https://"):
+ return mkclient(t)
+ return nameToComponent(t, comps)
+
+# Make a callable property
+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 mkproperty(name, l):
+ return property(name, l)
+
+# Evaluate a property, return a lambda function returning the property
+# value. The host, user, realm, nickname and email properties are configured
+# with the values from the HTTP request, if any.
+def evalProperty(p):
+ if car(p) == "host":
+ return mkproperty(car(p), lambda: hostProperty(cadr(p), environ))
+ if car(p) == "user":
+ return mkproperty(car(p), lambda: userProperty(cadr(p)))
+ if car(p) == "realm":
+ return mkproperty(car(p), lambda: hostProperty(cadr(p), environ))
+ if car(p) == "nickname":
+ return mkproperty(car(p), lambda: nicknameProperty(cadr(p)))
+ if car(p) == "email":
+ return mkproperty(car(p), lambda: emailProperty(cadr(p)))
+ return mkproperty(car(p), lambda: cadr(p))
+
+def currentUser():
+ try:
+ from google.appengine.api import users
+ return users.get_current_user()
+ except:
+ return None
+
+def userProperty(v):
+ user = currentUser()
+ return user.federated_identity() if user else v
+
+def nicknameProperty(v):
+ user = currentUser()
+ return user.nickname() if user else v
+
+def hostProperty(v, e):
+ return e.get("HTTP_HOST", e.get("SERVER_NAME", v)).split(":")[0]
+
+def emailProperty(v):
+ user = currentUser()
+ return user.email() if user else v
+
+# Evaluate a component, resolve its implementation, references and
+# properties
+def evalComponent(comp, comps):
+ comp.mod = __import__(comp.impl)
+
+ # Make a list of proxy lambda functions for the component references and properties
+ # A reference proxy is the callable lambda function of the component wired to the reference
+ # A property proxy is a lambda function that returns the value of the property
+ print >> stderr, "evalComponent", comp.impl, comp.svcs, comp.refs, comp.props
+ comp.proxies = tuple(map(lambda r: evalReference(r, comps), comp.refs)) + tuple(map(lambda p: evalProperty(p), comp.props))
+
+ return comp
+
+# Evaluate a list of components
+def evalComponents(comps):
+ return tuple(map(lambda c: evalComponent(c, comps), comps))
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test b/sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test
new file mode 100755
index 0000000000..9bd862c53a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test
@@ -0,0 +1,30 @@
+#!/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
+# 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.
+
+# Setup
+./wsgi-start target 8090 2>/dev/null
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./wsgi-stop target 8090
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test.py
new file mode 100644
index 0000000000..28f88efefc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/server-test.py
@@ -0,0 +1,44 @@
+# 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.
+
+# JSON-RPC test case
+
+def echo(x):
+ return x
+
+# ATOMPub test case
+
+def get(id):
+ if id == ("index.html",):
+ return ("text/plain", ("It works!",))
+ if id == ():
+ return ("Sample Feed", "123456789",
+ ("Item", "111", (("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99))),
+ ("Item", "222", (("'name", "Orange"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 3.55))),
+ ("Item", "333", (("'name", "Pear"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 1.55))))
+
+ entry = (("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99))
+ return ("Item", id[0], entry)
+
+def post(collection, item):
+ return ("123456789",)
+
+def put(id, item):
+ return True
+
+def delete(id):
+ return True
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/stream-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/stream-test.py
new file mode 100755
index 0000000000..2cff038f1e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/stream-test.py
@@ -0,0 +1,47 @@
+#!/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 stream functions
+
+import unittest
+from util import *
+
+def testStream():
+
+ s = cons_stream(0, lambda: cons_stream(1, lambda: cons(2, ())))
+ assert len(s) == 3
+ assert car(s) == 0
+ assert cadr(s) == 1
+ assert len(cdr(s)) == 2
+ assert s[0] == 0
+ assert s[1] == 1
+ assert s[2] == 2
+ assert s[:1] == (0, 1)
+ assert s[:5] == (0, 1, 2)
+ assert s[2:5] == (2,)
+ assert s[4:5] == ()
+ assert s[0:] == (0, 1, 2)
+ assert (0, 1, 2) == s[0:]
+
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testStream()
+ print "OK"
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/util-test b/sandbox/sebastien/cpp/apr-2/modules/wsgi/util-test
new file mode 100755
index 0000000000..aa8725a200
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/util-test
@@ -0,0 +1,43 @@
+#!/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
+# 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.
+
+# Run Python util test cases
+here=`readlink -f $0`; here=`dirname $here`
+python_prefix=`cat $here/../python/python.prefix`
+
+$python_prefix/bin/python stream-test.py
+rc=$?
+if [ "$rc" = "0" ]; then
+ $python_prefix/bin/python xml-test.py
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $python_prefix/bin/python atom-test.py
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $python_prefix/bin/python rss-test.py
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $python_prefix/bin/python json-test.py
+ rc=$?
+fi
+
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/util.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/util.py
new file mode 100644
index 0000000000..560101e32d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/util.py
@@ -0,0 +1,145 @@
+# 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.
+
+# Simple utility functions
+from sys import maxint
+
+# Scheme-like lists
+def cons(a, b):
+ return (a,) + b
+
+def car(l):
+ return l[0]
+
+def first(l):
+ return car(l)
+
+def cdr(l):
+ return l[1:]
+
+def rest(l):
+ return cdr(l)
+
+def cadr(l):
+ return car(cdr(l))
+
+def cddr(l):
+ return cdr(cdr(l))
+
+def caddr(l):
+ return car(cddr(l))
+
+def append(a, b):
+ return a + b
+
+def reverse(l):
+ r = list(l)
+ r.reverse()
+ return tuple(r)
+
+def isNil(l):
+ if isinstance(l, streampair):
+ return l.isNil()
+ return l == ()
+
+def isSymbol(v):
+ return isinstance(v, basestring) and v[0:1] == "'"
+
+def isList(v):
+ if getattr(v, '__iter__', False) == False:
+ return False
+ if isinstance(v, basestring) or isinstance(v, dict):
+ return False
+ return True
+
+def isTaggedList(v, t):
+ return isList(v) and not isNil(v) and car(v) == t
+
+
+# Scheme-like streams
+class streampair(object):
+ def __init__(self, car, cdr):
+ self.car = car
+ self.cdr = cdr
+
+ def __repr__(self):
+ return repr(self[0:len(self)])
+
+ def isNil(self):
+ return self.cdr == ()
+
+ def __len__(self):
+ if self.cdr == ():
+ return 0
+ return 1 + len(self.cdr())
+
+ def __getitem__(self, i):
+ if i == 0:
+ return self.car
+ return self.cdr()[i - 1]
+
+ def __getslice__(self, i, j):
+ if isNil(self):
+ return ()
+ if i > 0:
+ if j == maxint:
+ return self.cdr()[i - 1: j]
+ return self.cdr()[i - 1: j - 1]
+ if j == maxint:
+ return self
+ if j == 0:
+ return (self.car,)
+ return (self.car,) + self.cdr()[: j - 1]
+
+ def __eq__(self, other):
+ sl = len(self)
+ ol = len(other)
+ if sl != ol:
+ return False
+ return self[0: sl] == other[0: ol]
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+def cons_stream(car, cdr):
+ return streampair(car, cdr)
+
+
+# Scheme-like associations
+def assoc(k, l):
+ if l == ():
+ return None
+
+ if k == car(car(l)):
+ return car(l)
+ return assoc(k, cdr(l))
+
+# Currying / partial function application
+def curry(f, *args):
+ return lambda *a: f(*(args + a))
+
+# Split a path into a list of segments
+def tokens(path):
+ return tuple(filter(lambda s: len(s) != 0, path.split("/")))
+
+# Write a list of strings to a stream
+def writeStrings(l, os):
+ if l == ():
+ return os
+ os.write(car(l))
+ return writeStrings(cdr(l), os)
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/wiring-test b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wiring-test
new file mode 100755
index 0000000000..f3c1bbb840
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wiring-test
@@ -0,0 +1,75 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+uri=$1
+if [ "$uri" = "" ]; then
+ uri="http://localhost:8090"
+fi
+
+# Setup
+mkdir -p tmp
+./wsgi-start target 8090 2>/dev/null
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl $uri/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl $uri/client/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/test/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl $uri/client/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/test/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl $uri/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl $uri/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl $uri/client/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl $uri/client/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/test/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt htdocs/test/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+./wsgi-stop target 8090
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-start b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-start
new file mode 100755
index 0000000000..d020f3da14
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-start
@@ -0,0 +1,28 @@
+#!/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
+# 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.
+
+# Start WSGI server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+port=$2
+
+python_prefix=`cat $here/../python/python.prefix`
+cd $root
+$python_prefix/bin/python composite.py $port &
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-stop b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-stop
new file mode 100755
index 0000000000..7e12967adb
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-stop
@@ -0,0 +1,28 @@
+#!/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
+# 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.
+
+# Stop WSGI server
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+port=$2
+
+python_prefix=`cat $here/../python/python.prefix`
+py="$python_prefix/bin/python composite.py $port"
+
+kill `ps -ef | grep -v grep | grep "${py}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-test b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-test
new file mode 100755
index 0000000000..369ca5a677
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/wsgi-test
@@ -0,0 +1,71 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../http/curl.prefix`
+
+# Setup
+mkdir -p tmp
+./wsgi-start target 8090 2>/dev/null
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/wsgi/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/test/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/wsgi/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/test/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/wsgi/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/wsgi/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/test/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/wsgi/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/wsgi/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/test/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt htdocs/test/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+./wsgi-stop target 8090
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/xml-test.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/xml-test.py
new file mode 100755
index 0000000000..f60322bdc1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/xml-test.py
@@ -0,0 +1,74 @@
+#!/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 XML handling functions
+
+import unittest
+from elemutil import *
+from xmlutil import *
+
+customerXML = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<customer>" \
+ "<name>jdoe</name>" \
+ "<address><city>san francisco</city><state>ca</state></address>" \
+ "<account><id>1234</id><balance>1000</balance></account>" \
+ "<account><id>6789</id><balance>2000</balance></account>" \
+ "<account><id>4567</id><balance>3000</balance></account>" \
+ "</customer>\n"
+
+def testElements():
+ ad = (("'city", "san francisco"), ("'state", "ca"))
+ ac1 = (("'id", "1234"), ("'balance", 1000))
+ ac2 = (("'id", "6789"), ("'balance", 2000))
+ ac3 = (("'id", "4567"), ("'balance", 3000))
+ c = (("'customer", ("'name", "jdoe"), cons("'address", ad), ("'account", (ac1, ac2, ac3))),)
+ e = valuesToElements(c)
+ v = elementsToValues(e)
+ assert v == c
+ s = writeXML(e, True)
+ assert car(s) == customerXML
+
+ c2 = (("'customer", ("'name", "jdoe"), cons("'address", ad), cons("'account", ac1), cons("'account", ac2), cons("'account", ac3)),)
+ e2 = valuesToElements(c2);
+ v2 = elementsToValues(e2);
+ s2 = writeXML(e2, True)
+ assert car(s2) == customerXML
+
+ c3 = readXML((customerXML,))
+ v3 = elementsToValues(c3)
+ e3 = valuesToElements(v3)
+ s3 = writeXML(e3, True)
+ assert car(s3) == customerXML
+ return True
+
+def testValues():
+ l = (("'ns1:echoString", ("'@xmlns:ns1", "http://ws.apache.org/axis2/services/echo"), ("'text", "Hello World!")),)
+ e = valuesToElements(l)
+ lx = writeXML(e, True)
+ x = readXML(lx)
+ v = elementsToValues(x)
+ assert v == l
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testElements()
+ testValues()
+ print "OK"
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/xmlutil.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/xmlutil.py
new file mode 100644
index 0000000000..35ccb7f803
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/xmlutil.py
@@ -0,0 +1,122 @@
+# 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.
+
+# XML handling functions
+
+from StringIO import StringIO
+from xml.parsers import expat
+import xml.etree.ElementTree as et
+from util import *
+from elemutil import *
+
+# Read a list of XML attributes
+def readAttributes(a):
+ if a == ():
+ return a
+ return cons((attribute, "'" + car(car(a)), cadr(car(a))), readAttributes(cdr(a)))
+
+# Read an XML element
+def readElement(e):
+ l = (element, "'" + e.tag) + readAttributes(tuple(e.items())) + readElements(tuple(e.getchildren()))
+ if e.text == None:
+ return l
+ return l + (e.text,)
+
+# Read a list of XML elements
+def readElements(l):
+ if l == ():
+ return l
+ return cons(readElement(car(l)), readElements(cdr(l)))
+
+# Return true if a list of strings represents an XML document
+def isXML(l):
+ if isNil(l):
+ return False
+ if car(l)[0:5] != "<?xml":
+ return False
+ return True
+
+# Parse a list of strings representing an XML document
+class NamespaceParser(et.XMLTreeBuilder):
+ def __init__(self):
+ et.XMLTreeBuilder.__init__(self)
+ self._parser = parser = expat.ParserCreate(None)
+ parser.DefaultHandlerExpand = self._default
+ parser.StartElementHandler = self._start
+ parser.EndElementHandler = self._end
+ parser.CharacterDataHandler = self._data
+ try:
+ parser.buffer_text = 1
+ except AttributeError:
+ pass
+ try:
+ parser.ordered_attributes = 1
+ parser.specified_attributes = 1
+ parser.StartElementHandler = self._start_list
+ except AttributeError:
+ pass
+
+def parseXML(l):
+ s = StringIO()
+ writeStrings(l, s)
+ parser = NamespaceParser()
+ parser.feed(s.getvalue())
+ return parser.close()
+
+# Read a list of values from a list of strings representing an XML document
+def readXML(l):
+ e = parseXML(l)
+ return (readElement(e),)
+
+# Write a list of XML element and attribute tokens
+def expandElementValues(n, l):
+ if isNil(l):
+ return l
+ return cons(cons(element, cons(n, car(l))), expandElementValues(n, cdr(l)))
+
+def writeList(l, xml):
+ if isNil(l):
+ return xml
+ token = car(l)
+ if isTaggedList(token, attribute):
+ xml.attrib[attributeName(token)[1:]] = str(attributeValue(token))
+ elif isTaggedList(token, element):
+ if elementHasValue(token):
+ v = elementValue(token)
+ if isList(v):
+ e = expandElementValues(elementName(token), v)
+ writeList(e, xml)
+ else:
+ child = et.Element(elementName(token)[1:])
+ writeList(elementChildren(token), child)
+ xml.append(child)
+ else:
+ child = et.Element(elementName(token)[1:])
+ writeList(elementChildren(token), child)
+ xml.append(child)
+ else:
+ xml.text = str(token)
+ writeList(cdr(l), xml)
+ return xml
+
+# Convert a list of values to a list of strings representing an XML document
+def writeXML(l, xmlTag):
+ e = writeList(l, [])
+ if not xmlTag:
+ return (et.tostring(car(e)),)
+ return (et.tostring(car(e), "UTF-8") + "\n",)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/Makefile.am
new file mode 100644
index 0000000000..bd161fec30
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/Makefile.am
@@ -0,0 +1,22 @@
+# 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.
+
+SUBDIRS = store-scheme store-cpp store-python store-java store-gae store-sql store-nosql store-vhost store-cluster relay-python
+
+sample_DATA = README
+sampledir=$(prefix)/samples
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/README b/sandbox/sebastien/cpp/apr-2/samples/README
new file mode 100644
index 0000000000..818a2faaf8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/README
@@ -0,0 +1,3 @@
+Apache Tuscany SCA Samples
+==========================
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/loan-python/Makefile.am
new file mode 100644
index 0000000000..0d0027ce6b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/Makefile.am
@@ -0,0 +1,28 @@
+# 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.
+
+if WANT_PYTHON
+
+dist_sample_SCRIPTS = start stop
+sampledir = $(prefix)/samples/loan-python
+
+nobase_dist_sample_DATA = loan.py loan-approval.py util.py loan.composite htdocs/*.html
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/loan-python/htdocs/index.html
new file mode 100644
index 0000000000..f972af9555
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/htdocs/index.html
@@ -0,0 +1,156 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var component = new tuscany.sca.Component("Store");
+
+//@Reference
+var catalog = new tuscany.sca.Reference("catalog");
+
+//@Reference
+var shoppingCart = new tuscany.sca.Reference("shoppingCart");
+
+//@Reference
+var shoppingTotal = new tuscany.sca.Reference("shoppingTotal");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.apply("total", shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.apply("items", catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan-approval.py b/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan-approval.py
new file mode 100644
index 0000000000..3951f16eeb
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan-approval.py
@@ -0,0 +1,77 @@
+# 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.
+
+# Loan approval service implementation
+import uuid
+import sys
+from util import *
+from loan import *
+
+loansId = ("loans", "1234")
+
+# Return the list of loans
+def loans(cache):
+ l = cache("get", loansId)
+ if l is None:
+ return ()
+ return l
+
+# Post a new loan request
+def post(collection, item, cache):
+ id = str(uuid.uuid1())
+ loans = cons(cons(id, cdr(item)), loans(cache))
+ cache("put", loansId, loans)
+ return (id,)
+
+# Return the person currently processing a loan request
+def processor(l):
+ if approver(l) is not None:
+ return approver(l)
+ return assessor(l)
+
+# Return a list of loans that match a given criteria
+def get(r, cache):
+ # All the loans
+ if r == ():
+ return loans(cache)
+ # Loans that need approval
+ if car(r) == "needApproval":
+ return filter(lambda l: (amount(l) >= 10000 or risk(l) == "high") and approval(l) is None, loans(cache))
+ # Loans that need a risk assessment
+ if car(r) == "needAssessment":
+ return filter(lambda : amount(l) < 10000 and risk(l) is None, loans(cache))
+ # Loans currently under approval
+ if car(r) == "underApproval":
+ return filter(lambda l: approver(l) is not None, loans(cache))
+ # Loans currently under assessment
+ if car(r) == "underAssessment":
+ return filter(lambda l: assessor(l) is not None, loans(cache))
+ # Loan requests that are unassigned
+ if car(r) == "unassigned":
+ return filter(lambda l: processor(l) is None, loans(cache))
+ # Loan requests that are assigned and getting processed
+ if car(r) == "assigned":
+ return filter(lambda l: processor(l) == cadr(r), loans(cache))
+ # Approved loans
+ if car(r) == "approved":
+ return filter(lambda l: approval(l) == true, loans(cache))
+ # Denied loans
+ if car(r) == "denied":
+ return filter(lambda l: approval(l) == false, loans(cache))
+ # A particular loan
+ return filter(lambda l: id(l) == r, loans(cache))
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.composite b/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.composite
new file mode 100644
index 0000000000..0e64b5bf44
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.composite
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="LoanApprovalUI">
+ <t:implementation.widget/>
+ <reference name="loanApproval" target="LoanApproval"/>
+ </component>
+
+ <component name="LoanApproval">
+ <t:implementation.python script="loan-approval.py"/>
+ <service name="LoanApproval">
+ <t:binding.atom uri="loan-approval"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="Cache">
+ <implementation.cpp path="../../components/cache" library="libmemcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.py b/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.py
new file mode 100644
index 0000000000..9e345cd1f6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/loan.py
@@ -0,0 +1,45 @@
+# 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.
+
+from util import *
+
+# Loan data type
+
+def firstName(loan):
+ return assoc("'firstName", loan)
+
+def lastName(loan):
+ return assoc("'lastName", loan)
+
+def ssn(loan):
+ return assoc("'ssn", loan)
+
+def amount(loan):
+ return assoc("'amount", loan)
+
+def approver(loan):
+ return assoc("'approver", loan)
+
+def approval(loan):
+ return assoc("'approval", loan)
+
+def assessor(loan):
+ return assoc("'assessor", loan)
+
+def risk(loan):
+ return assoc("'risk", loan)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/server-test b/sandbox/sebastien/cpp/apr-2/samples/loan-python/server-test
new file mode 100755
index 0000000000..1612bc59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/start b/sandbox/sebastien/cpp/apr-2/samples/loan-python/start
new file mode 100755
index 0000000000..e7aa7d86ca
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/start
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite loan.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/stop b/sandbox/sebastien/cpp/apr-2/samples/loan-python/stop
new file mode 100755
index 0000000000..a59273b8ed
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/stop
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/loan-python/util.py b/sandbox/sebastien/cpp/apr-2/samples/loan-python/util.py
new file mode 100644
index 0000000000..560101e32d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/loan-python/util.py
@@ -0,0 +1,145 @@
+# 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.
+
+# Simple utility functions
+from sys import maxint
+
+# Scheme-like lists
+def cons(a, b):
+ return (a,) + b
+
+def car(l):
+ return l[0]
+
+def first(l):
+ return car(l)
+
+def cdr(l):
+ return l[1:]
+
+def rest(l):
+ return cdr(l)
+
+def cadr(l):
+ return car(cdr(l))
+
+def cddr(l):
+ return cdr(cdr(l))
+
+def caddr(l):
+ return car(cddr(l))
+
+def append(a, b):
+ return a + b
+
+def reverse(l):
+ r = list(l)
+ r.reverse()
+ return tuple(r)
+
+def isNil(l):
+ if isinstance(l, streampair):
+ return l.isNil()
+ return l == ()
+
+def isSymbol(v):
+ return isinstance(v, basestring) and v[0:1] == "'"
+
+def isList(v):
+ if getattr(v, '__iter__', False) == False:
+ return False
+ if isinstance(v, basestring) or isinstance(v, dict):
+ return False
+ return True
+
+def isTaggedList(v, t):
+ return isList(v) and not isNil(v) and car(v) == t
+
+
+# Scheme-like streams
+class streampair(object):
+ def __init__(self, car, cdr):
+ self.car = car
+ self.cdr = cdr
+
+ def __repr__(self):
+ return repr(self[0:len(self)])
+
+ def isNil(self):
+ return self.cdr == ()
+
+ def __len__(self):
+ if self.cdr == ():
+ return 0
+ return 1 + len(self.cdr())
+
+ def __getitem__(self, i):
+ if i == 0:
+ return self.car
+ return self.cdr()[i - 1]
+
+ def __getslice__(self, i, j):
+ if isNil(self):
+ return ()
+ if i > 0:
+ if j == maxint:
+ return self.cdr()[i - 1: j]
+ return self.cdr()[i - 1: j - 1]
+ if j == maxint:
+ return self
+ if j == 0:
+ return (self.car,)
+ return (self.car,) + self.cdr()[: j - 1]
+
+ def __eq__(self, other):
+ sl = len(self)
+ ol = len(other)
+ if sl != ol:
+ return False
+ return self[0: sl] == other[0: ol]
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+def cons_stream(car, cdr):
+ return streampair(car, cdr)
+
+
+# Scheme-like associations
+def assoc(k, l):
+ if l == ():
+ return None
+
+ if k == car(car(l)):
+ return car(l)
+ return assoc(k, cdr(l))
+
+# Currying / partial function application
+def curry(f, *args):
+ return lambda *a: f(*(args + a))
+
+# Split a path into a list of segments
+def tokens(path):
+ return tuple(filter(lambda s: len(s) != 0, path.split("/")))
+
+# Write a list of strings to a stream
+def writeStrings(l, os):
+ if l == ():
+ return os
+ os.write(car(l))
+ return writeStrings(cdr(l), os)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/relay-python/Makefile.am
new file mode 100644
index 0000000000..4e357eb330
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/Makefile.am
@@ -0,0 +1,25 @@
+# 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.
+
+if WANT_PYTHON
+
+dist_sample_SCRIPTS = start stop
+sampledir = $(prefix)/samples/relay-python
+
+nobase_dist_sample_DATA = html.py json.py xml.py rss.py relay.composite htdocs/*.html htdocs/test/*.html
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/index.html
new file mode 100644
index 0000000000..2025a5851d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/index.html
@@ -0,0 +1,31 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Relay</title>
+<body>
+
+<p><a href="/html">Sample HTML request</a></p>
+<p><a href="/jsontwit">Sample Twitter JSON request</a></p>
+<p><a href="/xmltwit">Sample Twitter XML request</a></p>
+<p><a href="/rsstwit">Sample Twitter RSS request</a></p>
+<p><a href="/jsonfb">Sample Facebook JSON request</a></p>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/test/index.html b/sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/test/index.html
new file mode 100644
index 0000000000..1bfb3e30c2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/htdocs/test/index.html
@@ -0,0 +1,21 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>It works!</h1></body></html>
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/html.py b/sandbox/sebastien/cpp/apr-2/samples/relay-python/html.py
new file mode 100644
index 0000000000..87a94a35ba
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/html.py
@@ -0,0 +1,22 @@
+# 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.
+
+# Content relay implementation
+def get(id, target):
+ #return ("text/plain", ("It works!",))
+ return target.get(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/json.py b/sandbox/sebastien/cpp/apr-2/samples/relay-python/json.py
new file mode 100644
index 0000000000..24f969d419
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/json.py
@@ -0,0 +1,24 @@
+# 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.
+
+# Relay implementation
+import uuid
+import sys
+
+def get(id, target):
+ return target.get(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/relay.composite b/sandbox/sebastien/cpp/apr-2/samples/relay-python/relay.composite
new file mode 100644
index 0000000000..2f5b92dee0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/relay.composite
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://relay"
+ name="relay">
+
+ <component name="JSONTwit">
+ <t:implementation.python script="json.py"/>
+ <service name="Relay">
+ <t:binding.http uri="jsontwit"/>
+ </service>
+ <reference name="target">
+ <t:binding.http uri="http://api.twitter.com/1/statuses/user_timeline.json?screen_name=jsdelfino"/>
+ </reference>
+ </component>
+
+ <component name="XMLTwit">
+ <t:implementation.python script="xml.py"/>
+ <service name="Relay">
+ <t:binding.http uri="xmltwit"/>
+ </service>
+ <reference name="target">
+ <t:binding.http uri="http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=jsdelfino"/>
+ </reference>
+ </component>
+
+ <component name="RSSTwit">
+ <t:implementation.python script="rss.py"/>
+ <service name="Relay">
+ <t:binding.http uri="rsstwit"/>
+ </service>
+ <reference name="target">
+ <t:binding.http uri="http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=jsdelfino"/>
+ </reference>
+ </component>
+
+ <component name="HTML">
+ <t:implementation.python script="html.py"/>
+ <service name="Relay">
+ <t:binding.http uri="html"/>
+ </service>
+ <reference name="target">
+ <t:binding.http uri="http://localhost:8090/test"/>
+ </reference>
+ </component>
+
+ <component name="JSONFB">
+ <t:implementation.python script="json.py"/>
+ <service name="Relay">
+ <t:binding.http uri="jsonfb"/>
+ </service>
+ <reference name="target">
+ <t:binding.http uri="https://graph.facebook.com/100001053301307"/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/rss.py b/sandbox/sebastien/cpp/apr-2/samples/relay-python/rss.py
new file mode 100644
index 0000000000..96e4491c1a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/rss.py
@@ -0,0 +1,25 @@
+# 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.
+
+import sys
+
+# Feed relay implementation
+def get(id, target):
+ v = target.get(id)
+ print >> sys.stderr, v
+ return v
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/start b/sandbox/sebastien/cpp/apr-2/samples/relay-python/start
new file mode 100755
index 0000000000..c156e43a52
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/start
@@ -0,0 +1,30 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite relay.composite
+
+EOF
+
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/stop b/sandbox/sebastien/cpp/apr-2/samples/relay-python/stop
new file mode 100755
index 0000000000..3b4f46694d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/stop
@@ -0,0 +1,20 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/relay-python/xml.py b/sandbox/sebastien/cpp/apr-2/samples/relay-python/xml.py
new file mode 100644
index 0000000000..24f969d419
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/relay-python/xml.py
@@ -0,0 +1,24 @@
+# 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.
+
+# Relay implementation
+import uuid
+import sys
+
+def get(id, target):
+ return target.get(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/Makefile.am
new file mode 100644
index 0000000000..e9aab86f10
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/Makefile.am
@@ -0,0 +1,36 @@
+# 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.
+
+if WANT_PYTHON
+if WANT_SQLDB
+if WANT_OPENID
+if WANT_LOG
+if WANT_QUEUE
+
+dist_sample_SCRIPTS = start stop ssl-start ssl-stop proxy-conf proxy-ssl-conf server-conf server-ssl-conf tunnel-ssl-conf sqldb-master-conf sqldb-standby-conf
+sampledir = $(prefix)/samples/store-cluster
+
+nobase_dist_sample_DATA = htdocs/*.html htdocs/*/*.html htdocs/domains/*/*.html htdocs/domains/*/*/*.html domains/*/*.py domains/*/*.composite shared/*.composite
+
+dist_noinst_SCRIPTS = server-test
+#TESTS = server-test
+
+endif
+endif
+endif
+endif
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/currency-converter.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/currency-converter.py
new file mode 100644
index 0000000000..2fded8f616
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/currency-converter.py
@@ -0,0 +1,29 @@
+# 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.
+
+# Currency converter implementation
+
+def convert(fr, to, amount):
+ if to == "EUR":
+ return amount * 0.70
+ return amount
+
+def symbol(currency):
+ if currency == "EUR":
+ return "E"
+ return "$"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/fruits-catalog.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/fruits-catalog.py
new file mode 100644
index 0000000000..fb20b4ff27
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/fruits-catalog.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Catalog implementation
+
+def items(converter, currencyCode):
+ code = currencyCode.eval()
+ def convert(price):
+ return converter.convert("USD", code, price)
+ symbol = converter.symbol(code)
+ return (
+ (("'name", "Passion"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
+ (("'name", "Mango"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
+ (("'name", "Pineapple"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
+ )
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/shopping-cart.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/shopping-cart.py
new file mode 100644
index 0000000000..44484ea5d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/shopping-cart.py
@@ -0,0 +1,76 @@
+# 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.
+
+# Shopping cart implementation
+import uuid
+import sys
+
+# Convert a particular host and user email to a cart id
+def cartid(host, email):
+ return ("cart", host.eval(), email.eval())
+
+# Get the shopping cart from the cache
+# Return an empty cart if not found
+def getcart(id, cache):
+ cart = cache.get(id)
+ if cart is None:
+ return ()
+ return cart
+
+# Post a new item to the cart, create a new cart if necessary
+def post(collection, item, cache, host, email):
+ id = str(uuid.uuid1())
+ cart = ((item[0], id, item[2]),) + getcart(cartid(host, email), cache)
+ cache.put(cartid(host, email), cart)
+ return (id,)
+
+
+# Find an item in the cart
+def find(id, cart):
+ if cart == ():
+ return ("Item", "0", ())
+ elif id == cart[0][1]:
+ return cart[0]
+ else:
+ return find(id, cart[1:])
+
+# Get items from the cart
+def get(id, cache, host, email):
+ if id == ():
+ return ("Your Cart", email.eval()) + getcart(cartid(host, email), cache)
+ return find(id[0], getcart(cartid(host, email), cache))
+
+# Delete items from the cart
+def delete(id, cache, host, email):
+ if id == ():
+ return cache.delete(cartid(host, email))
+ return True
+
+# Return the price of an item
+def price(item):
+ return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
+
+# Sum the prices of a list of items
+def sum(items):
+ if items == ():
+ return 0
+ return price(items[0]) + sum(items[1:])
+
+# Return the total price of the items in the cart
+def total(cache, host, email):
+ return sum(getcart(cartid(host, email), cache))
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.composite
new file mode 100644
index 0000000000..137027a50c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.composite
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <property name="host">localhost</property>
+ <property name="email">anonymous@localhost</property>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.py
new file mode 100644
index 0000000000..ff82f1d327
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/jane/store.py
@@ -0,0 +1,40 @@
+# 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.
+
+# Store implementation
+
+def post(item, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.post(item)
+
+def getall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.getall()
+
+def get(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.get(id)
+
+def items(catalog, shoppingCart, shoppingTotal):
+ return catalog.items()
+
+def total(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.total()
+
+def deleteall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.deleteall()
+
+def delete(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.delete(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/currency-converter.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/currency-converter.py
new file mode 100644
index 0000000000..2fded8f616
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/currency-converter.py
@@ -0,0 +1,29 @@
+# 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.
+
+# Currency converter implementation
+
+def convert(fr, to, amount):
+ if to == "EUR":
+ return amount * 0.70
+ return amount
+
+def symbol(currency):
+ if currency == "EUR":
+ return "E"
+ return "$"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/fruits-catalog.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/fruits-catalog.py
new file mode 100644
index 0000000000..6644421683
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/fruits-catalog.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Catalog implementation
+
+def items(converter, currencyCode):
+ code = currencyCode.eval()
+ def convert(price):
+ return converter.convert("USD", code, price)
+ symbol = converter.symbol(code)
+ return (
+ (("'name", "Apple"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
+ (("'name", "Orange"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
+ (("'name", "Pear"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
+ )
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/shopping-cart.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/shopping-cart.py
new file mode 100644
index 0000000000..44484ea5d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/shopping-cart.py
@@ -0,0 +1,76 @@
+# 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.
+
+# Shopping cart implementation
+import uuid
+import sys
+
+# Convert a particular host and user email to a cart id
+def cartid(host, email):
+ return ("cart", host.eval(), email.eval())
+
+# Get the shopping cart from the cache
+# Return an empty cart if not found
+def getcart(id, cache):
+ cart = cache.get(id)
+ if cart is None:
+ return ()
+ return cart
+
+# Post a new item to the cart, create a new cart if necessary
+def post(collection, item, cache, host, email):
+ id = str(uuid.uuid1())
+ cart = ((item[0], id, item[2]),) + getcart(cartid(host, email), cache)
+ cache.put(cartid(host, email), cart)
+ return (id,)
+
+
+# Find an item in the cart
+def find(id, cart):
+ if cart == ():
+ return ("Item", "0", ())
+ elif id == cart[0][1]:
+ return cart[0]
+ else:
+ return find(id, cart[1:])
+
+# Get items from the cart
+def get(id, cache, host, email):
+ if id == ():
+ return ("Your Cart", email.eval()) + getcart(cartid(host, email), cache)
+ return find(id[0], getcart(cartid(host, email), cache))
+
+# Delete items from the cart
+def delete(id, cache, host, email):
+ if id == ():
+ return cache.delete(cartid(host, email))
+ return True
+
+# Return the price of an item
+def price(item):
+ return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
+
+# Sum the prices of a list of items
+def sum(items):
+ if items == ():
+ return 0
+ return price(items[0]) + sum(items[1:])
+
+# Return the total price of the items in the cart
+def total(cache, host, email):
+ return sum(getcart(cartid(host, email), cache))
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.composite
new file mode 100644
index 0000000000..137027a50c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.composite
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <property name="host">localhost</property>
+ <property name="email">anonymous@localhost</property>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.py b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.py
new file mode 100644
index 0000000000..811b05c580
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/domains/joe/store.py
@@ -0,0 +1,40 @@
+# 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.
+
+# Store implementation
+
+def post(item, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.post(item)
+
+def getall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.getall()
+
+def get(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.get(id)
+
+def items(catalog, shoppingCart, shoppingTotal):
+ return catalog.items()
+
+def total(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.total()
+
+def deleteall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.deletall()
+
+def delete(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.delete(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/index.html
new file mode 100644
index 0000000000..238ed701f0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Jane's Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/login/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/login/index.html
new file mode 100644
index 0000000000..2eecc74b92
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/login/index.html
@@ -0,0 +1,194 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with an OpenID or OAuth provider</h1>
+
+<script type="text/javascript">
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function openauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(openauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitOpenIDSignin(w) {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.openIDSignin.openid_identifier.value = w();
+ document.openIDSignin.action = openauthReferrer();
+ document.openIDSignin.submit();
+}
+
+function withGoogle() {
+ return 'https://www.google.com/accounts/o8/id';
+}
+
+function withYahoo() {
+ return 'https://me.yahoo.com/';
+}
+
+function withMyOpenID() {
+ return 'http://www.myopenid.com/xrds';
+}
+
+function withVerisign() {
+ return 'https://pip.verisignlabs.com/';
+}
+
+function withMySpace() {
+ return 'https://api.myspace.com/openid';
+}
+
+function withGoogleApps() {
+ return 'https://www.google.com/accounts/o8/site-xrds?ns=2&hd=' + document.fields.domain.value;
+}
+
+function withLivejournal() {
+ return 'http://' + document.fields.ljuser.value + '.livejournal.com';
+}
+
+function withBlogspot() {
+ return 'http://' + document.fields.bsuser.value + '.blogspot.com';
+}
+
+function withBlogger() {
+ return 'http://' + document.fields.bguser.value + '.blogger.com';
+}
+
+function withXRDSEndpoint() {
+ return document.fields.endpoint.value;
+}
+
+function submitOAuth2Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
+ document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
+ document.oauth2Signin.mod_oauth2_client_id.value = parms[2];
+ document.oauth2Signin.mod_oauth2_info.value = parms[3];
+ document.oauth2Signin.action = openauthReferrer();
+ document.oauth2Signin.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'testfacebookapp', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'testgithubapp', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitOAuth1Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth1Signin.mod_oauth1_request_token.value = parms[0];
+ document.oauth1Signin.mod_oauth1_authorize.value = parms[1];
+ document.oauth1Signin.mod_oauth1_access_token.value = parms[2];
+ document.oauth1Signin.mod_oauth1_client_id.value = parms[3];
+ document.oauth1Signin.mod_oauth1_info.value = parms[4];
+ document.oauth1Signin.action = openauthReferrer();
+ document.oauth1Signin.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'testlinkedinapp', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'testtwitterapp', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="fields">
+<p>Sign in with your Google account<br/><input type="button" onclick="submitOpenIDSignin(withGoogle)" value="Sign in"/></p>
+<p>Sign in with your Yahoo account<br/><input type="button" onclick="submitOpenIDSignin(withYahoo)" value="Sign in"/></p>
+<p>Sign in with your MyOpenID account<br/><input type="button" onclick="submitOpenIDSignin(withMyOpenID)" value="Sign in"/></p>
+<p>Sign in with your Verisign account<br/><input type="button" onclick="submitOpenIDSignin(withVerisign)" value="Sign in"/></p>
+<p>Sign in with your MySpace account<br/><input type="button" onclick="submitOpenIDSignin(withMySpace)" value="Sign in"/></p>
+
+<p>Sign in with a Google apps domain<br/>
+<input type="text" size="20" name="domain" value="example.com"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withGoogleApps)" value="Sign in"/></p>
+
+<p>Sign in with your Livejournal account<br/>
+<input type="text" size="10" name="ljuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withLivejournal)" value="Sign in"/></p>
+
+<p>Sign in with your Blogspot account<br/>
+<input type="text" size="10" name="bsuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogspot)" value="Sign in"/></p>
+
+<p>Sign in with your Blogger account<br/>
+<input type="text" size="10" name="bguser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogger)" value="Sign in"/></p>
+
+<p>Sign in with an OpenID endpoint<br/>
+<input type="text" size="50" name="endpoint" value="https://www.google.com/accounts/o8/id"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withXRDSEndpoint)" value="Sign in"/></p>
+
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitOAuth2Signin(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitOAuth2Signin(withGithub)" value="Sign in"/></p>
+
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitOAuth1Signin(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitOAuth1Signin(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="openIDSignin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value=""/>
+</form>
+
+<form name="oauth2Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="oauth1Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/logout/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/logout/index.html
new file mode 100644
index 0000000000..02a92d1b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/jane/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/index.html
new file mode 100644
index 0000000000..c1cfc59aa7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Joe's Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/login/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/login/index.html
new file mode 100644
index 0000000000..2eecc74b92
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/login/index.html
@@ -0,0 +1,194 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with an OpenID or OAuth provider</h1>
+
+<script type="text/javascript">
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function openauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(openauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitOpenIDSignin(w) {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.openIDSignin.openid_identifier.value = w();
+ document.openIDSignin.action = openauthReferrer();
+ document.openIDSignin.submit();
+}
+
+function withGoogle() {
+ return 'https://www.google.com/accounts/o8/id';
+}
+
+function withYahoo() {
+ return 'https://me.yahoo.com/';
+}
+
+function withMyOpenID() {
+ return 'http://www.myopenid.com/xrds';
+}
+
+function withVerisign() {
+ return 'https://pip.verisignlabs.com/';
+}
+
+function withMySpace() {
+ return 'https://api.myspace.com/openid';
+}
+
+function withGoogleApps() {
+ return 'https://www.google.com/accounts/o8/site-xrds?ns=2&hd=' + document.fields.domain.value;
+}
+
+function withLivejournal() {
+ return 'http://' + document.fields.ljuser.value + '.livejournal.com';
+}
+
+function withBlogspot() {
+ return 'http://' + document.fields.bsuser.value + '.blogspot.com';
+}
+
+function withBlogger() {
+ return 'http://' + document.fields.bguser.value + '.blogger.com';
+}
+
+function withXRDSEndpoint() {
+ return document.fields.endpoint.value;
+}
+
+function submitOAuth2Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
+ document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
+ document.oauth2Signin.mod_oauth2_client_id.value = parms[2];
+ document.oauth2Signin.mod_oauth2_info.value = parms[3];
+ document.oauth2Signin.action = openauthReferrer();
+ document.oauth2Signin.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'testfacebookapp', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'testgithubapp', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitOAuth1Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth1Signin.mod_oauth1_request_token.value = parms[0];
+ document.oauth1Signin.mod_oauth1_authorize.value = parms[1];
+ document.oauth1Signin.mod_oauth1_access_token.value = parms[2];
+ document.oauth1Signin.mod_oauth1_client_id.value = parms[3];
+ document.oauth1Signin.mod_oauth1_info.value = parms[4];
+ document.oauth1Signin.action = openauthReferrer();
+ document.oauth1Signin.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'testlinkedinapp', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'testtwitterapp', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="fields">
+<p>Sign in with your Google account<br/><input type="button" onclick="submitOpenIDSignin(withGoogle)" value="Sign in"/></p>
+<p>Sign in with your Yahoo account<br/><input type="button" onclick="submitOpenIDSignin(withYahoo)" value="Sign in"/></p>
+<p>Sign in with your MyOpenID account<br/><input type="button" onclick="submitOpenIDSignin(withMyOpenID)" value="Sign in"/></p>
+<p>Sign in with your Verisign account<br/><input type="button" onclick="submitOpenIDSignin(withVerisign)" value="Sign in"/></p>
+<p>Sign in with your MySpace account<br/><input type="button" onclick="submitOpenIDSignin(withMySpace)" value="Sign in"/></p>
+
+<p>Sign in with a Google apps domain<br/>
+<input type="text" size="20" name="domain" value="example.com"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withGoogleApps)" value="Sign in"/></p>
+
+<p>Sign in with your Livejournal account<br/>
+<input type="text" size="10" name="ljuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withLivejournal)" value="Sign in"/></p>
+
+<p>Sign in with your Blogspot account<br/>
+<input type="text" size="10" name="bsuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogspot)" value="Sign in"/></p>
+
+<p>Sign in with your Blogger account<br/>
+<input type="text" size="10" name="bguser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogger)" value="Sign in"/></p>
+
+<p>Sign in with an OpenID endpoint<br/>
+<input type="text" size="50" name="endpoint" value="https://www.google.com/accounts/o8/id"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withXRDSEndpoint)" value="Sign in"/></p>
+
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitOAuth2Signin(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitOAuth2Signin(withGithub)" value="Sign in"/></p>
+
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitOAuth1Signin(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitOAuth1Signin(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="openIDSignin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value=""/>
+</form>
+
+<form name="oauth2Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="oauth1Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/logout/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/logout/index.html
new file mode 100644
index 0000000000..02a92d1b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/domains/joe/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/index.html
new file mode 100644
index 0000000000..21e32d7efc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/index.html
@@ -0,0 +1,34 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+</head>
+
+<body>
+<h1>Store</h1>
+<p>For this sample to work, add the sample domain to your /etc/hosts as follows:<br/>
+127.0.0.1 sca-store.com jane.sca-store.com joe.sca-store.com</p>
+
+<p/>
+<p>Jane's store at <a href="http://jane.sca-store.com/">jane.sca-store.com</a>
+<br/>Joe's store at <a href="http://joe.sca-store.com/">joe.sca-store.com</a></p>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/login/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/login/index.html
new file mode 100644
index 0000000000..2eecc74b92
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/login/index.html
@@ -0,0 +1,194 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with an OpenID or OAuth provider</h1>
+
+<script type="text/javascript">
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function openauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(openauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitOpenIDSignin(w) {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.openIDSignin.openid_identifier.value = w();
+ document.openIDSignin.action = openauthReferrer();
+ document.openIDSignin.submit();
+}
+
+function withGoogle() {
+ return 'https://www.google.com/accounts/o8/id';
+}
+
+function withYahoo() {
+ return 'https://me.yahoo.com/';
+}
+
+function withMyOpenID() {
+ return 'http://www.myopenid.com/xrds';
+}
+
+function withVerisign() {
+ return 'https://pip.verisignlabs.com/';
+}
+
+function withMySpace() {
+ return 'https://api.myspace.com/openid';
+}
+
+function withGoogleApps() {
+ return 'https://www.google.com/accounts/o8/site-xrds?ns=2&hd=' + document.fields.domain.value;
+}
+
+function withLivejournal() {
+ return 'http://' + document.fields.ljuser.value + '.livejournal.com';
+}
+
+function withBlogspot() {
+ return 'http://' + document.fields.bsuser.value + '.blogspot.com';
+}
+
+function withBlogger() {
+ return 'http://' + document.fields.bguser.value + '.blogger.com';
+}
+
+function withXRDSEndpoint() {
+ return document.fields.endpoint.value;
+}
+
+function submitOAuth2Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
+ document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
+ document.oauth2Signin.mod_oauth2_client_id.value = parms[2];
+ document.oauth2Signin.mod_oauth2_info.value = parms[3];
+ document.oauth2Signin.action = openauthReferrer();
+ document.oauth2Signin.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'testfacebookapp', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'testgithubapp', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitOAuth1Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth1Signin.mod_oauth1_request_token.value = parms[0];
+ document.oauth1Signin.mod_oauth1_authorize.value = parms[1];
+ document.oauth1Signin.mod_oauth1_access_token.value = parms[2];
+ document.oauth1Signin.mod_oauth1_client_id.value = parms[3];
+ document.oauth1Signin.mod_oauth1_info.value = parms[4];
+ document.oauth1Signin.action = openauthReferrer();
+ document.oauth1Signin.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'testlinkedinapp', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'testtwitterapp', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="fields">
+<p>Sign in with your Google account<br/><input type="button" onclick="submitOpenIDSignin(withGoogle)" value="Sign in"/></p>
+<p>Sign in with your Yahoo account<br/><input type="button" onclick="submitOpenIDSignin(withYahoo)" value="Sign in"/></p>
+<p>Sign in with your MyOpenID account<br/><input type="button" onclick="submitOpenIDSignin(withMyOpenID)" value="Sign in"/></p>
+<p>Sign in with your Verisign account<br/><input type="button" onclick="submitOpenIDSignin(withVerisign)" value="Sign in"/></p>
+<p>Sign in with your MySpace account<br/><input type="button" onclick="submitOpenIDSignin(withMySpace)" value="Sign in"/></p>
+
+<p>Sign in with a Google apps domain<br/>
+<input type="text" size="20" name="domain" value="example.com"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withGoogleApps)" value="Sign in"/></p>
+
+<p>Sign in with your Livejournal account<br/>
+<input type="text" size="10" name="ljuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withLivejournal)" value="Sign in"/></p>
+
+<p>Sign in with your Blogspot account<br/>
+<input type="text" size="10" name="bsuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogspot)" value="Sign in"/></p>
+
+<p>Sign in with your Blogger account<br/>
+<input type="text" size="10" name="bguser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogger)" value="Sign in"/></p>
+
+<p>Sign in with an OpenID endpoint<br/>
+<input type="text" size="50" name="endpoint" value="https://www.google.com/accounts/o8/id"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withXRDSEndpoint)" value="Sign in"/></p>
+
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitOAuth2Signin(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitOAuth2Signin(withGithub)" value="Sign in"/></p>
+
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitOAuth1Signin(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitOAuth1Signin(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="openIDSignin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value=""/>
+</form>
+
+<form name="oauth2Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="oauth1Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/logout/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/logout/index.html
new file mode 100644
index 0000000000..02a92d1b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/htdocs/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-conf
new file mode 100755
index 0000000000..b60e7ba7f9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-conf
@@ -0,0 +1,35 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+
+set -x
+
+# Configure a proxy balancer
+../../modules/http/httpd-conf $root sca-store.com $port/80 $root/htdocs
+../../modules/http/vhost-conf $root
+../../modules/http/proxy-conf $root
+../../modules/http/httpd-event-conf $root
+
+# Aggregate proxy balancer logs
+category=`basename $root`
+../../components/log/scribe-tail-start $category $root/logs/error_log
+../../components/log/scribe-tail-start $category $root/logs/access_log
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-ssl-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-ssl-conf
new file mode 100755
index 0000000000..fc329f0d18
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/proxy-ssl-conf
@@ -0,0 +1,40 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+sslport=$3
+
+set -x
+
+# Configure an SSL-enabled proxy balancer
+../../modules/http/httpd-conf $root sca-store.com $port $root/htdocs
+../../modules/http/vhost-conf $root
+../../modules/http/proxy-conf $root
+../../modules/http/httpd-event-conf $root
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C $root -x
+../../modules/http/httpd-ssl-conf $root $sslport
+../../modules/http/vhost-ssl-conf $root
+../../modules/http/proxy-ssl-conf $root
+
+# Aggregate proxy balancer logs
+category=`basename $root`
+../../components/log/scribe-tail-start $category $root/logs/error_log
+../../components/log/scribe-tail-start $category $root/logs/access_log
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-conf
new file mode 100755
index 0000000000..d274dd3d17
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-conf
@@ -0,0 +1,45 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+
+set -x
+
+# Configure an app server
+../../modules/http/httpd-conf $root sca-store.com $port/80 htdocs
+../../modules/http/vhost-conf $root
+../../modules/server/server-conf $root
+../../modules/python/python-conf $root
+cat >>$root/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/shared/
+SCAComposite shared.composite
+
+# Configure SCA Composite for mass dynamic virtual hosting
+SCAVirtualContribution `pwd`/domains/
+SCAVirtualComposite store.composite
+
+EOF
+
+# Aggregate app server logs
+category=`basename $root`
+../../components/log/scribe-tail-start $category $root/logs/error_log
+../../components/log/scribe-tail-start $category $root/logs/access_log
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-ssl-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-ssl-conf
new file mode 100755
index 0000000000..612dc6be47
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-ssl-conf
@@ -0,0 +1,63 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+sslport=$3
+
+set -x
+
+# Configure an SSL-enabled app server
+../../modules/http/httpd-conf $root sca-store.com $port htdocs
+../../modules/http/vhost-conf $root
+
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C $root -x
+../../modules/http/httpd-ssl-conf $root $sslport
+../../modules/http/vhost-ssl-conf $root
+
+../../modules/oauth/oauth-conf $root
+../../modules/oauth/oauth-memcached-conf $root localhost 11211
+../../modules/oauth/oauth-memcached-conf $root localhost 11212
+../../modules/oauth/oauth-memcached-conf $root localhost 11213
+../../modules/openid/openid-conf $root
+../../modules/openid/openid-step2-conf $root
+../../modules/openid/openid-memcached-conf $root localhost 11211
+../../modules/openid/openid-memcached-conf $root localhost 11212
+../../modules/openid/openid-memcached-conf $root localhost 11213
+../../modules/http/open-auth-conf $root
+../../modules/http/passwd-auth-conf $root foo foo
+
+../../modules/server/server-conf $root
+../../modules/python/python-conf $root
+cat >>$root/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/shared/
+SCAComposite shared.composite
+
+# Configure SCA Composite for mass dynamic virtual hosting
+SCAVirtualContribution `pwd`/domains/
+SCAVirtualComposite store.composite
+
+EOF
+
+# Aggregate app server logs
+category=`basename $root`
+../../components/log/scribe-tail-start $category $root/logs/error_log
+../../components/log/scribe-tail-start $category $root/logs/access_log
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-test
new file mode 100755
index 0000000000..68856f530e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/server-test
@@ -0,0 +1,61 @@
+#!/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
+# 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.
+
+# For this test to work, add the test domain to your etc/hosts as follows:
+# 127.0.0.1 sca-store.com joe.sca-store.com joe.sca-store.com
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://joe.sca-store.com/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/domains/joe/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://joe.sca-store.com/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://joe.sca-store.com/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://joe.sca-store.com/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/shared/shared.composite b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/shared/shared.composite
new file mode 100644
index 0000000000..b7eae5f78a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/shared/shared.composite
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://shared"
+ name="shared">
+
+ <component name="Cache">
+ <implementation.cpp path="../../../components/cache" library="libdatacache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <reference name="l1reader" target="Memcache"/>
+ <reference name="l1writer" target="Memcache"/>
+ <reference name="l2reader" target="Standbydb"/>
+ <reference name="l2writer" target="Masterdb"/>
+ </component>
+
+ <component name="Memcache">
+ <implementation.cpp path="../../../components/cache" library="libmemcache"/>
+ <service name="Memcache">
+ <t:binding.atom uri="memcache"/>
+ </service>
+ <property name="servers">localhost:11211,localhost:11212,localhost:11213</property>
+ </component>
+
+ <component name="Masterdb">
+ <implementation.cpp path="../../../components/sqldb" library="libsqldb"/>
+ <property name="conninfo">host=localhost port=5432 dbname=db</property>
+ <property name="table">store</property>
+ <service name="Masterdb">
+ <t:binding.atom uri="masterdb"/>
+ </service>
+ </component>
+
+ <component name="Standbydb">
+ <implementation.cpp path="../../../components/sqldb" library="libsqldb"/>
+ <property name="conninfo">host=localhost port=5433 dbname=db</property>
+ <property name="table">store</property>
+ <service name="Standbydb">
+ <t:binding.atom uri="standbydb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-master-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-master-conf
new file mode 100755
index 0000000000..83f78be999
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-master-conf
@@ -0,0 +1,47 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+httpport=$3
+
+set -x
+
+# Aggregate database server logs
+category=`basename $root`
+../../components/log/scribe-tail-start $category "sqldb" $root/logs/postgresql
+../../components/log/scribe-tail-start $category $root/logs/error_log
+../../components/log/scribe-tail-start $category $root/logs/access_log
+
+# Configure a database backup HTTP server
+../../modules/http/httpd-conf $root localhost $httpport $root/htdocs
+
+# Configure a database server
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ create="true"
+else
+ create="false"
+fi
+../../components/sqldb/pgsql-conf $root $port
+if [ "$create" = "true" ]; then
+ ../../components/sqldb/pgsql-start $root
+ ../../components/sqldb/pgsql localhost $port "create table store(key text, value text);" 1>>$root/logs/postgresql 2>&1
+ ../../components/sqldb/pgsql-stop $root
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-standby-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-standby-conf
new file mode 100755
index 0000000000..4998ead4b4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/sqldb-standby-conf
@@ -0,0 +1,40 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+httpport=$3
+mhost=$4
+mport=$5
+mhttpport=$6
+
+set -x
+
+# Aggregate database server logs
+category=`basename $root`
+../../components/log/scribe-tail-start $category "sqldb" $root/logs/postgresql
+../../components/log/scribe-tail-start $category $root/logs/error_log
+../../components/log/scribe-tail-start $category $root/logs/access_log
+
+# Configure a database backup HTTP server
+../../modules/http/httpd-conf $root localhost $httpport $root/htdocs
+
+# Configure a standby database server
+../../components/sqldb/pgsql-standby-conf $root $port $mhost $mport $mhttpport
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-start
new file mode 100755
index 0000000000..f80bb075d6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-start
@@ -0,0 +1,121 @@
+#!/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
+# 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.
+
+set -x
+
+# Redirect traffic from ports 80, 443 and 444 to proxy1
+sudo ../../ubuntu/ip-redirect-all 80 8090
+sudo ../../ubuntu/ip-redirect-all 443 8091
+sudo ../../ubuntu/ip-redirect-all 444 8092
+
+# Redirect traffic from ports 80, 443 and 444 to proxy2
+#sudo ../../ubuntu/ip-redirect-all 80 8093
+#sudo ../../ubuntu/ip-redirect-all 443 8094
+#sudo ../../ubuntu/ip-redirect-all 444 8095
+
+# Redirect traffic from ports 119 and 563 to tunnel
+sudo ../../ubuntu/ip-redirect-all 119 8119
+sudo ../../ubuntu/ip-redirect-all 563 8563
+
+# Generate SSL certificates
+../../modules/http/ssl-ca-conf tmp/ssl sca-store.com
+../../modules/http/ssl-cert-conf tmp/ssl localhost server
+../../modules/http/ssl-cert-conf tmp/ssl *.sca-store.com vhost
+../../modules/http/ssl-cert-conf tmp/ssl sca-store.com proxy
+../../modules/http/ssl-cert-conf tmp/ssl localhost tunnel
+
+# Start an SSL tunnel
+./tunnel-ssl-conf tmp/tunnel 8119/119 8563/563
+../../modules/http/httpd-start tmp/tunnel
+sleep 1
+
+# Start scribe logging
+../../modules/http/tunnel-ssl-conf tmp/tunnel 1465 localhost 563 1463
+../../modules/http/httpd-restart tmp/tunnel
+../../components/log/scribed-central-conf tmp/monitor
+../../components/log/scribed-client-conf tmp/monitor localhost 1465
+../../components/log/scribed-central-start tmp/monitor
+../../components/log/scribed-client-start tmp/monitor
+sleep 1
+
+# Start three memcached servers
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11211 localhost 563 11411
+../../components/cache/memcached-start 127.0.0.1:11411
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11212 localhost 563 11412
+../../components/cache/memcached-start 127.0.0.1:11412
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11213 localhost 563 11413
+../../components/cache/memcached-start 127.0.0.1:11413
+../../modules/http/httpd-restart tmp/tunnel
+sleep 1
+
+# Start a master and two hot standby databases
+../../modules/http/tunnel-ssl-conf tmp/tunnel 5432 localhost 563 5532
+../../modules/http/tunnel-ssl-conf tmp/tunnel 8502 localhost 563 8602
+../../modules/http/httpd-restart tmp/tunnel
+./sqldb-master-conf tmp/sqldb1 127.0.0.1:5532 127.0.0.1:8602
+../../components/sqldb/pgsql-start tmp/sqldb1
+../../modules/http/httpd-start tmp/sqldb1
+sleep 1
+
+../../modules/http/tunnel-ssl-conf tmp/tunnel 5433 localhost 563 5533
+../../modules/http/tunnel-ssl-conf tmp/tunnel 8503 localhost 563 8603
+../../modules/http/httpd-restart tmp/tunnel
+./sqldb-standby-conf tmp/sqldb2 127.0.0.1:5533 127.0.0.1:8603 localhost 5432 8502
+../../components/sqldb/pgsql-start tmp/sqldb2
+../../modules/http/httpd-start tmp/sqldb2
+
+../../modules/http/tunnel-ssl-conf tmp/tunnel 5434 localhost 563 5534
+../../modules/http/tunnel-ssl-conf tmp/tunnel 8504 localhost 563 8604
+../../modules/http/httpd-restart tmp/tunnel
+./sqldb-standby-conf tmp/sqldb3 127.0.0.1:5534 127.0.0.1:8604 localhost 5432 8502
+../../components/sqldb/pgsql-start tmp/sqldb3
+../../modules/http/httpd-start tmp/sqldb3
+
+# Start three app servers
+./server-ssl-conf tmp/server1 8101/80 8441/443
+../../modules/http/httpd-start tmp/server1
+sleep 1
+
+./server-ssl-conf tmp/server2 8102/80 8442/443
+../../modules/http/httpd-start tmp/server2
+sleep 1
+
+./server-ssl-conf tmp/server3 8103/80 8443/443
+../../modules/http/httpd-start tmp/server3
+sleep 1
+
+# Start two proxy balancers
+./proxy-ssl-conf tmp/proxy1 8090/80 8091/443
+../../modules/http/proxy-member-conf tmp/proxy1 localhost 8101
+../../modules/http/proxy-ssl-member-conf tmp/proxy1 localhost 8441
+../../modules/http/proxy-member-conf tmp/proxy1 localhost 8102
+../../modules/http/proxy-ssl-member-conf tmp/proxy1 localhost 8442
+../../modules/http/proxy-member-conf tmp/proxy1 localhost 8103
+../../modules/http/proxy-ssl-member-conf tmp/proxy1 localhost 8443
+../../modules/http/httpd-start tmp/proxy1
+
+./proxy-ssl-conf tmp/proxy2 8093/80 8094/443
+../../modules/http/proxy-member-conf tmp/proxy2 localhost 8101
+../../modules/http/proxy-ssl-member-conf tmp/proxy2 localhost 8441
+../../modules/http/proxy-member-conf tmp/proxy2 localhost 8102
+../../modules/http/proxy-ssl-member-conf tmp/proxy2 localhost 8442
+../../modules/http/proxy-member-conf tmp/proxy2 localhost 8103
+../../modules/http/proxy-ssl-member-conf tmp/proxy2 localhost 8443
+../../modules/http/httpd-start tmp/proxy2
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-stop b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-stop
new file mode 100755
index 0000000000..ff36721315
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/ssl-stop
@@ -0,0 +1,44 @@
+#!/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
+# 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.
+
+set -x
+
+../../modules/http/httpd-stop tmp/server1
+../../modules/http/httpd-stop tmp/server2
+../../modules/http/httpd-stop tmp/server3
+
+../../modules/http/httpd-stop tmp/proxy1
+../../modules/http/httpd-stop tmp/proxy2
+
+../../components/cache/memcached-stop 127.0.0.1:11411
+../../components/cache/memcached-stop 127.0.0.1:11412
+../../components/cache/memcached-stop 127.0.0.1:11413
+
+../../components/sqldb/pgsql-stop tmp/sqldb3
+../../modules/http/httpd-stop tmp/sqldb3
+../../components/sqldb/pgsql-stop tmp/sqldb2
+../../modules/http/httpd-stop tmp/sqldb2
+../../components/sqldb/pgsql-stop tmp/sqldb1
+../../modules/http/httpd-stop tmp/sqldb1
+
+../../modules/http/httpd-stop tmp/tunnel
+
+../../components/log/scribed-client-stop tmp/monitor
+../../components/log/scribed-central-stop tmp/monitor
+../../components/log/scribe-tail-stop tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/start b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/start
new file mode 100755
index 0000000000..67434d6a0e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/start
@@ -0,0 +1,79 @@
+#!/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
+# 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.
+
+set -x
+
+# Redirect traffic from port 80 to proxy1
+sudo ../../ubuntu/ip-redirect-all 80 8090
+
+# Redirect traffic from port 80 to proxy2
+#sudo ../../ubuntu/ip-redirect-all 80 8091
+
+# Start scribe logging
+../../components/log/scribed-central-conf tmp/monitor
+../../components/log/scribed-client-conf tmp/monitor localhost
+../../components/log/scribed-central-start tmp/monitor
+../../components/log/scribed-client-start tmp/monitor
+sleep 1
+
+# Start three memcached servers
+../../components/cache/memcached-start 11211
+../../components/cache/memcached-start 11212
+../../components/cache/memcached-start 11213
+
+# Start a master and two hot standby databases
+./sqldb-master-conf tmp/sqldb1 5432 8502
+../../components/sqldb/pgsql-start tmp/sqldb1
+../../modules/http/httpd-start tmp/sqldb1
+sleep 1
+
+./sqldb-standby-conf tmp/sqldb2 5433 8503 localhost 5432 8502
+../../components/sqldb/pgsql-start tmp/sqldb2
+../../modules/http/httpd-start tmp/sqldb2
+
+./sqldb-standby-conf tmp/sqldb3 5434 8504 localhost 5432 8502
+../../components/sqldb/pgsql-start tmp/sqldb3
+../../modules/http/httpd-start tmp/sqldb3
+
+# Start three app servers
+./server-conf tmp/server1 8101
+../../modules/http/httpd-start tmp/server1
+sleep 1
+
+./server-conf tmp/server2 8102
+../../modules/http/httpd-start tmp/server2
+sleep 1
+
+./server-conf tmp/server3 8103
+../../modules/http/httpd-start tmp/server3
+sleep 1
+
+# Start two proxy balancers
+./proxy-conf tmp/proxy1 8090
+../../modules/http/proxy-member-conf tmp/proxy1 localhost 8101
+../../modules/http/proxy-member-conf tmp/proxy1 localhost 8102
+../../modules/http/proxy-member-conf tmp/proxy1 localhost 8103
+../../modules/http/httpd-start tmp/proxy1
+
+./proxy-conf tmp/proxy2 8091
+../../modules/http/proxy-member-conf tmp/proxy2 localhost 8101
+../../modules/http/proxy-member-conf tmp/proxy2 localhost 8102
+../../modules/http/proxy-member-conf tmp/proxy2 localhost 8103
+../../modules/http/httpd-start tmp/proxy2
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/stop b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/stop
new file mode 100755
index 0000000000..b2fa11b7c4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/stop
@@ -0,0 +1,42 @@
+#!/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
+# 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.
+
+set -x
+
+../../modules/http/httpd-stop tmp/server1
+../../modules/http/httpd-stop tmp/server2
+../../modules/http/httpd-stop tmp/server3
+
+../../modules/http/httpd-stop tmp/proxy1
+../../modules/http/httpd-stop tmp/proxy2
+
+../../components/cache/memcached-stop 11211
+../../components/cache/memcached-stop 11212
+../../components/cache/memcached-stop 11213
+
+../../components/sqldb/pgsql-stop tmp/sqldb3
+../../modules/http/httpd-stop tmp/sqldb3
+../../components/sqldb/pgsql-stop tmp/sqldb2
+../../modules/http/httpd-stop tmp/sqldb2
+../../components/sqldb/pgsql-stop tmp/sqldb1
+../../modules/http/httpd-stop tmp/sqldb1
+
+../../components/log/scribed-client-stop tmp/monitor
+../../components/log/scribed-central-stop tmp/monitor
+../../components/log/scribe-tail-stop tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cluster/tunnel-ssl-conf b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/tunnel-ssl-conf
new file mode 100755
index 0000000000..7a9a8ad305
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cluster/tunnel-ssl-conf
@@ -0,0 +1,32 @@
+#!/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
+# 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.
+
+root=$1
+port=$2
+sslport=$3
+
+set -x
+
+# Configure an SSL-enabled tunnel server
+../../modules/http/httpd-conf $root sca-store.com $port $root/htdocs
+../../modules/http/httpd-event-conf $root
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C $root -x
+../../modules/http/httpd-ssl-conf $root $sslport
+../../modules/http/cert-auth-conf $root
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/Makefile.am
new file mode 100644
index 0000000000..1a642e583c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/Makefile.am
@@ -0,0 +1,40 @@
+# 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.
+
+
+dist_sample_SCRIPTS = start stop ssl-start
+sampledir = $(prefix)/samples/store-cpp
+
+nobase_dist_sample_DATA = currency-converter.cpp fruits-catalog.cpp shopping-cart.cpp store.composite htdocs/*.html
+
+sample_LTLIBRARIES = libcurrency-converter.la libfruits-catalog.la libshopping-cart.la
+noinst_DATA = libcurrency-converter.so libfruits-catalog.so libshopping-cart.so
+
+libcurrency_converter_la_SOURCES = currency-converter.cpp
+libcurrency-converter.so:
+ ln -s .libs/libcurrency-converter.so
+
+libfruits_catalog_la_SOURCES = fruits-catalog.cpp
+libfruits-catalog.so:
+ ln -s .libs/libfruits-catalog.so
+
+libshopping_cart_la_SOURCES = shopping-cart.cpp
+libshopping-cart.so:
+ ln -s .libs/libshopping-cart.so
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/currency-converter.cpp b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/currency-converter.cpp
new file mode 100644
index 0000000000..5f0702490a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/currency-converter.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Currency converter component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace store {
+
+/**
+ * Convert an amount from USD to a currency.
+ */
+const failable<value> convert(unused const value& from, const value& to, const value& amount) {
+ if (to == string("EUR"))
+ return value(0.70 * (double)amount);
+ return amount;
+}
+
+/**
+ * Return a currency symbol.
+ */
+const failable<value> symbol(const value& currency) {
+ if (currency == string("EUR"))
+ return value(string("E"));
+ return value(string("$"));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "convert")
+ return tuscany::store::convert(cadr(params), caddr(params), cadddr(params));
+ if (func == "symbol")
+ return tuscany::store::symbol(cadr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/fruits-catalog.cpp b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/fruits-catalog.cpp
new file mode 100644
index 0000000000..ce5ebfec6f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/fruits-catalog.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Catalog component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace store {
+
+/**
+ * Returns the catalog.
+ */
+struct convert {
+ const lambda<value(const list<value>&)> converter;
+ const string currency;
+ convert(const lambda<value(const list<value>&)>& converter, const string& currency) : converter(converter), currency(currency) {
+ }
+ const value operator()(const value& price) const {
+ return converter(mklist<value>("convert", string("USD"), currency, price));
+ }
+};
+
+const list<value> mkfruit(const string& name, const string& code, const string& symbol, const double price) {
+ return list<value>() +
+ mklist<value>("name", name) + mklist<value>("currencyCode", code) + mklist<value>("currencySymbol", symbol) + mklist<value>("price", price);
+}
+
+const failable<value> items(const lambda<value(const list<value>&)> converter, const lambda<value(const list<value>&)> currencyCode) {
+ const string currency(currencyCode(list<value>()));
+ const string symbol(converter(mklist<value>("symbol", currency)));
+ const lambda<value(const value&)> conv(convert(converter, currency));
+
+ return value(list<value>() +
+ mkfruit("Apple", currency, symbol, conv(2.99)) +
+ mkfruit("Orange", currency, symbol, conv(3.55)) +
+ mkfruit("Pear", currency, symbol, conv(1.55)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "items")
+ return tuscany::store::items(cadr(params), caddr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/index.html
new file mode 100644
index 0000000000..3945e45bb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-request.txt b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-request.txt
new file mode 100644
index 0000000000..ecf564cb98
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-request.txt
@@ -0,0 +1 @@
+{"id": 1, "method": "items", "params": []}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-result.txt b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-result.txt
new file mode 100644
index 0000000000..56f87d2778
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/items-result.txt
@@ -0,0 +1 @@
+{"id":1,"result":[{"name":"Apple","currencyCode":"USD","currencySymbol":"$","price":2.99},{"name":"Orange","currencyCode":"USD","currencySymbol":"$","price":3.55},{"name":"Pear","currencyCode":"USD","currencySymbol":"$","price":1.55}]} \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/shopping-cart-entry.xml b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/shopping-cart-entry.xml
new file mode 100644
index 0000000000..25a284294c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/htdocs/test/shopping-cart-entry.xml
@@ -0,0 +1 @@
+<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml"><item><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content></entry>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/server-test
new file mode 100755
index 0000000000..e0d8716449
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/shopping-cart.cpp b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/shopping-cart.cpp
new file mode 100644
index 0000000000..738ab2f4c7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/shopping-cart.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Shopping cart component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace store {
+
+const string cartId("1234");
+
+/**
+ * Get the shopping cart from the cache. Return an empty
+ * cart if not found.
+ */
+const list<value> getcart(const value& id, const lambda<value(const list<value>&)> cache) {
+ const value cart = cache(mklist<value>("get", mklist<value>(id)));
+ cerr << "cart value: " << cart << "\n";
+ const failable<value> fcart = cart;
+ cerr << "cart fvalue: " << fcart << "\n";
+ cerr << "cart content: " << content(fcart) << "\n";
+ cerr << "cart reason: " << reason(fcart) << "\n";
+ if (isNil(cart))
+ return value(list<value>());
+ return (list<value>)cart;
+}
+
+/**
+ * Post a new item to the cart. Create a new cart if necessary.
+ */
+const failable<value> post(unused const list<value>& collection, const value& item, const lambda<value(const list<value>&)> cache) {
+ const value id(mkuuid());
+ const list<value> newItem(mklist<value>(car<value>(item), id, caddr<value>(item)));
+ const list<value> cart(cons<value>(newItem, getcart(cartId, cache)));
+ cache(mklist<value>("put", mklist<value>(cartId), cart));
+ return value(mklist<value>(id));
+}
+
+/**
+ * Find an item in the cart.
+ */
+const value find(const value& id, const list<value>& cart) {
+ if (isNil(cart))
+ return cons<value>(string("Item"), mklist<value>("0", list<value>()));
+ if (id == cadr<value>(car(cart)))
+ return car(cart);
+ return find(id, cdr(cart));
+}
+
+/**
+ * Return items from the cart.
+ */
+const failable<value> get(const list<value>& id, const lambda<value(const list<value>&)> cache) {
+ if (isNil(id))
+ return value(append(mklist<value>(string("Your Cart"), cartId), getcart(cartId, cache)));
+ return find(car(id), getcart(cartId, cache));
+}
+
+/**
+ * Delete items from the cart.
+ */
+const failable<value> del(const list<value>& id, unused const lambda<value(const list<value>&)> cache) {
+ if (isNil(id))
+ return cache(mklist<value>("delete", mklist<value>(cartId)));
+ return value(true);
+}
+
+/**
+ * Return the price of an item.
+ */
+const double price(const list<value>& item) {
+ return cadr<value>(assoc<value>("price", caddr(item)));
+}
+
+/**
+ * Sum the prices of a list of items.
+ */
+const double sum(const list<value>& items) {
+ if (isNil(items))
+ return 0;
+ return price(car(items)) + sum(cdr(items));
+}
+
+/**
+ * Return the total price of the items in the cart.
+ */
+const failable<value> total(const lambda<value(const list<value>&)> cache) {
+ const list<value> cart(getcart(cartId, cache));
+ return value(sum(cart));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return tuscany::store::post(cadr(params), caddr(params), cadddr(params));
+ if (func == "get")
+ return tuscany::store::get(cadr(params), caddr(params));
+ if (func == "delete")
+ return tuscany::store::del(cadr(params), caddr(params));
+ if (func == "total")
+ return tuscany::store::total(cadr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/ssl-start
new file mode 100755
index 0000000000..01ee0eb76c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/ssl-start
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/basic-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/server/cpp-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/start b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/start
new file mode 100755
index 0000000000..7b9c0d6379
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/start
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/server/cpp-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/stop b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/stop
new file mode 100755
index 0000000000..a59273b8ed
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/stop
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-cpp/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/store.composite
new file mode 100644
index 0000000000..8b5edede99
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-cpp/store.composite
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.widget location="store.html"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <implementation.cpp path="." library="libfruits-catalog"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <implementation.cpp path="." library="libshopping-cart"/>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <implementation.cpp path="." library="libcurrency-converter"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.cpp path="../../components/cache" library="libmemcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-gae/Makefile.am
new file mode 100644
index 0000000000..09d5b516cf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/Makefile.am
@@ -0,0 +1,44 @@
+# 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.
+
+if WANT_PYTHON
+if WANT_GAE
+
+dist_sample_SCRIPTS = start stop
+sampledir = $(prefix)/samples/store-gae
+
+BUILT_SOURCES = target.stamp
+target.stamp: app.yaml *.py *.composite $(top_builddir)/modules/wsgi/*.py htdocs/* $(top_builddir)/modules/js/htdocs/*
+ mkdir -p target
+ cp app.yaml *.py *.composite `ls $(top_builddir)/modules/wsgi/*.py | grep -v "\-test"` target
+ mkdir -p target/htdocs
+ cp -R htdocs/* target/htdocs
+ cp -R $(top_builddir)/modules/js/htdocs/* target/htdocs
+ touch target.stamp
+
+clean-local:
+ rm -rf target.stamp target
+
+nobase_sample_DATA = target/app.yaml target/*.py target/*.composite target/htdocs/*.html target/htdocs/*.js
+
+EXTRA_DIST = app.yaml *.composite *.py htdocs/*.html
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
+
+endif
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/app.yaml b/sandbox/sebastien/cpp/apr-2/samples/store-gae/app.yaml
new file mode 100644
index 0000000000..6a4e6a2fab
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/app.yaml
@@ -0,0 +1,54 @@
+# 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.
+
+application: sca-store
+version: 1
+runtime: python
+api_version: 1
+skip_files:
+- ^(.*/)?app\.yaml
+- ^(.*/)?app\.yml
+- ^(.*/)?index\.yaml
+- ^(.*/)?index\.yml
+- ^(.*/)?#.*#
+- ^(.*/)?.*~
+- ^(.*/)?.*\.py[co]
+- ^(.*/)?.*/RCS/.*
+- ^(.*/)?\..*
+- ^(.*/)?.*-test$
+- ^(.*/)?.*\.cpp$
+- ^(.*/)?.*\.o$
+- ^(.*/)?core$
+- ^(.*/)?.*\.out$
+- ^(.*/)?.*\.log$
+- ^(.*/)?Makefile.*
+- ^(.*/)?tmp/.*
+- ^(.*/)?wsgi-start
+- ^(.*/)?wsgi-stop
+
+handlers:
+- url: /(.*\.(html|png))
+ static_files: htdocs/\1
+ upload: htdocs/(.*\.(html|png))
+ secure: always
+ login: required
+
+- url: /.*
+ script: composite.py
+ secure: always
+ login: required
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/currency-converter.py b/sandbox/sebastien/cpp/apr-2/samples/store-gae/currency-converter.py
new file mode 100644
index 0000000000..2fded8f616
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/currency-converter.py
@@ -0,0 +1,29 @@
+# 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.
+
+# Currency converter implementation
+
+def convert(fr, to, amount):
+ if to == "EUR":
+ return amount * 0.70
+ return amount
+
+def symbol(currency):
+ if currency == "EUR":
+ return "E"
+ return "$"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-backend.composite b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-backend.composite
new file mode 100644
index 0000000000..a543b9a6b5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-backend.composite
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store-backend">
+
+ <component name="Cache">
+ <implementation.python script="gmemcache.py"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-frontend.composite b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-frontend.composite
new file mode 100644
index 0000000000..e7e10e2de1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-frontend.composite
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store-frontend">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <service name="Cart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache">
+ <t:binding.http uri="https://sca-store-backend.appspot.com/cache"/>
+ </reference>
+ <property name="host">localhost</property>
+ <property name="email">anonymous@example.com</property>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-single.composite b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-single.composite
new file mode 100644
index 0000000000..4a5d53e695
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain-single.composite
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <service name="Cart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ <property name="host">localhost</property>
+ <property name="email">anonymous@example.com</property>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.python script="gmemcache.py"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain.composite b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain.composite
new file mode 100644
index 0000000000..4a5d53e695
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/domain.composite
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <service name="Cart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ <property name="host">localhost</property>
+ <property name="email">anonymous@example.com</property>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.python script="gmemcache.py"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/fruits-catalog.py b/sandbox/sebastien/cpp/apr-2/samples/store-gae/fruits-catalog.py
new file mode 100644
index 0000000000..4b2baca2ff
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/fruits-catalog.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Catalog implementation
+
+def items(converter, currencyCode):
+ code = currencyCode.eval()
+ def convert(price):
+ return converter.convert("USD", code, price)
+ symbol = converter.symbol(code)
+ return (
+ (("'name", "Platano"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
+ (("'name", "Banana"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
+ (("'name", "Guanabana"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
+ )
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/gmemcache.py b/sandbox/sebastien/cpp/apr-2/samples/store-gae/gmemcache.py
new file mode 100644
index 0000000000..61f1dc3486
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/gmemcache.py
@@ -0,0 +1,45 @@
+# 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.
+
+# Google AppEngine Memcached based cache implementation
+import uuid
+from google.appengine.api import memcache
+
+# Post a new item to the cache
+def post(collection, item):
+ id = collection + (str(uuid.uuid1()),)
+ r = memcache.add(repr(id), item, 600)
+ if r == False:
+ return None
+ return id
+
+# Get items from the cache
+def get(id):
+ item = memcache.get(repr(id))
+ return item
+
+# Update an item in the cache
+def put(id, item):
+ return memcache.set(repr(id), item, 600)
+
+# Delete items from the cache
+def delete(id):
+ r = memcache.delete(repr(id))
+ if r != 2:
+ return False
+ return True
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/index.html
new file mode 100644
index 0000000000..a38a8a0e4f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/index.html
@@ -0,0 +1,169 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.defun(sca.reference(store, "shoppingCart"), "email", "host");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+}
+
+function shoppingCart_hostResponse(host, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('host').innerHTML = host;
+}
+
+function shoppingCart_emailResponse(email, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('email').innerHTML = email;
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total,exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.email(shoppingCart_emailResponse);
+ shoppingCart.host(shoppingCart_hostResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<p>Welcome to: <span id="host"></span>, you're signed in as: <span id="email"></span><br/><a href="/logout">Sign out</a></p>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/test/items-result.txt b/sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/test/items-result.txt
new file mode 100644
index 0000000000..bbc07e8917
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/htdocs/test/items-result.txt
@@ -0,0 +1 @@
+{"id":1,"result":[{"price":2.9900000000000002,"currencyCode":"USD","name":"Platano","currencySymbol":"$"},{"price":3.5499999999999998,"currencyCode":"USD","name":"Banana","currencySymbol":"$"},{"price":1.55,"currencyCode":"USD","name":"Guanabana","currencySymbol":"$"}]} \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/htpasswd.py b/sandbox/sebastien/cpp/apr-2/samples/store-gae/htpasswd.py
new file mode 100644
index 0000000000..75d94f58b6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/htpasswd.py
@@ -0,0 +1,21 @@
+# 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.
+
+# Configure the user and password used for HTTP basic authentication
+user = "foo"
+passwd = "foo"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-gae/server-test
new file mode 100755
index 0000000000..4d42e9a5f5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/server-test
@@ -0,0 +1,59 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start 2>/dev/null
+sleep 2
+
+# Test HTTP GET (with authentication)
+mkdir -p tmp
+$curl_prefix/bin/curl -L -c tmp/cookies.txt -b tmp/cookies.txt "http://localhost:8090/_ah/login?email=test@example.com&action=Login&continue=http://localhost:8090/" 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl -b tmp/cookies.txt http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl -b tmp/cookies.txt http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl -b tmp/cookies.txt http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/shopping-cart.py b/sandbox/sebastien/cpp/apr-2/samples/store-gae/shopping-cart.py
new file mode 100644
index 0000000000..3c3168d77b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/shopping-cart.py
@@ -0,0 +1,82 @@
+# 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.
+
+# Shopping cart implementation
+import uuid
+import sys
+
+cartId = "1234"
+
+# Get the shopping cart from the cache
+# Return an empty cart if not found
+def getcart(id, cache):
+ cart = cache.get((id,))
+ if cart is None:
+ return ()
+ return cart
+
+# Post a new item to the cart, create a new cart if necessary
+def post(collection, item, cache, host, email):
+ id = str(uuid.uuid1())
+ cart = ((item[0], id, item[2]),) + getcart(cartId, cache)
+ cache.put((cartId,), cart)
+ return (id,)
+
+# Find an item in the cart
+def find(id, cart):
+ if cart == ():
+ return ("Item", "0", ())
+ elif id == cart[0][1]:
+ return cart[0]
+ else:
+ return find(id, cart[1:])
+
+# Get items from the cart
+def get(id, cache, host, email):
+ if id == ():
+ return ("Your Cart", cartId) + getcart(cartId, cache)
+ return find(id[0], getcart(cartId, cache))
+
+# Delete items from the cart
+def delete(id, cache, host, email):
+ if id == ():
+ return cache.delete((cartId,))
+ return True
+
+# Return the price of an item
+def price(item):
+ return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
+
+# Sum the prices of a list of items
+def sum(items):
+ if items == ():
+ return 0
+ return price(items[0]) + sum(items[1:])
+
+# Return the total price of the items in the cart
+def total(cache, host, email):
+ cart = getcart(cartId, cache)
+ return sum(cart)
+
+# Return the email of the cart owner
+def email(cache, host, email_):
+ return email_.eval()
+
+# Return the host that the app is running on
+def host(cache, host_, email):
+ return host_.eval()
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/start b/sandbox/sebastien/cpp/apr-2/samples/store-gae/start
new file mode 100755
index 0000000000..3c9644e656
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/start
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/wsgi/gae-start target 8090
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/stop b/sandbox/sebastien/cpp/apr-2/samples/store-gae/stop
new file mode 100755
index 0000000000..7c8a7e5551
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/stop
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/wsgi/gae-stop target 8090
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-gae/store.py b/sandbox/sebastien/cpp/apr-2/samples/store-gae/store.py
new file mode 100644
index 0000000000..ff82f1d327
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-gae/store.py
@@ -0,0 +1,40 @@
+# 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.
+
+# Store implementation
+
+def post(item, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.post(item)
+
+def getall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.getall()
+
+def get(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.get(id)
+
+def items(catalog, shoppingCart, shoppingTotal):
+ return catalog.items()
+
+def total(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.total()
+
+def deleteall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.deleteall()
+
+def delete(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.delete(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-java/Makefile.am
new file mode 100644
index 0000000000..f32ae72812
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/Makefile.am
@@ -0,0 +1,34 @@
+# 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.
+
+JAVAROOT = ${top_builddir}/samples/store-java
+
+if WANT_JAVA
+
+dist_sample_SCRIPTS = start stop ssl-start
+sampledir=$(prefix)/samples/store-java
+
+AM_JAVACFLAGS = -cp ${top_builddir}/modules/java/libmod-tuscany-java-${PACKAGE_VERSION}.jar:${JAVAROOT}
+dist_sample_JAVA = store/*.java
+CLEANFILES = *.stamp store/*.class
+
+nobase_dist_sample_DATA = store.composite htdocs/*.html store/*.*
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-java/htdocs/index.html
new file mode 100644
index 0000000000..3945e45bb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/htdocs/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-java/server-test
new file mode 100755
index 0000000000..1612bc59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-java/ssl-start
new file mode 100755
index 0000000000..3d4642dea6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/ssl-start
@@ -0,0 +1,38 @@
+#!/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
+# 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.
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/basic-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/java/java-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+export CLASSPATH=`pwd`/../../modules/java/libmod-tuscany-java-1.0.jar:`pwd`
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/start b/sandbox/sebastien/cpp/apr-2/samples/store-java/start
new file mode 100755
index 0000000000..c8146e9e46
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/start
@@ -0,0 +1,33 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/java/java-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+export CLASSPATH=`pwd`/../../modules/java/libmod-tuscany-java-1.0.jar:`pwd`
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/stop b/sandbox/sebastien/cpp/apr-2/samples/store-java/stop
new file mode 100755
index 0000000000..79d914e937
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/stop
@@ -0,0 +1,23 @@
+#!/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
+# 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.
+
+export CLASSPATH=`pwd`/../../modules/java/libmod-tuscany-java-1.0.jar:`pwd`
+
+../../modules/http/httpd-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-java/store.composite
new file mode 100644
index 0000000000..4b0db9d05c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/store.composite
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.widget location="store.html"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <implementation.java class="store.FruitsCatalogImpl"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <implementation.java class="store.ShoppingCartImpl"/>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <implementation.java class="store.CurrencyConverterImpl"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.cpp path="../../components/cache" library="libmemcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverter.java b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverter.java
new file mode 100644
index 0000000000..1ed15a670a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverter.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package store;
+
+public interface CurrencyConverter {
+
+ Double convert(String from, String to, Double amount);
+
+ String symbol(String currency);
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverterImpl.java b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverterImpl.java
new file mode 100644
index 0000000000..a6d0fd00b3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/CurrencyConverterImpl.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package store;
+
+/**
+ * Currency converter component implementation.
+ */
+public class CurrencyConverterImpl {
+
+ /**
+ * Convert an amount from USD to a currency.
+ */
+ public Double convert(String from, String to, Double amount) {
+ if ("EUR".equals(to))
+ return amount * 0.70;
+ return amount;
+ }
+
+ /**
+ * Return a currency symbol.
+ */
+ public String symbol(String currency) {
+ if ("EUR".equals(currency))
+ return "E";
+ return "$";
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/store/FruitsCatalogImpl.java b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/FruitsCatalogImpl.java
new file mode 100644
index 0000000000..8881543103
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/FruitsCatalogImpl.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package store;
+
+import static org.apache.tuscany.IterableUtil.*;
+
+import org.apache.tuscany.Service;
+
+/**
+ * Catalog component implementation.
+ */
+public class FruitsCatalogImpl {
+
+ /**
+ * Returns the catalog.
+ */
+ public Iterable<?> items(final CurrencyConverter converter, final Service currencyCode) {
+ final String code = currencyCode.eval();
+
+ class Converter {
+ Double convert(final Double price) {
+ return converter.convert(code, "USD", price);
+ }
+ }
+
+ final Converter c = new Converter();
+ final String symbol = converter.symbol(code);
+
+ return list(list(list("'name", "Apple"), list("'currencyCode", code), list("'currencySymbol", symbol), list("'price", c.convert(2.99))),
+ list(list("'name", "Orange"), list("'currencyCode", code), list("'currencySymbol", symbol), list("'price", c.convert(3.55))),
+ list(list("'name", "Pear"), list("'currencyCode", code), list("'currencySymbol", symbol), list("'price", c.convert(1.55))));
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-java/store/ShoppingCartImpl.java b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/ShoppingCartImpl.java
new file mode 100644
index 0000000000..e51beacc20
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-java/store/ShoppingCartImpl.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+package store;
+
+import static org.apache.tuscany.IterableUtil.*;
+import static org.apache.tuscany.UUIDUtil.*;
+
+import org.apache.tuscany.Service;
+
+/**
+ * Shopping cart component implementation.
+ */
+public class ShoppingCartImpl {
+
+ static String cartId = "1234";
+
+ /**
+ * Get the shopping cart from the cache. Return an empty cart if not found.
+ */
+ public Iterable<?> getcart(final String id, final Service cache) {
+ final Iterable<String> iid = list(id);
+ final Iterable<?> cart = cache.get(iid);
+ if(cart == null)
+ return list();
+ return cart;
+ }
+
+ /**
+ * Post a new item to the cart. Create a new cart if necessary.
+ */
+ public Iterable<String> post(final Iterable<String> collection, final Iterable<?> item, final Service cache) {
+ final String id = uuid();
+ final Iterable<?> newItem = list(car(item), id, caddr(item));
+ final Iterable<?> cart = cons(newItem, this.getcart(cartId, cache));
+ final Iterable<String> iid = list(cartId);
+ cache.put(iid, cart);
+ return list(id);
+ }
+
+ /**
+ * Find an item in the cart.
+ */
+ Iterable<?> find(final String id, final Iterable<?> cart) {
+ if(isNil(cart))
+ return cons("Item", list("0", list()));
+ if(id.equals(cadr(car(cart))))
+ return car(cart);
+ return this.find(id, cdr(cart));
+ }
+
+ /**
+ * Return items from the cart.
+ */
+ public Iterable<?> get(final Iterable<String> id, final Service cache) {
+ if(isNil(id))
+ return cons("Your Cart", cons(cartId, this.getcart(cartId, cache)));
+ return this.find((String)car(id), this.getcart(cartId, cache));
+ }
+
+ /**
+ * Delete items from the cart.
+ */
+ public Boolean delete(final Iterable<String> id, final Service cache) {
+ if(isNil(id)) {
+ final Iterable<String> iid = list(cartId);
+ return cache.delete(iid);
+ }
+ return true;
+ }
+
+ /**
+ * Return the price of an item.
+ */
+ Double price(final Iterable<?> item) {
+ return Double.valueOf((String)cadr(assoc("'price", caddr(item))));
+ }
+
+ /**
+ * Sum the prices of a list of items.
+ */
+ Double sum(final Iterable<?> items) {
+ if(isNil(items))
+ return 0.0;
+ return this.price((Iterable<?>)car(items)) + this.sum(cdr(items));
+ }
+
+ /**
+ * Return the total price of the items in the cart.
+ */
+ public Double total(final Service cache) {
+ final Iterable<?> cart = this.getcart(cartId, cache);
+ return this.sum(cart);
+ }
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/Makefile.am
new file mode 100644
index 0000000000..e69d8a164f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/Makefile.am
@@ -0,0 +1,25 @@
+# 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.
+
+dist_sample_SCRIPTS = start stop ssl-start
+sampledir = $(prefix)/samples/store-nosql
+
+nobase_dist_sample_DATA = currency-converter.scm fruits-catalog.scm shopping-cart.scm store.scm store.composite htdocs/*.html
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/currency-converter.scm b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/currency-converter.scm
new file mode 100644
index 0000000000..fc506c3d73
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/currency-converter.scm
@@ -0,0 +1,27 @@
+; 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.
+
+; Currency converter implementation
+
+(define (convert from to amount)
+ (if (equal? to "EUR") (* amount 0.70) amount)
+)
+
+(define (symbol currency)
+ (if (equal? currency "EUR") "E" "$")
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/fruits-catalog.scm b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/fruits-catalog.scm
new file mode 100644
index 0000000000..d55394b96a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/fruits-catalog.scm
@@ -0,0 +1,30 @@
+; 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.
+
+; Catalog implementation
+
+(define (items converter currencyCode)
+ (define code (currencyCode))
+ (define (convert price) (converter "convert" "USD" code price))
+ (define symbol (converter "symbol" code))
+ (list
+ (list (list 'name "Apple") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 2.99)))
+ (list (list 'name "Orange") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 3.55)))
+ (list (list 'name "Pear") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 1.55)))
+ )
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/htdocs/index.html
new file mode 100644
index 0000000000..3945e45bb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/htdocs/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/server-test
new file mode 100755
index 0000000000..1612bc59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/shopping-cart.scm b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/shopping-cart.scm
new file mode 100644
index 0000000000..61b169426f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/shopping-cart.scm
@@ -0,0 +1,82 @@
+; 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.
+
+; Shopping cart implementation
+
+(define cartId "1234")
+
+; Get the shopping cart from the cache
+; Return an empty cart if not found
+(define (getcart id cache)
+ (define cart (cache "get" (list id)))
+ (if (nul cart)
+ (list)
+ cart)
+)
+
+; Post a new item to the cart, create a new cart if necessary
+(define (post collection item cache)
+ (define id (uuid))
+ (define newItem (list (car item) id (caddr item)))
+ (define cart (cons newItem (getcart cartId cache)))
+ (cache "put" (list cartId) cart)
+ (list id)
+)
+
+; Find an item in the cart
+(define (find id cart)
+ (if (nul cart)
+ (cons "Item" (list "0" (list)))
+ (if (= id (cadr (car cart)))
+ (car cart)
+ (find id (cdr cart))))
+)
+
+; Get items from the cart
+(define (get id cache)
+ (if (nul id)
+ (cons "Your Cart" (cons cartId (getcart cartId cache)))
+ (find (car id) (getcart cartId cache))
+ )
+)
+
+; Delete items from the cart
+(define (delete id cache)
+ (if (nul id)
+ (cache "delete" (list cartId))
+ true
+ )
+)
+
+; Return the price of an item
+(define (price item)
+ (cadr (assoc 'price (caddr item)))
+)
+
+; Sum the prices of a list of items
+(define (sum items)
+ (if (nul items)
+ 0
+ (+ (price (car items)) (sum (cdr items))))
+)
+
+; Return the total price of the items in the cart
+(define (total cache)
+ (define cart (getcart cartId cache))
+ (sum cart)
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/ssl-start
new file mode 100755
index 0000000000..c536e9b3f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/ssl-start
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/basic-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/nosqldb/tinycdb -c -m tmp/store.cdb </dev/null
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/start b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/start
new file mode 100755
index 0000000000..79da4682b2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/start
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/nosqldb/tinycdb -c -m tmp/store.cdb </dev/null
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/stop b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/stop
new file mode 100755
index 0000000000..3b4f46694d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/stop
@@ -0,0 +1,20 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.composite
new file mode 100644
index 0000000000..90e4323318
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.composite
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.scheme script="store.scm"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.scheme script="fruits-catalog.scm"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.scheme script="shopping-cart.scm"/>
+ <service name="Cart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="NoSqldb"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.scheme script="currency-converter.scm"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="NoSqldb">
+ <implementation.cpp path="../../components/nosqldb" library="libnosqldb"/>
+ <property name="dbname">tmp/store.cdb</property>
+ <service name="NoSqldb">
+ <t:binding.atom uri="nosqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.scm b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.scm
new file mode 100644
index 0000000000..f54257343e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-nosql/store.scm
@@ -0,0 +1,47 @@
+; 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.
+
+; Store implementation
+
+(define (post item catalog shoppingCart shoppingTotal)
+ (shoppingCart "post" item)
+)
+
+(define (getall catalog shoppingCart shoppingTotal)
+ (shoppingCart "getall")
+)
+
+(define (get id catalog shoppingCart shoppingTotal)
+ (shoppingCart "get" id)
+)
+
+(define (items catalog shoppingCart shoppingTotal)
+ (catalog "items")
+)
+
+(define (total catalog shoppingCart shoppingTotal)
+ (shoppingCart "total")
+)
+
+(define (deleteall catalog shoppingCart shoppingTotal)
+ (shoppingCart "deleteall")
+)
+
+(define (delete id catalog shoppingCart shoppingTotal)
+ (shoppingCart "delete" id)
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-python/Makefile.am
new file mode 100644
index 0000000000..8db150cc0e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/Makefile.am
@@ -0,0 +1,28 @@
+# 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.
+
+if WANT_PYTHON
+
+dist_sample_SCRIPTS = start stop ssl-start uec2-start
+sampledir = $(prefix)/samples/store-python
+
+nobase_dist_sample_DATA = currency-converter.py fruits-catalog.py shopping-cart.py store.py store.composite htdocs/*.html htdocs/login/*.html htdocs/logout/*.html
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/currency-converter.py b/sandbox/sebastien/cpp/apr-2/samples/store-python/currency-converter.py
new file mode 100644
index 0000000000..2fded8f616
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/currency-converter.py
@@ -0,0 +1,29 @@
+# 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.
+
+# Currency converter implementation
+
+def convert(fr, to, amount):
+ if to == "EUR":
+ return amount * 0.70
+ return amount
+
+def symbol(currency):
+ if currency == "EUR":
+ return "E"
+ return "$"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/fruits-catalog.py b/sandbox/sebastien/cpp/apr-2/samples/store-python/fruits-catalog.py
new file mode 100644
index 0000000000..8289afcac5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/fruits-catalog.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Catalog implementation
+
+def items(converter, currencyCode):
+ code = currencyCode.eval()
+ def convert(price):
+ return converter.convert("USD", code, price)
+ symbol = converter.symbol(code)
+ return (
+ (("'name", "Mango"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
+ (("'name", "Passion"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
+ (("'name", "Kiwi"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
+ )
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/index.html
new file mode 100644
index 0000000000..3945e45bb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/login/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/login/index.html
new file mode 100644
index 0000000000..3f312e4ca4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/login/index.html
@@ -0,0 +1,40 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in</h1>
+
+<script type="text/javascript">
+function submitFormSignin() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.formSignin.httpd_location.value = '/';
+ document.formSignin.submit();
+}
+</script>
+
+<form name="formSignin" method="POST" action="/login/dologin">
+<table border="0">
+<tr><td>Username:</td><td><input type="text" name="httpd_username" value=""/></td></tr>
+<tr><td>Password:</td><td><input type="password" name="httpd_password" value=""/></td></tr>
+<tr><td><input type="button" onclick="submitFormSignin()" value="Sign in"/></td><td></td></tr>
+</table>
+<input type="hidden" name="httpd_location" value="/"/>
+</form>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/logout/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/logout/index.html
new file mode 100644
index 0000000000..1ac6e39a1c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyFormAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/test/items-result.txt b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/test/items-result.txt
new file mode 100644
index 0000000000..788b7cdf89
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/htdocs/test/items-result.txt
@@ -0,0 +1 @@
+{"id":1,"result":[{"name":"Mango","currencyCode":"USD","currencySymbol":"$","price":2.99},{"name":"Passion","currencyCode":"USD","currencySymbol":"$","price":3.55},{"name":"Kiwi","currencyCode":"USD","currencySymbol":"$","price":1.55}]} \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-python/server-test
new file mode 100755
index 0000000000..27490c580b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/shopping-cart.py b/sandbox/sebastien/cpp/apr-2/samples/store-python/shopping-cart.py
new file mode 100644
index 0000000000..feb7398ed9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/shopping-cart.py
@@ -0,0 +1,75 @@
+# 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.
+
+# Shopping cart implementation
+import uuid
+import sys
+
+cartId = "1234"
+
+# Get the shopping cart from the cache
+# Return an empty cart if not found
+def getcart(id, cache):
+ cart = cache.get((id,))
+ if cart is None:
+ return ()
+ return cart
+
+# Post a new item to the cart, create a new cart if necessary
+def post(collection, item, cache):
+ id = str(uuid.uuid1())
+ cart = ((item[0], id, item[2]),) + getcart(cartId, cache)
+ cache.put((cartId,), cart)
+ return (id,)
+
+
+# Find an item in the cart
+def find(id, cart):
+ if cart == ():
+ return ("Item", "0", ())
+ elif id == cart[0][1]:
+ return cart[0]
+ else:
+ return find(id, cart[1:])
+
+# Get items from the cart
+def get(id, cache):
+ if id == ():
+ return ("Your Cart", cartId) + getcart(cartId, cache)
+ return find(id[0], getcart(cartId, cache))
+
+# Delete items from the cart
+def delete(id, cache):
+ if id == ():
+ return cache.delete((cartId,))
+ return True
+
+# Return the price of an item
+def price(item):
+ return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
+
+# Sum the prices of a list of items
+def sum(items):
+ if items == ():
+ return 0
+ return price(items[0]) + sum(items[1:])
+
+# Return the total price of the items in the cart
+def total(cache):
+ cart = getcart(cartId, cache)
+ return sum(cart)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-python/ssl-start
new file mode 100755
index 0000000000..60b9bb5ace
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/ssl-start
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/open-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/start b/sandbox/sebastien/cpp/apr-2/samples/store-python/start
new file mode 100755
index 0000000000..8df7875634
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/start
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/stop b/sandbox/sebastien/cpp/apr-2/samples/store-python/stop
new file mode 100755
index 0000000000..a59273b8ed
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/stop
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-python/store.composite
new file mode 100644
index 0000000000..912898123b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/store.composite
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.cpp path="../../components/cache" library="libmemcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/store.py b/sandbox/sebastien/cpp/apr-2/samples/store-python/store.py
new file mode 100644
index 0000000000..b71f505dd1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/store.py
@@ -0,0 +1,40 @@
+# 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.
+
+# Store implementation
+
+def post(item, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.post(item)
+
+def getall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.getall()
+
+def get(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.get(id)
+
+def items(catalog, shoppingCart, shoppingTotal):
+ return catalog.items()
+
+def total(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.gettotal()
+
+def deleteall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.deleteall()
+
+def delete(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.delete(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-python/uec2-start b/sandbox/sebastien/cpp/apr-2/samples/store-python/uec2-start
new file mode 100755
index 0000000000..84c170e596
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-python/uec2-start
@@ -0,0 +1,46 @@
+#!/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
+# 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.
+
+# Pass your EC2 public host name
+if [ "$1" != "" ]; then
+ host=$1
+else
+ host="localhost"
+fi
+
+# Ports 80, 443, 444, 8090, 8453, 8454 need to be open
+sudo ../../ubuntu/ip-redirect-all 80 8090
+sudo ../../ubuntu/ip-redirect-all 443 8453
+
+../../modules/http/ssl-ca-conf tmp $host
+../../modules/http/ssl-cert-conf tmp $host
+../../modules/http/httpd-conf tmp $host 8090/80 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453/443
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/Makefile.am
new file mode 100644
index 0000000000..2330d45422
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/Makefile.am
@@ -0,0 +1,30 @@
+# 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.
+
+dist_sample_SCRIPTS = start stop ssl-start
+sampledir = $(prefix)/samples/store-scheme
+
+nobase_dist_sample_DATA = currency-converter.scm fruits-catalog.scm shopping-cart.scm store.scm store.composite htdocs/*.html
+
+EXTRA_DIST = script-test.scm
+
+dist_noinst_SCRIPTS = server-test
+noinst_PROGRAMS = script-test
+script_test_SOURCES = script-test.cpp
+script_test_LDFLAGS = -lxml2 -lmozjs
+
+TESTS = script-test server-test
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/currency-converter.scm b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/currency-converter.scm
new file mode 100644
index 0000000000..fc506c3d73
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/currency-converter.scm
@@ -0,0 +1,27 @@
+; 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.
+
+; Currency converter implementation
+
+(define (convert from to amount)
+ (if (equal? to "EUR") (* amount 0.70) amount)
+)
+
+(define (symbol currency)
+ (if (equal? currency "EUR") "E" "$")
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/fruits-catalog.scm b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/fruits-catalog.scm
new file mode 100644
index 0000000000..d55394b96a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/fruits-catalog.scm
@@ -0,0 +1,30 @@
+; 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.
+
+; Catalog implementation
+
+(define (items converter currencyCode)
+ (define code (currencyCode))
+ (define (convert price) (converter "convert" "USD" code price))
+ (define symbol (converter "symbol" code))
+ (list
+ (list (list 'name "Apple") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 2.99)))
+ (list (list 'name "Orange") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 3.55)))
+ (list (list 'name "Pear") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 1.55)))
+ )
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/htdocs/index.html
new file mode 100644
index 0000000000..3945e45bb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/htdocs/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.cpp b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.cpp
new file mode 100644
index 0000000000..0d5a9ccf9d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Store Test case.
+ */
+
+#include <assert.h>
+#include <regex.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "xml.hpp"
+#include "../../modules/scheme/driver.hpp"
+#include "../../modules/json/json.hpp"
+
+namespace store {
+
+using namespace tuscany;
+
+bool testScript() {
+ gc_scoped_pool pool;
+
+ ifstream is("script-test.scm");
+ ostringstream os;
+ scheme::evalDriverRun(is, os);
+ assert(contains(str(os), "(\"Sample Feed\" \""));
+ assert(contains(str(os), "\" (\"Item\" \""));
+ assert(contains(str(os), "\" ((name \"Orange\") (currencyCode \"USD\") (currencySymbol \"$\") (price 3.55))) (\"Item\" \""));
+ assert(contains(str(os), "\" ((name \"Apple\") (currencyCode \"USD\") (currencySymbol \"$\") (price 2.99))))"));
+ return true;
+}
+
+bool testEval() {
+ {
+ gc_scoped_pool pool;
+ ifstream is("script-test.scm");
+ ostringstream os;
+ scheme::setupDisplay(os);
+ scheme::Env globalEnv = scheme::setupEnvironment();
+ const value exp(mklist<value>("storeui_service", string("items")));
+ const value val = scheme::evalScript(exp, is, globalEnv);
+
+ ostringstream vs;
+ vs << val;
+ assert(contains(str(vs), "(((name \"Apple\") (currencyCode \"USD\") (currencySymbol \"$\") (price 2.99)) ((name \"Orange\") (currencyCode \"USD\") (currencySymbol \"$\") (price 3.55)) ((name \"Pear\") (currencyCode \"USD\") (currencySymbol \"$\") (price 1.55)))"));
+ }
+
+ {
+ gc_scoped_pool pool;
+ ifstream is("script-test.scm");
+ ostringstream os;
+ scheme::setupDisplay(os);
+
+ scheme::Env globalEnv = scheme::setupEnvironment();
+ const value exp(mklist<value>("storeui_service", string("total")));
+ const value res = scheme::evalScript(exp, is, globalEnv);
+
+ ostringstream rs;
+ rs << res;
+ assert(contains(str(rs), "10"));
+ }
+ return true;
+}
+
+}
+
+int main() {
+
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ store::testScript();
+ store::testEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.scm b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.scm
new file mode 100644
index 0000000000..50b587b8f1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/script-test.scm
@@ -0,0 +1,140 @@
+; 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.
+
+; Currency implementation
+
+(define (currency_convert from to amount)
+ (if (equal? to "EUR") (* amount 0.70) amount)
+)
+
+(define (currency_symbol currency)
+ (if (equal? currency "EUR") "E" "$")
+)
+
+(define (currency_impl op args)
+ (cond
+ ((equal? op "convert") (apply currency_convert args))
+ ((equal? op "symbol") (apply currency_symbol args))
+ )
+)
+
+; Currency composite
+
+(define (currency_service op . args) (currency_impl op args))
+
+; Catalog implementation
+
+(define (catalog_get converter)
+ (define (convert price) (converter "convert" "USD" "USD" price))
+
+ (define code "USD")
+ (define symbol (converter "symbol" code))
+
+ (list
+ (list (list 'name "Apple") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price 2.99))
+ (list (list 'name "Orange") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price 3.55))
+ (list (list 'name "Pear") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price 1.55))
+ )
+)
+
+(define (catalog_impl converter op args)
+ (cond
+ ((equal? op "items") (apply catalog_get (cons converter args)))
+ )
+)
+
+; Catalog composite
+
+(define (catalog_service op . args) (catalog_impl currency_service op args))
+
+; Cart implementation
+
+(define (cart_post content item)
+ (cons (cons "Item" (list (uuid) item)) content)
+)
+
+(define (cart_getall content)
+ (cons "Sample Feed" (cons (uuid) content))
+)
+
+(define (cart_getentry id)
+ (define entry (list (list 'name "Apple") (list 'currencyCode "USD") (list 'currencySymbol "$") (list 'price 2.99)))
+ (cons "Item" (list id entry))
+)
+
+(define (cart_total)
+ 10.0
+)
+
+(define (cart_impl op args)
+ (cond
+ ((equal? op "post") (apply cart_post args))
+ ((equal? op "getall") (apply cart_getall args))
+ ((equal? op "getentry") (apply cart_getentry args))
+ ((equal? op "total") (apply cart_total args))
+ )
+)
+
+; Store UI implementation
+
+(define (storeui_post cart content item)
+ (cart "post" content item)
+)
+
+(define (storeui_getcart cart content)
+ (cart "getall" content)
+)
+
+(define (storeui_getentry cart id)
+ (cart "getentry" id)
+)
+
+(define (storeui_items catalog)
+ (catalog "items")
+)
+
+(define (storeui_total cart)
+ (cart "total")
+)
+
+(define (storeui_impl cart catalog op args)
+ (cond
+ ((equal? op "post") (apply storeui_post (cons cart args)))
+ ((equal? op "getall") (apply storeui_getcart (cons cart args)))
+ ((equal? op "getentry") (apply storeui_getentry (cons cart args)))
+ ((equal? op "items") (apply storeui_items (cons catalog args)))
+ ((equal? op "total") (apply storeui_total (cons cart args)))
+ )
+)
+
+; Store UI composite
+
+(define (cart_service op . args) (cart_impl op args))
+
+(define (storeui_service op . args) (storeui_impl cart_service catalog_service op args))
+
+; Store UI test case
+
+(define catalog (storeui_service "items"))
+(define empty (list))
+(define apple (car catalog))
+(define orange (car (cdr catalog)))
+(define added1 (storeui_service "post" empty apple))
+(define added2 (storeui_service "post" added1 orange))
+(display (storeui_service "getall" added2))
+(display (storeui_service "total"))
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/server-test
new file mode 100755
index 0000000000..1612bc59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/shopping-cart.scm b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/shopping-cart.scm
new file mode 100644
index 0000000000..61b169426f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/shopping-cart.scm
@@ -0,0 +1,82 @@
+; 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.
+
+; Shopping cart implementation
+
+(define cartId "1234")
+
+; Get the shopping cart from the cache
+; Return an empty cart if not found
+(define (getcart id cache)
+ (define cart (cache "get" (list id)))
+ (if (nul cart)
+ (list)
+ cart)
+)
+
+; Post a new item to the cart, create a new cart if necessary
+(define (post collection item cache)
+ (define id (uuid))
+ (define newItem (list (car item) id (caddr item)))
+ (define cart (cons newItem (getcart cartId cache)))
+ (cache "put" (list cartId) cart)
+ (list id)
+)
+
+; Find an item in the cart
+(define (find id cart)
+ (if (nul cart)
+ (cons "Item" (list "0" (list)))
+ (if (= id (cadr (car cart)))
+ (car cart)
+ (find id (cdr cart))))
+)
+
+; Get items from the cart
+(define (get id cache)
+ (if (nul id)
+ (cons "Your Cart" (cons cartId (getcart cartId cache)))
+ (find (car id) (getcart cartId cache))
+ )
+)
+
+; Delete items from the cart
+(define (delete id cache)
+ (if (nul id)
+ (cache "delete" (list cartId))
+ true
+ )
+)
+
+; Return the price of an item
+(define (price item)
+ (cadr (assoc 'price (caddr item)))
+)
+
+; Sum the prices of a list of items
+(define (sum items)
+ (if (nul items)
+ 0
+ (+ (price (car items)) (sum (cdr items))))
+)
+
+; Return the total price of the items in the cart
+(define (total cache)
+ (define cart (getcart cartId cache))
+ (sum cart)
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/ssl-start
new file mode 100755
index 0000000000..70e62f1f04
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/ssl-start
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/basic-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/start b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/start
new file mode 100755
index 0000000000..ffd7173ee2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/start
@@ -0,0 +1,31 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/stop b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/stop
new file mode 100755
index 0000000000..a59273b8ed
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/stop
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.composite
new file mode 100644
index 0000000000..fd58ae6c9d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.composite
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.scheme script="store.scm"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.scheme script="fruits-catalog.scm"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.scheme script="shopping-cart.scm"/>
+ <service name="Cart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.scheme script="currency-converter.scm"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.cpp path="../../components/cache" library="libmemcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.scm b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.scm
new file mode 100644
index 0000000000..f54257343e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-scheme/store.scm
@@ -0,0 +1,47 @@
+; 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.
+
+; Store implementation
+
+(define (post item catalog shoppingCart shoppingTotal)
+ (shoppingCart "post" item)
+)
+
+(define (getall catalog shoppingCart shoppingTotal)
+ (shoppingCart "getall")
+)
+
+(define (get id catalog shoppingCart shoppingTotal)
+ (shoppingCart "get" id)
+)
+
+(define (items catalog shoppingCart shoppingTotal)
+ (catalog "items")
+)
+
+(define (total catalog shoppingCart shoppingTotal)
+ (shoppingCart "total")
+)
+
+(define (deleteall catalog shoppingCart shoppingTotal)
+ (shoppingCart "deleteall")
+)
+
+(define (delete id catalog shoppingCart shoppingTotal)
+ (shoppingCart "delete" id)
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-sql/Makefile.am
new file mode 100644
index 0000000000..3b738e3972
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/Makefile.am
@@ -0,0 +1,28 @@
+# 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.
+
+if WANT_SQLDB
+
+dist_sample_SCRIPTS = start stop ssl-start
+sampledir = $(prefix)/samples/store-sql
+
+nobase_dist_sample_DATA = currency-converter.scm fruits-catalog.scm shopping-cart.scm store.scm store.composite htdocs/*.html
+
+dist_noinst_SCRIPTS = server-test
+TESTS = server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/currency-converter.scm b/sandbox/sebastien/cpp/apr-2/samples/store-sql/currency-converter.scm
new file mode 100644
index 0000000000..fc506c3d73
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/currency-converter.scm
@@ -0,0 +1,27 @@
+; 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.
+
+; Currency converter implementation
+
+(define (convert from to amount)
+ (if (equal? to "EUR") (* amount 0.70) amount)
+)
+
+(define (symbol currency)
+ (if (equal? currency "EUR") "E" "$")
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/fruits-catalog.scm b/sandbox/sebastien/cpp/apr-2/samples/store-sql/fruits-catalog.scm
new file mode 100644
index 0000000000..d55394b96a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/fruits-catalog.scm
@@ -0,0 +1,30 @@
+; 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.
+
+; Catalog implementation
+
+(define (items converter currencyCode)
+ (define code (currencyCode))
+ (define (convert price) (converter "convert" "USD" code price))
+ (define symbol (converter "symbol" code))
+ (list
+ (list (list 'name "Apple") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 2.99)))
+ (list (list 'name "Orange") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 3.55)))
+ (list (list 'name "Pear") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 1.55)))
+ )
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-sql/htdocs/index.html
new file mode 100644
index 0000000000..3945e45bb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/htdocs/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-sql/server-test
new file mode 100755
index 0000000000..1612bc59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/server-test
@@ -0,0 +1,58 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://localhost:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://localhost:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/shopping-cart.scm b/sandbox/sebastien/cpp/apr-2/samples/store-sql/shopping-cart.scm
new file mode 100644
index 0000000000..61b169426f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/shopping-cart.scm
@@ -0,0 +1,82 @@
+; 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.
+
+; Shopping cart implementation
+
+(define cartId "1234")
+
+; Get the shopping cart from the cache
+; Return an empty cart if not found
+(define (getcart id cache)
+ (define cart (cache "get" (list id)))
+ (if (nul cart)
+ (list)
+ cart)
+)
+
+; Post a new item to the cart, create a new cart if necessary
+(define (post collection item cache)
+ (define id (uuid))
+ (define newItem (list (car item) id (caddr item)))
+ (define cart (cons newItem (getcart cartId cache)))
+ (cache "put" (list cartId) cart)
+ (list id)
+)
+
+; Find an item in the cart
+(define (find id cart)
+ (if (nul cart)
+ (cons "Item" (list "0" (list)))
+ (if (= id (cadr (car cart)))
+ (car cart)
+ (find id (cdr cart))))
+)
+
+; Get items from the cart
+(define (get id cache)
+ (if (nul id)
+ (cons "Your Cart" (cons cartId (getcart cartId cache)))
+ (find (car id) (getcart cartId cache))
+ )
+)
+
+; Delete items from the cart
+(define (delete id cache)
+ (if (nul id)
+ (cache "delete" (list cartId))
+ true
+ )
+)
+
+; Return the price of an item
+(define (price item)
+ (cadr (assoc 'price (caddr item)))
+)
+
+; Sum the prices of a list of items
+(define (sum items)
+ (if (nul items)
+ 0
+ (+ (price (car items)) (sum (cdr items))))
+)
+
+; Return the total price of the items in the cart
+(define (total cache)
+ (define cart (getcart cartId cache))
+ (sum cart)
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-sql/ssl-start
new file mode 100755
index 0000000000..58ce2070ee
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/ssl-start
@@ -0,0 +1,39 @@
+#!/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
+# 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.
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/basic-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../components/sqldb/pgsql-conf tmp
+../../components/sqldb/pgsql-start tmp
+../../components/sqldb/pgsql "create table store(key text, value text);" 1>/dev/null 2>&1
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/start b/sandbox/sebastien/cpp/apr-2/samples/store-sql/start
new file mode 100755
index 0000000000..95881294d1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/start
@@ -0,0 +1,34 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/
+SCAComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../components/sqldb/pgsql-conf tmp
+../../components/sqldb/pgsql-start tmp
+../../components/sqldb/pgsql "create table store(key text, value text);" 1>/dev/null 2>&1
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/stop b/sandbox/sebastien/cpp/apr-2/samples/store-sql/stop
new file mode 100755
index 0000000000..2226018a3f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/stop
@@ -0,0 +1,22 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
+../../components/sqldb/pgsql-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-sql/store.composite
new file mode 100644
index 0000000000..a10740b5f9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/store.composite
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.scheme script="store.scm"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.scheme script="fruits-catalog.scm"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.scheme script="shopping-cart.scm"/>
+ <service name="Cart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.scheme script="currency-converter.scm"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+ <component name="Cache">
+ <implementation.cpp path="../../components/cache" library="libdatacache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <reference name="l1reader" target="Memcache"/>
+ <reference name="l1writer" target="Memcache"/>
+ <reference name="l2reader" target="Sqldb"/>
+ <reference name="l2writer" target="Sqldb"/>
+ </component>
+
+ <component name="Memcache">
+ <implementation.cpp path="../../components/cache" library="libmemcache"/>
+ <service name="Memcache">
+ <t:binding.atom uri="memcache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+ <component name="Sqldb">
+ <implementation.cpp path="../../components/sqldb" library="libsqldb"/>
+ <property name="conninfo">host=localhost port=5432 dbname=db</property>
+ <property name="table">store</property>
+ <service name="Sqldb">
+ <t:binding.atom uri="sqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-sql/store.scm b/sandbox/sebastien/cpp/apr-2/samples/store-sql/store.scm
new file mode 100644
index 0000000000..f54257343e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-sql/store.scm
@@ -0,0 +1,47 @@
+; 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.
+
+; Store implementation
+
+(define (post item catalog shoppingCart shoppingTotal)
+ (shoppingCart "post" item)
+)
+
+(define (getall catalog shoppingCart shoppingTotal)
+ (shoppingCart "getall")
+)
+
+(define (get id catalog shoppingCart shoppingTotal)
+ (shoppingCart "get" id)
+)
+
+(define (items catalog shoppingCart shoppingTotal)
+ (catalog "items")
+)
+
+(define (total catalog shoppingCart shoppingTotal)
+ (shoppingCart "total")
+)
+
+(define (deleteall catalog shoppingCart shoppingTotal)
+ (shoppingCart "deleteall")
+)
+
+(define (delete id catalog shoppingCart shoppingTotal)
+ (shoppingCart "delete" id)
+)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/Makefile.am b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/Makefile.am
new file mode 100644
index 0000000000..6c7dba1808
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/Makefile.am
@@ -0,0 +1,28 @@
+# 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.
+
+if WANT_PYTHON
+
+dist_sample_SCRIPTS = start stop ssl-start uec2-start
+sampledir = $(prefix)/samples/store-vhost
+
+nobase_dist_sample_DATA = htdocs/*.html htdocs/domains/*/*.html domains/*/*.py domains/*/*.composite shared/*.composite
+
+dist_noinst_SCRIPTS = server-test
+#TESTS = server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/currency-converter.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/currency-converter.py
new file mode 100644
index 0000000000..2fded8f616
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/currency-converter.py
@@ -0,0 +1,29 @@
+# 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.
+
+# Currency converter implementation
+
+def convert(fr, to, amount):
+ if to == "EUR":
+ return amount * 0.70
+ return amount
+
+def symbol(currency):
+ if currency == "EUR":
+ return "E"
+ return "$"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/fruits-catalog.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/fruits-catalog.py
new file mode 100644
index 0000000000..fb20b4ff27
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/fruits-catalog.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Catalog implementation
+
+def items(converter, currencyCode):
+ code = currencyCode.eval()
+ def convert(price):
+ return converter.convert("USD", code, price)
+ symbol = converter.symbol(code)
+ return (
+ (("'name", "Passion"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
+ (("'name", "Mango"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
+ (("'name", "Pineapple"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
+ )
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/shopping-cart.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/shopping-cart.py
new file mode 100644
index 0000000000..feb7398ed9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/shopping-cart.py
@@ -0,0 +1,75 @@
+# 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.
+
+# Shopping cart implementation
+import uuid
+import sys
+
+cartId = "1234"
+
+# Get the shopping cart from the cache
+# Return an empty cart if not found
+def getcart(id, cache):
+ cart = cache.get((id,))
+ if cart is None:
+ return ()
+ return cart
+
+# Post a new item to the cart, create a new cart if necessary
+def post(collection, item, cache):
+ id = str(uuid.uuid1())
+ cart = ((item[0], id, item[2]),) + getcart(cartId, cache)
+ cache.put((cartId,), cart)
+ return (id,)
+
+
+# Find an item in the cart
+def find(id, cart):
+ if cart == ():
+ return ("Item", "0", ())
+ elif id == cart[0][1]:
+ return cart[0]
+ else:
+ return find(id, cart[1:])
+
+# Get items from the cart
+def get(id, cache):
+ if id == ():
+ return ("Your Cart", cartId) + getcart(cartId, cache)
+ return find(id[0], getcart(cartId, cache))
+
+# Delete items from the cart
+def delete(id, cache):
+ if id == ():
+ return cache.delete((cartId,))
+ return True
+
+# Return the price of an item
+def price(item):
+ return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
+
+# Sum the prices of a list of items
+def sum(items):
+ if items == ():
+ return 0
+ return price(items[0]) + sum(items[1:])
+
+# Return the total price of the items in the cart
+def total(cache):
+ cart = getcart(cartId, cache)
+ return sum(cart)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.composite
new file mode 100644
index 0000000000..01553025d9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.composite
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.py
new file mode 100644
index 0000000000..ff82f1d327
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/jane/store.py
@@ -0,0 +1,40 @@
+# 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.
+
+# Store implementation
+
+def post(item, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.post(item)
+
+def getall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.getall()
+
+def get(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.get(id)
+
+def items(catalog, shoppingCart, shoppingTotal):
+ return catalog.items()
+
+def total(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.total()
+
+def deleteall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.deleteall()
+
+def delete(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.delete(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/currency-converter.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/currency-converter.py
new file mode 100644
index 0000000000..2fded8f616
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/currency-converter.py
@@ -0,0 +1,29 @@
+# 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.
+
+# Currency converter implementation
+
+def convert(fr, to, amount):
+ if to == "EUR":
+ return amount * 0.70
+ return amount
+
+def symbol(currency):
+ if currency == "EUR":
+ return "E"
+ return "$"
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/fruits-catalog.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/fruits-catalog.py
new file mode 100644
index 0000000000..6644421683
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/fruits-catalog.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Catalog implementation
+
+def items(converter, currencyCode):
+ code = currencyCode.eval()
+ def convert(price):
+ return converter.convert("USD", code, price)
+ symbol = converter.symbol(code)
+ return (
+ (("'name", "Apple"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(2.99))),
+ (("'name", "Orange"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(3.55))),
+ (("'name", "Pear"), ("'currencyCode", code), ("'currencySymbol", symbol), ("'price", convert(1.55)))
+ )
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/shopping-cart.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/shopping-cart.py
new file mode 100644
index 0000000000..feb7398ed9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/shopping-cart.py
@@ -0,0 +1,75 @@
+# 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.
+
+# Shopping cart implementation
+import uuid
+import sys
+
+cartId = "1234"
+
+# Get the shopping cart from the cache
+# Return an empty cart if not found
+def getcart(id, cache):
+ cart = cache.get((id,))
+ if cart is None:
+ return ()
+ return cart
+
+# Post a new item to the cart, create a new cart if necessary
+def post(collection, item, cache):
+ id = str(uuid.uuid1())
+ cart = ((item[0], id, item[2]),) + getcart(cartId, cache)
+ cache.put((cartId,), cart)
+ return (id,)
+
+
+# Find an item in the cart
+def find(id, cart):
+ if cart == ():
+ return ("Item", "0", ())
+ elif id == cart[0][1]:
+ return cart[0]
+ else:
+ return find(id, cart[1:])
+
+# Get items from the cart
+def get(id, cache):
+ if id == ():
+ return ("Your Cart", cartId) + getcart(cartId, cache)
+ return find(id[0], getcart(cartId, cache))
+
+# Delete items from the cart
+def delete(id, cache):
+ if id == ():
+ return cache.delete((cartId,))
+ return True
+
+# Return the price of an item
+def price(item):
+ return float(filter(lambda x: x[0] == "'price", item[2])[0][1])
+
+# Sum the prices of a list of items
+def sum(items):
+ if items == ():
+ return 0
+ return price(items[0]) + sum(items[1:])
+
+# Return the total price of the items in the cart
+def total(cache):
+ cart = getcart(cartId, cache)
+ return sum(cart)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.composite b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.composite
new file mode 100644
index 0000000000..01553025d9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.composite
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://store"
+ name="store">
+
+ <component name="Store">
+ <t:implementation.python script="store.py"/>
+ <service name="Widget">
+ <t:binding.http uri="store"/>
+ </service>
+ <reference name="catalog" target="Catalog"/>
+ <reference name="shoppingCart" target="ShoppingCart/Cart"/>
+ <reference name="shoppingTotal" target="ShoppingCart/Total"/>
+ </component>
+
+ <component name="Catalog">
+ <t:implementation.python script="fruits-catalog.py"/>
+ <property name="currencyCode">USD</property>
+ <service name="Catalog">
+ <t:binding.jsonrpc uri="catalog"/>
+ </service>
+ <reference name="currencyConverter" target="CurrencyConverter"/>
+ </component>
+
+ <component name="ShoppingCart">
+ <t:implementation.python script="shopping-cart.py"/>
+ <service name="ShoppingCart">
+ <t:binding.atom uri="shoppingCart"/>
+ </service>
+ <service name="Total">
+ <t:binding.jsonrpc uri="total"/>
+ </service>
+ <reference name="cache" target="Cache"/>
+ </component>
+
+ <component name="CurrencyConverter">
+ <t:implementation.python script="currency-converter.py"/>
+ <service name="CurrencyConverter">
+ <t:binding.jsonrpc uri="currencyConverter"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.py b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.py
new file mode 100644
index 0000000000..ff82f1d327
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/domains/joe/store.py
@@ -0,0 +1,40 @@
+# 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.
+
+# Store implementation
+
+def post(item, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.post(item)
+
+def getall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.getall()
+
+def get(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.get(id)
+
+def items(catalog, shoppingCart, shoppingTotal):
+ return catalog.items()
+
+def total(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.total()
+
+def deleteall(catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.deleteall()
+
+def delete(id, catalog, shoppingCart, shoppingTotal):
+ return shoppingCart.delete(id)
+
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/jane/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/jane/index.html
new file mode 100644
index 0000000000..238ed701f0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/jane/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Jane's Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/joe/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/joe/index.html
new file mode 100644
index 0000000000..c1cfc59aa7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/domains/joe/index.html
@@ -0,0 +1,150 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+
+<script type="text/javascript" src="/component.js"></script>
+
+<script type="text/javascript">
+var store = sca.component("Store");
+var catalog = sca.defun(sca.reference(store, "catalog"), "items");
+var shoppingCart = sca.reference(store, "shoppingCart");
+var shoppingTotal = sca.defun(sca.reference(store, "shoppingTotal"), "total");
+
+var catalogItems;
+
+function catalog_itemsResponse(items, exception) {
+ if (exception){
+ alert(exception.message);
+ return;
+ }
+ var catalog = "";
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+}
+
+function shoppingCart_getResponse(feed) {
+ if (feed != null) {
+ var entries = feed.getElementsByTagName("entry");
+ var list = "";
+ for (var i=0; i<entries.length; i++) {
+ var content = entries[i].getElementsByTagName("content")[0];
+ var name = content.getElementsByTagName("name")[0].firstChild.nodeValue;
+ var price = content.getElementsByTagName("price")[0].firstChild.nodeValue;
+ list += name + ' - ' + price + ' <br>';
+ }
+ document.getElementById("shoppingCart").innerHTML = list;
+
+ shoppingTotal.total(shoppingTotal_totalResponse);
+ }
+}
+
+function shoppingTotal_totalResponse(total, exception) {
+ if (exception) {
+ alert(exception.message);
+ return;
+ }
+ document.getElementById('total').innerHTML = total;
+}
+
+function shoppingCart_postResponse(entry) {
+ shoppingCart.get("", shoppingCart_getResponse);
+}
+
+function addToCart() {
+ var items = document.catalogForm.items;
+ var j = 0;
+ for (var i=0; i<items.length; i++)
+ if (items[i].checked) {
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
+ shoppingCart.post(entry, shoppingCart_postResponse);
+ items[i].checked = false;
+ }
+}
+function checkoutCart() {
+ document.getElementById('store').innerHTML='<h2>' +
+ 'Thanks for Shopping With Us!</h2>'+
+ '<h2>Your Order</h2>'+
+ '<form name="orderForm">'+
+ document.getElementById('shoppingCart').innerHTML+
+ '<br>'+
+ document.getElementById('total').innerHTML+
+ '<br>'+
+ '<br>'+
+ '<input type="submit" value="Continue Shopping">'+
+ '</form>';
+ shoppingCart.del("", null);
+}
+function deleteCart() {
+ shoppingCart.del("", null);
+ document.getElementById('shoppingCart').innerHTML = "";
+ document.getElementById('total').innerHTML = "";
+}
+
+function init() {
+ try {
+ catalog.items(catalog_itemsResponse);
+ shoppingCart.get("", shoppingCart_getResponse);
+ } catch(e){
+ alert(e);
+ }
+}
+</script>
+
+</head>
+
+<body onload="init()">
+<h1>Joe's Store</h1>
+<div id="store">
+<h2>Catalog</h2>
+<form name="catalogForm">
+<div id="catalog" ></div>
+<br>
+<input type="button" onClick="addToCart()" value="Add to Cart">
+</form>
+<br>
+
+<h2>Your Shopping Cart</h2>
+<form name="shoppingCartForm">
+<div id="shoppingCart"></div>
+<br>
+<div id="total"></div>
+<br>
+<input type="button" onClick="checkoutCart()" value="Checkout">
+<input type="button" onClick="deleteCart()" value="Empty">
+<a href="shoppingCart/">(feed)</a>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/index.html
new file mode 100644
index 0000000000..e0239392ff
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/htdocs/index.html
@@ -0,0 +1,34 @@
+<!--
+ * 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.
+-->
+<html>
+<head>
+<title>Store</title>
+</head>
+
+<body>
+<h1>Store</h1>
+<p>For this sample to work, add the sample domain to your /etc/hosts as follows:<br/>
+127.0.0.1 sca-store.com jane.sca-store.com joe.sca-store.com</p>
+
+<p/>
+<p>Jane's store at <a href="http://jane.sca-store.com:8090/">jane.sca-store.com</a>
+<br/>Joe's store at <a href="http://joe.sca-store.com:8090/">joe.sca-store.com</a></p>
+
+</body>
+</html>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/server-test b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/server-test
new file mode 100755
index 0000000000..405da2165d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/server-test
@@ -0,0 +1,61 @@
+#!/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
+# 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.
+
+echo "Testing..."
+here=`readlink -f $0`; here=`dirname $here`
+curl_prefix=`cat $here/../../modules/http/curl.prefix`
+
+# Setup
+./start
+sleep 2
+
+# For this test to work, add the test domain to your etc/hosts as follows:
+# 127.0.0.1 sca-store.com joe.sca-store.com joe.sca-store.com
+
+# Test HTTP GET
+$curl_prefix/bin/curl http://joe.sca-store.com:8090/ 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/domains/joe/index.html
+rc=$?
+
+# Test Catalog
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://joe.sca-store.com:8090/references/Store/catalog -X POST -H "Content-type: application/json-rpc" --data @../store-cpp/htdocs/test/items-request.txt >tmp/items-result.txt 2>/dev/null
+ diff tmp/items-result.txt ../store-cpp/htdocs/test/items-result.txt
+ rc=$?
+fi
+
+# Test Shopping Cart
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://joe.sca-store.com:8090/references/Store/shoppingCart -X POST -H "Content-type: application/atom+xml" --data @../store-cpp/htdocs/test/shopping-cart-entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ $curl_prefix/bin/curl http://joe.sca-store.com:8090/references/Store/shoppingCart >tmp/shopping-cart-feed.xml 2>/dev/null
+ grep "3.55" tmp/shopping-cart-feed.xml >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+./stop
+sleep 2
+
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/shared/shared.composite b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/shared/shared.composite
new file mode 100644
index 0000000000..55a0c1f8d6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/shared/shared.composite
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://shared"
+ name="shared">
+
+ <component name="Cache">
+ <implementation.cpp path="../../../components/cache" library="libmemcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="cache"/>
+ </service>
+ <property name="servers">localhost:11211</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/ssl-start b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/ssl-start
new file mode 100755
index 0000000000..6f715afb89
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/ssl-start
@@ -0,0 +1,46 @@
+#!/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
+# 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.
+
+# For this sample to work, add the sample domain to your /etc/hosts as follows:
+# 127.0.0.1 sca-store.com jane.sca-store.com joe.sca-store.com
+
+../../modules/http/ssl-ca-conf tmp sca-store.com
+../../modules/http/ssl-cert-conf tmp sca-store.com server
+../../modules/http/ssl-cert-conf tmp *.sca-store.com vhost
+../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs
+../../modules/http/vhost-conf tmp
+../../modules/http/httpd-ssl-conf tmp 8453
+../../modules/http/vhost-ssl-conf tmp
+../../modules/http/basic-auth-conf tmp
+../../modules/http/passwd-auth-conf tmp foo foo
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/shared/
+SCAComposite shared.composite
+
+# Configure SCA Composite for mass dynamic virtual Hosting
+SCAVirtualContribution `pwd`/domains/
+SCAVirtualComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/start b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/start
new file mode 100755
index 0000000000..16ffe351ec
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/start
@@ -0,0 +1,36 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs
+../../modules/http/vhost-conf tmp
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite
+SCAContribution `pwd`/shared/
+SCAComposite shared.composite
+
+# Configure SCA Composite for mass dynamic virtual hosting
+SCAVirtualContribution `pwd`/domains/
+SCAVirtualComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/stop b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/stop
new file mode 100755
index 0000000000..a59273b8ed
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/stop
@@ -0,0 +1,21 @@
+#!/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
+# 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.
+
+../../modules/http/httpd-stop tmp
+../../components/cache/memcached-stop
diff --git a/sandbox/sebastien/cpp/apr-2/samples/store-vhost/uec2-start b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/uec2-start
new file mode 100755
index 0000000000..b8a267d617
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/samples/store-vhost/uec2-start
@@ -0,0 +1,50 @@
+#!/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
+# 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.
+
+# Pass your EC2 public host name
+if [ "$1" != "" ]; then
+ host=$1
+else
+ # Default to dummy test domain
+ host="sca-store.com"
+fi
+
+# Ports 80, 443, 444, 8090, 8453, 8454 need to be open
+sudo ../../ubuntu/ip-redirect-all 80 8090
+sudo ../../ubuntu/ip-redirect-all 443 8453
+
+../../modules/http/ssl-ca-conf tmp $host
+../../modules/http/ssl-cert-conf tmp $host server
+../../modules/http/ssl-cert-conf tmp "*.$host" vhost
+../../modules/http/httpd-conf tmp $host 8090/80 htdocs
+../../modules/http/vhost-conf tmp
+../../modules/http/httpd-ssl-conf tmp 8453/443
+../../modules/http/vhost-ssl-conf tmp
+../../modules/server/server-conf tmp
+../../modules/python/python-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+# Configure SCA Composite for mass dynamic virtual Hosting
+SCAVirtualContribution `pwd`/domains/
+SCAVirtualComposite store.composite
+
+EOF
+
+../../components/cache/memcached-start
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/Makefile.am b/sandbox/sebastien/cpp/apr-2/ubuntu/Makefile.am
new file mode 100644
index 0000000000..21e045d4b5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/Makefile.am
@@ -0,0 +1,22 @@
+# 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.
+
+dist_ubuntu_SCRIPTS = ip-redirect ip-redirect-all uec2-conf uec2-setenv uec2-ssh uec2-start uec2-status uec2-stop
+ubuntudir=$(prefix)/ubuntu
+
+dist_noinst_SCRIPTS = ubuntu-bin-all-image ubuntu-dev-all-image ubuntu-install-all uec2-bin-all-image uec2-dev-all-image
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect b/sandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect
new file mode 100755
index 0000000000..e78c63935b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect
@@ -0,0 +1,35 @@
+# 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.
+
+# Redirect TCP/IP traffic to a particular IP address from one port to another
+# port. This is useful to handle incoming traffic on a standard reserved port
+# like 80 or 443 for example in an unprivileged user process bound to a non
+# reserved port.
+# Example: ip-redirect 80 8090 10.1.1.1
+
+sport=$1
+tport=$2
+dest=$3
+
+# Redirect external incoming traffic
+sudo /sbin/iptables -t nat -S PREROUTING | grep "\-d $dest/" | grep "\-p tcp" | grep "\-\-dport $sport" | grep "\-j REDIRECT" | sed "s/^-A/-D/" | awk -F "\t" '{ printf "sudo /sbin/iptables -t nat %s\n", $1 }' | /bin/sh
+sudo /sbin/iptables -t nat -A PREROUTING --destination $dest -p tcp --dport $sport -j REDIRECT --to-ports $tport
+
+# Redirect local traffic as well
+sudo /sbin/iptables -t nat -S OUTPUT | grep "\-d $dest/" | grep "\-p tcp" | grep "\-\-dport $sport" | grep "\-j REDIRECT" | sed "s/^-A/-D/" | awk -F "\t" '{ printf "sudo /sbin/iptables -t nat %s\n", $1 }' | /bin/sh
+sudo /sbin/iptables -t nat -A OUTPUT --destination $dest -p tcp --dport $sport -j REDIRECT --to-ports $tport
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect-all b/sandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect-all
new file mode 100755
index 0000000000..f796b0589e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/ip-redirect-all
@@ -0,0 +1,31 @@
+# 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.
+
+# Redirect TCP/IP traffic to all local addresses from one port to another
+# Example: ip-redirect 80 8090
+
+here=`readlink -f $0`; here=`dirname $here`
+sport=$1
+tport=$2
+
+# Cleanup existing rules
+sudo /sbin/iptables -t nat -S PREROUTING | grep "\-p tcp" | grep "\-\-dport $sport" | grep "\-j REDIRECT" | sed "s/^-A/-D/" | awk -F "\t" '{ printf "sudo /sbin/iptables -t nat %s\n", $1 }' | /bin/sh
+sudo /sbin/iptables -t nat -S OUTPUT | grep "\-p tcp" | grep "\-\-dport $sport" | grep "\-j REDIRECT" | sed "s/^-A/-D/" | awk -F "\t" '{ printf "sudo /sbin/iptables -t nat %s\n", $1 }' | /bin/sh
+
+# Redirect traffic
+/sbin/ifconfig | grep "inet addr:" | awk -F ":" '{ print $2 }' | awk '{ print $1 }' | xargs -i $here/ip-redirect $sport $tport {}
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-bin-all-image b/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-bin-all-image
new file mode 100755
index 0000000000..a3da2132e4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-bin-all-image
@@ -0,0 +1,95 @@
+# 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.
+
+# Install a complete distribution, the required system tools and libraries,
+# the runtime dependencies and the Tuscany SCA runtime on a fresh Ubuntu Server
+# 10.10 64-bit image.
+
+# Display commands as they are executed
+set -x
+
+# First update the system
+sudo apt-get update
+
+# Create install directory
+u=`id -un`
+g=`id -gn`
+sudo mkdir -p /mnt/tuscany
+sudo chown $u /mnt/tuscany
+sudo chgrp $g /mnt/tuscany
+cd /mnt/tuscany
+
+# Install core dev tools
+sudo apt-get -y install wget git-core autoconf automake libtool g++
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Apache HTTP server
+sudo apt-get -y install libssl-dev libpcre3-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Memcached
+sudo apt-get -y install libevent-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by TraceMonkey
+sudo apt-get -y install autoconf2.13 zip
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Apache Axis2/C
+sudo apt-get -y install pkg-config
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Apache Qpid/C++
+sudo apt-get -y install libboost-dev libboost-program-options-dev libboost-filesystem-dev uuid-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Apache Vysper
+sudo apt-get -y install openjdk-6-jdk
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Require by HTML Tidy
+sudo apt-get -y install cvs
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by PostgreSQL
+sudo apt-get -y install libreadline-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Apache Thrift
+sudo apt-get -y install bison flex python-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+# Required by Facebook Scribe
+sudo apt-get -y install gawk
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+
+# Download and install the Tuscany runtime
+wget http://people.apache.org/~jsdelfino/tuscany/test/tuscany-sca-cpp-all-1.0.tar.gz
+tar xzf tuscany-sca-cpp-all-1.0.tar.gz
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-dev-all-image b/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-dev-all-image
new file mode 100755
index 0000000000..28d55e697e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-dev-all-image
@@ -0,0 +1,41 @@
+# 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.
+
+# Install a complete distribution, the required system tools and libraries,
+# the runtime dependencies and the Tuscany SCA runtime on a fresh Ubuntu
+# Server 10.10 64-bit image.
+
+# Display commands as they are executed
+set -x
+
+# First update the system
+sudo apt-get update
+
+# Create install directory
+u=`id -un`
+g=`id -gn`
+sudo mkdir -p /mnt/tuscany
+sudo chown $u /mnt/tuscany
+sudo chgrp $g /mnt/tuscany
+cd /mnt/tuscany
+
+# Download and run install script
+sudo apt-get -y install wget
+wget http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-install-all
+chmod +x ./ubuntu-install-all
+./ubuntu-install-all
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-install-all b/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-install-all
new file mode 100755
index 0000000000..c91b683ca1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/ubuntu-install-all
@@ -0,0 +1,340 @@
+# 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.
+
+# Install a complete distribution, the required system tools and libraries, the
+# runtime dependencies and the Tuscany SCA runtime on a fresh Ubuntu Server
+# 10.10 64-bit system.
+
+# Display commands as they are executed
+set -x
+
+# Build and install in the current directory
+build=`pwd`
+
+# Install core dev tools
+sudo apt-get -y install wget git-core autoconf automake libtool g++
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+
+# Build Libexpat
+wget http://sourceforge.net/projects/expat/files/expat/2.0.1/expat-2.0.1.tar.gz/download
+mv download expat-2.0.1.tar.gz
+tar xzf expat-2.0.1.tar.gz
+cd expat-2.0.1
+./configure --prefix=$build/expat-2.0.1-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Apache HTTP server
+sudo apt-get -y install libssl-dev libpcre3-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://archive.apache.org/dist/httpd/httpd-2.3.8.tar.gz
+tar xzf httpd-2.3.8.tar.gz
+wget http://archive.apache.org/dist/httpd/httpd-2.3.8-deps.tar.gz
+tar xzf httpd-2.3.8-deps.tar.gz
+cd httpd-2.3.8
+./configure --enable-ssl --enable-proxy --enable-usertrack --enable-mods-shared=most --enable-mpms-shared="prefork worker event" --with-included-apr --with-expat=$build/expat-2.0.1-bin --with-mpm=prefork --prefix=$build/httpd-2.3.8-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Memcached
+sudo apt-get -y install libevent-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz
+tar xzf memcached-1.4.5.tar.gz
+cd memcached-1.4.5
+./configure --prefix=$build/memcached-1.4.5-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Tinycdb
+wget http://www.corpit.ru/mjt/tinycdb/tinycdb_0.77.tar.gz
+tar xzf tinycdb_0.77.tar.gz
+cd tinycdb-0.77
+make all shared
+make prefix=$build/tinycdb-0.77-bin install-all install-sharedlib
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Libcurl
+wget http://curl.haxx.se/download/curl-7.19.5.tar.gz
+tar xzf curl-7.19.5.tar.gz
+cd curl-7.19.5
+./configure --prefix=$build/curl-7.19.5-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Libxml2
+wget ftp://xmlsoft.org/libxml2/libxml2-sources-2.7.7.tar.gz
+tar xzf libxml2-sources-2.7.7.tar.gz
+cd libxml2-2.7.7
+./configure --prefix=$build/libxml2-2.7.7-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build TraceMonkey
+sudo apt-get -y install autoconf2.13 zip
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget -O tracemonkey-e4364736e170.tar.gz http://hg.mozilla.org/tracemonkey/archive/e4364736e170.tar.gz
+tar xzf tracemonkey-e4364736e170.tar.gz
+cd tracemonkey-e4364736e170/js/src
+autoconf2.13
+./configure --prefix=$build/tracemonkey-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Install Google AppEngine SDK
+wget http://googleappengine.googlecode.com/files/google_appengine_1.4.0.zip
+unzip google_appengine_1.4.0.zip
+
+# Build Apache Axis2/C
+sudo apt-get -y install pkg-config
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://www.apache.org/dist/ws/axis2-c/1_6_0/axis2c-src-1.6.0.tar.gz
+tar xzf axis2c-src-1.6.0.tar.gz
+cd axis2c-src-1.6.0
+./configure --enable-libxml2 LIBXML2_CFLAGS="-I$build/libxml2-2.7.7-bin/include/libxml2" LIBXML2_LIBS="-L$build/libxml2-2.7.7-bin/lib -lxml2" --enable-openssl --with-apache2=$build/httpd-2.3.8-bin/include --prefix=$build/axis2c-1.6.0-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+export AXIS2C_HOME=$build/axis2c-1.6.0-bin
+cd samples
+./configure --prefix=$build/axis2c-1.6.0-bin --with-axis2=$build/axis2c-1.6.0-bin/include/axis2-1.6.0
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Apache Qpid/C++
+sudo apt-get -y install libboost-dev libboost-program-options-dev libboost-filesystem-dev uuid-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://www.apache.org/dist/qpid/0.6/qpid-cpp-0.6.tar.gz
+tar xzf qpid-cpp-0.6.tar.gz
+cd qpidc-0.6
+./configure --prefix=$build/qpidc-0.6-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Libstrophe
+git clone git://github.com/jsdelfino/libstrophe.git
+cd libstrophe
+./bootstrap.sh
+./configure --prefix=$build/libstrophe-bin --with-expat=$build/expat-2.0.1-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Install Apache Vysper
+sudo apt-get -y install openjdk-6-jdk
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://www.apache.org/dist/mina/vysper/0.5/vysper-0.5-bin.tar.gz
+tar xzf vysper-0.5-bin.tar.gz
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+
+# Build HTML Tidy
+sudo apt-get -y install cvs
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cvs -z3 -d:pserver:anonymous@tidy.cvs.sourceforge.net:/cvsroot/tidy co -P tidy
+cd tidy
+sh build/gnuauto/setup.sh
+./configure --prefix=$build/htmltidy-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Libopkele
+git clone git://github.com/jsdelfino/libopkele.git
+cd libopkele
+./autogen.bash
+./configure --prefix=$build/libopkele-bin --with-curl=$build/curl-7.19.5-bin --with-expat=$build/expat-2.0.1-bin --with-htmltidy=$build/htmltidy-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Mod_auth_openid
+git clone git://github.com/jsdelfino/mod_auth_openid.git
+cd mod_auth_openid
+./autogen.sh
+./configure --prefix=$build/mod-auth-openid-bin --with-apr=$build/httpd-2.3.8-bin --with-httpd=$build/httpd-2.3.8-bin --with-curl=$build/curl-7.19.5-bin --with-libopkele=$build/libopkele-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Liboauth
+wget http://liboauth.sourceforge.net/pool/liboauth-0.9.1.tar.gz
+tar xzf liboauth-0.9.1.tar.gz
+cd liboauth-0.9.1
+./configure --prefix=$build/liboauth-0.9.1-bin CURL_CFLAGS="-I$build/curl-7.19.5-bin/include" CURL_LIBS="-L$build/curl-7.19.5-bin/lib -R$build/curl-7.19.5-bin/lib -lcurl"
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build PostgreSQL
+sudo apt-get -y install libreadline-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget ftp://ftp9.us.postgresql.org/pub/mirrors/postgresql/source/v9.0.1/postgresql-9.0.1.tar.gz
+tar xzf postgresql-9.0.1.tar.gz
+cd postgresql-9.0.1
+./configure --prefix=$build/postgresql-9.0.1-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Apache Thrift
+sudo apt-get -y install bison flex python-dev
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://www.apache.org/dist/incubator/thrift/0.2.0-incubating/thrift-0.2.0-incubating.tar.gz
+tar xzf thrift-0.2.0-incubating.tar.gz
+cd thrift-0.2.0
+./bootstrap.sh
+./configure --prefix=$build/thrift-0.2.0-bin PY_PREFIX=$build/thrift-0.2.0-bin --with-java=no --with-erlang=no --with-perl=no --with-ruby=no --with-csharp=no --disable-static
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Facebook fb303
+cd thrift-0.2.0/contrib/fb303
+./bootstrap.sh
+./configure --prefix=$build/thrift-0.2.0-bin/contrib/fb303 PY_PREFIX=$build/thrift-0.2.0-bin/contrib/fb303 --with-thriftpath=$build/thrift-0.2.0-bin --disable-static
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cp cpp/lib/libfb303.so $build/thrift-0.2.0-bin/contrib/fb303/lib
+cd $build
+
+# Build Facebook Scribe
+sudo apt-get -y install gawk
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+wget http://github.com/downloads/facebook/scribe/scribe-2.2.tar.gz
+tar xzf scribe-2.2.tar.gz
+cd scribe
+./bootstrap.sh --prefix=$build/scribe-2.2-bin PY_PREFIX=$build/scribe-2.2-bin --with-thriftpath=$build/thrift-0.2.0-bin --with-fb303path=$build/thrift-0.2.0-bin/contrib/fb303 --disable-static
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cp src/lib/libscribe.so $build/scribe-2.2-bin/lib
+cd $build
+
+# Build Apache Libcloud
+wget http://www.apache.org/dist/incubator/libcloud/apache-libcloud-incubating-0.3.1.tar.bz2
+tar xjf apache-libcloud-incubating-0.3.1.tar.bz2
+cd apache-libcloud-0.3.1
+python setup.py build
+python setup.py install --home $build/libcloud-0.3.1-bin
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Build Tuscany SCA
+git clone git://git.apache.org/tuscany-sca-cpp.git
+cd tuscany-sca-cpp
+cp etc/git-exclude .git/info/exclude
+./bootstrap
+./configure --prefix=$build/tuscany-sca-cpp-bin --with-curl=$build/curl-7.19.5-bin --with-apr=$build/httpd-2.3.8-bin --with-httpd=$build/httpd-2.3.8-bin --with-memcached=$build/memcached-1.4.5-bin --with-tinycdb=$build/tinycdb-0.77-bin --with-js-include=$build/tracemonkey-bin/include/js --with-js-lib=$build/tracemonkey-bin/lib --with-libcloud=$build/libcloud-0.3.1-bin --enable-threads --enable-python --enable-gae --with-gae=$build/google_appengine --enable-java --with-java=/usr/lib/jvm/java-6-openjdk --enable-webservice --with-libxml2=$build/libxml2-2.7.7-bin --with-axis2c=$build/axis2c-1.6.0-bin --enable-queue --with-qpidc=$build/qpidc-0.6-bin --enable-chat --with-libstrophe=$build/libstrophe-bin --with-vysper=$build/vysper-0.5 --enable-sqldb --with-pgsql=$build/postgresql-9.0.1-bin --enable-log --with-thrift=$build/thrift-0.2.0-bin --with-scribe=$build/scribe-2.2-bin --enable-openid --with-mod-auth-openid=$build/mod-auth-openid-bin --enable-oauth --with-liboauth=$build/liboauth-0.9.1-bin
+make
+make install
+if [ "$?" != "0" ]; then
+ exit $?
+fi
+cd $build
+
+# Create bin archive
+tar czf tuscany-sca-cpp-all-1.0.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin axis2c-1.6.0-bin libxml2-2.7.7-bin curl-7.19.5-bin httpd-2.3.8-bin tracemonkey-bin google_appengine libstrophe-bin memcached-1.4.5-bin tinycdb-0.77-bin qpidc-0.6-bin vysper-0.5 postgresql-9.0.1-bin thrift-0.2.0-bin scribe-2.2-bin libcloud-0.3.1-bin htmltidy-bin libopkele-bin mod-auth-openid-bin liboauth-0.9.1-bin
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-bin-all-image b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-bin-all-image
new file mode 100755
index 0000000000..10e9efa241
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-bin-all-image
@@ -0,0 +1,23 @@
+# 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.
+
+# Install a Tuscany image on an EC2 instance
+host=$1
+
+# Download and execute Tuscany SCA install script
+ssh -i $HOME/.ec2/ec2-tuscany-keypair.pem ubuntu@$host "wget http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-bin-all-image; chmod 700 ./ubuntu-bin-all-image; ./ubuntu-bin-all-image"
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-conf b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-conf
new file mode 100755
index 0000000000..34ec6f5d49
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-conf
@@ -0,0 +1,39 @@
+# 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.
+
+# Configure EC2 for use with Tuscany SCA
+here=`readlink -f $0`; here=`dirname $here`
+$here/uec2-setenv
+
+# Display commands as they are executed
+set -x
+
+# Install EC2 tools
+# See https://help.ubuntu.com/community/EC2StartersGuide for more info
+sudo apt-get install ec2-api-tools
+
+# Create an EC2 SSH keypair if necessary
+if [ ! -f $HOME/.ec2/ec2-tuscany-keypair.pem ]; then
+ ec2-add-keypair ec2-tuscany-keypair --region us-west-1 > $HOME/.ec2/ec2-tuscany-keypair.pem
+ chmod 600 $HOME/.ec2/ec2-tuscany-keypair.pem
+fi
+
+# Authorize SSH, HTTP and HTTPS access to EC2 instances
+ec2-authorize default -p 22 --region us-west-1
+ec2-authorize default -p 80 --region us-west-1
+ec2-authorize default -p 443 --region us-west-1
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-dev-all-image b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-dev-all-image
new file mode 100755
index 0000000000..f8ec8e5164
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-dev-all-image
@@ -0,0 +1,23 @@
+# 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.
+
+# Build a Tuscany image on an EC2 instance
+host=$1
+
+# Download and execute Tuscany SCA install script
+ssh -i $HOME/.ec2/ec2-tuscany-keypair.pem ubuntu@$host "wget http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-dev-all-image; chmod 700 ./ubuntu-dev-all-image; ./ubuntu-dev-all-image"
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-setenv b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-setenv
new file mode 100755
index 0000000000..67d57df83a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-setenv
@@ -0,0 +1,34 @@
+# 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.
+
+# Configure EC2 environment variables
+export JAVA_HOME=/usr/lib/jvm/java-6-openjdk
+
+# Expect to find your EC2 private key and X.509 certificate in $HOME/.ec2
+key=`ls $HOME/.ec2/pk-*.pem`
+if [ "$key" = "" ]; then
+ echo "Couldn't find EC2 private key $HOME/.ec2/pk-*.pem"
+ exit 1
+fi
+cert=`ls $HOME/.ec2/cert-*.pem`
+if [ "$cert" = "" ]; then
+ echo "Couldn't find EC2 X.509 certificate $HOME/.ec2/pk-*.pem"
+ exit 1
+fi
+export EC2_PRIVATE_KEY=$key
+export EC2_CERT=$cert
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-ssh b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-ssh
new file mode 100755
index 0000000000..0e334f5c08
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-ssh
@@ -0,0 +1,21 @@
+# 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.
+
+# SSH to an EC2 instance
+host=$1
+ssh -i $HOME/.ec2/ec2-tuscany-keypair.pem ubuntu@$host
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-start b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-start
new file mode 100755
index 0000000000..72b6571877
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-start
@@ -0,0 +1,38 @@
+# 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.
+
+# Start an Ubuntu 10.10 64-bit EC2 instance for use with Tuscany
+
+here=`readlink -f $0`; here=`dirname $here`
+$here/uec2-setenv
+
+# Here are the AMI IDs you can use in the different EC2 regions:
+# Ubuntu 10.10 64-bit (elastic block storage)
+# US east 1 - ami-548c783d
+# US west 1 - ami-ca1f4f8f
+# EU west 1 - ami-405c6934
+# AP s.east - ami-68136d3a
+# More AMI IDs at http://uec-images.ubuntu.com
+
+# Here are some of the instance types you can use:
+# t1.micro
+# m1.large
+
+#ec2-run-instances "ami-ca1f4f8f" -t m1.large -k ec2-tuscany-keypair --region us-west-1
+#ec2-run-instances "ami-ca1f4f8f" -t t1.micro -k ec2-tuscany-keypair --region us-west-1
+ec2-run-instances "ami-ca1f4f8f" -t t1.micro -k ec2-tuscany-keypair --region us-west-1
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-status b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-status
new file mode 100755
index 0000000000..46d426b6f1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-status
@@ -0,0 +1,23 @@
+# 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.
+
+# Display the status of EC2 instances
+here=`readlink -f $0`; here=`dirname $here`
+$here/uec2-setenv
+
+ec2-describe-instances --region us-west-1
+
diff --git a/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-stop b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-stop
new file mode 100755
index 0000000000..0399f2b3f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/ubuntu/uec2-stop
@@ -0,0 +1,24 @@
+# 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.
+
+# Terminate an EC2 instance
+instance=$1
+here=`readlink -f $0`; here=`dirname $here`
+$here/uec2-setenv
+
+ec2-terminate-instances $instance --region us-west-1
+
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/XMLSchema.dtd b/sandbox/sebastien/cpp/apr-2/xsd/external/XMLSchema.dtd
new file mode 100644
index 0000000000..e8e8f7625a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/XMLSchema.dtd
@@ -0,0 +1,402 @@
+<!-- DTD for XML Schemas: Part 1: Structures
+ Public Identifier: "-//W3C//DTD XMLSCHEMA 200102//EN"
+ Official Location: http://www.w3.org/2001/XMLSchema.dtd -->
+<!-- $Id: XMLSchema.dtd,v 1.31 2001/10/24 15:50:16 ht Exp $ -->
+<!-- Note this DTD is NOT normative, or even definitive. --> <!--d-->
+<!-- prose copy in the structures REC is the definitive version --> <!--d-->
+<!-- (which shouldn't differ from this one except for this --> <!--d-->
+<!-- comment and entity expansions, but just in case) --> <!--d-->
+<!-- With the exception of cases with multiple namespace
+ prefixes for the XML Schema namespace, any XML document which is
+ not valid per this DTD given redefinitions in its internal subset of the
+ 'p' and 's' parameter entities below appropriate to its namespace
+ declaration of the XML Schema namespace is almost certainly not
+ a valid schema. -->
+
+<!-- The simpleType element and its constituent parts
+ are defined in XML Schema: Part 2: Datatypes -->
+<!ENTITY % xs-datatypes PUBLIC 'datatypes' 'datatypes.dtd' >
+
+<!ENTITY % p 'xs:'> <!-- can be overriden in the internal subset of a
+ schema document to establish a different
+ namespace prefix -->
+<!ENTITY % s ':xs'> <!-- if %p is defined (e.g. as foo:) then you must
+ also define %s as the suffix for the appropriate
+ namespace declaration (e.g. :foo) -->
+<!ENTITY % nds 'xmlns%s;'>
+
+<!-- Define all the element names, with optional prefix -->
+<!ENTITY % schema "%p;schema">
+<!ENTITY % complexType "%p;complexType">
+<!ENTITY % complexContent "%p;complexContent">
+<!ENTITY % simpleContent "%p;simpleContent">
+<!ENTITY % extension "%p;extension">
+<!ENTITY % element "%p;element">
+<!ENTITY % unique "%p;unique">
+<!ENTITY % key "%p;key">
+<!ENTITY % keyref "%p;keyref">
+<!ENTITY % selector "%p;selector">
+<!ENTITY % field "%p;field">
+<!ENTITY % group "%p;group">
+<!ENTITY % all "%p;all">
+<!ENTITY % choice "%p;choice">
+<!ENTITY % sequence "%p;sequence">
+<!ENTITY % any "%p;any">
+<!ENTITY % anyAttribute "%p;anyAttribute">
+<!ENTITY % attribute "%p;attribute">
+<!ENTITY % attributeGroup "%p;attributeGroup">
+<!ENTITY % include "%p;include">
+<!ENTITY % import "%p;import">
+<!ENTITY % redefine "%p;redefine">
+<!ENTITY % notation "%p;notation">
+
+<!-- annotation elements -->
+<!ENTITY % annotation "%p;annotation">
+<!ENTITY % appinfo "%p;appinfo">
+<!ENTITY % documentation "%p;documentation">
+
+<!-- Customisation entities for the ATTLIST of each element type.
+ Define one of these if your schema takes advantage of the
+ anyAttribute='##other' in the schema for schemas -->
+
+<!ENTITY % schemaAttrs ''>
+<!ENTITY % complexTypeAttrs ''>
+<!ENTITY % complexContentAttrs ''>
+<!ENTITY % simpleContentAttrs ''>
+<!ENTITY % extensionAttrs ''>
+<!ENTITY % elementAttrs ''>
+<!ENTITY % groupAttrs ''>
+<!ENTITY % allAttrs ''>
+<!ENTITY % choiceAttrs ''>
+<!ENTITY % sequenceAttrs ''>
+<!ENTITY % anyAttrs ''>
+<!ENTITY % anyAttributeAttrs ''>
+<!ENTITY % attributeAttrs ''>
+<!ENTITY % attributeGroupAttrs ''>
+<!ENTITY % uniqueAttrs ''>
+<!ENTITY % keyAttrs ''>
+<!ENTITY % keyrefAttrs ''>
+<!ENTITY % selectorAttrs ''>
+<!ENTITY % fieldAttrs ''>
+<!ENTITY % includeAttrs ''>
+<!ENTITY % importAttrs ''>
+<!ENTITY % redefineAttrs ''>
+<!ENTITY % notationAttrs ''>
+<!ENTITY % annotationAttrs ''>
+<!ENTITY % appinfoAttrs ''>
+<!ENTITY % documentationAttrs ''>
+
+<!ENTITY % complexDerivationSet "CDATA">
+ <!-- #all or space-separated list drawn from derivationChoice -->
+<!ENTITY % blockSet "CDATA">
+ <!-- #all or space-separated list drawn from
+ derivationChoice + 'substitution' -->
+
+<!ENTITY % mgs '%all; | %choice; | %sequence;'>
+<!ENTITY % cs '%choice; | %sequence;'>
+<!ENTITY % formValues '(qualified|unqualified)'>
+
+
+<!ENTITY % attrDecls '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
+
+<!ENTITY % particleAndAttrs '((%mgs; | %group;)?, %attrDecls;)'>
+
+<!-- This is used in part2 -->
+<!ENTITY % restriction1 '((%mgs; | %group;)?)'>
+
+%xs-datatypes;
+
+<!-- the duplication below is to produce an unambiguous content model
+ which allows annotation everywhere -->
+<!ELEMENT %schema; ((%include; | %import; | %redefine; | %annotation;)*,
+ ((%simpleType; | %complexType;
+ | %element; | %attribute;
+ | %attributeGroup; | %group;
+ | %notation; ),
+ (%annotation;)*)* )>
+<!ATTLIST %schema;
+ targetNamespace %URIref; #IMPLIED
+ version CDATA #IMPLIED
+ %nds; %URIref; #FIXED 'http://www.w3.org/2001/XMLSchema'
+ xmlns CDATA #IMPLIED
+ finalDefault %complexDerivationSet; ''
+ blockDefault %blockSet; ''
+ id ID #IMPLIED
+ elementFormDefault %formValues; 'unqualified'
+ attributeFormDefault %formValues; 'unqualified'
+ xml:lang CDATA #IMPLIED
+ %schemaAttrs;>
+<!-- Note the xmlns declaration is NOT in the Schema for Schemas,
+ because at the Infoset level where schemas operate,
+ xmlns(:prefix) is NOT an attribute! -->
+<!-- The declaration of xmlns is a convenience for schema authors -->
+
+<!-- The id attribute here and below is for use in external references
+ from non-schemas using simple fragment identifiers.
+ It is NOT used for schema-to-schema reference, internal or
+ external. -->
+
+<!-- a type is a named content type specification which allows attribute
+ declarations-->
+<!-- -->
+
+<!ELEMENT %complexType; ((%annotation;)?,
+ (%simpleContent;|%complexContent;|
+ %particleAndAttrs;))>
+
+<!ATTLIST %complexType;
+ name %NCName; #IMPLIED
+ id ID #IMPLIED
+ abstract %boolean; #IMPLIED
+ final %complexDerivationSet; #IMPLIED
+ block %complexDerivationSet; #IMPLIED
+ mixed (true|false) 'false'
+ %complexTypeAttrs;>
+
+<!-- particleAndAttrs is shorthand for a root type -->
+<!-- mixed is disallowed if simpleContent, overriden if complexContent
+ has one too. -->
+
+<!-- If anyAttribute appears in one or more referenced attributeGroups
+ and/or explicitly, the intersection of the permissions is used -->
+
+<!ELEMENT %complexContent; ((%annotation;)?, (%restriction;|%extension;))>
+<!ATTLIST %complexContent;
+ mixed (true|false) #IMPLIED
+ id ID #IMPLIED
+ %complexContentAttrs;>
+
+<!-- restriction should use the branch defined above, not the simple
+ one from part2; extension should use the full model -->
+
+<!ELEMENT %simpleContent; ((%annotation;)?, (%restriction;|%extension;))>
+<!ATTLIST %simpleContent;
+ id ID #IMPLIED
+ %simpleContentAttrs;>
+
+<!-- restriction should use the simple branch from part2, not the
+ one defined above; extension should have no particle -->
+
+<!ELEMENT %extension; ((%annotation;)?, (%particleAndAttrs;))>
+<!ATTLIST %extension;
+ base %QName; #REQUIRED
+ id ID #IMPLIED
+ %extensionAttrs;>
+
+<!-- an element is declared by either:
+ a name and a type (either nested or referenced via the type attribute)
+ or a ref to an existing element declaration -->
+
+<!ELEMENT %element; ((%annotation;)?, (%complexType;| %simpleType;)?,
+ (%unique; | %key; | %keyref;)*)>
+<!-- simpleType or complexType only if no type|ref attribute -->
+<!-- ref not allowed at top level -->
+<!ATTLIST %element;
+ name %NCName; #IMPLIED
+ id ID #IMPLIED
+ ref %QName; #IMPLIED
+ type %QName; #IMPLIED
+ minOccurs %nonNegativeInteger; #IMPLIED
+ maxOccurs CDATA #IMPLIED
+ nillable %boolean; #IMPLIED
+ substitutionGroup %QName; #IMPLIED
+ abstract %boolean; #IMPLIED
+ final %complexDerivationSet; #IMPLIED
+ block %blockSet; #IMPLIED
+ default CDATA #IMPLIED
+ fixed CDATA #IMPLIED
+ form %formValues; #IMPLIED
+ %elementAttrs;>
+<!-- type and ref are mutually exclusive.
+ name and ref are mutually exclusive, one is required -->
+<!-- In the absence of type AND ref, type defaults to type of
+ substitutionGroup, if any, else the ur-type, i.e. unconstrained -->
+<!-- default and fixed are mutually exclusive -->
+
+<!ELEMENT %group; ((%annotation;)?,(%mgs;)?)>
+<!ATTLIST %group;
+ name %NCName; #IMPLIED
+ ref %QName; #IMPLIED
+ minOccurs %nonNegativeInteger; #IMPLIED
+ maxOccurs CDATA #IMPLIED
+ id ID #IMPLIED
+ %groupAttrs;>
+
+<!ELEMENT %all; ((%annotation;)?, (%element;)*)>
+<!ATTLIST %all;
+ minOccurs (1) #IMPLIED
+ maxOccurs (1) #IMPLIED
+ id ID #IMPLIED
+ %allAttrs;>
+
+<!ELEMENT %choice; ((%annotation;)?, (%element;| %group;| %cs; | %any;)*)>
+<!ATTLIST %choice;
+ minOccurs %nonNegativeInteger; #IMPLIED
+ maxOccurs CDATA #IMPLIED
+ id ID #IMPLIED
+ %choiceAttrs;>
+
+<!ELEMENT %sequence; ((%annotation;)?, (%element;| %group;| %cs; | %any;)*)>
+<!ATTLIST %sequence;
+ minOccurs %nonNegativeInteger; #IMPLIED
+ maxOccurs CDATA #IMPLIED
+ id ID #IMPLIED
+ %sequenceAttrs;>
+
+<!-- an anonymous grouping in a model, or
+ a top-level named group definition, or a reference to same -->
+
+<!-- Note that if order is 'all', group is not allowed inside.
+ If order is 'all' THIS group must be alone (or referenced alone) at
+ the top level of a content model -->
+<!-- If order is 'all', minOccurs==maxOccurs==1 on element/any inside -->
+<!-- Should allow minOccurs=0 inside order='all' . . . -->
+
+<!ELEMENT %any; (%annotation;)?>
+<!ATTLIST %any;
+ namespace CDATA '##any'
+ processContents (skip|lax|strict) 'strict'
+ minOccurs %nonNegativeInteger; '1'
+ maxOccurs CDATA '1'
+ id ID #IMPLIED
+ %anyAttrs;>
+
+<!-- namespace is interpreted as follows:
+ ##any - - any non-conflicting WFXML at all
+
+ ##other - - any non-conflicting WFXML from namespace other
+ than targetNamespace
+
+ ##local - - any unqualified non-conflicting WFXML/attribute
+ one or - - any non-conflicting WFXML from
+ more URI the listed namespaces
+ references
+
+ ##targetNamespace ##local may appear in the above list,
+ with the obvious meaning -->
+
+<!ELEMENT %anyAttribute; (%annotation;)?>
+<!ATTLIST %anyAttribute;
+ namespace CDATA '##any'
+ processContents (skip|lax|strict) 'strict'
+ id ID #IMPLIED
+ %anyAttributeAttrs;>
+<!-- namespace is interpreted as for 'any' above -->
+
+<!-- simpleType only if no type|ref attribute -->
+<!-- ref not allowed at top level, name iff at top level -->
+<!ELEMENT %attribute; ((%annotation;)?, (%simpleType;)?)>
+<!ATTLIST %attribute;
+ name %NCName; #IMPLIED
+ id ID #IMPLIED
+ ref %QName; #IMPLIED
+ type %QName; #IMPLIED
+ use (prohibited|optional|required) #IMPLIED
+ default CDATA #IMPLIED
+ fixed CDATA #IMPLIED
+ form %formValues; #IMPLIED
+ %attributeAttrs;>
+<!-- type and ref are mutually exclusive.
+ name and ref are mutually exclusive, one is required -->
+<!-- default for use is optional when nested, none otherwise -->
+<!-- default and fixed are mutually exclusive -->
+<!-- type attr and simpleType content are mutually exclusive -->
+
+<!-- an attributeGroup is a named collection of attribute decls, or a
+ reference thereto -->
+<!ELEMENT %attributeGroup; ((%annotation;)?,
+ (%attribute; | %attributeGroup;)*,
+ (%anyAttribute;)?) >
+<!ATTLIST %attributeGroup;
+ name %NCName; #IMPLIED
+ id ID #IMPLIED
+ ref %QName; #IMPLIED
+ %attributeGroupAttrs;>
+
+<!-- ref iff no content, no name. ref iff not top level -->
+
+<!-- better reference mechanisms -->
+<!ELEMENT %unique; ((%annotation;)?, %selector;, (%field;)+)>
+<!ATTLIST %unique;
+ name %NCName; #REQUIRED
+ id ID #IMPLIED
+ %uniqueAttrs;>
+
+<!ELEMENT %key; ((%annotation;)?, %selector;, (%field;)+)>
+<!ATTLIST %key;
+ name %NCName; #REQUIRED
+ id ID #IMPLIED
+ %keyAttrs;>
+
+<!ELEMENT %keyref; ((%annotation;)?, %selector;, (%field;)+)>
+<!ATTLIST %keyref;
+ name %NCName; #REQUIRED
+ refer %QName; #REQUIRED
+ id ID #IMPLIED
+ %keyrefAttrs;>
+
+<!ELEMENT %selector; ((%annotation;)?)>
+<!ATTLIST %selector;
+ xpath %XPathExpr; #REQUIRED
+ id ID #IMPLIED
+ %selectorAttrs;>
+<!ELEMENT %field; ((%annotation;)?)>
+<!ATTLIST %field;
+ xpath %XPathExpr; #REQUIRED
+ id ID #IMPLIED
+ %fieldAttrs;>
+
+<!-- Schema combination mechanisms -->
+<!ELEMENT %include; (%annotation;)?>
+<!ATTLIST %include;
+ schemaLocation %URIref; #REQUIRED
+ id ID #IMPLIED
+ %includeAttrs;>
+
+<!ELEMENT %import; (%annotation;)?>
+<!ATTLIST %import;
+ namespace %URIref; #IMPLIED
+ schemaLocation %URIref; #IMPLIED
+ id ID #IMPLIED
+ %importAttrs;>
+
+<!ELEMENT %redefine; (%annotation; | %simpleType; | %complexType; |
+ %attributeGroup; | %group;)*>
+<!ATTLIST %redefine;
+ schemaLocation %URIref; #REQUIRED
+ id ID #IMPLIED
+ %redefineAttrs;>
+
+<!ELEMENT %notation; (%annotation;)?>
+<!ATTLIST %notation;
+ name %NCName; #REQUIRED
+ id ID #IMPLIED
+ public CDATA #REQUIRED
+ system %URIref; #IMPLIED
+ %notationAttrs;>
+
+<!-- Annotation is either application information or documentation -->
+<!-- By having these here they are available for datatypes as well
+ as all the structures elements -->
+
+<!ELEMENT %annotation; (%appinfo; | %documentation;)*>
+<!ATTLIST %annotation; %annotationAttrs;>
+
+<!-- User must define annotation elements in internal subset for this
+ to work -->
+<!ELEMENT %appinfo; ANY> <!-- too restrictive -->
+<!ATTLIST %appinfo;
+ source %URIref; #IMPLIED
+ id ID #IMPLIED
+ %appinfoAttrs;>
+<!ELEMENT %documentation; ANY> <!-- too restrictive -->
+<!ATTLIST %documentation;
+ source %URIref; #IMPLIED
+ id ID #IMPLIED
+ xml:lang CDATA #IMPLIED
+ %documentationAttrs;>
+
+<!NOTATION XMLSchemaStructures PUBLIC
+ 'structures' 'http://www.w3.org/2001/XMLSchema.xsd' >
+<!NOTATION XML PUBLIC
+ 'REC-xml-1998-0210' 'http://www.w3.org/TR/1998/REC-xml-19980210' >
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/datatypes.dtd b/sandbox/sebastien/cpp/apr-2/xsd/external/datatypes.dtd
new file mode 100644
index 0000000000..685e89a57e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/datatypes.dtd
@@ -0,0 +1,204 @@
+<!--
+ DTD for XML Schemas: Part 2: Datatypes
+ $Id: datatypes.dtd,v 1.23 2001/03/16 17:36:30 ht Exp $
+ Note this DTD is NOT normative, or even definitive. - - the
+ prose copy in the datatypes REC is the definitive version
+ (which shouldn't differ from this one except for this comment
+ and entity expansions, but just in case)
+ -->
+
+<!--
+ This DTD cannot be used on its own, it is intended
+ only for incorporation in XMLSchema.dtd, q.v.
+ -->
+
+<!-- Define all the element names, with optional prefix -->
+<!ENTITY % simpleType "%p;simpleType">
+<!ENTITY % restriction "%p;restriction">
+<!ENTITY % list "%p;list">
+<!ENTITY % union "%p;union">
+<!ENTITY % maxExclusive "%p;maxExclusive">
+<!ENTITY % minExclusive "%p;minExclusive">
+<!ENTITY % maxInclusive "%p;maxInclusive">
+<!ENTITY % minInclusive "%p;minInclusive">
+<!ENTITY % totalDigits "%p;totalDigits">
+<!ENTITY % fractionDigits "%p;fractionDigits">
+<!ENTITY % length "%p;length">
+<!ENTITY % minLength "%p;minLength">
+<!ENTITY % maxLength "%p;maxLength">
+<!ENTITY % enumeration "%p;enumeration">
+<!ENTITY % whiteSpace "%p;whiteSpace">
+<!ENTITY % pattern "%p;pattern">
+
+<!--
+ Customisation entities for the ATTLIST of each element
+ type. Define one of these if your schema takes advantage
+ of the anyAttribute='##other' in the schema for schemas
+ -->
+
+<!ENTITY % simpleTypeAttrs "">
+<!ENTITY % restrictionAttrs "">
+<!ENTITY % listAttrs "">
+<!ENTITY % unionAttrs "">
+<!ENTITY % maxExclusiveAttrs "">
+<!ENTITY % minExclusiveAttrs "">
+<!ENTITY % maxInclusiveAttrs "">
+<!ENTITY % minInclusiveAttrs "">
+<!ENTITY % totalDigitsAttrs "">
+<!ENTITY % fractionDigitsAttrs "">
+<!ENTITY % lengthAttrs "">
+<!ENTITY % minLengthAttrs "">
+<!ENTITY % maxLengthAttrs "">
+<!ENTITY % enumerationAttrs "">
+<!ENTITY % whiteSpaceAttrs "">
+<!ENTITY % patternAttrs "">
+
+<!-- Define some entities for informative use as attribute
+ types -->
+<!ENTITY % URIref "CDATA">
+<!ENTITY % XPathExpr "CDATA">
+<!ENTITY % QName "NMTOKEN">
+<!ENTITY % QNames "NMTOKENS">
+<!ENTITY % NCName "NMTOKEN">
+<!ENTITY % nonNegativeInteger "NMTOKEN">
+<!ENTITY % boolean "(true|false)">
+<!ENTITY % simpleDerivationSet "CDATA">
+<!--
+ #all or space-separated list drawn from derivationChoice
+ -->
+
+<!--
+ Note that the use of 'facet' below is less restrictive
+ than is really intended: There should in fact be no
+ more than one of each of minInclusive, minExclusive,
+ maxInclusive, maxExclusive, totalDigits, fractionDigits,
+ length, maxLength, minLength within datatype,
+ and the min- and max- variants of Inclusive and Exclusive
+ are mutually exclusive. On the other hand, pattern and
+ enumeration may repeat.
+ -->
+<!ENTITY % minBound "(%minInclusive; | %minExclusive;)">
+<!ENTITY % maxBound "(%maxInclusive; | %maxExclusive;)">
+<!ENTITY % bounds "%minBound; | %maxBound;">
+<!ENTITY % numeric "%totalDigits; | %fractionDigits;">
+<!ENTITY % ordered "%bounds; | %numeric;">
+<!ENTITY % unordered
+ "%pattern; | %enumeration; | %whiteSpace; | %length; |
+ %maxLength; | %minLength;">
+<!ENTITY % facet "%ordered; | %unordered;">
+<!ENTITY % facetAttr
+ "value CDATA #REQUIRED
+ id ID #IMPLIED">
+<!ENTITY % fixedAttr "fixed %boolean; #IMPLIED">
+<!ENTITY % facetModel "(%annotation;)?">
+<!ELEMENT %simpleType;
+ ((%annotation;)?, (%restriction; | %list; | %union;))>
+<!ATTLIST %simpleType;
+ name %NCName; #IMPLIED
+ final %simpleDerivationSet; #IMPLIED
+ id ID #IMPLIED
+ %simpleTypeAttrs;>
+<!-- name is required at top level -->
+<!ELEMENT %restriction; ((%annotation;)?,
+ (%restriction1; |
+ ((%simpleType;)?,(%facet;)*)),
+ (%attrDecls;))>
+<!ATTLIST %restriction;
+ base %QName; #IMPLIED
+ id ID #IMPLIED
+ %restrictionAttrs;>
+<!--
+ base and simpleType child are mutually exclusive,
+ one is required.
+
+ restriction is shared between simpleType and
+ simpleContent and complexContent (in XMLSchema.xsd).
+ restriction1 is for the latter cases, when this
+ is restricting a complex type, as is attrDecls.
+ -->
+<!ELEMENT %list; ((%annotation;)?,(%simpleType;)?)>
+<!ATTLIST %list;
+ itemType %QName; #IMPLIED
+ id ID #IMPLIED
+ %listAttrs;>
+<!--
+ itemType and simpleType child are mutually exclusive,
+ one is required
+ -->
+<!ELEMENT %union; ((%annotation;)?,(%simpleType;)*)>
+<!ATTLIST %union;
+ id ID #IMPLIED
+ memberTypes %QNames; #IMPLIED
+ %unionAttrs;>
+<!--
+ At least one item in memberTypes or one simpleType
+ child is required
+ -->
+
+<!ELEMENT %maxExclusive; %facetModel;>
+<!ATTLIST %maxExclusive;
+ %facetAttr;
+ %fixedAttr;
+ %maxExclusiveAttrs;>
+<!ELEMENT %minExclusive; %facetModel;>
+<!ATTLIST %minExclusive;
+ %facetAttr;
+ %fixedAttr;
+ %minExclusiveAttrs;>
+
+<!ELEMENT %maxInclusive; %facetModel;>
+<!ATTLIST %maxInclusive;
+ %facetAttr;
+ %fixedAttr;
+ %maxInclusiveAttrs;>
+<!ELEMENT %minInclusive; %facetModel;>
+<!ATTLIST %minInclusive;
+ %facetAttr;
+ %fixedAttr;
+ %minInclusiveAttrs;>
+
+<!ELEMENT %totalDigits; %facetModel;>
+<!ATTLIST %totalDigits;
+ %facetAttr;
+ %fixedAttr;
+ %totalDigitsAttrs;>
+<!ELEMENT %fractionDigits; %facetModel;>
+<!ATTLIST %fractionDigits;
+ %facetAttr;
+ %fixedAttr;
+ %fractionDigitsAttrs;>
+
+<!ELEMENT %length; %facetModel;>
+<!ATTLIST %length;
+ %facetAttr;
+ %fixedAttr;
+ %lengthAttrs;>
+<!ELEMENT %minLength; %facetModel;>
+<!ATTLIST %minLength;
+ %facetAttr;
+ %fixedAttr;
+ %minLengthAttrs;>
+<!ELEMENT %maxLength; %facetModel;>
+<!ATTLIST %maxLength;
+ %facetAttr;
+ %fixedAttr;
+ %maxLengthAttrs;>
+
+<!-- This one can be repeated -->
+<!ELEMENT %enumeration; %facetModel;>
+<!ATTLIST %enumeration;
+ %facetAttr;
+ %enumerationAttrs;>
+
+<!ELEMENT %whiteSpace; %facetModel;>
+<!ATTLIST %whiteSpace;
+ %facetAttr;
+ %fixedAttr;
+ %whiteSpaceAttrs;>
+
+<!-- This one can be repeated -->
+<!ELEMENT %pattern; %facetModel;>
+<!ATTLIST %pattern;
+ %facetAttr;
+ %patternAttrs;>
+
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-secext-1.0.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-secext-1.0.xsd
new file mode 100644
index 0000000000..6829a00f4b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-secext-1.0.xsd
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+Copyright © OASIS Open 2002-2004. All Rights Reserved.
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+This document and the information contained herein is provided on an “AS IS” basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+-->
+<xsd:schema targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all" version="0.2">
+ <xsd:import namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" schemaLocation="oasis-200401-wss-wssecurity-utility-1.0.xsd"/>
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
+ <xsd:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
+ <xsd:complexType name="AttributedString">
+ <xsd:annotation>
+ <xsd:documentation>This type represents an element with arbitrary attributes.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute ref="wsu:Id"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="PasswordString">
+ <xsd:annotation>
+ <xsd:documentation>This type is used for password elements per Section 4.1.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="wsse:AttributedString">
+ <xsd:attribute name="Type" type="xsd:anyURI"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="EncodedString">
+ <xsd:annotation>
+ <xsd:documentation>This type is used for elements containing stringified binary data.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="wsse:AttributedString">
+ <xsd:attribute name="EncodingType" type="xsd:anyURI"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="UsernameTokenType">
+ <xsd:annotation>
+ <xsd:documentation>This type represents a username token per Section 4.1</xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="Username" type="wsse:AttributedString"/>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute ref="wsu:Id"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:complexType name="BinarySecurityTokenType">
+ <xsd:annotation>
+ <xsd:documentation>A security token that is encoded in binary</xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="wsse:EncodedString">
+ <xsd:attribute name="ValueType" type="xsd:anyURI"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="KeyIdentifierType">
+ <xsd:annotation>
+ <xsd:documentation>A security token key identifier</xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="wsse:EncodedString">
+ <xsd:attribute name="ValueType" type="xsd:anyURI"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:simpleType name="tUsage">
+ <xsd:annotation>
+ <xsd:documentation>Typedef to allow a list of usages (as URIs).</xsd:documentation>
+ </xsd:annotation>
+ <xsd:list itemType="xsd:anyURI"/>
+ </xsd:simpleType>
+ <xsd:attribute name="Usage" type="tUsage">
+ <xsd:annotation>
+ <xsd:documentation>This global attribute is used to indicate the usage of a referenced or indicated token within the containing context</xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:complexType name="ReferenceType">
+ <xsd:annotation>
+ <xsd:documentation>This type represents a reference to an external security token.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute name="URI" type="xsd:anyURI"/>
+ <xsd:attribute name="ValueType" type="xsd:anyURI"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:complexType name="EmbeddedType">
+ <xsd:annotation>
+ <xsd:documentation>This type represents a reference to an embedded security token.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:any processContents="lax"/>
+ </xsd:choice>
+ <xsd:attribute name="ValueType" type="xsd:anyURI"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:complexType name="SecurityTokenReferenceType">
+ <xsd:annotation>
+ <xsd:documentation>This type is used reference a security token.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:any processContents="lax"/>
+ </xsd:choice>
+ <xsd:attribute ref="wsu:Id"/>
+ <xsd:attribute ref="wsse:Usage"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:complexType name="SecurityHeaderType">
+ <xsd:annotation>
+ <xsd:documentation>This complexType defines header block to use for security-relevant data directed at a specific SOAP actor.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>The use of "any" is to allow extensibility and different forms of security data.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:any>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:complexType name="TransformationParametersType">
+ <xsd:annotation>
+ <xsd:documentation>This complexType defines a container for elements to be specified from any namespace as properties/parameters of a DSIG transformation.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>The use of "any" is to allow extensibility from any namespace.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:any>
+ </xsd:sequence>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:complexType>
+ <xsd:element name="UsernameToken" type="wsse:UsernameTokenType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines the wsse:UsernameToken element per Section 4.1.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="BinarySecurityToken" type="wsse:BinarySecurityTokenType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines the wsse:BinarySecurityToken element per Section 4.2.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="Reference" type="wsse:ReferenceType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines a security token reference</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="Embedded" type="wsse:EmbeddedType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines a security token embedded reference</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="KeyIdentifier" type="wsse:KeyIdentifierType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines a key identifier reference</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="SecurityTokenReference" type="wsse:SecurityTokenReferenceType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines the wsse:SecurityTokenReference per Section 4.3.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="Security" type="wsse:SecurityHeaderType">
+ <xsd:annotation>
+ <xsd:documentation>This element defines the wsse:Security SOAP header element per Section 4.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="TransformationParameters" type="wsse:TransformationParametersType">
+ <xsd:annotation>
+ <xsd:documentation>This element contains properties for transformations from any namespace, including DSIG.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="Password" type="wsse:PasswordString"/>
+ <xsd:element name="Nonce" type="wsse:EncodedString"/>
+ <xsd:simpleType name="FaultcodeEnum">
+ <xsd:restriction base="xsd:QName">
+ <xsd:enumeration value="wsse:UnsupportedSecurityToken"/>
+ <xsd:enumeration value="wsse:UnsupportedAlgorithm"/>
+ <xsd:enumeration value="wsse:InvalidSecurity"/>
+ <xsd:enumeration value="wsse:InvalidSecurityToken"/>
+ <xsd:enumeration value="wsse:FailedAuthentication"/>
+ <xsd:enumeration value="wsse:FailedCheck"/>
+ <xsd:enumeration value="wsse:SecurityTokenUnavailable"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+</xsd:schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-utility-1.0.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-utility-1.0.xsd
new file mode 100644
index 0000000000..f8d74e9c6e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/oasis-200401-wss-wssecurity-utility-1.0.xsd
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
+OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
+Copyright © OASIS Open 2002-2004. All Rights Reserved.
+This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
+The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
+This document and the information contained herein is provided on an “AS IS” basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+-->
+<xsd:schema targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+
+
+
+xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.1">
+ <!-- // Fault Codes /////////////////////////////////////////// -->
+ <xsd:simpleType name="tTimestampFault">
+ <xsd:annotation>
+ <xsd:documentation>
+This type defines the fault code value for Timestamp message expiration.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:QName">
+ <xsd:enumeration value="wsu:MessageExpired"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <!-- // Global attributes //////////////////////////////////// -->
+ <xsd:attribute name="Id" type="xsd:ID">
+ <xsd:annotation>
+ <xsd:documentation>
+This global attribute supports annotating arbitrary elements with an ID.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attributeGroup name="commonAtts">
+ <xsd:annotation>
+ <xsd:documentation>
+Convenience attribute group used to simplify this schema.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute ref="wsu:Id" use="optional"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:attributeGroup>
+ <!-- // Utility types //////////////////////////////////////// -->
+ <xsd:complexType name="AttributedDateTime">
+ <xsd:annotation>
+ <xsd:documentation>
+This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attributeGroup ref="wsu:commonAtts"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="AttributedURI">
+ <xsd:annotation>
+ <xsd:documentation>
+This type is for elements whose [children] is an anyURI and can have arbitrary attributes.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:anyURI">
+ <xsd:attributeGroup ref="wsu:commonAtts"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <!-- // Timestamp header components /////////////////////////// -->
+ <xsd:complexType name="TimestampType">
+ <xsd:annotation>
+ <xsd:documentation>
+This complex type ties together the timestamp related elements into a composite type.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element ref="wsu:Created" minOccurs="0"/>
+ <xsd:element ref="wsu:Expires" minOccurs="0"/>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:any namespace="##other" processContents="lax"/>
+ </xsd:choice>
+ </xsd:sequence>
+ <xsd:attributeGroup ref="wsu:commonAtts"/>
+ </xsd:complexType>
+ <xsd:element name="Timestamp" type="wsu:TimestampType">
+ <xsd:annotation>
+ <xsd:documentation>
+This element allows Timestamps to be applied anywhere element wildcards are present,
+including as a SOAP header.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <!-- global element decls to allow individual elements to appear anywhere -->
+ <xsd:element name="Expires" type="wsu:AttributedDateTime">
+ <xsd:annotation>
+ <xsd:documentation>
+This element allows an expiration time to be applied anywhere element wildcards are present.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="Created" type="wsu:AttributedDateTime">
+ <xsd:annotation>
+ <xsd:documentation>
+This element allows a creation time to be applied anywhere element wildcards are present.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+</xsd:schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/ws-addr.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/ws-addr.xsd
new file mode 100644
index 0000000000..f6fc9c53b0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/ws-addr.xsd
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ W3C XML Schema defined in the Web Services Addressing 1.0 specification
+ http://www.w3.org/TR/ws-addr-core
+
+ Copyright © 2005 World Wide Web Consortium,
+
+ (Massachusetts Institute of Technology, European Research Consortium for
+ Informatics and Mathematics, Keio University). All Rights Reserved. This
+ work is distributed under the W3C® Software License [1] 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.
+
+ [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+ $Id: ws-addr.xsd,v 1.2 2008/07/23 13:38:16 plehegar Exp $
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.w3.org/2005/08/addressing" targetNamespace="http://www.w3.org/2005/08/addressing" blockDefault="#all" elementFormDefault="qualified" finalDefault="" attributeFormDefault="unqualified">
+
+ <!-- Constructs from the WS-Addressing Core -->
+
+ <xs:element name="EndpointReference" type="tns:EndpointReferenceType"/>
+ <xs:complexType name="EndpointReferenceType" mixed="false">
+ <xs:sequence>
+ <xs:element name="Address" type="tns:AttributedURIType"/>
+ <xs:element ref="tns:ReferenceParameters" minOccurs="0"/>
+ <xs:element ref="tns:Metadata" minOccurs="0"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <xs:element name="ReferenceParameters" type="tns:ReferenceParametersType"/>
+ <xs:complexType name="ReferenceParametersType" mixed="false">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <xs:element name="Metadata" type="tns:MetadataType"/>
+ <xs:complexType name="MetadataType" mixed="false">
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+ <xs:element name="MessageID" type="tns:AttributedURIType"/>
+ <xs:element name="RelatesTo" type="tns:RelatesToType"/>
+ <xs:complexType name="RelatesToType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute name="RelationshipType" type="tns:RelationshipTypeOpenEnum" use="optional" default="http://www.w3.org/2005/08/addressing/reply"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:simpleType name="RelationshipTypeOpenEnum">
+ <xs:union memberTypes="tns:RelationshipType xs:anyURI"/>
+ </xs:simpleType>
+
+ <xs:simpleType name="RelationshipType">
+ <xs:restriction base="xs:anyURI">
+ <xs:enumeration value="http://www.w3.org/2005/08/addressing/reply"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="ReplyTo" type="tns:EndpointReferenceType"/>
+ <xs:element name="From" type="tns:EndpointReferenceType"/>
+ <xs:element name="FaultTo" type="tns:EndpointReferenceType"/>
+ <xs:element name="To" type="tns:AttributedURIType"/>
+ <xs:element name="Action" type="tns:AttributedURIType"/>
+
+ <xs:complexType name="AttributedURIType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <!-- Constructs from the WS-Addressing SOAP binding -->
+
+ <xs:attribute name="IsReferenceParameter" type="xs:boolean"/>
+
+ <xs:simpleType name="FaultCodesOpenEnumType">
+ <xs:union memberTypes="tns:FaultCodesType xs:QName"/>
+ </xs:simpleType>
+
+ <xs:simpleType name="FaultCodesType">
+ <xs:restriction base="xs:QName">
+ <xs:enumeration value="tns:InvalidAddressingHeader"/>
+ <xs:enumeration value="tns:InvalidAddress"/>
+ <xs:enumeration value="tns:InvalidEPR"/>
+ <xs:enumeration value="tns:InvalidCardinality"/>
+ <xs:enumeration value="tns:MissingAddressInEPR"/>
+ <xs:enumeration value="tns:DuplicateMessageID"/>
+ <xs:enumeration value="tns:ActionMismatch"/>
+ <xs:enumeration value="tns:MessageAddressingHeaderRequired"/>
+ <xs:enumeration value="tns:DestinationUnreachable"/>
+ <xs:enumeration value="tns:ActionNotSupported"/>
+ <xs:enumeration value="tns:EndpointUnavailable"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="RetryAfter" type="tns:AttributedUnsignedLongType"/>
+ <xs:complexType name="AttributedUnsignedLongType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:unsignedLong">
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:element name="ProblemHeaderQName" type="tns:AttributedQNameType"/>
+ <xs:complexType name="AttributedQNameType" mixed="false">
+ <xs:simpleContent>
+ <xs:extension base="xs:QName">
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:element name="ProblemIRI" type="tns:AttributedURIType"/>
+
+ <xs:element name="ProblemAction" type="tns:ProblemActionType"/>
+ <xs:complexType name="ProblemActionType" mixed="false">
+ <xs:sequence>
+ <xs:element ref="tns:Action" minOccurs="0"/>
+ <xs:element name="SoapAction" minOccurs="0" type="xs:anyURI"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+
+</xs:schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/ws-policy.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/ws-policy.xsd
new file mode 100644
index 0000000000..71d5da4f5b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/ws-policy.xsd
@@ -0,0 +1,141 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!--
+
+ W3C XML Schema defined in the Web Services Policy 1.5
+ Framework specification
+
+ http://www.w3.org/TR/ws-policy-framework
+
+ Copyright © 2006 World Wide Web Consortium,
+
+ (Massachusetts Institute of Technology, European Research Consortium for
+ Informatics and Mathematics, Keio University). All Rights Reserved. This
+ work is distributed under the W3C® Software License [1] 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.
+
+ [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+ $Id: ws-policy.xsd,v 1.2 2007/02/14 16:38:37 fsasaki Exp $
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:tns="http://www.w3.org/ns/ws-policy"
+ xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+ xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+ targetNamespace="http://www.w3.org/ns/ws-policy" blockDefault="#all"
+ elementFormDefault="qualified">
+
+ <xs:import
+ namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+ schemaLocation="oasis-200401-wss-wssecurity-secext-1.0.xsd" />
+
+ <xs:import
+ namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+ schemaLocation="oasis-200401-wss-wssecurity-utility-1.0.xsd" />
+
+ <xs:import
+ namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="xml.xsd" />
+
+ <!-- Constructs from the Web Services Policy 1.5 Framework -->
+
+ <xs:element name="Policy" >
+ <xs:complexType>
+
+ <xs:complexContent>
+ <xs:extension base="tns:OperatorContentType" >
+ <xs:attribute name="Name" type="xs:anyURI" />
+ <xs:anyAttribute namespace="##any" processContents="lax" />
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="All" type="tns:OperatorContentType" />
+ <xs:element name="ExactlyOne" type="tns:OperatorContentType" />
+
+ <xs:complexType name="OperatorContentType" >
+ <xs:sequence>
+ <xs:choice minOccurs="0" maxOccurs="unbounded" >
+ <xs:element ref="tns:Policy" />
+ <xs:element ref="tns:All" />
+ <xs:element ref="tns:ExactlyOne" />
+
+ <xs:element ref="tns:PolicyReference" />
+ <xs:any namespace="##other" processContents="lax" />
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:element name="PolicyReference" >
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="URI" type="xs:anyURI" use="required" />
+
+ <xs:attribute name="Digest" type="xs:base64Binary" />
+ <xs:attribute name="DigestAlgorithm"
+ type="xs:anyURI"
+ default="http://www.w3.org/ns/ws-policy/Sha1Exc"
+ />
+ <xs:anyAttribute namespace="##any" processContents="lax" />
+ </xs:complexType>
+ </xs:element>
+
+ <xs:attribute name="Optional" type="xs:boolean" default="false" />
+ <xs:attribute name="Ignorable" type="xs:boolean" default="false" />
+
+ <!-- Constructs from the Web Services Policy 1.5 Attachment -->
+
+ <xs:attribute name="PolicyURIs" >
+ <xs:simpleType>
+ <xs:list itemType="xs:anyURI" />
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:element name="PolicyAttachment" >
+ <xs:complexType>
+ <xs:sequence>
+
+ <xs:element ref="tns:AppliesTo" />
+ <xs:choice maxOccurs="unbounded" >
+ <xs:element ref="tns:Policy" />
+ <xs:element ref="tns:PolicyReference" />
+ </xs:choice>
+ <!-- omitted only because it causes the content model to be non-determistic
+ <xs:element ref="wsse:Security" minOccurs="0" />
+-->
+ <xs:any namespace="##other"
+ processContents="lax"
+ minOccurs="0"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##any" processContents="lax" />
+
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="AppliesTo" >
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##any"
+ processContents="lax"
+ maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:anyAttribute namespace="##any" processContents="lax" />
+
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="URI">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:anyAttribute namespace="##any" processContents="lax" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+
+</xs:schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/wsdl20-instance.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/wsdl20-instance.xsd
new file mode 100644
index 0000000000..7fb8c1beed
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/wsdl20-instance.xsd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd">
+<!--
+ W3C XML Schema defined in the Web Services Description (WSDL)
+ Version 2.0 specification
+ http://www.w3.org/TR/wsdl20
+
+ Copyright © 2007 World Wide Web Consortium,
+
+ (Massachusetts Institute of Technology, European Research Consortium for
+ Informatics and Mathematics, Keio University). All Rights Reserved. This
+ work is distributed under the W3C® Software License [1] 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.
+
+ [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+ $Id: wsdl20-instance.xsd,v 1.1 2007/06/19 15:59:38 plehegar Exp $
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdli="http://www.w3.org/ns/wsdl-instance" targetNamespace="http://www.w3.org/ns/wsdl-instance" elementFormDefault="qualified" finalDefault="" blockDefault="" attributeFormDefault="unqualified">
+
+ <xs:attribute name="wsdlLocation">
+ <xs:annotation>
+ <xs:documentation>
+ This attribute can be used to provide some hints on where
+ additional WSDL information for a given namespace can be
+ found in order to help with QName resolution
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:list itemType="xs:anyURI"/>
+ </xs:simpleType>
+ </xs:attribute>
+
+</xs:schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/xml.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/xml.xsd
new file mode 100644
index 0000000000..ac4b0ec8e6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/xml.xsd
@@ -0,0 +1,117 @@
+<?xml version='1.0'?>
+<!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd" >
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
+
+ <xs:annotation>
+ <xs:documentation>
+ See http://www.w3.org/XML/1998/namespace.html and
+ http://www.w3.org/TR/REC-xml for information about this namespace.
+
+ This schema document describes the XML namespace, in a form
+ suitable for import by other schema documents.
+
+ Note that local names in this namespace are intended to be defined
+ only by the World Wide Web Consortium or its subgroups. The
+ following names are currently defined in this namespace and should
+ not be used with conflicting semantics by any Working Group,
+ specification, or document instance:
+
+ base (as an attribute name): denotes an attribute whose value
+ provides a URI to be used as the base for interpreting any
+ relative URIs in the scope of the element on which it
+ appears; its value is inherited. This name is reserved
+ by virtue of its definition in the XML Base specification.
+
+ lang (as an attribute name): denotes an attribute whose value
+ is a language code for the natural language of the content of
+ any element; its value is inherited. This name is reserved
+ by virtue of its definition in the XML specification.
+
+ space (as an attribute name): denotes an attribute whose
+ value is a keyword indicating what whitespace processing
+ discipline is intended for the content of the element; its
+ value is inherited. This name is reserved by virtue of its
+ definition in the XML specification.
+
+ Father (in any context at all): denotes Jon Bosak, the chair of
+ the original XML Working Group. This name is reserved by
+ the following decision of the W3C XML Plenary and
+ XML Coordination groups:
+
+ In appreciation for his vision, leadership and dedication
+ the W3C XML Plenary on this 10th day of February, 2000
+ reserves for Jon Bosak in perpetuity the XML name
+ xml:Father
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>This schema defines attributes and an attribute group
+ suitable for use by
+ schemas wishing to allow xml:base, xml:lang or xml:space attributes
+ on elements they define.
+
+ To enable this, such a schema must import this schema
+ for the XML namespace, e.g. as follows:
+ &lt;schema . . .>
+ . . .
+ &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2001/03/xml.xsd"/>
+
+ Subsequently, qualified reference to any of the attributes
+ or the group defined below will have the desired effect, e.g.
+
+ &lt;type . . .>
+ . . .
+ &lt;attributeGroup ref="xml:specialAttrs"/>
+
+ will define a type which will schema-validate an instance
+ element with any of those attributes</xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>In keeping with the XML Schema WG's standard versioning
+ policy, this schema document will persist at
+ http://www.w3.org/2001/03/xml.xsd.
+ At the date of issue it can also be found at
+ http://www.w3.org/2001/xml.xsd.
+ The schema document at that URI may however change in the future,
+ in order to remain compatible with the latest version of XML Schema
+ itself. In other words, if the XML Schema namespace changes, the version
+ of this document at
+ http://www.w3.org/2001/xml.xsd will change
+ accordingly; the version at
+ http://www.w3.org/2001/03/xml.xsd will not change.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang" type="xs:language">
+ <xs:annotation>
+ <xs:documentation>In due course, we should install the relevant ISO 2- and 3-letter
+ codes as the enumerated possible values . . .</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="space" default="preserve">
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="base" type="xs:anyURI">
+ <xs:annotation>
+ <xs:documentation>See http://www.w3.org/TR/xmlbase/ for
+ information about this attribute.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ </xs:attributeGroup>
+
+</xs:schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/external/xmldsig-core-schema.xsd b/sandbox/sebastien/cpp/apr-2/xsd/external/xmldsig-core-schema.xsd
new file mode 100644
index 0000000000..c4e9808cfd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/external/xmldsig-core-schema.xsd
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE schema
+ PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "XMLSchema.dtd"
+ [
+ <!ATTLIST schema
+ xmlns:ds CDATA #FIXED "http://www.w3.org/2000/09/xmldsig#">
+ <!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>
+ <!ENTITY % p ''>
+ <!ENTITY % s ''>
+ ]>
+
+<!-- Schema for XML Signatures
+ http://www.w3.org/2000/09/xmldsig#
+ $Revision$ on $Date$ by $Author: reagle $
+
+ Copyright 2001 The Internet Society and W3C (Massachusetts Institute
+ of Technology, Institut National de Recherche en Informatique et en
+ Automatique, Keio University). All Rights Reserved.
+ http://www.w3.org/Consortium/Legal/
+
+ This document is governed by the W3C Software License [1] as described
+ in the FAQ [2].
+
+ [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
+ [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
+-->
+
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ targetNamespace="http://www.w3.org/2000/09/xmldsig#"
+ version="0.1" elementFormDefault="qualified">
+
+<!-- Basic Types Defined for Signatures -->
+
+<simpleType name="CryptoBinary">
+ <restriction base="base64Binary">
+ </restriction>
+</simpleType>
+
+<!-- Start Signature -->
+
+<element name="Signature" type="ds:SignatureType"/>
+<complexType name="SignatureType">
+ <sequence>
+ <element ref="ds:SignedInfo"/>
+ <element ref="ds:SignatureValue"/>
+ <element ref="ds:KeyInfo" minOccurs="0"/>
+ <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="SignatureValue" type="ds:SignatureValueType"/>
+ <complexType name="SignatureValueType">
+ <simpleContent>
+ <extension base="base64Binary">
+ <attribute name="Id" type="ID" use="optional"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+<!-- Start SignedInfo -->
+
+<element name="SignedInfo" type="ds:SignedInfoType"/>
+<complexType name="SignedInfoType">
+ <sequence>
+ <element ref="ds:CanonicalizationMethod"/>
+ <element ref="ds:SignatureMethod"/>
+ <element ref="ds:Reference" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/>
+ <complexType name="CanonicalizationMethodType" mixed="true">
+ <sequence>
+ <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
+ <!-- (0,unbounded) elements from (1,1) namespace -->
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+ <element name="SignatureMethod" type="ds:SignatureMethodType"/>
+ <complexType name="SignatureMethodType" mixed="true">
+ <sequence>
+ <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
+ <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
+ <!-- (0,unbounded) elements from (1,1) external namespace -->
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+<!-- Start Reference -->
+
+<element name="Reference" type="ds:ReferenceType"/>
+<complexType name="ReferenceType">
+ <sequence>
+ <element ref="ds:Transforms" minOccurs="0"/>
+ <element ref="ds:DigestMethod"/>
+ <element ref="ds:DigestValue"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+ <attribute name="URI" type="anyURI" use="optional"/>
+ <attribute name="Type" type="anyURI" use="optional"/>
+</complexType>
+
+ <element name="Transforms" type="ds:TransformsType"/>
+ <complexType name="TransformsType">
+ <sequence>
+ <element ref="ds:Transform" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <element name="Transform" type="ds:TransformType"/>
+ <complexType name="TransformType" mixed="true">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ <!-- (1,1) elements from (0,unbounded) namespaces -->
+ <element name="XPath" type="string"/>
+ </choice>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+ </complexType>
+
+<!-- End Reference -->
+
+<element name="DigestMethod" type="ds:DigestMethodType"/>
+<complexType name="DigestMethodType" mixed="true">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Algorithm" type="anyURI" use="required"/>
+</complexType>
+
+<element name="DigestValue" type="ds:DigestValueType"/>
+<simpleType name="DigestValueType">
+ <restriction base="base64Binary"/>
+</simpleType>
+
+<!-- End SignedInfo -->
+
+<!-- Start KeyInfo -->
+
+<element name="KeyInfo" type="ds:KeyInfoType"/>
+<complexType name="KeyInfoType" mixed="true">
+ <choice maxOccurs="unbounded">
+ <element ref="ds:KeyName"/>
+ <element ref="ds:KeyValue"/>
+ <element ref="ds:RetrievalMethod"/>
+ <element ref="ds:X509Data"/>
+ <element ref="ds:PGPData"/>
+ <element ref="ds:SPKIData"/>
+ <element ref="ds:MgmtData"/>
+ <any processContents="lax" namespace="##other"/>
+ <!-- (1,1) elements from (0,unbounded) namespaces -->
+ </choice>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="KeyName" type="string"/>
+ <element name="MgmtData" type="string"/>
+
+ <element name="KeyValue" type="ds:KeyValueType"/>
+ <complexType name="KeyValueType" mixed="true">
+ <choice>
+ <element ref="ds:DSAKeyValue"/>
+ <element ref="ds:RSAKeyValue"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </complexType>
+
+ <element name="RetrievalMethod" type="ds:RetrievalMethodType"/>
+ <complexType name="RetrievalMethodType">
+ <sequence>
+ <element ref="ds:Transforms" minOccurs="0"/>
+ </sequence>
+ <attribute name="URI" type="anyURI"/>
+ <attribute name="Type" type="anyURI" use="optional"/>
+ </complexType>
+
+<!-- Start X509Data -->
+
+<element name="X509Data" type="ds:X509DataType"/>
+<complexType name="X509DataType">
+ <sequence maxOccurs="unbounded">
+ <choice>
+ <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
+ <element name="X509SKI" type="base64Binary"/>
+ <element name="X509SubjectName" type="string"/>
+ <element name="X509Certificate" type="base64Binary"/>
+ <element name="X509CRL" type="base64Binary"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </sequence>
+</complexType>
+
+<complexType name="X509IssuerSerialType">
+ <sequence>
+ <element name="X509IssuerName" type="string"/>
+ <element name="X509SerialNumber" type="integer"/>
+ </sequence>
+</complexType>
+
+<!-- End X509Data -->
+
+<!-- Begin PGPData -->
+
+<element name="PGPData" type="ds:PGPDataType"/>
+<complexType name="PGPDataType">
+ <choice>
+ <sequence>
+ <element name="PGPKeyID" type="base64Binary"/>
+ <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <sequence>
+ <element name="PGPKeyPacket" type="base64Binary"/>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ </choice>
+</complexType>
+
+<!-- End PGPData -->
+
+<!-- Begin SPKIData -->
+
+<element name="SPKIData" type="ds:SPKIDataType"/>
+<complexType name="SPKIDataType">
+ <sequence maxOccurs="unbounded">
+ <element name="SPKISexp" type="base64Binary"/>
+ <any namespace="##other" processContents="lax" minOccurs="0"/>
+ </sequence>
+</complexType>
+
+<!-- End SPKIData -->
+
+<!-- End KeyInfo -->
+
+<!-- Start Object (Manifest, SignatureProperty) -->
+
+<element name="Object" type="ds:ObjectType"/>
+<complexType name="ObjectType" mixed="true">
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##any" processContents="lax"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+ <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
+ <attribute name="Encoding" type="anyURI" use="optional"/>
+</complexType>
+
+<element name="Manifest" type="ds:ManifestType"/>
+<complexType name="ManifestType">
+ <sequence>
+ <element ref="ds:Reference" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+<element name="SignatureProperties" type="ds:SignaturePropertiesType"/>
+<complexType name="SignaturePropertiesType">
+ <sequence>
+ <element ref="ds:SignatureProperty" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+ <element name="SignatureProperty" type="ds:SignaturePropertyType"/>
+ <complexType name="SignaturePropertyType" mixed="true">
+ <choice maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ <!-- (1,1) elements from (1,unbounded) namespaces -->
+ </choice>
+ <attribute name="Target" type="anyURI" use="required"/>
+ <attribute name="Id" type="ID" use="optional"/>
+ </complexType>
+
+<!-- End Object (Manifest, SignatureProperty) -->
+
+<!-- Start Algorithm Parameters -->
+
+<simpleType name="HMACOutputLengthType">
+ <restriction base="integer"/>
+</simpleType>
+
+<!-- Start KeyValue Element-types -->
+
+<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
+<complexType name="DSAKeyValueType">
+ <sequence>
+ <sequence minOccurs="0">
+ <element name="P" type="ds:CryptoBinary"/>
+ <element name="Q" type="ds:CryptoBinary"/>
+ </sequence>
+ <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
+ <element name="Y" type="ds:CryptoBinary"/>
+ <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
+ <sequence minOccurs="0">
+ <element name="Seed" type="ds:CryptoBinary"/>
+ <element name="PgenCounter" type="ds:CryptoBinary"/>
+ </sequence>
+ </sequence>
+</complexType>
+
+<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
+<complexType name="RSAKeyValueType">
+ <sequence>
+ <element name="Modulus" type="ds:CryptoBinary"/>
+ <element name="Exponent" type="ds:CryptoBinary"/>
+ </sequence>
+</complexType>
+
+<!-- End KeyValue Element-types -->
+
+<!-- End Signature -->
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-1.1-cd05.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-1.1-cd05.xsd
new file mode 100644
index 0000000000..51cc513276
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-1.1-cd05.xsd
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2010. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <include schemaLocation="sca-interface-java-1.1-cd04.xsd"/>
+ <include schemaLocation="sca-interface-wsdl-1.1-cd05.xsd"/>
+ <include schemaLocation="sca-interface-cpp-1.1-cd04.xsd"/>
+
+ <include schemaLocation="sca-implementation-java-1.1-cd02.xsd"/>
+ <include schemaLocation="sca-implementation-composite-1.1-cd05.xsd"/>
+ <include schemaLocation="sca-implementation-cpp-1.1-cd04.xsd"/>
+
+ <include schemaLocation="sca-binding-ws-1.1-cd04.xsd"/>
+ <include schemaLocation="sca-binding-sca-1.1-cd05.xsd"/>
+
+ <include schemaLocation="sca-definitions-1.1-cd05.xsd"/>
+ <include schemaLocation="sca-policy-1.1-cd03.xsd"/>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-binding-sca-1.1-cd05.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-binding-sca-1.1-cd05.xsd
new file mode 100644
index 0000000000..a337296d45
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-binding-sca-1.1-cd05.xsd
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <!-- SCA Binding -->
+ <element name="binding.sca" type="sca:SCABinding"
+ substitutionGroup="sca:binding"/>
+ <complexType name="SCABinding">
+ <complexContent>
+ <extension base="sca:Binding"/>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-binding-ws-1.1-cd04.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-binding-ws-1.1-cd04.xsd
new file mode 100644
index 0000000000..cf71892578
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-binding-ws-1.1-cd04.xsd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:wsdli="http://www.w3.org/ns/wsdl-instance"
+ xmlns:wsa="http://www.w3.org/2005/08/addressing"
+ elementFormDefault="qualified">
+
+ <import namespace="http://www.w3.org/ns/wsdl-instance"
+ schemaLocation="external/wsdl20-instance.xsd"/>
+ <import namespace="http://www.w3.org/2005/08/addressing"
+ schemaLocation="external/ws-addr.xsd"/>
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <element name="binding.ws" type="sca:WebServiceBinding"
+ substitutionGroup="sca:binding"/>
+
+ <complexType name="WebServiceBinding">
+ <complexContent>
+ <extension base="sca:Binding">
+ <sequence>
+ <element ref="wsa:EndpointReference"
+ minOccurs="0" maxOccurs="unbounded"/>
+ <!-- any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/-->
+ </sequence>
+ <attribute name="wsdlElement" type="anyURI" use="optional"/>
+ <attribute ref="wsdli:wsdlLocation" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-core-1.1-cd05.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-core-1.1-cd05.xsd
new file mode 100644
index 0000000000..466a1466e7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-core-1.1-cd05.xsd
@@ -0,0 +1,478 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-policy-1.1-cd03.xsd"/>
+ <import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="external/xml.xsd"/>
+
+ <!-- Common extension base for SCA definitions -->
+ <complexType name="CommonExtensionBase">
+ <sequence>
+ <element ref="sca:documentation" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <element name="documentation" type="sca:Documentation"/>
+ <complexType name="Documentation" mixed="true">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute ref="xml:lang"/>
+ </complexType>
+
+ <!-- Component Type -->
+ <element name="componentType" type="sca:ComponentType"/>
+ <complexType name="ComponentType">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <element ref="sca:implementation" minOccurs="0"/>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="service" type="sca:ComponentService"/>
+ <element name="reference"
+ type="sca:ComponentTypeReference"/>
+ <element name="property" type="sca:Property"/>
+ </choice>
+ <!-- any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/ -->
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Composite -->
+ <element name="composite" type="sca:Composite"/>
+ <complexType name="Composite">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <element ref="sca:include" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ <element name="service" type="sca:Service"/>
+ <element name="property" type="sca:Property"/>
+ <element name="component" type="sca:Component"/>
+ <element name="reference" type="sca:Reference"/>
+ <element name="wire" type="sca:Wire"/>
+ </choice>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="targetNamespace" type="anyURI" use="required"/>
+ <attribute name="local" type="boolean" use="optional"
+ default="false"/>
+ <attribute name="autowire" type="boolean" use="optional"
+ default="false"/>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Contract base type for Service, Reference -->
+ <complexType name="Contract" abstract="true">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <element ref="sca:interface" minOccurs="0" maxOccurs="1" />
+ <element ref="sca:binding" minOccurs="0"
+ maxOccurs="unbounded" />
+ <element ref="sca:callback" minOccurs="0" maxOccurs="1" />
+ <element ref="sca:requires" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:policySetAttachment" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:extensions" minOccurs="0" maxOccurs="1" />
+ </sequence>
+ <attribute name="name" type="NCName" use="required" />
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional" />
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Service -->
+ <complexType name="Service">
+ <complexContent>
+ <extension base="sca:Contract">
+ <attribute name="promote" type="anyURI" use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Interface -->
+ <element name="interface" type="sca:Interface" abstract="true"/>
+ <complexType name="Interface" abstract="true">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ </choice>
+ <attribute name="remotable" type="boolean" use="optional"/>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Reference -->
+ <complexType name="Reference">
+ <complexContent>
+ <extension base="sca:Contract">
+ <attribute name="target" type="sca:listOfAnyURIs"
+ use="optional"/>
+ <attribute name="wiredByImpl" type="boolean" use="optional"
+ default="false"/>
+ <attribute name="multiplicity" type="sca:Multiplicity"
+ use="required"/>
+ <attribute name="promote" type="sca:listOfAnyURIs"
+ use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Property -->
+ <complexType name="SCAPropertyBase" mixed="true">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <!-- NOT an extension point; This any exists to accept
+ the element-based or complex type property
+ i.e. no element-based extension point under "sca:property" -->
+ </sequence>
+ <!-- mixed="true" to handle simple type -->
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="type" type="QName" use="optional"/>
+ <attribute name="element" type="QName" use="optional"/>
+ <attribute name="many" type="boolean" use="optional" default="false"/>
+ <attribute name="value" type="anySimpleType" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <complexType name="Property" mixed="true">
+ <complexContent mixed="true">
+ <extension base="sca:SCAPropertyBase">
+ <attribute name="mustSupply" type="boolean" use="optional"
+ default="false"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="PropertyValue" mixed="true">
+ <complexContent mixed="true">
+ <extension base="sca:SCAPropertyBase">
+ <attribute name="source" type="string" use="optional"/>
+ <attribute name="file" type="anyURI" use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Binding -->
+ <element name="binding" type="sca:Binding" abstract="true"/>
+ <complexType name="Binding" abstract="true">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <element ref="sca:wireFormat" minOccurs="0" maxOccurs="1" />
+ <element ref="sca:operationSelector" minOccurs="0"
+ maxOccurs="1" />
+ <element ref="sca:requires" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:policySetAttachment" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="uri" type="anyURI" use="optional"/>
+ <attribute name="name" type="NCName" use="optional"/>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Binding Type -->
+ <element name="bindingType" type="sca:BindingType"/>
+ <complexType name="BindingType">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <!-- any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/-->
+ </sequence>
+ <attribute name="type" type="QName" use="required"/>
+ <attribute name="alwaysProvides" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="mayProvide" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- WireFormat Type -->
+ <element name="wireFormat" type="sca:WireFormatType" abstract="true"/>
+ <complexType name="WireFormatType" abstract="true">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded" />
+ </sequence>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <!-- OperationSelector Type -->
+ <element name="operationSelector" type="sca:OperationSelectorType"
+ abstract="true"/>
+ <complexType name="OperationSelectorType" abstract="true">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded" />
+ </sequence>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <!-- Callback -->
+ <element name="callback" type="sca:Callback"/>
+ <complexType name="Callback">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:binding"/>
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ <!-- any namespace="##other" processContents="lax"/ -->
+ </choice>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Component -->
+ <complexType name="Component">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <element ref="sca:implementation" minOccurs="1"
+ maxOccurs="1"/>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="service" type="sca:ComponentService"/>
+ <element name="reference" type="sca:ComponentReference"/>
+ <element name="property" type="sca:PropertyValue"/>
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ </choice>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="autowire" type="boolean" use="optional"/>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Component Service -->
+ <complexType name="ComponentService">
+ <complexContent>
+ <extension base="sca:Contract">
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Component Reference -->
+ <complexType name="ComponentReference">
+ <complexContent>
+ <extension base="sca:Contract">
+ <attribute name="autowire" type="boolean" use="optional"/>
+ <attribute name="target" type="sca:listOfAnyURIs"
+ use="optional"/>
+ <attribute name="wiredByImpl" type="boolean" use="optional"
+ default="false"/>
+ <attribute name="multiplicity" type="sca:Multiplicity"
+ use="optional" default="1..1"/>
+ <attribute name="nonOverridable" type="boolean" use="optional"
+ default="false"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Component Type Reference -->
+ <complexType name="ComponentTypeReference">
+ <complexContent>
+ <restriction base="sca:ComponentReference">
+ <sequence>
+ <element ref="sca:documentation" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:interface" minOccurs="0"/>
+ <element ref="sca:binding" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:callback" minOccurs="0"/>
+ <element ref="sca:requires" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:policySetAttachment" minOccurs="0"
+ maxOccurs="unbounded"/>
+ <element ref="sca:extensions" minOccurs="0" maxOccurs="1" />
+ </sequence>
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="autowire" type="boolean" use="optional"/>
+ <attribute name="wiredByImpl" type="boolean" use="optional"
+ default="false"/>
+ <attribute name="multiplicity" type="sca:Multiplicity"
+ use="optional" default="1..1"/>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </restriction>
+ </complexContent>
+ </complexType>
+
+
+ <!-- Implementation -->
+ <element name="implementation" type="sca:Implementation" abstract="true"/>
+ <complexType name="Implementation" abstract="true">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ </choice>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="policySets" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Implementation Type -->
+ <element name="implementationType" type="sca:ImplementationType"/>
+ <complexType name="ImplementationType">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="type" type="QName" use="required"/>
+ <attribute name="alwaysProvides" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="mayProvide" type="sca:listOfQNames"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Wire -->
+ <complexType name="Wire">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="source" type="anyURI" use="required"/>
+ <attribute name="target" type="anyURI" use="required"/>
+ <attribute name="replace" type="boolean" use="optional"
+ default="false"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Include -->
+ <element name="include" type="sca:Include"/>
+ <complexType name="Include">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <attribute name="name" type="QName"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Extensions element -->
+ <element name="extensions">
+ <complexType>
+ <sequence>
+ <any namespace="##other" processContents="lax"
+ minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ </element>
+
+ <!-- Intents within WSDL documents -->
+ <attribute name="requires" type="sca:listOfQNames"/>
+
+ <!-- Global attribute definition for @callback to mark a WSDL port type
+ as having a callback interface defined in terms of a second port
+ type. -->
+ <attribute name="callback" type="anyURI"/>
+
+ <!-- Value type definition for property values -->
+ <element name="value" type="sca:ValueType"/>
+ <complexType name="ValueType" mixed="true">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0"
+ maxOccurs='unbounded'/>
+ </sequence>
+ <!-- mixed="true" to handle simple type -->
+ <anyAttribute namespace="##any" processContents="lax"/>
+ </complexType>
+
+ <!-- Miscellaneous simple type definitions -->
+ <simpleType name="Multiplicity">
+ <restriction base="string">
+ <enumeration value="0..1"/>
+ <enumeration value="1..1"/>
+ <enumeration value="0..n"/>
+ <enumeration value="1..n"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="OverrideOptions">
+ <restriction base="string">
+ <enumeration value="no"/>
+ <enumeration value="may"/>
+ <enumeration value="must"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="listOfQNames">
+ <list itemType="QName"/>
+ </simpleType>
+
+ <simpleType name="listOfAnyURIs">
+ <list itemType="anyURI"/>
+ </simpleType>
+
+ <simpleType name="CreateResource">
+ <restriction base="string">
+ <enumeration value="always" />
+ <enumeration value="never" />
+ <enumeration value="ifnotexist" />
+ </restriction>
+ </simpleType>
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-definitions-1.1-cd05.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-definitions-1.1-cd05.xsd
new file mode 100644
index 0000000000..8f2f20db19
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-definitions-1.1-cd05.xsd
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+ <include schemaLocation="sca-policy-1.1-cd03.xsd"/>
+
+ <!-- Definitions -->
+ <element name="definitions" type="sca:tDefinitions"/>
+ <complexType name="tDefinitions">
+ <complexContent>
+ <extension base="sca:CommonExtensionBase">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:intent"/>
+ <element ref="sca:policySet"/>
+ <element ref="sca:bindingType"/>
+ <element ref="sca:implementationType"/>
+ <any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </choice>
+ <attribute name="targetNamespace" type="anyURI" use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-composite-1.1-cd05.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-composite-1.1-cd05.xsd
new file mode 100644
index 0000000000..f2780f9895
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-composite-1.1-cd05.xsd
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <!-- Composite Implementation -->
+ <element name="implementation.composite" type="sca:SCAImplementation"
+ substitutionGroup="sca:implementation"/>
+ <complexType name="SCAImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="name" type="QName" use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-cpp-1.1-cd04.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-cpp-1.1-cd04.xsd
new file mode 100644
index 0000000000..b54ced4e4e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-cpp-1.1-cd04.xsd
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2006,2010. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd" />
+
+ <element name="implementation.cpp" type="sca:CPPImplementation"
+ substitutionGroup="sca:implementation" />
+ <complexType name="CPPImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <element name="function"
+ type="sca:CPPImplementationFunction" minOccurs="0"
+ maxOccurs="unbounded" />
+ <any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded" />
+ </sequence>
+ <attribute name="library" type="NCName" use="required" />
+ <attribute name="header" type="NCName" use="required" />
+ <attribute name="path" type="string" use="optional" />
+ <attribute name="class" type="Name" use="optional" />
+ <attribute name="componentType" type="string"
+ use="optional" />
+ <attribute name="scope"
+ type="sca:CPPImplementationScope" use="optional" />
+ <attribute name="eagerInit" type="boolean"
+ use="optional" />
+ <attribute name="allowsPassByReference" type="boolean"
+ use="optional" />
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <simpleType name="CPPImplementationScope">
+ <restriction base="string">
+ <enumeration value="stateless" />
+ <enumeration value="composite" />
+ </restriction>
+ </simpleType>
+
+ <complexType name="CPPImplementationFunction">
+ <sequence>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ </choice>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded" />
+ </sequence>
+ <attribute name="name" type="NCName" use="required" />
+ <attribute name="requires" type="sca:listOfQNames" use="optional" />
+ <attribute name="policySets" type="sca:listOfQNames" use="optional" />
+ <attribute name="allowsPassByReference" type="boolean"
+ use="optional" />
+ <anyAttribute namespace="##other" processContents="lax" />
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-java-1.1-cd02.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-java-1.1-cd02.xsd
new file mode 100644
index 0000000000..2856a51450
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-implementation-java-1.1-cd02.xsd
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2010. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <!-- Java Implementation -->
+ <element name="implementation.java" type="sca:JavaImplementation"
+ substitutionGroup="sca:implementation"/>
+ <complexType name="JavaImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="class" type="NCName" use="required"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema> \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-cpp-1.1-cd04.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-cpp-1.1-cd04.xsd
new file mode 100644
index 0000000000..b07bf01f1d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-cpp-1.1-cd04.xsd
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <!--
+ Copyright(C) OASIS(R) 2006,2010. All Rights Reserved. OASIS trademark,
+ IPR and other policies apply.
+ -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd" />
+
+ <element name="interface.cpp" type="sca:CPPInterface"
+ substitutionGroup="sca:interface" />
+
+ <complexType name="CPPInterface">
+ <complexContent>
+ <extension base="sca:Interface">
+ <sequence>
+ <element name="function" type="sca:CPPFunction" minOccurs="0"
+ maxOccurs="unbounded" />
+ <element name="callbackFunction" type="sca:CPPFunction"
+ minOccurs="0" maxOccurs="unbounded" />
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded" />
+ </sequence>
+ <attribute name="header" type="string" use="required" />
+ <attribute name="class" type="Name" use="required" />
+ <attribute name="callbackHeader" type="string" use="optional" />
+ <attribute name="callbackClass" type="Name" use="optional" />
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="CPPFunction">
+ <sequence>
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element ref="sca:requires"/>
+ <element ref="sca:policySetAttachment"/>
+ </choice>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded" />
+ </sequence>
+ <attribute name="name" type="NCName" use="required" />
+ <attribute name="requires" type="sca:listOfQNames" use="optional" />
+ <attribute name="policySets" type="sca:listOfQNames" use="optional" />
+ <attribute name="oneWay" type="boolean" use="optional" />
+ <attribute name="exclude" type="boolean" use="optional" />
+ <anyAttribute namespace="##other" processContents="lax" />
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-java-1.1-cd04.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-java-1.1-cd04.xsd
new file mode 100644
index 0000000000..7b78e13749
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-java-1.1-cd04.xsd
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2010. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <!-- Java Interface -->
+ <element name="interface.java" type="sca:JavaInterface"
+ substitutionGroup="sca:interface"/>
+ <complexType name="JavaInterface">
+ <complexContent>
+ <extension base="sca:Interface">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="interface" type="NCName" use="required"/>
+ <attribute name="callbackInterface" type="NCName"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-wsdl-1.1-cd05.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-wsdl-1.1-cd05.xsd
new file mode 100644
index 0000000000..8d3510be7d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-interface-wsdl-1.1-cd05.xsd
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2009. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+
+ <!-- WSDL Interface -->
+ <element name="interface.wsdl" type="sca:WSDLPortType"
+ substitutionGroup="sca:interface"/>
+ <complexType name="WSDLPortType">
+ <complexContent>
+ <extension base="sca:Interface">
+ <sequence>
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="interface" type="anyURI" use="required"/>
+ <attribute name="callbackInterface" type="anyURI"
+ use="optional"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/sca-policy-1.1-cd03.xsd b/sandbox/sebastien/cpp/apr-2/xsd/sca-policy-1.1-cd03.xsd
new file mode 100644
index 0000000000..81d7eb346c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/sca-policy-1.1-cd03.xsd
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright(C) OASIS(R) 2005,2010. All Rights Reserved.
+ OASIS trademark, IPR and other policies apply. -->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
+ elementFormDefault="qualified">
+
+ <include schemaLocation="sca-core-1.1-cd05.xsd"/>
+ <import namespace="http://www.w3.org/ns/ws-policy"
+ schemaLocation="external/ws-policy.xsd"/>
+
+ <element name="intent" type="sca:Intent"/>
+ <complexType name="Intent">
+ <sequence>
+ <element name="description" type="string" minOccurs="0"
+ maxOccurs="1" />
+ <element name="qualifier" type="sca:IntentQualifier"
+ minOccurs="0" maxOccurs="unbounded" />
+ <any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="constrains" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="requires" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="excludes" type="sca:listOfQNames"
+ use="optional"/>
+ <attribute name="mutuallyExclusive" type="boolean"
+ use="optional" default="false"/>
+ <attribute name="intentType"
+ type="sca:InteractionOrImplementation"
+ use="optional" default="interaction"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <complexType name="IntentQualifier">
+ <sequence>
+ <element name="description" type="string" minOccurs="0"
+ maxOccurs="1" />
+ <any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="default" type="boolean" use="optional"
+ default="false"/>
+ </complexType>
+
+ <element name="requires">
+ <complexType>
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ </sequence>
+ <attribute name="intents" type="sca:listOfQNames" use="required"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ </element>
+
+ <element name="policySet" type="sca:PolicySet"/>
+ <complexType name="PolicySet">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="policySetReference"
+ type="sca:PolicySetReference"/>
+ <element name="intentMap" type="sca:IntentMap"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ <attribute name="name" type="NCName" use="required"/>
+ <attribute name="provides" type="sca:listOfQNames"/>
+ <attribute name="appliesTo" type="string" use="optional"/>
+ <attribute name="attachTo" type="string" use="optional"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <element name="policySetAttachment">
+ <complexType>
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ </sequence>
+ <attribute name="name" type="QName" use="required"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+ </element>
+
+ <complexType name="PolicySetReference">
+ <attribute name="name" type="QName" use="required"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <complexType name="IntentMap">
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element name="qualifier" type="sca:Qualifier"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ <attribute name="provides" type="QName" use="required"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <complexType name="Qualifier">
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <any namespace="##other" processContents="lax"/>
+ </sequence>
+ <attribute name="name" type="string" use="required"/>
+ <anyAttribute namespace="##other" processContents="lax"/>
+ </complexType>
+
+ <simpleType name="listOfNCNames">
+ <list itemType="NCName"/>
+ </simpleType>
+
+ <simpleType name="InteractionOrImplementation">
+ <restriction base="string">
+ <enumeration value="interaction"/>
+ <enumeration value="implementation"/>
+ </restriction>
+ </simpleType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-atom.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-atom.xsd
new file mode 100644
index 0000000000..603455a1f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-atom.xsd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="binding.atom" type="t:AtomBinding" substitutionGroup="sca:binding"/>
+
+ <complexType name="AtomBinding">
+ <complexContent>
+ <extension base="sca:Binding">
+ <!-- sequence>
+ <any namespace="##targetNamespace" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence -->
+ <attribute name="title" type="string" use="optional"/>
+ <attribute name="description" type="string" use="optional"/>
+ <!-- anyAttribute namespace="##any" processContents="lax"/ -->
+ </extension>
+ </complexContent>
+ </complexType>
+</schema> \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-http.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-http.xsd
new file mode 100644
index 0000000000..67feb54963
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-http.xsd
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="binding.http" type="t:HTTPBinding" substitutionGroup="sca:binding"/>
+
+ <complexType name="HTTPBinding">
+ <complexContent>
+ <extension base="sca:Binding">
+ <sequence>
+ <!-- any namespace="##targetNamespace" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/ -->
+ </sequence>
+ <!-- anyAttribute namespace="##any" processContents="lax"/-->
+ </extension>
+ </complexContent>
+ </complexType>
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-jsonrpc.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-jsonrpc.xsd
new file mode 100644
index 0000000000..d1bdcbdfae
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-jsonrpc.xsd
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="binding.jsonrpc" type="t:JSONRPCBinding" substitutionGroup="sca:binding"/>
+
+ <complexType name="JSONRPCBinding">
+ <complexContent>
+ <extension base="sca:Binding">
+ <sequence>
+ <!-- any namespace="##targetNamespace" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/ -->
+ </sequence>
+ <!-- anyAttribute namespace="##any" processContents="lax"/ -->
+ </extension>
+ </complexContent>
+ </complexType>
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rest.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rest.xsd
new file mode 100644
index 0000000000..f19a0c4248
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rest.xsd
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="binding.rest" type="t:RESTBinding" substitutionGroup="sca:binding"/>
+
+
+ <complexType name="RESTBinding">
+ <complexContent>
+ <extension base="sca:Binding">
+ <sequence>
+ <element ref="t:http-headers" minOccurs="0" maxOccurs="1"/>
+ <!-- any namespace="##targetNamespace" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/ -->
+ </sequence>
+ <!-- anyAttribute namespace="##any" processContents="lax"/-->
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="HTTPHeadersType">
+ <sequence>
+ <element ref="t:header" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <element name="http-headers" type="t:HTTPHeadersType"/>
+
+ <complexType name="HTTPHeaderType">
+ <attribute name="name" type="string" use="required" />
+ <attribute name="value" type="string" use="required" />
+ </complexType>
+
+ <element name="header" type="t:HTTPHeaderType" />
+
+ <!-- wire formats -->
+ <complexType name="WireFormatJSONType">
+ <complexContent>
+ <extension base="sca:WireFormatType"/>
+ </complexContent>
+ </complexType>
+
+ <element name="wireFormat.json" type="t:WireFormatJSONType"
+ substitutionGroup="sca:wireFormat"/>
+
+ <complexType name="WireFormatXMLType">
+ <complexContent>
+ <extension base="sca:WireFormatType"/>
+ </complexContent>
+ </complexType>
+
+ <element name="wireFormat.xml" type="t:WireFormatXMLType"
+ substitutionGroup="sca:wireFormat"/>
+
+ <!-- operation selectors -->
+ <complexType name="OperationSelectorJAXRSType">
+ <complexContent>
+ <extension base="sca:OperationSelectorType"/>
+ </complexContent>
+ </complexType>
+ <element name="operationSelector.jaxrs"
+ type="t:OperationSelectorJAXRSType"
+ substitutionGroup="sca:operationSelector"/>
+
+ <complexType name="OperationSelectorRPCType">
+ <complexContent>
+ <extension base="sca:OperationSelectorType"/>
+ </complexContent>
+ </complexType>
+ <element name="operationSelector.rpc"
+ type="t:OperationSelectorRPCType"
+ substitutionGroup="sca:operationSelector"/>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rss.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rss.xsd
new file mode 100644
index 0000000000..9857ec62b7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-binding-rss.xsd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="binding.rss" type="t:RSSBinding" substitutionGroup="sca:binding"/>
+
+ <complexType name="RSSBinding">
+ <complexContent>
+ <extension base="sca:Binding">
+ <!--sequence>
+ <any namespace="##targetNamespace" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </sequence -->
+ <attribute name="title" type="string" use="optional"/>
+ <attribute name="description" type="string" use="optional"/>
+ <!--anyAttribute namespace="##any" processContents="lax"/-->
+ </extension>
+ </complexContent>
+ </complexType>
+</schema> \ No newline at end of file
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-python.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-python.xsd
new file mode 100644
index 0000000000..182111daa6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-python.xsd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="implementation.python" type="t:PythonImplementation" substitutionGroup="sca:implementation"/>
+
+ <complexType name="PythonImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <any namespace="##targetNamespace" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="script" type="anyURI" use="required"/>
+ <anyAttribute namespace="##any" processContents="lax"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-scheme.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-scheme.xsd
new file mode 100644
index 0000000000..9282918612
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-scheme.xsd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="implementation.scheme" type="t:SchemeImplementation" substitutionGroup="sca:implementation"/>
+
+ <complexType name="SchemeImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <any namespace="##targetNamespace" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="script" type="anyURI" use="required"/>
+ <anyAttribute namespace="##any" processContents="lax"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-widget.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-widget.xsd
new file mode 100644
index 0000000000..8ebc8fc477
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1-implementation-widget.xsd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <element name="implementation.widget" type="t:WidgetImplementation" substitutionGroup="sca:implementation"/>
+
+ <complexType name="WidgetImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <any namespace="##targetNamespace" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="location" type="anyURI" use="required"/>
+ <anyAttribute namespace="##any" processContents="lax"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1.xsd b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1.xsd
new file mode 100644
index 0000000000..1f6347ba98
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/xsd/tuscany-sca-1.1.xsd
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" schemaLocation="sca-1.1-cd05.xsd"/>
+
+ <include schemaLocation="tuscany-sca-1.1-binding-atom.xsd"/>
+ <include schemaLocation="tuscany-sca-1.1-binding-http.xsd"/>
+ <include schemaLocation="tuscany-sca-1.1-binding-jsonrpc.xsd"/>
+ <include schemaLocation="tuscany-sca-1.1-binding-rest.xsd"/>
+ <include schemaLocation="tuscany-sca-1.1-binding-rss.xsd"/>
+
+ <include schemaLocation="tuscany-sca-1.1-implementation-python.xsd"/>
+ <include schemaLocation="tuscany-sca-1.1-implementation-scheme.xsd"/>
+ <include schemaLocation="tuscany-sca-1.1-implementation-widget.xsd"/>
+</schema>