diff options
author | giorgio <giorgio@13f79535-47bb-0310-9956-ffa450edef68> | 2012-09-05 08:31:30 +0000 |
---|---|---|
committer | giorgio <giorgio@13f79535-47bb-0310-9956-ffa450edef68> | 2012-09-05 08:31:30 +0000 |
commit | c9bfccc35345ce58fb5774d4b0b6a9868b262c0a (patch) | |
tree | fe84dd4b90f2acd0b933550b6978094926c1d733 /sca-cpp/branches | |
parent | 5ddabdaf1ff856aae79dadc045ef2aeff08c7887 (diff) |
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1381061 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/branches')
769 files changed, 76765 insertions, 0 deletions
diff --git a/sca-cpp/branches/lightweight-sca/.gitignore b/sca-cpp/branches/lightweight-sca/.gitignore new file mode 100644 index 0000000000..cb61e71d6c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/.gitignore @@ -0,0 +1,155 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# 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 +*.dylib +Makefile +.deps/ +.libs/ +m4/ +*.m4 +config.guess +config.sub +config.status +all.js +cache-manifest.cmf +*-min.html +*-min.js +*-min.css +intro*.png +intro*.b64 +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 +*~ +*.swp +tags +doxygen +*.pyc +*.class +*.stamp +*.jar +*.prefix +*.crt +/*.patch +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 +scheme-test +scheme-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 +scribe-status +js-test +js-shell +file-test +test-start* +test-stop* +xml-value +value-xml +json-value +value-json +element-value +value-element +hosting/server/nuvem +hosting/server/lib +hosting/server/data/apps/*/nuvem +hosting/server/data/apps/*/lib +hosting/server/data/authn +chat-send +opencl-shell +opencl-test + diff --git a/sca-cpp/branches/lightweight-sca/AUTHORS b/sca-cpp/branches/lightweight-sca/AUTHORS new file mode 100644 index 0000000000..b06da1bf3a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/AUTHORS @@ -0,0 +1,5 @@ +Apache Tuscany SCA Runtime +========================== + +The Apache Software Foundation (http://www.apache.org/) + diff --git a/sca-cpp/branches/lightweight-sca/COPYING b/sca-cpp/branches/lightweight-sca/COPYING new file mode 100644 index 0000000000..6b0b1270ff --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/ChangeLog b/sca-cpp/branches/lightweight-sca/ChangeLog new file mode 100644 index 0000000000..a4151dc22a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/INSTALL b/sca-cpp/branches/lightweight-sca/INSTALL new file mode 100644 index 0000000000..c66c88bce5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/INSTALL @@ -0,0 +1,264 @@ +Apache Tuscany SCA Runtime +========================== + +Automated installation on Ubuntu Server 12.04 +============================================= + +Tuscany provides automated install scripts for Ubuntu Server 12.04. +You can start with a fresh Ubuntu Server system and these scripts will take care +of all the download, build and installation steps for you. + +ubuntu/ubuntu-install: +Build and installation of the most commonly used Tuscany features with most +dependencies built from source. + +ubuntu/ubuntu-install-all: +Build and installation of all the Tuscany features 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 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-install +chmod +x ./ubuntu-install +./ubuntu-install + +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 Server. + +Automated installation on Max OS X 10.7.4 +========================================= + +Tuscany provides an automated install script for Mac OS X 10.7.4 and Xcode 4.1. +You can start with a fresh Mac OS X 10.7.4 + Xcode 4.1 system and the script +will take care of all the download, build and installation steps for you. + +macos/macos-install: +Build and installation of the most commonly used Tuscany features with all +dependencies built from source. + +To run the automated installation: +mkdir tuscany +cd tuscany +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/macos/macos-install +chmod +x ./macos-install +./macos-install + +The installation script will display each command as it's executed. + +The dependencies will be built using the GCC compiler. The Tuscany SCA runtime +will be built using the Apple Clang/LLVM compiler. + +That's all you need to do to build and install the Tuscany SCA runtime on Mac +OS X. + + +Step by step build and installation +=================================== + +For manual build and install steps on other systems than Ubuntu Server and Mac +OS X, or if you need to customize your installation, read on... + +The Tuscany SCA Linux build uses the GNU Autotools tool chain. + +First install the following development tools: +autoconf-2.68 +automake-1.11 +libtool-2.4.2 +doxygen-1.7.1 +gcc-g++-4.6.1 + +Then install the following development dependencies: + +Apache HTTP server and APR: +httpd-2.4.2 (http://httpd.apache.org/) +apr-1.4.6 and apr-util-1.4.1 (http://apr.apache.org/) +built with OpenSSL libssl-0.9.8, libpcre3-8.12, +and expat 2.0.1 + +Memcached: +memcached-1.4.7 (http://memcached.org/) +built with libevent-1.4.14 + +XML: +libxml2-2.7.7 (http://xmlsoft.org/) + +CURL: +curl-7-24.0 + +JSON: +Mozilla SpiderMonkey libmozjs 1.8.5 and +(https://developer.mozilla.org/en/SpiderMonkey) +built with Mozilla nspr-4.8.8 + +Key/value persistent store: +tinycdb-0.77 (http://www.corpit.ru/mjt/tinycdb.html) + +Optional dependencies: + +Web application firewall: +Mod-security 2.6.6 (http://www.modsecurity.org/) +with the Mod-security core rule set 2.2.5 + +Web page optimizations: +Page Speed SDK 1.9 (http://code.google.com/p/page-speed/) + +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 libuuid1-2.19.1, libboost-1.46.1, libboost-program-options-1.46.1 and +libboost-filesystem-1.46.1 + +Python: +Python 2.7.3 (http://www.python.org/) +Google AppEngine 1.4.0 (http://code.google.com/appengine/) + +OpenCL: +an OpenCL SDK (http://software.intel.com/en-us/articles/opencl-sdk/, +http://developer.nvidia.com/, http://developer.amd.com/sdks/amdappsdk) + +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 + +Key/value persistent store: +Google LevelDB 1.2 (http://code.google.com/p/leveldb/) + +SQL database: +PostgreSQL 9.1.2 (http://www.postgresql.org/) +PgBouncer 1.5 (http://wiki.postgresql.org/wiki/PgBouncer) + +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 memory usage debugging using Electric Fence add: +--enable-efence + +To enable memory usage debugging using mmap add: +--enable-malloc-mmap + +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 OpenCL component implementations: +--enable-opencl + +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 and PgBouncer): +--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 build the support for Mod-security: +--enable-mod-security + +To enable Page Speed Web page optimizations: +--enable-pagespeed + +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 Server 12.04 with some of the +most useful options and the corresponding dependencies installed under $build: + +./configure --prefix=$build/tuscany-sca-cpp-bin \ +--enable-threads --enable-maintainer-mode \ +--with-curl=$build/curl-7.24.0-bin --with-libxml2=$build/libxml2-2.7.7-bin \ +--with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin \ +--with-httpd=$build/httpd-2.4.2-bin \ +--with-memcached=$build/memcached-1.4.7-bin \ +--with-tinycdb=$build/tinycdb-0.77-bin \ +--with-js-include=$build/js-1.8.5-bin/include/js \ +--with-js-lib=$build/js-1.8.5-bin/lib \ +--enable-python --with-python=$build/python-2.7.3-bin \ +--enable-sqldb --with-pgsql=$build/postgresql-9.1.2-bin \ +--with-pgbouncer=$build/pgbouncer-1.5-bin \ +--enable-log --with-thrift=$build/thrift-0.2.0-bin \ +--with-scribe=$build/scribe-2.2-bin \ +--enable-oauth --with-liboauth=$build/liboauth-0.9.1-bin \ +--enable-mod-security --with-mod-security=$build/modsecurity-apache-2.6.6-bin \ +--enable-pagespeed --with-pagespeed=$build/page-speed-1.9-bin + +To build the Tuscany SCA runtime, do this: +make + +To run the tests, do this: +make check + +To install the Tuscany SCA binaries, do this: +make install + +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 + diff --git a/sca-cpp/branches/lightweight-sca/LICENSE b/sca-cpp/branches/lightweight-sca/LICENSE new file mode 100644 index 0000000000..ff3e0653d1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/Makefile.am b/sca-cpp/branches/lightweight-sca/Makefile.am new file mode 100644 index 0000000000..10d04d8c0c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 hosting samples doc macos 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/sca-cpp/branches/lightweight-sca/NEWS b/sca-cpp/branches/lightweight-sca/NEWS new file mode 100644 index 0000000000..dea502fcae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/NOTICE b/sca-cpp/branches/lightweight-sca/NOTICE new file mode 100644 index 0000000000..615f6b1f87 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/README b/sca-cpp/branches/lightweight-sca/README new file mode 100644 index 0000000000..1d81008041 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/README @@ -0,0 +1,127 @@ +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; +Constdb: fast persistent store for mostly constant data, using TinyCDB; +Filedb: key/value persistent store, using plain files; +Http: HTTP client, using Libcurl; +Smtp: SMTP client, using Libcurl; +Kvdb: fast key/value persistent store, using LevelDB; +Log: distributed logger, using Facebook Scribe; +Queue: AMQP queuing, using Apache Qpid/C; +Sqldb: SQL database, using PostgreSQL and PgBouncer; +Webservice: Web service gateway, using Apache Axis2/C. + +These components present a simple ATOMPub REST interface, allowing you to work +with a data cache, a database, a message queue or a chat connection for example +very simply using HTTP GET, POST, PUT and DELETE methods. + + +Getting the source code +======================= + +To checkout the source code, do this: +git clone git://git.apache.org/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/.git +curl -OL http://git.apache.org/authors.txt +cd .. +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 data encoding + | | |-- edit Composite app editor + | | |-- http HTTP protocol + | | |-- java Support for Java components + | | |-- json JSON data encoding + | | |-- oauth User signin using OAuth + | | |-- opencl Support for OpenCL components + | | |-- openid User signin using OpenID + | | |-- python Support for Python components + | | |-- rss RSS data encoding + | | |-- 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 + | | |-- constdb TinyCDB constant persistent store + | | |-- filedb Plain file persistent store + | | |-- http HTTP client + | | |-- kvdb LevelDB key/value persistent store + | | |-- log Scribe logger + | | |-- queue AMQP message queue + | | |-- smtp SMTP client + | | |-- 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 + | | + | |-- macos Automated install on Mac OS X 10.7.4 + | |-- ubuntu Automated install on Ubuntu 12.04 + | |-- patches Temporary patches to some of the dependencies + | + |-- 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/sca-cpp/branches/lightweight-sca/bootstrap b/sca-cpp/branches/lightweight-sca/bootstrap new file mode 100755 index 0000000000..77850981e3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/bootstrap @@ -0,0 +1,32 @@ +#!/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. + +libtoolize="$(type -P glibtoolize || type -P libtoolize)" +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/sca-cpp/branches/lightweight-sca/components/Makefile.am b/sca-cpp/branches/lightweight-sca/components/Makefile.am new file mode 100644 index 0000000000..6d3807058c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 http smtp log constdb filedb queue sqldb webservice + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/Makefile.am b/sca-cpp/branches/lightweight-sca/components/cache/Makefile.am new file mode 100644 index 0000000000..0240a32bb4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/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. + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/components/cache + +dist_comp_SCRIPTS = memcached-log-conf 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 partitioner.componentType *.scm + +comp_LTLIBRARIES = libmemcache.la libdatacache.la libmemocache.la libpartitioner.la +noinst_DATA = libmemcache${libsuffix} libdatacache${libsuffix} libmemocache${libsuffix} libpartitioner${libsuffix} + +libmemcache_la_SOURCES = memcache.cpp +libmemcache${libsuffix}: + ln -s .libs/libmemcache${libsuffix} + +libdatacache_la_SOURCES = datacache.cpp +libdatacache${libsuffix}: + ln -s .libs/libdatacache${libsuffix} + +libmemocache_la_SOURCES = memocache.cpp +libmemocache${libsuffix}: + ln -s .libs/libmemocache${libsuffix} + +libpartitioner_la_SOURCES = partitioner.cpp +libpartitioner${libsuffix}: + ln -s .libs/libpartitioner${libsuffix} + +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 +TESTS = memcached-test server-test diff --git a/sca-cpp/branches/lightweight-sca/components/cache/adder-test.scm b/sca-cpp/branches/lightweight-sca/components/cache/adder-test.scm new file mode 100644 index 0000000000..ccd5bc555f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/cache/cache.composite b/sca-cpp/branches/lightweight-sca/components/cache/cache.composite new file mode 100644 index 0000000000..a85f909db9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/cache.composite @@ -0,0 +1,100 @@ +<?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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="memcache"> + + <component name="memcache"> + <implementation.cpp path="." library="libmemcache"/> + <service name="memcache"> + <binding.http uri="memcache"/> + </service> + <property name="server">localhost</property> + <property name="server">localhost:11212</property> + <property name="server">localhost:11213</property> + </component> + + <component name="l2cache"> + <implementation.cpp path="." library="libmemcache"/> + <service name="l2cache"> + <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"> + <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"> + <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"> + <binding.http uri="adder"/> + </service> + </component> + + <component name="partitioner"> + <implementation.cpp path="." library="libpartitioner"/> + <service name="partitioner"> + <binding.http uri="partitioner"/> + </service> + <reference name="selector" target="selector"/> + <reference name="partition" target="partition1"/> + <reference name="partition" target="partition2"/> + </component> + + <component name="selector"> + <implementation.scheme script="select-test.scm"/> + <service name="selector"> + <binding.http uri="selector"/> + </service> + </component> + + <component name="partition1"> + <implementation.scheme script="partition1-test.scm"/> + <service name="partition1"> + <binding.http uri="partition1"/> + </service> + </component> + + <component name="partition2"> + <implementation.scheme script="partition2-test.scm"/> + <service name="partition2"> + <binding.http uri="partition2"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/cache/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/cache/client-test.cpp new file mode 100644 index 0000000000..63d1691f8b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/client-test.cpp @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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"); +const string partition1uri("http://localhost:8090/partitioner/a"); +const string partition2uri("http://localhost:8090/partitioner/b"); + +bool testCache(const string& uri) { + http::CURLSession cs("", "", "", "", 0); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$3.55"))); + const list<value> b = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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("", "", "", "", 0); + + 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; +} + +bool testPartitioner() { + http::CURLSession cs("", "", "", "", 0); + + const failable<value> res1 = http::get(partition1uri, cs); + assert(hasContent(res1)); + assert(cadr<value>(content(res1)) == string("1")); + + const failable<value> res2 = http::get(partition2uri, cs); + assert(hasContent(res2)); + assert(cadr<value>(content(res2)) == string("2")); + + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$4.55"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + + http::CURLSession cs("", "", "", "", 0); + 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::testPartitioner(); + tuscany::cache::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/components/cache/datacache.componentType b/sca-cpp/branches/lightweight-sca/components/cache/datacache.componentType new file mode 100644 index 0000000000..ca6284c661 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/cache/datacache.cpp b/sca-cpp/branches/lightweight-sca/components/cache/datacache.cpp new file mode 100644 index 0000000000..c259ec33c6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/datacache.cpp @@ -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. + */ + +/* $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). + */ + +#define WANT_HTTPD_LOG 1 +#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)) { + ostringstream os; + os << "Couldn't get cache entry: " << key; + return mkfailure<value>(str(os), 404, false); + } + + // 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/sca-cpp/branches/lightweight-sca/components/cache/memcache-test.cpp b/sca-cpp/branches/lightweight-sca/components/cache/memcache-test.cpp new file mode 100644 index 0000000000..85fc339f1a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcache-test.cpp @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 { + gc_scoped_pool p; + 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::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::memcache::testMemCached(); + tuscany::memcache::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcache.componentType b/sca-cpp/branches/lightweight-sca/components/cache/memcache.componentType new file mode 100644 index 0000000000..8eee91dad6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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="server" type="xsd:string">localhost</property> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcache.cpp b/sca-cpp/branches/lightweight-sca/components/cache/memcache.cpp new file mode 100644 index 0000000000..738a6ddd5a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcache.cpp @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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>(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>(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>(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 mkfailure<value>(); + } + +private: + memcache::MemCached& ch; +}; + +/** + * Convert a list of properties to a list of server addresses. + */ +const list<string> servers(const list<value>& params) { + if (isNil(params)) + return list<string>(); + const value s = ((lambda<value(const list<value>&)>)car(params))(list<value>()); + return cons<string>(s, servers(cdr(params))); +} + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Connect to memcached + memcache::MemCached& ch = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(servers(params))); + + // 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/sca-cpp/branches/lightweight-sca/components/cache/memcache.hpp b/sca-cpp/branches/lightweight-sca/components/cache/memcache.hpp new file mode 100644 index 0000000000..f18405b2ec --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcache.hpp @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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) : p(), owner(true) { + debug(host, "memcache::memcached::host"); + debug(port, "memcache::memcached::port"); + apr_memcache_create(pool(p), 1, 0, &mc); + addServer(host, port); + } + + MemCached(const list<string>& servers) : p(), owner(true) { + debug(servers, "memcache::memcached::servers"); + apr_memcache_create(pool(p), (apr_uint16_t)length(servers), 0, &mc); + addServers(servers); + } + + MemCached(const MemCached& c) : p(c.p), owner(false), mc(c.mc) { + debug("memcache::memcached::copy"); + } + + const MemCached& operator=(const MemCached& c) { + debug("memcache::memcached::operator="); + if(this == &c) + return *this; + p = c.p; + owner = false; + mc = c.mc; + return *this; + } + + ~MemCached() { + } + +private: + gc_child_pool p; + bool owner; + 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(p), c_str(host), (apr_port_t)port, 1, 1, 1, 600, &server); + if (sc != APR_SUCCESS) { + ostringstream os; + os << "Couldn't connect to memcached server: " << host << ":" << port; + return mkfailure<bool>(str(os)); + } + const apr_status_t as = apr_memcache_add_server(mc, server); + if (as != APR_SUCCESS) + return mkfailure<bool>("Couldn't 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) { + ostringstream os; + os << "Couldn't add memcached entry: " << key; + return mkfailure<bool>(str(os)); + } + + 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) { + ostringstream os; + os << "Couldn't set memcached entry: " << key; + return mkfailure<bool>(str(os)); + } + + 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; + gc_local_pool lp; + const apr_status_t rc = apr_memcache_getp(cache.mc, pool(lp), nospaces(c_str(ks)), &data, &size, NULL); + if (rc != APR_SUCCESS) { + ostringstream os; + os << "Couldn't get memcached entry: " << key; + return mkfailure<value>(str(os), 404, false); + } + 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) { + ostringstream os; + os << "Couldn't delete memcached entry: " << key; + return mkfailure<bool>(str(os)); + } + + debug(true, "memcache::delete::result"); + return true; +} + +} +} + +#endif /* tuscany_memcache_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcached-log-conf b/sca-cpp/branches/lightweight-sca/components/cache/memcached-log-conf new file mode 100755 index 0000000000..d8a4896eff --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcached-log-conf @@ -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. + +# Configure memcached logging +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/memcached +if [ "$2" = "" ]; then + cat >$root/memcached/log.conf << EOF +cat >>$root/logs/memcached +EOF + +else + cat >$root/memcached/log.conf << EOF +$2 +EOF + +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcached-ssl-test b/sca-cpp/branches/lightweight-sca/components/cache/memcached-ssl-test new file mode 100755 index 0000000000..a9d42ffd83 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcached-ssl-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. + +# Setup +rm -rf tmp +../../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 tmp 11411 +./memcached-start tmp 11412 +./memcached-start tmp 11413 + +../../modules/http/httpd-conf tmp/tunnel localhost 8089 htdocs +../../modules/http/httpd-event-conf tmp/tunnel +../../modules/http/httpd-tunnel-ssl-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 +../../modules/http/httpd-event-conf tmp/server +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/httpd-tunnel-ssl-conf tmp/server +../../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 tmp 11411 +./memcached-stop tmp 11412 +./memcached-stop tmp 11413 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcached-start b/sca-cpp/branches/lightweight-sca/components/cache/memcached-start new file mode 100755 index 0000000000..ca6c4ac721 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcached-start @@ -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. + +# Start memcached +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +addr=$2 +if [ "$addr" = "" ]; then + host="" + port="11211" +else + host=`$here/../../modules/http/httpd-addr ip $addr` + port=`$here/../../modules/http/httpd-addr port $addr` +fi + +memcached_prefix=`cat $here/memcached.prefix` + +if [ -f "$root/memcached/log.conf" ]; then + log=`cat $root/memcached/log.conf` + v="-v" +else + mkdir -p $root/logs + log="cat >>$root/logs/memcached" + v="" +fi +mkdir -p $root/memcached +echo $log > $root/memcached/logger + +if [ "$host" = "" ]; then + nohup /bin/sh -c "($memcached_prefix/bin/memcached -d -m 4 -p $port $v 2>&1 | sh $root/memcached/logger)" 1>/dev/null 2>/dev/null & +else + nohup /bin/sh -c "($memcached_prefix/bin/memcached -d -l $host -m 4 -p $port $v 2>&1 | sh $root/memcached/logger)" 1>/dev/null 2>/dev/null & +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcached-stop b/sca-cpp/branches/lightweight-sca/components/cache/memcached-stop new file mode 100755 index 0000000000..a36c03c06a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcached-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. + +# Stop memcached +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +addr=$2 +if [ "$addr" = "" ]; then + host="" + port="11211" +else + host=`$here/../../modules/http/httpd-addr ip $addr` + port=`$here/../../modules/http/httpd-addr port $addr` +fi + +memcached_prefix=`cat $here/memcached.prefix` +if [ "$host" = "" ]; then + mc="$memcached_prefix/bin/memcached -d -m 4 -p $port" +else + mc="$memcached_prefix/bin/memcached -d -l $host -m 4 -p $port" +fi + +k=`ps -ef | grep -v grep | grep "${mc}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memcached-test b/sca-cpp/branches/lightweight-sca/components/cache/memcached-test new file mode 100755 index 0000000000..dc274bd4aa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memcached-test @@ -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. + +# Setup +rm -rf tmp +./memcached-start tmp 11211 +./memcached-start tmp 11212 +./memcached-start tmp 11213 +sleep 1 + +# Test +./memcache-test 2>/dev/null +rc=$? + +# Cleanup +./memcached-stop tmp 11211 +./memcached-stop tmp 11212 +./memcached-stop tmp 11213 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/cache/memocache.componentType b/sca-cpp/branches/lightweight-sca/components/cache/memocache.componentType new file mode 100644 index 0000000000..f32677544f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/cache/memocache.cpp b/sca-cpp/branches/lightweight-sca/components/cache/memocache.cpp new file mode 100644 index 0000000000..e7e52cdc59 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/memocache.cpp @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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/sca-cpp/branches/lightweight-sca/components/cache/partition1-test.scm b/sca-cpp/branches/lightweight-sca/components/cache/partition1-test.scm new file mode 100644 index 0000000000..547539e2a1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/partition1-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. + +; Partition test case + +(define (get key) (list key "1")) + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/partition2-test.scm b/sca-cpp/branches/lightweight-sca/components/cache/partition2-test.scm new file mode 100644 index 0000000000..60644128df --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/partition2-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. + +; Partition test case + +(define (get key) (list key "2")) + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/partitioner.componentType b/sca-cpp/branches/lightweight-sca/components/cache/partitioner.componentType new file mode 100644 index 0000000000..9ff2d4f0b5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/partitioner.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="partitioner"/> + <reference name="selector"/> + <reference name="partition" multiplicity="0..n"/> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/cache/partitioner.cpp b/sca-cpp/branches/lightweight-sca/components/cache/partitioner.cpp new file mode 100644 index 0000000000..e3f04ba112 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/partitioner.cpp @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 partitioner component implementation which forwards data access requests to a + * dynamically selected data store component. The selection is externalized, performed + * by a selector component, responsible for selecting the target data store given the + * data access request key and a list of references to available data store components. + * This pattern can be used for sharding or load balancing for example. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" + +namespace tuscany { +namespace partitioner { + +/** + * Return the target partition for a key. + */ +const failable<lambda<value(const list<value>&)> > partition(const value& key, const lambda<value(const list<value>&)>& selector, const list<value>& partitions) { + + // Call the selector component to convert the given key to a partition number + const value p = selector(mklist<value>("get", key, partitions)); + if (isNil(p)) { + ostringstream os; + os << "Couldn't get partition number: " << key; + return mkfailure<lambda<value(const list<value>&)> >(str(os), -1, false); + } + return (const lambda<value(const list<value>&)>)p; +} + +/** + * Get an item from a partition. + */ +const failable<value> get(const value& key, const lambda<value(const list<value>&)>& selector, const list<value>& partitions) { + + // Select partition + const failable<lambda<value(const list<value>&)> > p = partition(key, selector, partitions); + if (!hasContent(p)) + return mkfailure<value>(p); + + // Get from selected partition + const value val = content(p)(mklist<value>("get", key)); + if (isNil(val)) { + ostringstream os; + os << "Couldn't get entry from partition: " << key; + return mkfailure<value>(str(os), 404, false); + } + + return val; +} + +/** + * Post an item to a partition. + */ +const failable<value> post(const value& key, const value& val, const lambda<value(const list<value>&)>& selector, const list<value>& partitions) { + const value id = append<value>(key, mklist(mkuuid())); + + // Select partition + const failable<lambda<value(const list<value>&)> > p = partition(id, selector, partitions); + if (!hasContent(p)) + return mkfailure<value>(p); + + // Put into select partition + content(p)(mklist<value>("put", id, val)); + + return id; +} + +/** + * Put an item into a partition. + */ +const failable<value> put(const value& key, const value& val, const lambda<value(const list<value>&)>& selector, const list<value>& partitions) { + + // Select partition + const failable<lambda<value(const list<value>&)> > p = partition(key, selector, partitions); + if (!hasContent(p)) + return mkfailure<value>(p); + + // Put into selected partition + content(p)(mklist<value>("put", key, val)); + + return value(true); +} + +/** + * Delete an item from a partition. + */ +const failable<value> del(const value& key, const lambda<value(const list<value>&)>& selector, const list<value>& partitions) { + + // Select partition + const failable<lambda<value(const list<value>&)> > p = partition(key, selector, partitions); + if (!hasContent(p)) + return mkfailure<value>(p); + + // Delete from selected partition + content(p)(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::partitioner::get(cadr(params), caddr(params), cdddr(params)); + if (func == "post") + return tuscany::partitioner::post(cadr(params), caddr(params), cadddr(params), cddddr(params)); + if (func == "put") + return tuscany::partitioner::put(cadr(params), caddr(params), cadddr(params), cddddr(params)); + if (func == "delete") + return tuscany::partitioner::del(cadr(params), caddr(params), cdddr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/cache/select-test.scm b/sca-cpp/branches/lightweight-sca/components/cache/select-test.scm new file mode 100644 index 0000000000..9baa82a5da --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/select-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. + +; Partition selector test case + +(define (get key partitions) (if (= (car key) "a") (car partitions) (cadr partitions))) + diff --git a/sca-cpp/branches/lightweight-sca/components/cache/server-test b/sca-cpp/branches/lightweight-sca/components/cache/server-test new file mode 100755 index 0000000000..951159c4c8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/cache/server-test @@ -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. + +# Setup +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../modules/server/server-conf tmp +../../modules/server/scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite cache.composite +EOF + +./memcached-start tmp 11211 +./memcached-start tmp 11212 +./memcached-start tmp 11213 +./memcached-start tmp 11411 +./memcached-start tmp 11412 +./memcached-start tmp 11413 +../../modules/http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +./memcached-stop tmp 11211 +./memcached-stop tmp 11212 +./memcached-stop tmp 11213 +./memcached-stop tmp 11411 +./memcached-stop tmp 11412 +./memcached-stop tmp 11413 +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/chat/Makefile.am b/sca-cpp/branches/lightweight-sca/components/chat/Makefile.am new file mode 100644 index 0000000000..5c995ad452 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/Makefile.am @@ -0,0 +1,78 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 chat-sender2.componentType *.scm + +comp_LTLIBRARIES = libchat-sendreceiver.la libchat-sender.la libchat-sender2.la +noinst_DATA = libchat-sendreceiver${libsuffix} libchat-sender${libsuffix} libchat-sender2${libsuffix} + +libchat_sendreceiver_la_SOURCES = chat-sendreceiver.cpp +libchat_sendreceiver_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv +libchat-sendreceiver${libsuffix}: + ln -s .libs/libchat-sendreceiver${libsuffix} + +libchat_sender_la_SOURCES = chat-sender.cpp +libchat_sender_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv +libchat-sender${libsuffix}: + ln -s .libs/libchat-sender${libsuffix} + +libchat_sender2_la_SOURCES = chat-sender2.cpp +libchat_sender2_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv +libchat-sender2${libsuffix}: + ln -s .libs/libchat-sender2${libsuffix} + +chat_send_SOURCES = chat-send.cpp +chat_send_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv + +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 + +comp_PROGRAMS = chat-send + +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 server-test +endif + +endif diff --git a/sca-cpp/branches/lightweight-sca/components/chat/chat-send.cpp b/sca-cpp/branches/lightweight-sca/components/chat/chat-send.cpp new file mode 100644 index 0000000000..bb3907acfd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/chat-send.cpp @@ -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. + */ + +/* $Rev$ $Date$ */ + +/** + * Test sending a message to an XMPP id. + */ + +#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 { + +bool sendmsg(const string& jid, const string& pass, const string& to, const string& msg) { + XMPPClient xc(jid, pass); + const failable<bool> c = connect(xc); + assert(hasContent(c)); + const failable<bool> p = post(to, msg, xc); + assert(hasContent(p)); + return true; +} + +} +} + +int main(unused const int argc, const char** argv) { + tuscany::chat::sendmsg(argv[1], argv[2], argv[3], argv[4]); + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/components/chat/chat-sender.componentType b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender.componentType new file mode 100644 index 0000000000..01838f0260 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/chat/chat-sender.cpp b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender.cpp new file mode 100644 index 0000000000..a4cabef8de --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender.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$ */ + +/** + * XMPP chat sender component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#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>(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 mkfailure<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(const list<value>&)>)car(props))(list<value>()); + const value pass = ((lambda<value(const 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>(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/sca-cpp/branches/lightweight-sca/components/chat/chat-sender2.componentType b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender2.componentType new file mode 100644 index 0000000000..fb7a61ed90 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender2.componentType @@ -0,0 +1,31 @@ +<?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="jid"/> + <reference name="pass"/> + <reference name="to"/> + <reference name="msg"/> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/chat/chat-sender2.cpp b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender2.cpp new file mode 100644 index 0000000000..0e00728022 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/chat-sender2.cpp @@ -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. + */ + +/* $Rev$ $Date$ */ + +/** + * XMPP chat sender component implementation. + * This sender gets its configuration from a single property and its + * input data from component references instead of function parameters. + */ + +#define WANT_HTTPD_LOG 1 +#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 lambda<value(const list<value>&)>& jid, const lambda<value(const list<value>&)>& pass, const lambda<value(const list<value>&)>& to, const lambda<value(const list<value>&)>& msg, const list<value>& params) { + + const value vjid = jid(mklist<value>("get", params)); + const value vpass = pass(mklist<value>("get", params)); + const value vto = to(mklist<value>("get", params)); + const value vmsg = msg(mklist<value>("get", params)); + debug(vjid, "chat::post::from"); + debug(vto, "chat::post::to"); + debug(vmsg, "chat::post::value"); + + // Create an XMPP client session + XMPPClient xc(vjid, vpass); + const failable<bool> c = connect(xc); + if (!hasContent(c)) + return mkfailure<value>(c); + + // Post the message + const failable<bool> r = post(vto, vmsg, xc); + if (!hasContent(r)) + return mkfailure<value>(r); + return value(mklist<value>(vto)); +} + +/** + * Chat sender component lambda function + */ +class chatSender { +public: + chatSender(const lambda<value(const list<value>&)>& jid, const lambda<value(const list<value>&)>& pass, const lambda<value(const list<value>&)>& to, const lambda<value(const list<value>&)>& msg) : jid(jid), pass(pass), to(to), msg(msg) { + } + + const value operator()(const list<value>& params) const { + const tuscany::value func(car(params)); + if (func == "get") + return post(jid, pass, to, msg, cdr(params)); + + // Stop the chat sender component + if (func != "stop") + return mkfailure<value>(); + debug("chat::sender::stop"); + return failable<value>(value(lambda<value(const list<value>&)>())); + } + +private: + const lambda<value(const list<value>&)> jid; + const lambda<value(const list<value>&)> pass; + const lambda<value(const list<value>&)> to; + const lambda<value(const list<value>&)> msg; +}; + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + + // Return the chat sender component lambda function + return value(lambda<value(const list<value>&)>(chatSender(car(params), cadr(params), caddr(params), cadddr(params)))); +} + +} +} +} + +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/sca-cpp/branches/lightweight-sca/components/chat/chat-sendreceiver.componentType b/sca-cpp/branches/lightweight-sca/components/chat/chat-sendreceiver.componentType new file mode 100644 index 0000000000..0367c38f55 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/chat/chat-sendreceiver.cpp b/sca-cpp/branches/lightweight-sca/components/chat/chat-sendreceiver.cpp new file mode 100644 index 0000000000..bfbd32b9ae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/chat-sendreceiver.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$ */ + +/** + * XMPP chat sender/receiver component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#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>(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 mkfailure<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(const list<value>&)>)car(props))(list<value>()); + const value pass = ((lambda<value(const 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>(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/sca-cpp/branches/lightweight-sca/components/chat/chat.composite b/sca-cpp/branches/lightweight-sca/components/chat/chat.composite new file mode 100644 index 0000000000..3318ae6d8d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/chat.composite @@ -0,0 +1,51 @@ +<?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" + 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"> + <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"> + <binding.http uri="print-chatter"/> + </service> + <reference name="relay" target="print"/> + </component> + + <component name="print"> + <implementation.scheme script="server-test.scm"/> + <service name="print"> + <binding.http uri="print"/> + </service> + <reference name="report" target="print-chatter"/> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/chat/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/chat/client-test.cpp new file mode 100644 index 0000000000..220382fa89 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/client-test.cpp @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); +const list<value> entry = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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("", "", "", "", 0); + 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/sca-cpp/branches/lightweight-sca/components/chat/echo-test b/sca-cpp/branches/lightweight-sca/components/chat/echo-test new file mode 100755 index 0000000000..c155d4a9a8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/chat/server-test b/sca-cpp/branches/lightweight-sca/components/chat/server-test new file mode 100755 index 0000000000..7b5fabfe14 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/server-test @@ -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. + +# Setup +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../modules/server/server-conf tmp +../../modules/server/scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite chat.composite +EOF + +./vysper-start +sleep 3 +../../modules/http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +sleep 1 +./vysper-stop +sleep 1 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/chat/server-test.scm b/sca-cpp/branches/lightweight-sca/components/chat/server-test.scm new file mode 100644 index 0000000000..a6023708e1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/chat/test/TestVysperServer.java b/sca-cpp/branches/lightweight-sca/components/chat/test/TestVysperServer.java new file mode 100644 index 0000000000..3d2b7d7c3e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/chat/vysper-classpath b/sca-cpp/branches/lightweight-sca/components/chat/vysper-classpath new file mode 100755 index 0000000000..e164200ed2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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/sca-cpp/branches/lightweight-sca/components/chat/vysper-start b/sca-cpp/branches/lightweight-sca/components/chat/vysper-start new file mode 100755 index 0000000000..b7fcad5217 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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/sca-cpp/branches/lightweight-sca/components/chat/vysper-stop b/sca-cpp/branches/lightweight-sca/components/chat/vysper-stop new file mode 100755 index 0000000000..0fec98400d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/vysper-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 Vysper test XMPP server +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +java_prefix=`cat $here/../../modules/java/java.prefix` +k=`ps -ef | grep -v grep | grep "${java_prefix}/jre/bin/java" | grep "vysper" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/chat/xmpp-test.cpp b/sca-cpp/branches/lightweight-sca/components/chat/xmpp-test.cpp new file mode 100644 index 0000000000..6b7fa3439f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/chat/xmpp.hpp b/sca-cpp/branches/lightweight-sca/components/chat/xmpp.hpp new file mode 100644 index 0000000000..aa006029fa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/chat/xmpp.hpp @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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() { + debug("chat::xmppruntime"); + xmpp_initialize(); + log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); + } + + ~XMPPRuntime() { + debug("chat::~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)); + debug(jid, "chat::xmppclient::jid"); + } + + XMPPClient(const XMPPClient& xc) : owner(false), ctx(xc.ctx), conn(xc.conn), listener(xc.listener), connecting(xc.connecting), connected(xc.connected), disconnecting(xc.disconnecting) { + debug("chat::xmppclient::copy"); + } + + const XMPPClient& operator=(const XMPPClient& xc) { + debug("chat::xmppclient::operator="); + if(this == &xc) + return *this; + owner = false; + ctx = xc.ctx; + conn = xc.conn; + listener = xc.listener; + connecting = xc.connecting; + connected = xc.connected; + disconnecting = xc.disconnecting; + return *this; + } + + ~XMPPClient() { + debug("chat::~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); + + 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>(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>(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/sca-cpp/branches/lightweight-sca/components/constdb/Makefile.am b/sca-cpp/branches/lightweight-sca/components/constdb/Makefile.am new file mode 100644 index 0000000000..e4504a53e7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/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/constdb + +dist_comp_SCRIPTS = tinycdb +compdir=$(prefix)/components/constdb + +comp_DATA = tinycdb.prefix +tinycdb.prefix: $(top_builddir)/config.status + echo ${TINYCDB_PREFIX} >tinycdb.prefix + +EXTRA_DIST = constdb.composite constdb.componentType + +comp_LTLIBRARIES = libconstdb.la +noinst_DATA = libconstdb${libsuffix} + +libconstdb_la_SOURCES = constdb.cpp +libconstdb_la_LDFLAGS = -L${TINYCDB_LIB} -R${TINYCDB_LIB} -lcdb +libconstdb${libsuffix}: + ln -s .libs/libconstdb${libsuffix} + +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 = constdb-test server-test +noinst_PROGRAMS = tinycdb-test client-test +TESTS = constdb-test server-test + diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/constdb/client-test.cpp new file mode 100644 index 0000000000..ea45762cd6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/client-test.cpp @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 constdb { + +const string uri("http://localhost:8090/constdb"); + +bool testConstDb() { + http::CURLSession cs("", "", "", "", 0); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$3.55"))); + const list<value> b = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$4.55"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + + http::CURLSession cs("", "", "", "", 0); + 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 << "ConstDb get test " << time(gl, 5, 200) << " ms" << endl; + + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::constdb::testConstDb(); + tuscany::constdb::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/constdb-test b/sca-cpp/branches/lightweight-sca/components/constdb/constdb-test new file mode 100755 index 0000000000..420b98559c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/constdb-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 +rm -rf tmp +mkdir -p tmp +./tinycdb -c -m tmp/test.cdb </dev/null + +# Test +./tinycdb-test 2>/dev/null +rc=$? + +# Cleanup +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/constdb.componentType b/sca-cpp/branches/lightweight-sca/components/constdb/constdb.componentType new file mode 100644 index 0000000000..c96d2c8f1f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/constdb.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="constdb"/> + <property name="dbname" type="xsd:string"/> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/constdb.composite b/sca-cpp/branches/lightweight-sca/components/constdb/constdb.composite new file mode 100644 index 0000000000..ea6b4907c8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/constdb.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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="constdb"> + + <component name="constdb"> + <implementation.cpp path="." library="libconstdb"/> + <property name="dbname">tmp/test.cdb</property> + <service name="constdb"> + <binding.http uri="constdb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/constdb.cpp b/sca-cpp/branches/lightweight-sca/components/constdb/constdb.cpp new file mode 100644 index 0000000000..6d1cb15baf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/constdb.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$ */ + +/** + * TinyCDB-based database component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "tinycdb.hpp" + +namespace tuscany { +namespace constdb { + +/** + * 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>(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>(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>(val); + return value(content(val)); +} + +/** + * Component implementation lambda function. + */ +class applyConstDb { +public: + applyConstDb(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 mkfailure<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(const 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>&)>(applyConstDb(cdb))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::constdb::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/server-test b/sca-cpp/branches/lightweight-sca/components/constdb/server-test new file mode 100755 index 0000000000..abeceaf98e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/server-test @@ -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. + +# Setup +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../modules/server/server-conf tmp +../../modules/server/scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite constdb.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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb b/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb new file mode 100755 index 0000000000..3e5c23957f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +tinycdb_prefix=`cat $here/tinycdb.prefix` + +$tinycdb_prefix/bin/cdb $* + diff --git a/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb-test.cpp b/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb-test.cpp new file mode 100644 index 0000000000..b3b4ea7fd7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/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/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb.hpp b/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb.hpp new file mode 100644 index 0000000000..68be0a09dc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/constdb/tinycdb.hpp @@ -0,0 +1,488 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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; +} + +/** + * Convert a database name to an absolute path. + */ +const string absdbname(const string& name) { + if (length(name) == 0 || c_str(name)[0] == '/') + return name; + char cwd[512]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + return name; + return string(cwd) + "/" + name; +} + +/** + * Represents a TinyCDB connection. + */ +class TinyCDB { +public: + TinyCDB() : owner(false), fd(-1) { + st.st_ino = 0; + } + + TinyCDB(const string& name) : owner(true), name(absdbname(name)), fd(-1) { + debug(name, "tinycdb::tinycdb::name"); + st.st_ino = 0; + } + + TinyCDB(const TinyCDB& c) : owner(false), name(c.name), fd(c.fd) { + debug("tinycdb::tinycdb::copy"); + st.st_ino = c.st.st_ino; + } + + const TinyCDB& operator=(const TinyCDB& c) { + debug("tinycdb::tinycdb::operator="); + if(this == &c) + return *this; + owner = false; + name = c.name; + fd = c.fd; + st.st_ino = c.st.st_ino; + return *this; + } + + ~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>(ffd); + const int fd = content(ffd); + + // Read the db header + unsigned int pos = 0; + if (lseek(fd, 0, SEEK_SET) != 0) + return mkfailure<bool>("Couldn't seek to tinycdb database start"); + if (::read(fd, buf, 2048) != 2048) + return mkfailure<bool>("Couldn't 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>("Couldn'tt 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>("Couldn't 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>("Couldn't 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>("Couldn't rename temporary tinycdb database"); + cdbclose(cdb); + failable<int> ffd = cdbopen(cdb); + if (!hasContent(ffd)) + return mkfailure<bool>(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>(string("Couldn't add tinycdb entry: ") + ks); + 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>(string("Couldn't add tinycdb entry: ") + ks); + 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>(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) { + ostringstream os; + os << "Couldn't get tinycdb entry: " << key; + return mkfailure<value>(str(os), 404, false); + } + 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/sca-cpp/branches/lightweight-sca/components/filedb/Makefile.am b/sca-cpp/branches/lightweight-sca/components/filedb/Makefile.am new file mode 100644 index 0000000000..c6589a1b7b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/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. + +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${libsuffix} + +libfiledb_la_SOURCES = filedb.cpp +libfiledb_la_LDFLAGS = -lxml2 -lmozjs +libfiledb${libsuffix}: + ln -s .libs/libfiledb${libsuffix} + +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/sca-cpp/branches/lightweight-sca/components/filedb/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/filedb/client-test.cpp new file mode 100644 index 0000000000..e0f98d8c3b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/client-test.cpp @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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("", "", "", "", 0); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$3.55"))); + const list<value> b = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$4.55"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + + http::CURLSession cs("", "", "", "", 0); + 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/sca-cpp/branches/lightweight-sca/components/filedb/file-test.cpp b/sca-cpp/branches/lightweight-sca/components/filedb/file-test.cpp new file mode 100644 index 0000000000..ff57bd79ce --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/filedb/filedb-test b/sca-cpp/branches/lightweight-sca/components/filedb/filedb-test new file mode 100755 index 0000000000..6d2d66424a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/filedb-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 +rm -rf tmp +mkdir -p tmp +mkdir -p tmp/schemedb +mkdir -p tmp/xmldb +mkdir -p tmp/jsondb + +# Test +./file-test 2>/dev/null +rc=$? + +# Cleanup +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/filedb/filedb.componentType b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.componentType new file mode 100644 index 0000000000..31f996ef3e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/filedb/filedb.composite b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.composite new file mode 100644 index 0000000000..e6cc69b9db --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.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" + 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"> + <binding.http uri="filedb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/filedb/filedb.cpp b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.cpp new file mode 100644 index 0000000000..8644a78574 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.cpp @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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>(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>(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>(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 mkfailure<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(const list<value>&)>)car(params))(list<value>()); + const value format = ((lambda<value(const list<value>&)>)cadr(params))(list<value>()); + + filedb::FileDB& db = *(new (gc_new<filedb::FileDB>()) filedb::FileDB(absdbname(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/sca-cpp/branches/lightweight-sca/components/filedb/filedb.hpp b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.hpp new file mode 100644 index 0000000000..9c3017d0d8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/filedb.hpp @@ -0,0 +1,265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 { + +/** + * Convert a database name to an absolute path. + */ +const string absdbname(const string& name) { + if (length(name) == 0 || c_str(name)[0] == '/') + return name; + char cwd[512]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + return name; + return string(cwd) + "/" + name; +} + +/** + * Represents a FileDB connection. + */ +class FileDB { +public: + FileDB() : owner(false) { + } + + FileDB(const string& name, const string& format) : owner(true), name(absdbname(name)), format(format) { + debug(name, "filedb::filedb::name"); + debug(format, "filedb::filedb::format"); + } + + FileDB(const FileDB& c) : owner(false), name(c.name), format(c.format) { + debug("filedb::filedb::copy"); + } + + const FileDB& operator=(const FileDB& c) { + debug("filedb::filedb::operator="); + if(this == &c) + return *this; + owner = false; + name = c.name; + format = c.format; + return *this; + } + + ~FileDB() { + } + +private: + bool owner; + string name; + string format; + + friend const failable<bool> write(const value& v, ostream& os, const string& format); + friend const failable<value> read(istream& is, const string& format); + 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; + const string name = root + "/" + (isString(car(path))? (string)car(path) : 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; + const string dir = root + "/" + (isString(car(path))? (string)car(path) : 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) { + 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>(s); + write(content(s), os); + return true; + } + if (format == "json") { + js::JSContext jscx; + failable<list<string> > s = json::writeJSON(valuesToElements(v), jscx); + if (!hasContent(s)) + return mkfailure<bool>(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) { + if (format == "scheme") { + return scheme::readValue(is); + } + if (format == "xml") { + const value v = elementsToValues(readXML(streamList(is))); + return v; + } + if (format == "json") { + js::JSContext jscx; + const failable<list<value> > fv = json::readJSON(streamList(is), jscx); + if (!hasContent(fv)) + return mkfailure<value>(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); + const string fn = filename(key, db.name); + debug(fn, "filedb::post::filename"); + ofstream os(fn); + if (os.fail()) { + ostringstream os; + os << "Couldn't post file database entry: " << key; + return mkfailure<bool>(str(os)); + } + const failable<bool> r = write(val, os, db.format); + + 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); + const string fn = filename(key, db.name); + debug(fn, "filedb::put::filename"); + ofstream os(fn); + if (os.fail()) { + ostringstream os; + os << "Couldn't put file database entry: " << key; + return mkfailure<bool>(str(os)); + } + const failable<bool> r = write(val, os, db.format); + + 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"); + + const string fn = filename(key, db.name); + debug(fn, "filedb::get::filename"); + ifstream is(fn); + if (is.fail()) { + ostringstream os; + os << "Couldn't get file database entry: " << key; + return mkfailure<value>(str(os), 404, false); + } + const failable<value> val = read(is, db.format); + + 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 string fn = filename(key, db.name); + debug(fn, "filedb::del::filename"); + const int rc = unlink(c_str(fn)); + if (rc == -1) { + ostringstream os; + os << "Couldn't delete file database entry: " << key; + return mkfailure<bool>(str(os)); + } + + debug(true, "filedb::delete::result"); + return true; +} + +} +} + +#endif /* tuscany_filedb_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/components/filedb/server-test b/sca-cpp/branches/lightweight-sca/components/filedb/server-test new file mode 100755 index 0000000000..94afe464e1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/filedb/server-test @@ -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. + +# Setup +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/http/Makefile.am b/sca-cpp/branches/lightweight-sca/components/http/Makefile.am new file mode 100644 index 0000000000..623be12298 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/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. + +compdir=$(prefix)/components/http + +EXTRA_DIST = http.composite httpget.componentType httppost.componentType httpput.componentType httppatch.componentType httpdelete.componentType *.scm + +comp_LTLIBRARIES = libhttpget.la libhttpdelete.la libhttppost.la libhttpput.la libhttppatch.la +noinst_DATA = libhttpget${libsuffix} libhttpdelete${libsuffix} libhttppost${libsuffix} libhttpput${libsuffix} libhttppatch${libsuffix} + +libhttpget_la_SOURCES = httpget.cpp +libhttpget_la_LDFLAGS = -lxml2 -lmozjs -curl +libhttpget${libsuffix}: + ln -s .libs/libhttpget${libsuffix} + +libhttpdelete_la_SOURCES = httpdelete.cpp +libhttpdelete_la_LDFLAGS = -lxml2 -lmozjs -curl +libhttpdelete${libsuffix}: + ln -s .libs/libhttpdelete${libsuffix} + +libhttppost_la_SOURCES = httppost.cpp +libhttppost_la_LDFLAGS = -lxml2 -lmozjs -curl +libhttppost${libsuffix}: + ln -s .libs/libhttppost${libsuffix} + +libhttpput_la_SOURCES = httpput.cpp +libhttpput_la_LDFLAGS = -lxml2 -lmozjs -curl +libhttpput${libsuffix}: + ln -s .libs/libhttpput${libsuffix} + +libhttppatch_la_SOURCES = httppatch.cpp +libhttppatch_la_LDFLAGS = -lxml2 -lmozjs -curl +libhttppatch${libsuffix}: + ln -s .libs/libhttppatch${libsuffix} + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +dist_noinst_SCRIPTS = server-test +noinst_PROGRAMS = client-test +TESTS = server-test + diff --git a/sca-cpp/branches/lightweight-sca/components/http/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/http/client-test.cpp new file mode 100644 index 0000000000..bb1918f1f8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/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 HTTP components. + */ + +#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 http { + +const string getURI("http://localhost:8090/httpget"); +const string postURI("http://localhost:8090/httppost"); +const string putURI("http://localhost:8090/httpput"); +const string deleteURI("http://localhost:8090/httpdelete"); + +bool testGet() { + http::CURLSession cs("", "", "", "", 0); + + const failable<value> val = http::get(getURI, cs); + assert(hasContent(val)); + return true; +} + +struct getLoop { + http::CURLSession& cs; + getLoop(http::CURLSession& cs) : cs(cs) { + } + const bool operator()() const { + const failable<value> val = http::get(getURI, cs); + assert(hasContent(val)); + return true; + } +}; + +bool testGetPerf() { + http::CURLSession cs("", "", "", "", 0); + + const lambda<bool()> gl = getLoop(cs); + cout << "HTTP get test " << time(gl, 5, 200) << " ms" << endl; + + return true; +} + +bool testPost() { + http::CURLSession cs("", "", "", "", 0); + + const failable<value> val = http::get(postURI, cs); + assert(hasContent(val)); + return true; +} + +bool testPut() { + http::CURLSession cs("", "", "", "", 0); + + const failable<value> val = http::get(putURI, cs); + assert(hasContent(val)); + return true; +} + +bool testDelete() { + http::CURLSession cs("", "", "", "", 0); + + const failable<value> val = http::get(deleteURI, cs); + assert(hasContent(val)); + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::http::testGet(); + tuscany::http::testGetPerf(); + tuscany::http::testPost(); + tuscany::http::testPut(); + tuscany::http::testDelete(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/components/http/content-test.scm b/sca-cpp/branches/lightweight-sca/components/http/content-test.scm new file mode 100644 index 0000000000..f381546190 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/content-test.scm @@ -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. + +; Content test case + +(define (get id) + (list (list 'entry '(title "Item") '(id "111") '(content (item (name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99))))) +) + diff --git a/sca-cpp/branches/lightweight-sca/components/http/http.composite b/sca-cpp/branches/lightweight-sca/components/http/http.composite new file mode 100644 index 0000000000..32c0da62c0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/http.composite @@ -0,0 +1,93 @@ +<?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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="http"> + + <component name="httpget"> + <implementation.cpp path="." library="libhttpget"/> + <property name="timeout">0</property> + <service name="httpget"> + <binding.http uri="httpget"/> + </service> + <reference name="url" target="url-test"/> + </component> + + <component name="httppost"> + <implementation.cpp path="." library="libhttppost"/> + <property name="timeout">0</property> + <service name="httppost"> + <binding.http uri="httppost"/> + </service> + <reference name="url" target="url-test"/> + <reference name="content" target="content-test"/> + </component> + + <component name="httpput"> + <implementation.cpp path="." library="libhttpput"/> + <property name="timeout">0</property> + <service name="httpput"> + <binding.http uri="httpput"/> + </service> + <reference name="url" target="url-test"/> + <reference name="content" target="content-test"/> + </component> + + <component name="httppatch"> + <implementation.cpp path="." library="libhttppatch"/> + <property name="timeout">0</property> + <service name="httppatch"> + <binding.http uri="httppatch"/> + </service> + <reference name="url" target="url-test"/> + <reference name="content" target="content-test"/> + </component> + + <component name="httpdelete"> + <implementation.cpp path="." library="libhttpdelete"/> + <property name="timeout">0</property> + <service name="httpdelete"> + <binding.http uri="httpdelete"/> + </service> + <reference name="url" target="url-test"/> + </component> + + <component name="url-test"> + <implementation.scheme script="url-test.scm"/> + <service name="url-test"> + <binding.http uri="url-test"/> + </service> + </component> + + <component name="content-test"> + <implementation.scheme script="content-test.scm"/> + <service name="content-test"> + <binding.http uri="content-test"/> + </service> + </component> + + <component name="scheme-test"> + <implementation.scheme script="server-test.scm"/> + <service name="scheme"> + <binding.http uri="scheme"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/http/httpdelete.componentType b/sca-cpp/branches/lightweight-sca/components/http/httpdelete.componentType new file mode 100644 index 0000000000..c2d728a538 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httpdelete.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"> + + <property name="timeout"/> + <service name="httpdelete"/> + <reference name="url"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/http/httpdelete.cpp b/sca-cpp/branches/lightweight-sca/components/http/httpdelete.cpp new file mode 100644 index 0000000000..c725461ec2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httpdelete.cpp @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../../modules/http/http.hpp" + +namespace tuscany { +namespace httpdelete { + +/** + * Evaluate an HTTP delete. + */ +const failable<value> get(const lambda<value(const list<value>&)>& url, http::CURLSession& ch) { + debug("httpdelete::get"); + const value u = url(mklist<value>("get", list<value>())); + debug(u, "httpdelete::get::url"); + return http::del(u, ch); +} + +/** + * Component implementation lambda function. + */ +class applyhttp { +public: + applyhttp(const lambda<value(const list<value>&)>& url, const perthread_ptr<http::CURLSession>& ch) : url(url), ch(ch) { + } + + const value operator()(const list<value>& params) const { + debug(params, "httpdelete::applyhttp::params"); + const value func(car(params)); + if (func == "get") + return get(url, *ch); + return mkfailure<value>(); + } + +private: + const lambda<value(const list<value>&)> url; + perthread_ptr<http::CURLSession> ch; +}; + +/** + * Create a new CURL session. + */ +class newsession { +public: + newsession(const lambda<value(const list<value>&)>& timeout) : timeout(timeout) { + } + const gc_ptr<http::CURLSession> operator()() const { + const int t = atoi(c_str((string)timeout(list<value>()))); + return new (gc_new<http::CURLSession>()) http::CURLSession("", "", "", "", t); + } +private: + const lambda<value(const list<value>&)> timeout; +}; + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Create a CURL session + const perthread_ptr<http::CURLSession> ch = perthread_ptr<http::CURLSession>(lambda<gc_ptr<http::CURLSession>()>(newsession(cadr(params)))); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyhttp(car(params), ch))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::httpdelete::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/http/httpget.componentType b/sca-cpp/branches/lightweight-sca/components/http/httpget.componentType new file mode 100644 index 0000000000..c6c24fbed8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httpget.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"> + + <property name="timeout"/> + <service name="httpget"/> + <reference name="url"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/http/httpget.cpp b/sca-cpp/branches/lightweight-sca/components/http/httpget.cpp new file mode 100644 index 0000000000..884dc1a6ff --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httpget.cpp @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../../modules/http/http.hpp" + +namespace tuscany { +namespace httpget { + +/** + * Evaluate an HTTP get. + */ +const failable<value> get(const lambda<value(const list<value>&)>& url, http::CURLSession& ch) { + debug("httpget::get"); + const value u = url(mklist<value>("get", list<value>())); + debug(u, "httpget::get::url"); + return http::get(u, ch); +} + +/** + * Component implementation lambda function. + */ +class applyhttp { +public: + applyhttp(const lambda<value(const list<value>&)>& url, const perthread_ptr<http::CURLSession>& ch) : url(url), ch(ch) { + } + + const value operator()(const list<value>& params) const { + debug(params, "httpget::applyhttp::params"); + const value func(car(params)); + if (func == "get") + return get(url, *ch); + return mkfailure<value>(); + } + +private: + const lambda<value(const list<value>&)> url; + perthread_ptr<http::CURLSession> ch; +}; + + +/** + * Create a new CURL session. + */ +class newsession { +public: + newsession(const lambda<value(const list<value>&)>& timeout) : timeout(timeout) { + } + const gc_ptr<http::CURLSession> operator()() const { + const int t = atoi(c_str((string)timeout(list<value>()))); + return new (gc_new<http::CURLSession>()) http::CURLSession("", "", "", "", t); + } +private: + const lambda<value(const list<value>&)> timeout; +}; + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Create a CURL session + const perthread_ptr<http::CURLSession> ch = perthread_ptr<http::CURLSession>(lambda<gc_ptr<http::CURLSession>()>(newsession(cadr(params)))); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyhttp(car(params), ch))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::httpget::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/http/httppatch.componentType b/sca-cpp/branches/lightweight-sca/components/http/httppatch.componentType new file mode 100644 index 0000000000..eb3a96078b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httppatch.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"> + + <property name="timeout"/> + <service name="httppatch"/> + <reference name="url"/> + <reference name="content"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/http/httppatch.cpp b/sca-cpp/branches/lightweight-sca/components/http/httppatch.cpp new file mode 100644 index 0000000000..051b1e09ac --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httppatch.cpp @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../../modules/http/http.hpp" + +namespace tuscany { +namespace httppatch { + +/** + * Evaluate an HTTP patch. + */ +const failable<value> get(const lambda<value(const list<value>&)>& url, const lambda<value(const list<value>&)>& val, http::CURLSession& ch) { + debug("httppatch::get"); + const value u = url(mklist<value>("get", list<value>())); + const value v = val(mklist<value>("get", list<value>())); + debug(u, "httppatch::get::url"); + debug(v, "httppatch::get::val"); + return http::patch(v, u, ch); +} + +/** + * Component implementation lambda function. + */ +class applyhttp { +public: + applyhttp(const lambda<value(const list<value>&)>& url, const lambda<value(const list<value>&)>& val, const perthread_ptr<http::CURLSession>& ch) : url(url), val(val), ch(ch) { + } + + const value operator()(const list<value>& params) const { + debug(params, "httppatch::applyhttp::params"); + const value func(car(params)); + if (func == "get") + return get(url, val, *ch); + return mkfailure<value>(); + } + +private: + const lambda<value(const list<value>&)> url; + const lambda<value(const list<value>&)> val; + perthread_ptr<http::CURLSession> ch; +}; + +/** + * Create a new CURL session. + */ +class newsession { +public: + newsession(const lambda<value(const list<value>&)>& timeout) : timeout(timeout) { + } + const gc_ptr<http::CURLSession> operator()() const { + const int t = atoi(c_str((string)timeout(list<value>()))); + return new (gc_new<http::CURLSession>()) http::CURLSession("", "", "", "", t); + } +private: + const lambda<value(const list<value>&)> timeout; +}; + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Create a CURL session + const perthread_ptr<http::CURLSession> ch = perthread_ptr<http::CURLSession>(lambda<gc_ptr<http::CURLSession>()>(newsession(caddr(params)))); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyhttp(car(params), cadr(params), ch))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::httppatch::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/http/httppost.componentType b/sca-cpp/branches/lightweight-sca/components/http/httppost.componentType new file mode 100644 index 0000000000..42b0096446 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httppost.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"> + + <property name="timeout"/> + <service name="httppost"/> + <reference name="url"/> + <reference name="content"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/http/httppost.cpp b/sca-cpp/branches/lightweight-sca/components/http/httppost.cpp new file mode 100644 index 0000000000..84fd984e19 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httppost.cpp @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../../modules/http/http.hpp" + +namespace tuscany { +namespace httppost { + +/** + * Evaluate an HTTP post. + */ +const failable<value> get(const lambda<value(const list<value>&)>& url, const lambda<value(const list<value>&)>& val, http::CURLSession& ch) { + debug("httppost::get"); + const value u = url(mklist<value>("get", list<value>())); + const value v = val(mklist<value>("get", list<value>())); + debug(u, "httppost::get::url"); + debug(v, "httppost::get::val"); + return http::post(v, u, ch); +} + +/** + * Component implementation lambda function. + */ +class applyhttp { +public: + applyhttp(const lambda<value(const list<value>&)>& url, const lambda<value(const list<value>&)>& val, const perthread_ptr<http::CURLSession>& ch) : url(url), val(val), ch(ch) { + } + + const value operator()(const list<value>& params) const { + debug(params, "httppost::applyhttp::params"); + const value func(car(params)); + if (func == "get") + return get(url, val, *ch); + return mkfailure<value>(); + } + +private: + const lambda<value(const list<value>&)> url; + const lambda<value(const list<value>&)> val; + perthread_ptr<http::CURLSession> ch; +}; + +/** + * Create a new CURL session. + */ +class newsession { +public: + newsession(const lambda<value(const list<value>&)>& timeout) : timeout(timeout) { + } + const gc_ptr<http::CURLSession> operator()() const { + const int t = atoi(c_str((string)timeout(list<value>()))); + return new (gc_new<http::CURLSession>()) http::CURLSession("", "", "", "", t); + } +private: + const lambda<const value(const list<value>&)> timeout; +}; + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Create a CURL session + const perthread_ptr<http::CURLSession> ch = perthread_ptr<http::CURLSession>(lambda<gc_ptr<http::CURLSession>()>(newsession(caddr(params)))); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyhttp(car(params), cadr(params), ch))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::httppost::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/http/httpput.componentType b/sca-cpp/branches/lightweight-sca/components/http/httpput.componentType new file mode 100644 index 0000000000..791a7faa8a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httpput.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"> + + <property name="timeout"/> + <service name="httpput"/> + <reference name="url"/> + <reference name="content"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/http/httpput.cpp b/sca-cpp/branches/lightweight-sca/components/http/httpput.cpp new file mode 100644 index 0000000000..2ae5da396e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/httpput.cpp @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../../modules/http/http.hpp" + +namespace tuscany { +namespace httpput { + +/** + * Evaluate an HTTP put. + */ +const failable<value> get(const lambda<value(const list<value>&)>& url, const lambda<value(const list<value>&)>& val, http::CURLSession& ch) { + debug("httpput::get"); + const value u = url(mklist<value>("get", list<value>())); + const value v = val(mklist<value>("get", list<value>())); + debug(u, "httpput::get::url"); + debug(v, "httpput::get::val"); + return http::put(v, u, ch); +} + +/** + * Component implementation lambda function. + */ +class applyhttp { +public: + applyhttp(const lambda<value(const list<value>&)>& url, const lambda<value(const list<value>&)>& val, const perthread_ptr<http::CURLSession>& ch) : url(url), val(val), ch(ch) { + } + + const value operator()(const list<value>& params) const { + debug(params, "httpput::applyhttp::params"); + const value func(car(params)); + if (func == "get") + return get(url, val, *ch); + return mkfailure<value>(); + } + +private: + const lambda<value(const list<value>&)> url; + const lambda<value(const list<value>&)> val; + perthread_ptr<http::CURLSession> ch; +}; + +/** + * Create a new CURL session. + */ +class newsession { +public: + newsession(const lambda<value(const list<value>&)>& timeout) : timeout(timeout) { + } + const gc_ptr<http::CURLSession> operator()() const { + const int t = atoi(c_str((string)timeout(list<value>()))); + return new (gc_new<http::CURLSession>()) http::CURLSession("", "", "", "", t); + } +private: + const lambda<value(const list<value>&)> timeout; +}; + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Create a CURL session + const perthread_ptr<http::CURLSession> ch = perthread_ptr<http::CURLSession>(lambda<gc_ptr<http::CURLSession>()>(newsession(caddr(params)))); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyhttp(car(params), cadr(params), ch))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::httpput::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/http/server-test b/sca-cpp/branches/lightweight-sca/components/http/server-test new file mode 100755 index 0000000000..7e3116c59d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/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 +rm -rf tmp +../../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 http.composite +EOF + +../../modules/http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/http/server-test.scm b/sca-cpp/branches/lightweight-sca/components/http/server-test.scm new file mode 100644 index 0000000000..4bbff6e5c2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/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) + '((feed (title "Sample Feed") (id "123456789") (entry + (((title "Item") (id "111") (content (item (name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99)))) + ((title "Item") (id "222") (content (item (name "Orange") (currencyCode "USD") (currencySymbol "$") (price 3.55)))) + ((title "Item") (id "333") (content (item (name "Pear") (currencyCode "USD") (currencySymbol "$") (price 1.55)))))))) + + (list (list 'entry '(title "Item") (list 'id (car id)) '(content (item (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/sca-cpp/branches/lightweight-sca/components/http/url-test.scm b/sca-cpp/branches/lightweight-sca/components/http/url-test.scm new file mode 100644 index 0000000000..dd92720c32 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/http/url-test.scm @@ -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. + +; URL test case + +(define (get id) + "http://localhost:8090/scheme" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/Makefile.am b/sca-cpp/branches/lightweight-sca/components/kvdb/Makefile.am new file mode 100644 index 0000000000..3212f3f5c8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/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${LEVELDB_INCLUDE} + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/components/kvdb + +dist_comp_SCRIPTS = leveldb +compdir=$(prefix)/components/kvdb + +comp_DATA = leveldb.prefix +leveldb.prefix: $(top_builddir)/config.status + echo ${LEVELDB_PREFIX} >leveldb.prefix + +EXTRA_DIST = kvdb.composite kvdb.componentType + +comp_LTLIBRARIES = libkvdb.la +noinst_DATA = libkvdb${libsuffix} + +libkvdb_la_SOURCES = kvdb.cpp +libkvdb_la_LDFLAGS = -L${LEVELDB_LIB} -R${LEVELDB_LIB} -lleveldb +libkvdb${libsuffix}: + ln -s .libs/libkvdb${libsuffix} + +leveldb_test_SOURCES = leveldb-test.cpp +leveldb_test_LDFLAGS = -L${LEVELDB_LIB} -R${LEVELDB_LIB} -lleveldb + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +dist_noinst_SCRIPTS = kvdb-test server-test +noinst_PROGRAMS = leveldb-test client-test +TESTS = kvdb-test server-test + diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/kvdb/client-test.cpp new file mode 100644 index 0000000000..5f0ef21d00 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/client-test.cpp @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 KV (Key-Value) 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$3.55"))); + const list<value> b = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$4.55"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb-test b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb-test new file mode 100755 index 0000000000..420b98559c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb-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 +rm -rf tmp +mkdir -p tmp +./tinycdb -c -m tmp/test.cdb </dev/null + +# Test +./tinycdb-test 2>/dev/null +rc=$? + +# Cleanup +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.componentType b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.componentType new file mode 100644 index 0000000000..1c56ab6807 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.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="nvdb"/> + <property name="dbname" type="xsd:string"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.composite b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.composite new file mode 100644 index 0000000000..378f418cfc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="nvdb"> + + <component name="nvdb"> + <implementation.cpp path="." library="libnvdb"/> + <property name="dbname">tmp/test.cdb</property> + <service name="nvdb"> + <binding.http uri="nvdb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.cpp b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.cpp new file mode 100644 index 0000000000..0df8f13882 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/kvdb.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$ */ + +/** + * LevelDB-based database component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "leveldb.hpp" + +namespace tuscany { +namespace nvdb { + +/** + * Get an item from the database. + */ +const failable<value> get(const list<value>& params, leveldb::LevelDB& cdb) { + return leveldb::get(car(params), cdb); +} + +/** + * Post an item to the database. + */ +const failable<value> post(const list<value>& params, leveldb::LevelDB& cdb) { + const value id = append<value>(car(params), mklist(mkuuid())); + const failable<bool> val = leveldb::post(id, cadr(params), cdb); + if (!hasContent(val)) + return mkfailure<value>(val); + return id; +} + +/** + * Put an item into the database. + */ +const failable<value> put(const list<value>& params, leveldb::LevelDB& cdb) { + const failable<bool> val = leveldb::put(car(params), cadr(params), cdb); + if (!hasContent(val)) + return mkfailure<value>(val); + return value(content(val)); +} + +/** + * Delete an item from the database. + */ +const failable<value> del(const list<value>& params, leveldb::LevelDB& cdb) { + const failable<bool> val = leveldb::del(car(params), cdb); + if (!hasContent(val)) + return mkfailure<value>(val); + return value(content(val)); +} + +/** + * Component implementation lambda function. + */ +class applyNoSqldb { +public: + applyNoSqldb(leveldb::LevelDB& 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 mkfailure<value>(); + } + +private: + leveldb::LevelDB& cdb; +}; + +/** + * Start the component. + */ +const failable<value> start(unused const list<value>& params) { + // Connect to the configured database and table + const value dbname = ((lambda<const value(list<value>&)>)car(params))(list<value>()); + leveldb::LevelDB& cdb = *(new (gc_new<leveldb::LevelDB>()) leveldb::LevelDB(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/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb b/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb new file mode 100755 index 0000000000..f9c54465f6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb @@ -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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +leveldb_prefix=`cat $here/leveldb.prefix` + +$leveldb_prefix/bin/cdb $* + diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb-test.cpp b/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb-test.cpp new file mode 100644 index 0000000000..b3b4ea7fd7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb-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/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb.hpp b/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb.hpp new file mode 100644 index 0000000000..05a89a76f7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/leveldb.hpp @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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_leveldb_hpp +#define tuscany_leveldb_hpp + +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <leveldb/db.h> + +#include "string.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../../modules/scheme/eval.hpp" + +namespace tuscany { +namespace leveldb { + +/** + * 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; +} + +/** + * Convert a database name to an absolute path. + */ +const string absdbname(const string& name) { + if (length(name) == 0 || c_str(name)[0] == '/') + return name; + char cwd[512]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + return name; + return string(cwd) + "/" + name; +} + +/** + * Represents a LevelDB connection. + */ +class LevelDB { +public: + LevelDB() : owner(false), fd(-1) { + debug("leveldb::leveldb"); + st.st_ino = 0; + } + + LevelDB(const string& name) : owner(true), name(absdbname(name)), fd(-1) { + debug(name, "leveldb::leveldb::name"); + st.st_ino = 0; + } + + LevelDB(const LevelDB& c) : owner(false), name(c.name), fd(c.fd) { + debug("leveldb::leveldb::copy"); + st.st_ino = c.st.st_ino; + } + + const LevelDB& operator=(const LevelDB& c) { + debug("leveldb::leveldb::operator="); + if(this == &c) + return *this; + owner = false; + name = c.name; + fd = c.fd; + st.st_ino = c.st.st_ino; + return *this; + } + + ~LevelDB() { + debug("leveldb::~leveldb"); + if (!owner) + return; + if (fd == -1) + return; + close(fd); + } + +private: + bool owner; + string name; + leveldb::DB* db; + struct stat st; + + friend const string dbname(const LevelDB& db); + friend const failable<int> dbopen(LevelDB& db); + friend const failable<bool> dbclose(LevelDB& db); +}; + +/** + * Return the name of the database. + */ +const string dbname(const LevelDB& db) { + return db.name; +} + +/** + * Open a database. + */ +const failable<int> dbopen(LevelDB& db) { + + // Get database file serial number + struct stat st; + const int s = stat(c_str(db.name), &st); + if (s == -1) + return mkfailure<int>(string("Couldn't leveldb read database stat: ") + db.name); + + leveldb::DB* ldb; + leveldb::Options options; + options.create_if_missing = true; + leveldb::Status status = leveldb::DB::Open(options, s, &ldb); + db.db = ldb; +} + +/** + * Close a database. + */ +const failable<bool> dbclose(LevelDB& db) { + delete db.db; + db.db = NULL; + return true; +} + + +const failable<bool> post(const value& key, const value& val, LevelDB& db) { + debug(key, "leveldb::post::key"); + debug(val, "leveldb::post::value"); + debug(dbname(db), "leveldb::post::dbname"); + + const string ks(scheme::writeValue(key)); + const string vs(scheme::writeValue(val)); + + put(ks, vs, db); + + debug(r, "leveldb::post::result"); + return r; +} + + +const failable<bool> put(const value& key, const value& val, LevelDB& db) { + debug(key, "leveldb::put::key"); + debug(val, "leveldb::put::value"); + debug(dbname(db), "leveldb::put::dbname"); + + const string ks(scheme::writeValue(key)); + const string vs(scheme::writeValue(val)); + + debug(r, "leveldb::put::result"); + return r; +} + +/** + * Get an item from the database. + */ +const failable<value> get(const value& key, LevelDB& db) { + debug(key, "leveldb::get::key"); + debug(dbname(db), "leveldb::get::dbname"); + + const string ks(scheme::writeValue(key)); + + std::string data; + db.db->Get(leveldb::ReadOptions(), key, &data); + const value val(scheme::readValue(string(data))); + + debug(val, "leveldb::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 db_make& dbm) const { + return true; + } +}; + +const failable<bool> del(const value& key, LevelDB& db) { + debug(key, "leveldb::delete::key"); + debug(dbname(db), "leveldb::delete::dbname"); + + const string ks(scheme::writeValue(key)); + + leveldb::Status s = db.db->Delete(leveldb::WriteOptions(), key); + + debug(r, "leveldb::delete::result"); + return s.ok(); +} + +} +} + +#endif /* tuscany_leveldb_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/components/kvdb/server-test b/sca-cpp/branches/lightweight-sca/components/kvdb/server-test new file mode 100755 index 0000000000..ebf01b9b4b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/kvdb/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 +rm -rf tmp +../../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 + +./leveldb -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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/log/Makefile.am b/sca-cpp/branches/lightweight-sca/components/log/Makefile.am new file mode 100644 index 0000000000..0e96be5697 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/Makefile.am @@ -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. + +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-central-firehose-conf scribed-central-mkfirehose 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; (ls gen-cpp/*.cpp gen-cpp/*.h | xargs -I {} -t ./thrift-pragmas {}) + +CLEANFILES = gen-cpp/* + +comp_LTLIBRARIES = liblog.la liblogger.la +noinst_DATA = liblog${libsuffix} liblogger${libsuffix} + +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 -Wno-return-type +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${libsuffix}: + ln -s .libs/liblog${libsuffix} + +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 -Wno-return-type +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${libsuffix}: + ln -s .libs/liblogger${libsuffix} + +comp_PROGRAMS = scribe-cat scribe-status + +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 -Wno-return-type +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 + +nodist_scribe_status_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_status_CXXFLAGS = -Wno-unused-parameter -Wno-conversion -Wno-return-type +scribe_status_SOURCES = scribe-status.cpp +scribe_status_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/sca-cpp/branches/lightweight-sca/components/log/adder-test.scm b/sca-cpp/branches/lightweight-sca/components/log/adder-test.scm new file mode 100644 index 0000000000..ccd5bc555f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/log/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/log/client-test.cpp new file mode 100644 index 0000000000..d8cac5ee81 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/client-test.cpp @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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("", "", "", "", 0); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + + http::CURLSession cs("", "", "", "", 0); + 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("", "", "", "", 0); + + 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/sca-cpp/branches/lightweight-sca/components/log/client-test.scm b/sca-cpp/branches/lightweight-sca/components/log/client-test.scm new file mode 100644 index 0000000000..1da6ca3564 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/log/fb303.thrift b/sca-cpp/branches/lightweight-sca/components/log/fb303.thrift new file mode 100644 index 0000000000..66c8315274 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/log/log.componentType b/sca-cpp/branches/lightweight-sca/components/log/log.componentType new file mode 100644 index 0000000000..e661f568f1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/log/log.composite b/sca-cpp/branches/lightweight-sca/components/log/log.composite new file mode 100644 index 0000000000..c6755f3655 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/log.composite @@ -0,0 +1,58 @@ +<?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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="log"> + + <component name="log"> + <implementation.cpp path="." library="liblog"/> + <property name="host"></property> + <property name="category">default</property> + <service name="log"> + <binding.http uri="log"/> + </service> + </component> + + <component name="client"> + <implementation.scheme script="client-test.scm"/> + <service name="client"> + <binding.http uri="client"/> + </service> + <reference name="adder" target="logger"/> + </component> + + <component name="logger"> + <implementation.cpp path="." library="liblogger"/> + <property name="host"></property> + <property name="category">default</property> + <service name="logger"> + <binding.http uri="logger"/> + </service> + <reference name="relay" target="adder"/> + </component> + + <component name="adder"> + <implementation.scheme script="adder-test.scm"/> + <service name="adder"> + <binding.http uri="adder"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/log/log.cpp b/sca-cpp/branches/lightweight-sca/components/log/log.cpp new file mode 100644 index 0000000000..f7f7086192 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/log.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$ */ + +/** + * Scribe-based log component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../../modules/http/http.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& host, const value& category, scribe::Scribe& sc) { + debug(cadr(params), "log::post::value"); + const failable<bool> val = scribe::log(cadr(params), host, category, sc); + if (!hasContent(val)) + return mkfailure<value>(val); + return value(mklist<value>(true)); +} + +/** + * Component implementation lambda function. + */ +class applyLog { +public: + applyLog(const value& host, const value& category, scribe::Scribe& sc) : host(host), category(category), sc(sc) { + } + + const value operator()(const list<value>& params) const { + const value func(car(params)); + if (func == "post") + return post(cdr(params), host, category, sc); + return mkfailure<value>(); + } + +private: + const value host; + const value category; + scribe::Scribe& sc; +}; + +/** + * Start the component. + */ +const failable<value> start(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 host = ((lambda<value(const list<value>&)>)car(params))(list<value>()); + const value category = ((lambda<value(const list<value>&)>)cadr(params))(list<value>()); + debug(host, "log::start::host"); + debug(category, "log::start::category"); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyLog(host, 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/sca-cpp/branches/lightweight-sca/components/log/logger.componentType b/sca-cpp/branches/lightweight-sca/components/log/logger.componentType new file mode 100644 index 0000000000..1c9546e685 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/log/logger.cpp b/sca-cpp/branches/lightweight-sca/components/log/logger.cpp new file mode 100644 index 0000000000..d7969036ab --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/logger.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$ */ + +/** + * Scribe-based logger component implementation, used to intercept + * and log service invocations. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../../modules/http/http.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& host, const value& category, scribe::Scribe& sc) : relay(relay), host(host), category(category), sc(sc) { + } + + const value operator()(const list<value>& params) const { + // Log the function params + debug(params, "logger::apply::params"); + scribe::log(params, host, category, sc); + + // Relay the function call + const failable<value> res = relay(params); + + // Log the result + scribe::log(res, host, category, sc); + return res; + } + +private: + const lambda<value(const list<value>&)> relay; + const value host; + const value category; + scribe::Scribe& sc; +}; + +/** + * Start the component. + */ +const failable<value> start(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 host = ((lambda<value(const list<value>&)>)cadr(params))(list<value>()); + const value category = ((lambda<value(const list<value>&)>)caddr(params))(list<value>()); + debug(host, "logger::start::host"); + debug(category, "logger::start::category"); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applyLog(rel, host, 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/sca-cpp/branches/lightweight-sca/components/log/scribe-cat.cpp b/sca-cpp/branches/lightweight-sca/components/log/scribe-cat.cpp new file mode 100644 index 0000000000..254e2167ae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribe-cat.cpp @@ -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. + */ + +/* $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& host, const string& category, const string& type) { + // Connect to Scribe + scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe(host, 1464)); + + // Read lines from stdin and log them + char buf[8193]; + for (;;) { + gc_scoped_pool p; + + // Write line prefix + ostringstream os; + if (length(type) != 0) + os << "[" << logTime() << "] [" << type << "] "; + const string prefix = str(os); + const int pl = length(prefix); + strcpy(buf, c_str(prefix)); + + // Read log line + const char* s = fgets(buf + pl, 8192 - pl, stdin); + if (s == NULL) + return 0; + + // Remove trailing '\n' + const size_t l = strlen(s); + if (l > 0) + buf[pl + l - 1] = '\0'; + + // Log the line + const failable<bool> val = scribe::log(buf, host, category, sc); + if (!hasContent(val)) + return 1; + } +} + +} +} + +int main(const int argc, const char** argv) { + return tuscany::scribecat::cat(argc < 2? "localhost" : argv[1], argc < 3? "default" : argv[2], argc < 4? "" : argv[3]); +} + diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribe-status.cpp b/sca-cpp/branches/lightweight-sca/components/log/scribe-status.cpp new file mode 100644 index 0000000000..79f7572947 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribe-status.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$ */ + +/** + * 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 scribestatus { + +const int status(const string& host, const int port) { + // Connect to Scribe + scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe(host, port)); + + // Get its status + const failable<string> fs = scribe::status(sc); + + // Interpret and display results + if (!hasContent(fs)) { + cerr << reason(fs) << " : " << rcode(fs) << endl; + return 2; + } + const string s = content(fs); + cout << s << endl; + if (s == "ALIVE") + return 0; + if (s == "STARTING" || s == "STOPPING" || s == "WARNING") + return 1; + return 2; +} + +} +} + +int main(const int argc, const char** argv) { + return tuscany::scribestatus::status(argc < 2? "localhost" : argv[1], argc < 3? 1463 : atoi(argv[2])); +} + diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribe-tail-start b/sca-cpp/branches/lightweight-sca/components/log/scribe-tail-start new file mode 100755 index 0000000000..fc469b5488 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribe-tail-start @@ -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. + +# Tail a file and pipe into scribe-cat +here=`echo "import os; print os.path.realpath('$0')" | python`; 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 +host=`hostname` + +mkdir -p `dirname $file` +touch $file +file=`echo "import os; print os.path.realpath('$file')" | python` + +tail -f -n 0 $file | $here/scribe-cat $host $category $type & + diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribe-tail-stop b/sca-cpp/branches/lightweight-sca/components/log/scribe-tail-stop new file mode 100755 index 0000000000..0d43570a6f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribe-tail-stop @@ -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. + +# Stop tailing a file +here=`echo "import os; print os.path.realpath('$0')" | python`; 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=`echo "import os; print os.path.realpath('$file')" | python` + +cmd="tail -f -n 0 $file" +k=`ps -ef | grep -v grep | grep "${cmd}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribe-test b/sca-cpp/branches/lightweight-sca/components/log/scribe-test new file mode 100755 index 0000000000..bc34f6f650 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribe.hpp b/sca-cpp/branches/lightweight-sca/components/log/scribe.hpp new file mode 100644 index 0000000000..0f0570be64 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribe.hpp @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 +#undef OK + +// Ignore integer conversion issues in Thrift and Scribe headers +#ifdef WANT_MAINTAINER_WARNINGS +#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_WARNINGS +#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) { + debug(host, "scribe::scribe::host"); + debug(port, "scribe::scribe::port"); + init(host, port); + } + + Scribe(const Scribe& c) : owner(false) { + debug("scribe::scribe::copy"); + client = c.client; + transport = c.transport; + } + + const Scribe& operator=(const Scribe& c) { + debug("scribe::scribe::operator="); + if(this == &c) + return *this; + owner = false; + client = c.client; + transport = c.transport; + return *this; + } + + ~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 string& host, const value& category, const Scribe& sc); + friend const failable<string> status(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 string& host, 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)); + ostringstream os; + os << "[" << host << "] " << vs; + + try { + ::scribe::thrift::LogEntry entry; + entry.category = c_str(cs); + entry.message = c_str(str(os)); + 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; +} + +/** + * Return Scribe status. + */ +const failable<string> status(const Scribe& sc) { + debug("scribe::status"); + + try { + ::facebook::fb303::fb_status s = sc.client->getStatus(); + switch(s) { + case ::facebook::fb303::DEAD: + debug("DEAD", "scribe::status::result"); + return string("DEAD"); + case ::facebook::fb303::STARTING: + debug("STARTING", "scribe::status::result"); + return string("STARTING"); + case ::facebook::fb303::ALIVE: + debug("ALIVE", "scribe::status::result"); + return string("ALIVE"); + case ::facebook::fb303::STOPPING: + debug("STOPPING", "scribe::status::result"); + return string("STOPPING"); + case ::facebook::fb303::STOPPED: + debug("STOPPED", "scribe::status::result"); + return string("STOPPED"); + case ::facebook::fb303::WARNING: + debug("WARNING", "scribe::status::result"); + return string("WARNING"); + } + return mkfailure<string>("Unknown status"); + } catch (const std::exception& e) { + return mkfailure<string>(e.what()); + } +} + +} +} + +#endif /* tuscany_scribe_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribe.thrift b/sca-cpp/branches/lightweight-sca/components/log/scribe.thrift new file mode 100644 index 0000000000..592e8b630e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/log/scribed-central-conf b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-conf new file mode 100755 index 0000000000..3c62107da5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-conf @@ -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. + +# Generate a Scribe central conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +if [ "$host" = "" ]; then + host="*" +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 +host=$host +port=1463 +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> +category=default +type=file +target_write_size=20480 +max_write_interval=1 +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> +category=default +type=file +target_write_size=20480 +max_write_interval=1 +fs_type=std +file_path=$root/scribe/logs/central-secondary +base_filename=central +max_size=3000000 +</secondary> + +</store> +EOF diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribed-central-firehose-conf b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-firehose-conf new file mode 100755 index 0000000000..f76aed58c9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-firehose-conf @@ -0,0 +1,126 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +if [ "$host" = "" ]; then + host="*" +fi + +mkdir -p $root/scribe/conf +mkdir -p $root/scribe/logs/central +mkdir -p $root/scribe/logs/central-secondary +mkdir -p $root/scribe/logs/firehose +mkdir -p $root/scribe/logs/firehose-secondary + +cat >$root/scribe/conf/scribe-central.conf <<EOF +# Generated by: scribed-central-conf $* +# Scribe central configuration +host=$host +port=1463 +max_msg_per_second=2000000 +check_interval=3 + +# Log store configuration +<store> +category=default +type=multi +target_write_size=20480 +max_write_interval=1 + +<store0> +category=default +type=buffer +target_write_size=20480 +max_write_interval=1 +buffer_send_rate=2 +retry_interval=30 +retry_interval_range=10 + +<primary> +category=default +type=file +target_write_size=20480 +max_write_interval=1 +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> +category=default +type=file +target_write_size=20480 +max_write_interval=1 +fs_type=std +file_path=$root/scribe/logs/central-secondary +base_filename=central +max_size=3000000 +</secondary> + +</store0> + +<store1> +category=default +type=buffer +target_write_size=20480 +max_write_interval=1 +buffer_send_rate=2 +retry_interval=30 +retry_interval_range=10 + +<primary> +category=default +type=file +target_write_size=20480 +max_write_interval=1 +fs_type=std +file_path=$root/scribe/logs/firehose +base_filename=central +max_size=1000000 +add_newlines=1 +write_stats=no +create_symlink=no +</primary> + +<secondary> +category=default +type=file +target_write_size=20480 +max_write_interval=1 +fs_type=std +file_path=$root/scribe/logs/firehose-secondary +base_filename=central +max_size=3000000 +</secondary> + +</store1> + +</store> + +EOF diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribed-central-mkfirehose b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-mkfirehose new file mode 100755 index 0000000000..9b02305d1d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-mkfirehose @@ -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. + +# Create a firehose fifo pipe for a log category +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +category=$2 +if [ "$category" = "" ]; then + category="default" +fi + +mkdir -p $root/scribe/logs/firehose/$category +if [ ! -e "$root/scribe/logs/firehose/$category/$category""_00000" ]; then + mkfifo "$root/scribe/logs/firehose/$category/$category""_00000" +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribed-central-start b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-start new file mode 100755 index 0000000000..9aff8a1466 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +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/sca-cpp/branches/lightweight-sca/components/log/scribed-central-stop b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-stop new file mode 100755 index 0000000000..2d301149b8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribed-central-stop @@ -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. + +# Stop central scribed +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +scribe_prefix=`cat $here/scribe.prefix` +thrift_prefix=`cat $here/thrift.prefix` +scribed="$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-central.conf" + +k=`ps -ef | grep -v grep | grep "${scribed}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/log/scribed-client-conf b/sca-cpp/branches/lightweight-sca/components/log/scribed-client-conf new file mode 100755 index 0000000000..e0a35581c7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribed-client-conf @@ -0,0 +1,70 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +if [ "$3" = "" ]; then + host="*" + central=$2 +else + host=$2 + central=$3 +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 +host=$host +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=1463 +</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/sca-cpp/branches/lightweight-sca/components/log/scribed-client-start b/sca-cpp/branches/lightweight-sca/components/log/scribed-client-start new file mode 100755 index 0000000000..acf52c535f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +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/sca-cpp/branches/lightweight-sca/components/log/scribed-client-stop b/sca-cpp/branches/lightweight-sca/components/log/scribed-client-stop new file mode 100755 index 0000000000..d6a6345f29 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/scribed-client-stop @@ -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. + +# Stop client scribed +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +scribe_prefix=`cat $here/scribe.prefix` +thrift_prefix=`cat $here/thrift.prefix` +scribed="$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-client.conf" + +k=`ps -ef | grep -v grep | grep "${scribed}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/log/server-test b/sca-cpp/branches/lightweight-sca/components/log/server-test new file mode 100755 index 0000000000..6c9cf47135 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/server-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. + +# Setup +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/log/thrift-pragmas b/sca-cpp/branches/lightweight-sca/components/log/thrift-pragmas new file mode 100755 index 0000000000..3950ce9984 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/log/thrift-pragmas @@ -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. + +# Patch generated Thrift files, disable some compile warnings + +tmpfile=`mktemp -t thrift-pragmas.XXX` +cat >$tmpfile << EOF +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused" +#pragma GCC diagnostic ignored "-Wreturn-type" +EOF + +cat $1 >>$tmpfile +cat $tmpfile >$1 + +rm $tmpfile diff --git a/sca-cpp/branches/lightweight-sca/components/queue/Makefile.am b/sca-cpp/branches/lightweight-sca/components/queue/Makefile.am new file mode 100644 index 0000000000..c44722a523 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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${libsuffix} libqueue-listener${libsuffix} + +libqueue_sender_la_SOURCES = queue-sender.cpp +libqueue_sender_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon +libqueue-sender${libsuffix}: + ln -s .libs/libqueue-sender${libsuffix} + +libqueue_listener_la_SOURCES = queue-listener.cpp +libqueue_listener_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon +libqueue-listener${libsuffix}: + ln -s .libs/libqueue-listener${libsuffix} + +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/sca-cpp/branches/lightweight-sca/components/queue/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/queue/client-test.cpp new file mode 100644 index 0000000000..30bfe07bf7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/client-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 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_WARNINGS +#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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); +const list<value> entry = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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/sca-cpp/branches/lightweight-sca/components/queue/qpid-test.cpp b/sca-cpp/branches/lightweight-sca/components/queue/qpid-test.cpp new file mode 100644 index 0000000000..27db7734b0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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_WARNINGS +#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/sca-cpp/branches/lightweight-sca/components/queue/qpid.hpp b/sca-cpp/branches/lightweight-sca/components/queue/qpid.hpp new file mode 100644 index 0000000000..ef53c529e8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/qpid.hpp @@ -0,0 +1,277 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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_WARNINGS +#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) { + debug("queue::qpidonnection"); + c.open("localhost", 5672); + } + + QpidConnection(const bool owner) : owner(owner) { + debug("queue::qpidonnection"); + c.open("localhost", 5672); + } + + QpidConnection(const QpidConnection& qc) : owner(false), c(qc.c) { + debug("queue::qpidonnection::copy"); + } + + const QpidConnection& operator=(const QpidConnection& qc) { + debug("queue::qpidonnection::operator="); + if(this == &c) + return *this; + owner = false; + c = qc.c; + return *this; + } + + ~QpidConnection() { + debug("queue::~qpidonnection"); + 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()) { + debug("queue::qpidsession"); + } + + QpidSession(QpidConnection& qc, const bool owner) : owner(owner), s(qc.c.newSession()) { + debug("queue::qpidsession"); + } + + QpidSession(const QpidSession& qs) : owner(false), s(qs.s) { + debug("queue::qpidsession::copy"); + } + + ~QpidSession() { + debug("queue::~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_WARNINGS +#pragma GCC diagnostic warning "-Wconversion" +#pragma GCC diagnostic warning "-Wredundant-decls" +#endif + +#endif /* tuscany_qpid_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/components/queue/qpidd-start b/sca-cpp/branches/lightweight-sca/components/queue/qpidd-start new file mode 100755 index 0000000000..a65065182c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +qpid_prefix=`cat $here/qpidc.prefix` +$qpid_prefix/sbin/qpidd & diff --git a/sca-cpp/branches/lightweight-sca/components/queue/qpidd-stop b/sca-cpp/branches/lightweight-sca/components/queue/qpidd-stop new file mode 100755 index 0000000000..c8af680d78 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/qpidd-stop @@ -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. + +# Stop qpidd +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +qpid_prefix=`cat $here/qpidc.prefix` +qpidd="$qpid_prefix/sbin/qpidd" + +k=`ps -ef | grep -v grep | grep "${qpidd}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/queue/queue-listener.componentType b/sca-cpp/branches/lightweight-sca/components/queue/queue-listener.componentType new file mode 100644 index 0000000000..1e94f9a2df --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/queue/queue-listener.cpp b/sca-cpp/branches/lightweight-sca/components/queue/queue-listener.cpp new file mode 100644 index 0000000000..483d0de65a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/queue-listener.cpp @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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_WARNINGS +#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 mkfailure<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(const list<value>&)>)cadr(params))(list<value>()); + const value key = isList(pk)? (list<value>)pk : mklist<value>(pk); + const value qname = ((lambda<value(const 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/sca-cpp/branches/lightweight-sca/components/queue/queue-sender.componentType b/sca-cpp/branches/lightweight-sca/components/queue/queue-sender.componentType new file mode 100644 index 0000000000..fc06bf2dcf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/queue/queue-sender.cpp b/sca-cpp/branches/lightweight-sca/components/queue/queue-sender.cpp new file mode 100644 index 0000000000..202a0e4435 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/queue-sender.cpp @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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_WARNINGS +#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(const 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>(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/sca-cpp/branches/lightweight-sca/components/queue/queue.composite b/sca-cpp/branches/lightweight-sca/components/queue/queue.composite new file mode 100644 index 0000000000..9b6939e4bc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/queue.composite @@ -0,0 +1,55 @@ +<?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" + 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"> + <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"> + <implementation.scheme script="server-test.scm"/> + <service name="print"> + <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"> + <binding.http uri="report-sender"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/queue/send-test b/sca-cpp/branches/lightweight-sca/components/queue/send-test new file mode 100755 index 0000000000..f2cc53d851 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/queue/server-test b/sca-cpp/branches/lightweight-sca/components/queue/server-test new file mode 100755 index 0000000000..269d3f9376 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/queue/server-test @@ -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. + +# Setup +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/queue/server-test.scm b/sca-cpp/branches/lightweight-sca/components/queue/server-test.scm new file mode 100644 index 0000000000..1a89ce8b31 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/smtp/Makefile.am b/sca-cpp/branches/lightweight-sca/components/smtp/Makefile.am new file mode 100644 index 0000000000..41fa686b9a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/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. + +compdir=$(prefix)/components/smtp + +EXTRA_DIST = smtp.composite smtppost.componentType *.scm + +comp_LTLIBRARIES = libsmtppost.la +noinst_DATA = libsmtppost${libsuffix} + +libsmtppost_la_SOURCES = smtppost.cpp +libsmtppost_la_LDFLAGS = -lxml2 -lmozjs -curl +libsmtppost${libsuffix}: + ln -s .libs/libsmtppost${libsuffix} + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +dist_noinst_SCRIPTS = server-test +noinst_PROGRAMS = client-test +#TESTS = server-test + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/smtp/client-test.cpp new file mode 100644 index 0000000000..10274a6248 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/client-test.cpp @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 SMTP post 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 smtp { + +const string postURI("http://localhost:8090/smtppost"); + +bool testPost() { + http::CURLSession cs("", "", "", "", 0); + + const failable<value> val = http::get(postURI, cs); + assert(hasContent(val)); + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::smtp::testPost(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/content-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/content-test.scm new file mode 100644 index 0000000000..eaf4a868c5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/content-test.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. + +; Content test case + +(define (get id) +(list "text/plain; charset=utf-8" (list +"test test test + +- Jean-Sebastien" +)) +) + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/from-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/from-test.scm new file mode 100644 index 0000000000..083c060844 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/from-test.scm @@ -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. + +; From test case + +(define (get id) + "<jane@example.com>" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/password-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/password-test.scm new file mode 100644 index 0000000000..0a28776865 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/password-test.scm @@ -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. + +; Password test case + +(define (get id) + "password" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/server-test b/sca-cpp/branches/lightweight-sca/components/smtp/server-test new file mode 100755 index 0000000000..c111021c85 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/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 +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-loglevel-conf tmp debug +../../modules/server/server-conf tmp +../../modules/server/scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite smtp.composite +EOF + +../../modules/http/httpd-start tmp +sleep 2 + +# Test +./client-test #2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/smtp.composite b/sca-cpp/branches/lightweight-sca/components/smtp/smtp.composite new file mode 100644 index 0000000000..c740b68bc9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/smtp.composite @@ -0,0 +1,87 @@ +<?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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="smtp"> + + <component name="smtppost"> + <implementation.cpp path="." library="libsmtppost"/> + <service name="smtppost"> + <binding.http uri="smtppost"/> + </service> + <reference name="url" target="url-test"/> + <reference name="user" target="user-test"/> + <reference name="password" target="password-test"/> + <reference name="from" target="from-test"/> + <reference name="to" target="to-test"/> + <reference name="subject" target="subject-test"/> + <reference name="content" target="content-test"/> + </component> + + <component name="url-test"> + <implementation.scheme script="url-test.scm"/> + <service name="url-test"> + <binding.http uri="url-test"/> + </service> + </component> + + <component name="password-test"> + <implementation.scheme script="password-test.scm"/> + <service name="password-test"> + <binding.http uri="password-test"/> + </service> + </component> + + <component name="user-test"> + <implementation.scheme script="user-test.scm"/> + <service name="user-test"> + <binding.http uri="user-test"/> + </service> + </component> + + <component name="from-test"> + <implementation.scheme script="from-test.scm"/> + <service name="from-test"> + <binding.http uri="from-test"/> + </service> + </component> + + <component name="to-test"> + <implementation.scheme script="to-test.scm"/> + <service name="to-test"> + <binding.http uri="to-test"/> + </service> + </component> + + <component name="subject-test"> + <implementation.scheme script="subject-test.scm"/> + <service name="subject-test"> + <binding.http uri="subject-test"/> + </service> + </component> + + <component name="content-test"> + <implementation.scheme script="content-test.scm"/> + <service name="content-test"> + <binding.http uri="content-test"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/smtppost.componentType b/sca-cpp/branches/lightweight-sca/components/smtp/smtppost.componentType new file mode 100644 index 0000000000..f33673b53e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/smtppost.componentType @@ -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. +--> +<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="smtppost"/> + <reference name="url"/> + <reference name="user"/> + <reference name="password"/> + <reference name="from"/> + <reference name="to"/> + <reference name="subject"/> + <reference name="content"/> + +</componentType> diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/smtppost.cpp b/sca-cpp/branches/lightweight-sca/components/smtp/smtppost.cpp new file mode 100644 index 0000000000..1030ccc223 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/smtppost.cpp @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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$ */ + +/** + * SMTP client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../../modules/http/http.hpp" + +namespace tuscany { +namespace smtppost { + +/** + * Post/send an email message using SMTP. + */ +const failable<value> post(const string& url, const string& user, const string& pass, const string& from, const string& to, const string& subject, const value& val, http::CURLSession& cs) { + // Convert value to a content request + const failable<list<list<string> > > freq = http::contentRequest(val, url); + if (!hasContent(freq)) + return mkfailure<value>(freq); + const list<list<string> > req = content(freq); + debug(req, "smtp::post::input"); + + // Setup the CURL session + const failable<CURL*> fch = http::setup(url, cs); + if (!hasContent(fch)) { + http::cleanup(cs); + return mkfailure<value>(fch); + } + CURL* ch = content(fch); + curl_easy_setopt(ch, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + + // Convert message to a string + ostringstream os; + os << "From: " << from << "\n"; + os << "To: " << to << "\n"; + os << "Subject: " << subject << "\n"; + os << car(car(req)) << "\n\n"; + write(cadr(req), os); + + // Setup the read callbacks + http::CURLReadContext rcx(mklist(str(os))); + curl_easy_setopt(ch, CURLOPT_READFUNCTION, (size_t (*)(void*, size_t, size_t, void*))http::readCallback); + curl_easy_setopt(ch, CURLOPT_READDATA, &rcx); + + // Setup the message properties + curl_easy_setopt(ch, CURLOPT_USERNAME, c_str(user)); + curl_easy_setopt(ch, CURLOPT_PASSWORD, c_str(pass)); + curl_easy_setopt(ch, CURLOPT_MAIL_FROM, c_str(from)); + struct curl_slist* rcpt = curl_slist_append(NULL, c_str(to)); + curl_easy_setopt(ch, CURLOPT_MAIL_RCPT, rcpt); + + // Perform the SMTP send + const CURLcode rc = curl_easy_perform(ch); + + // Free the recipients + curl_slist_free_all(rcpt); + + // Return the CURL return code or true + if (rc) { + http::cleanup(cs); + return mkfailure<value>(string(curl_easy_strerror(rc))); + } + + http::cleanup(cs); + return value(true); +} + +/** + * Evaluate an SMTP post/send. + */ +const failable<value> get(const lambda<value(const list<value>&)>& url, + const lambda<value(const list<value>&)>& user, const lambda<value(const list<value>&)>& pass, + const lambda<value(const list<value>&)>& from, const lambda<value(const list<value>&)>& to, + const lambda<value(const list<value>&)>& subject, const lambda<value(const list<value>&)>& val, + http::CURLSession& ch) { + debug("smtppost::get"); + const value u = url(mklist<value>("get", list<value>())); + const value i = user(mklist<value>("get", list<value>())); + const value p = pass(mklist<value>("get", list<value>())); + const value f = from(mklist<value>("get", list<value>())); + const value t = to(mklist<value>("get", list<value>())); + const value s = subject(mklist<value>("get", list<value>())); + const value v = val(mklist<value>("get", list<value>())); + debug(u, "smtppost::get::url"); + debug(i, "smtppost::get::user"); + debug(p, "smtppost::get::pass"); + debug(f, "smtppost::get::from"); + debug(t, "smtppost::get::to"); + debug(s, "smtppost::get::subject"); + debug(v, "smtppost::get::val"); + return post(u, i, p, f, t, s, v, ch); +} + +/** + * Component implementation lambda function. + */ +class applysmtp { +public: + applysmtp(const lambda<value(const list<value>&)>& url, + const lambda<value(const list<value>&)>& user, const lambda<value(const list<value>&)>& pass, + const lambda<value(const list<value>&)>& from, const lambda<value(const list<value>&)>& to, + const lambda<value(const list<value>&)>& subject, const lambda<value(const list<value>&)>& val, + perthread_ptr<http::CURLSession>& ch) : + url(url), user(user), pass(pass), from(from), to(to), subject(subject), val(val), ch(ch) { + } + + const value operator()(const list<value>& params) const { + debug(params, "smtppost::applysmtp::params"); + const value func(car(params)); + if (func == "get") + return get(url, user, pass, from, to, subject, val, *ch); + return mkfailure<value>(); + } + +private: + const lambda<value(const list<value>&)> url; + const lambda<value(const list<value>&)> user; + const lambda<value(const list<value>&)> pass; + const lambda<value(const list<value>&)> from; + const lambda<value(const list<value>&)> to; + const lambda<value(const list<value>&)> subject; + const lambda<value(const list<value>&)> val; + perthread_ptr<http::CURLSession> ch; +}; + +/** + * Create a new CURL session. + */ +const gc_ptr<http::CURLSession> newsession() { + return new (gc_new<http::CURLSession>()) http::CURLSession("", "", "", "", 0); +} + +/** + * Start the component. + */ +const failable<value> start(const list<value>& params) { + // Create a CURL session + perthread_ptr<http::CURLSession> ch = perthread_ptr<http::CURLSession>(lambda<gc_ptr<http::CURLSession>()>(newsession)); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applysmtp(car(params), cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params), ch))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::smtppost::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/subject-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/subject-test.scm new file mode 100644 index 0000000000..6a296cbea8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/subject-test.scm @@ -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. + +; Subject test case + +(define (get id) + "Test email" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/to-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/to-test.scm new file mode 100644 index 0000000000..079df89301 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/to-test.scm @@ -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. + +; To test case + +(define (get id) + "<jane@example.com>" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/url-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/url-test.scm new file mode 100644 index 0000000000..aa73c59d5c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/url-test.scm @@ -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. + +; URL test case + +(define (get id) + "smtp://smtp.gmail.com:587" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/smtp/user-test.scm b/sca-cpp/branches/lightweight-sca/components/smtp/user-test.scm new file mode 100644 index 0000000000..13862ac70c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/smtp/user-test.scm @@ -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. + +; URL test case + +(define (get id) + "jane" +) + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/Makefile.am b/sca-cpp/branches/lightweight-sca/components/sqldb/Makefile.am new file mode 100644 index 0000000000..9ce5f26713 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/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_SQLDB + +INCLUDES = -I${PGSQL_INCLUDE} + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/components/sqldb + +dist_comp_SCRIPTS = pgsql-conf pgsql-log-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf pgsql-archive pgsql-backup pgsql-restore pgsql-clean-archive +compdir=$(prefix)/components/sqldb + +comp_DATA = pgsql.prefix pgbouncer.prefix +pgsql.prefix: $(top_builddir)/config.status + echo ${PGSQL_PREFIX} >pgsql.prefix +pgbouncer.prefix: $(top_builddir)/config.status + echo ${PGBOUNCER_PREFIX} >pgbouncer.prefix + +EXTRA_DIST = sqldb.composite sqldb.componentType + +comp_LTLIBRARIES = libsqldb.la +noinst_DATA = libsqldb${libsuffix} + +libsqldb_la_SOURCES = sqldb.cpp +libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq +libsqldb${libsuffix}: + ln -s .libs/libsqldb${libsuffix} + +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/sca-cpp/branches/lightweight-sca/components/sqldb/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/sqldb/client-test.cpp new file mode 100644 index 0000000000..0cbcb57363 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/client-test.cpp @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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("", "", "", "", 0); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$3.55"))); + const list<value> b = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$4.55"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + + http::CURLSession cs("", "", "", "", 0); + 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/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql new file mode 100755 index 0000000000..8a60068ab7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql @@ -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. + +# Run SQL command +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pgsql_prefix=`cat $here/pgsql.prefix` + +if [ "$2" = "" ]; then + host="localhost" + port="6432" + cmd="$1" +else + host="$1" + port="$2" + cmd="$3" +fi + +if [ "$cmd" = "" ]; then + $pgsql_prefix/bin/psql -h $host -p $port db +else + $pgsql_prefix/bin/psql -h $host -p $port -c "$cmd" db +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-archive b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-archive new file mode 100755 index 0000000000..128e6eb539 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-archive @@ -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. + +# PostgreSQL archive command +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=$3 +walp=$4 +walf=$5 + +# Copy WAL to archive directory +if [ ! -f $root/sqldb/archive/$walf ]; then + cp $walp $root/sqldb/archive/$walf + rc=$? + if [ "$rc" != "0" ]; then + exit $rc + fi +fi + +# Trigger a backup if we have 10 WAL files archived since the last backup +lastbak=`ls $root/sqldb/archive | sort -r | grep "\.backup$" | head -1` +if [ "$lastbak" = "" ]; then + exit 0 +fi +wals=`ls $root/sqldb/archive | sort -r | grep -v "\.backup\.tar\.gz$"` + +w=0 +for f in $wals; do + if [ "$f" = "$lastbak" ]; then + break + fi + w=$((w+1)) + + if [ "$w" = "10" ]; then + nohup /bin/sh -c "$here/pgsql-backup $root $host $port" 1>/dev/null 2>/dev/null & + break + fi +done + +exit 0 + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-backup b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-backup new file mode 100755 index 0000000000..ff660ad20d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-backup @@ -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. + +# Backup postgresql data directory +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +if [ "$2" = "" ]; then + host="localhost" + port="6432" +else + host="$2" + port="$3" +fi + +pgsql_prefix=`cat $here/pgsql.prefix` + +if [ -f "$root/sqldb/log.conf" ]; then + pgsql_log=`cat $root/sqldb/log.conf` +else + mkdir -p $root/logs + pgsql_log="cat >>$root/logs/postgresql" +fi +mkdir -p $root/sqldb +echo $pgsql_log >$root/sqldb/logger + +mkdir -p $root/sqldb/backup +mkdir -p $root/sqldb/archive + +# Make sure that only one backup is in progress at a time +if [ -f $root/sqldb/backup/inprogress ]; then + exit 0 +fi +touch $root/sqldb/backup/inprogress + +# Backup +stamp=`date +%Y%m%d%H%M%S` +$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('$stamp', true)" db 2>&1 | sh $root/sqldb/logger + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + tar=gnutar +else + tar=tar +fi +$tar -C $root/sqldb --exclude data/postmaster.pid --exclude data/postmaster.opts --exclude data/pg_xlog --ignore-failed-read -czf $root/sqldb/backup/$stamp.backup.tar.gz data +rc=$? +if [ "$rc" = "0" ]; then + mv $root/sqldb/backup/$stamp.backup.tar.gz $root/sqldb/archive/$stamp.backup.tar.gz +fi + +$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_stop_backup()" db 2>&1 | sh $root/sqldb/logger + +if [ "$rc" != "0" ]; then + rm -f $root/sqldb/backup/inprogress + exit $rc +fi + +# Clean obsolete backup and WAL files +$here/pgsql-clean-archive $root + +rm -f $root/sqldb/backup/inprogress + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-clean-archive b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-clean-archive new file mode 100755 index 0000000000..0e52fade89 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-clean-archive @@ -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. + +# Cleanup database archive. +# Keep the last two backups and corresponding WAL files. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +baks=`ls $root/sqldb/archive | sort -r | grep "\.backup$" | head -2` +wals=`ls $root/sqldb/archive | sort -r | grep -v "\.backup\.tar\.gz$"` +tars=`ls $root/sqldb/archive | sort -r | grep "\.backup\.tar\.gz$"` + +for f in $baks; do + if [ "$lastbak" = "" ]; then + lastbak=$f + else + prevbak=$f + fi +done + +w=0 +for f in $wals; do + if [ "$w" = "2" ]; then + rm $root/sqldb/archive/$f + fi + if [ "$w" = "1" ]; then + w=2 + fi + if [ "$f" = "$prevbak" ]; then + w=1 + fi +done + +t=0 +for f in $tars; do + if [ "$t" = "2" ]; then + rm $root/sqldb/archive/$f + fi + t=$((t+1)) +done + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-conf b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-conf new file mode 100755 index 0000000000..8adbb902c9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-conf @@ -0,0 +1,194 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +addr=$2 +if [ "$addr" = "" ]; then + host="localhost" + listen="*" + port="5432" +else + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + listen="*" + else + listen=$host + fi + port=`$here/../../modules/http/httpd-addr port $addr` +fi +bport=`expr $port + 1000` + +pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` + +user=`id -un` + +mkdir -p $root/sqldb/data +chmod 700 $root/sqldb/data +mkdir -p $root/sqldb/archive +mkdir -p $root/sqldb/backup + +if [ -f "$root/sqldb/log.conf" ]; then + pgsql_log=`cat $root/sqldb/log.conf` +else + mkdir -p $root/logs + pgsql_log="cat >>$root/logs/postgresql" +fi +mkdir -p $root/sqldb +mkdir -p $root/sqldb/tmp +echo $pgsql_log >$root/sqldb/logger + +# Initialize PostgreSQL +if [ ! -f $root/sqldb/data/postgresql.conf ]; then + $pgsql_prefix/bin/pg_ctl init -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger + 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 $* + +# Setup logging +log_min_messages = NOTICE +log_min_error_statement = NOTICE +log_min_duration_statement = -1 +log_checkpoints = on +log_connections = off +log_disconnections = off +log_duration = off +log_lock_waits = on +log_statement = none + +# Listen +listen_addresses = '$listen' +port = $port +unix_socket_directory = '$root/sqldb/tmp' + +# Setup archival +archive_mode = on +archive_command = '$here/pgsql-archive $root $host $bport %p %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 if it's not created yet +nohup /bin/sh -c "($pgsql_prefix/bin/pg_ctl start -W -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger)" 1>/dev/null 2>/dev/null & +sti=0 +while [ $sti -ne 30 ]; do + st=`$pgsql_prefix/bin/pg_ctl status -D $root/sqldb/data | grep 'server is running'` + if [ "$st" != "" ]; then + break + fi + sleep 1 + sti=$((sti+1)) +done + +$pgsql_prefix/bin/createdb -h $host -p $port db 2>&1 | sh $root/sqldb/logger + +# Create default user roles +$pgsql_prefix/bin/psql -h $host -p $port -c "create role standby with login replication" db 2>&1 | sh $root/sqldb/logger +$pgsql_prefix/bin/psql -h $host -p $port -c "create role bouncer with login" db 2>&1 | sh $root/sqldb/logger + +# Backup the db if there's no backup for it yet +baks=`ls $root/sqldb/archive | sort -r | grep "\.backup\.tar\.gz$"` +if [ "$baks" = "" ]; then + $here/pgsql-backup $root $host $port +fi + +$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger + +# Generate database restore script +mkdir -p $root/sqldb/scripts +cat >$root/sqldb/scripts/restore <<EOF +#!/bin/sh +$here/pgsql-restore $root +EOF +chmod 700 $root/sqldb/scripts/restore + +# 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-restore "$root/sqldb/scripts/restore" +Alias /pgsql-archive "$root/sqldb/archive" + +EOF + +fi + +# Configure PgBouncer +mkdir -p $root/logs +id=`id -un` +cat >$root/sqldb/data/pgbouncer.conf <<EOF + +[databases] +db = host=$host port=$port dbname=db user=bouncer + +[pgbouncer] +pool_mode = session +listen_addr = $listen +listen_port = $bport +unix_socket_dir = +auth_type = trust +auth_file=$root/sqldb/data/pgbouncer-auth.conf +logfile = $root/logs/pgbouncer +pidfile = $root/logs/pgbouncer.pid +max_client_conn = 1000 +pool_mode = transaction +server_reset_query = +default_pool_size = 500 +min_pool_size = 5 +reserve_pool_size = 50 +log_connections = 0 +log_disconnections = 0 +stats_period = 3600 +admin_users = $id + +EOF + +cat >$root/sqldb/data/pgbouncer-auth.conf <<EOF +"$id" "password" + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-log-conf b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-log-conf new file mode 100755 index 0000000000..c68b4b718d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-log-conf @@ -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. + +# Configure postgresql logging +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/sqldb +if [ "$2" = "" ]; then + cat >$root/sqldb/log.conf << EOF +cat >>$root/logs/postgresql +EOF + +else + cat >$root/sqldb/log.conf << EOF +$2 +EOF + +fi + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-restore b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-restore new file mode 100755 index 0000000000..e91eba2a6b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-restore @@ -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. + +# Backup postgresql data directory +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +tar=`ls $root/sqldb/archive | sort -r | grep "\.backup\.tar\.gz$" | head -1` + +echo "Content-type: application/x-compressed" +echo "" + +cat $root/sqldb/archive/$tar + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-standby-conf b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-standby-conf new file mode 100755 index 0000000000..5f76b5b332 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-standby-conf @@ -0,0 +1,193 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +# Server address +addr=$2 +if [ "$addr" = "" ]; then + host="localhost" + listen="*" + port="5432" +else + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + listen="*" + else + listen=$host + fi + port=`$here/../../modules/http/httpd-addr port $addr` +fi +bport=`expr $port + 1000` + +# 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` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` + +user=`id -un` + +mkdir -p $root/sqldb/data +chmod 700 $root/sqldb/data +mkdir -p $root/sqldb/archive +mkdir -p $root/sqldb/backup + +if [ -f "$root/sqldb/log.conf" ]; then + pgsql_log=`cat $root/sqldb/log.conf` +else + mkdir -p $root/logs + pgsql_log="cat >>$root/logs/postgresql" +fi +mkdir -p $root/sqldb +mkdir -p $root/sqldb/tmp +echo $pgsql_log >$root/sqldb/logger + +# Initialize from a backup of the master +if [ ! -f $root/sqldb/data/postgresql.conf ]; then + uname=`uname -s` + if [ $uname = "Darwin" ]; then + tar=gnutar + else + tar=tar + fi + (curl -L -# http://$mhost:$mhttpport/pgsql-restore | $tar -C $root/sqldb -xz) 2>&1 | grep -v "100.0%" | sh $root/sqldb/logger + 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: pgsql-standby-conf $* + +# Setup logging +log_min_messages = NOTICE +log_min_error_statement = NOTICE +log_min_duration_statement = -1 +log_checkpoints = on +log_connections = off +log_disconnections = off +log_duration = off +log_lock_waits = on +log_statement = none + +# Listen +listen_addresses = '$listen' +port = $port +unix_socket_directory = '$root/sqldb/tmp' + +# Setup archival +archive_mode = on +archive_command = '$here/pgsql-archive $root $host $bport %p %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-standby-conf $* + +# Start in standby mode +standby_mode = 'on' +primary_conninfo = 'host=$mhost port=$mport user=standby' + +# Failover +trigger_file = '$root/sqldb/failover' + +restore_command = 'curl -L -# http://$mhost:$mhttpport/pgsql-archive/%f -o "%p" 2>&1 | grep -v "100.0%"' + +EOF + +# Generate database restore script +mkdir -p $root/sqldb/scripts +cat >$root/sqldb/scripts/restore <<EOF +#!/bin/sh +$here/pgsql-restore $root +EOF +chmod 700 $root/sqldb/scripts/restore + +# Configure HTTPD to serve backup and archive files +if [ -f "$root/conf/httpd.conf" ]; then + cat >>$root/conf/httpd.conf <<EOF +# Generated by: pgsql-standby-conf $* + +# Serve PostgreSQL backup and WAL archive files +ScriptAlias /pgsql-restore "$root/sqldb/scripts/restore" +Alias /pgsql-archive "$root/sqldb/archive" + +EOF + +fi + +# Configure PgBouncer +mkdir -p $root/logs +id=`id -un` +cat >$root/sqldb/data/pgbouncer.conf <<EOF + +[databases] +db = host=$host port=$port dbname=db user=bouncer + +[pgbouncer] +pool_mode = session +listen_addr = $listen +listen_port = $bport +unix_socket_dir = +auth_type = trust +auth_file=$root/sqldb/data/pgbouncer-auth.conf +logfile = $root/logs/pgbouncer +pidfile = $root/logs/pgbouncer.pid +max_client_conn = 1000 +pool_mode = transaction +server_reset_query = +default_pool_size = 500 +min_pool_size = 5 +reserve_pool_size = 50 +log_connections = 0 +log_disconnections = 0 +stats_period = 3600 +admin_users = $id + +EOF + +cat >$root/sqldb/data/pgbouncer-auth.conf <<EOF +"$id" "password" + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-standby-test.cpp b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-standby-test.cpp new file mode 100644 index 0000000000..2cd25f874a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=6432 dbname=db", "test"); + PGSql rpg("host=localhost port=6433 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=6432 dbname=db", "test"); + PGSql rpg("host=localhost port=6433 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/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-start b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-start new file mode 100755 index 0000000000..6b388d29f0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-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. + +# Start postgresql +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` + +if [ -f "$root/sqldb/log.conf" ]; then + pgsql_log=`cat $root/sqldb/log.conf` +else + mkdir -p $root/logs + pgsql_log="cat >>$root/logs/postgresql" +fi +mkdir -p $root/sqldb +echo $pgsql_log >$root/sqldb/logger + +nohup /bin/sh -c "($pgsql_prefix/bin/pg_ctl start -W -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger)" 1>/dev/null 2>/dev/null & +sti=0 +while [ $sti -ne 30 ]; do + st=`$pgsql_prefix/bin/pg_ctl status -D $root/sqldb/data | grep 'server is running'` + if [ "$st" != "" ]; then + break + fi + sleep 1 + sti=$((sti+1)) +done + +# Start PgBouncer +mkdir -p $root/logs +$pgbouncer_prefix/bin/pgbouncer -q -d $root/sqldb/data/pgbouncer.conf + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-stop b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-stop new file mode 100755 index 0000000000..16b6506838 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-stop @@ -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. + +# Stop postgresql +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` + +if [ -f "$root/sqldb/log.conf" ]; then + pgsql_log=`cat $root/sqldb/log.conf` +else + mkdir -p $root/logs + pgsql_log="cat >>$root/logs/postgresql" +fi +mkdir -p $root/sqldb +echo $pgsql_log >$root/sqldb/logger + +pgb="$pgbouncer_prefix/bin/pgbouncer -q -d $root/sqldb/data/pgbouncer.conf" +k=`ps -ef | grep -v grep | grep "${pgb}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + +$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger + diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-test.cpp b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql-test.cpp new file mode 100644 index 0000000000..d10ab5f4c2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=6432 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=6432 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/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql.hpp b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql.hpp new file mode 100644 index 0000000000..581cd943e6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/pgsql.hpp @@ -0,0 +1,249 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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) { + debug("pgsql::pgsql"); + } + + PGSql(const string& conninfo, const string& table) : owner(true), conn(NULL), conninfo(conninfo), table(table) { + debug(conninfo, "pgsql::pgsql::conninfo"); + debug(table, "pgsql::pgsql::table"); + + // Connect to the database + conn = PQconnectdb(c_str(conninfo)); + if (PQstatus(conn) != CONNECTION_OK) { + mkfailure<bool>(string("Couldn't connect to postgresql database: ") + PQerrorMessage(conn)); + return; + } + + // 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) { + mkfailure<bool>(string("Couldn't execute postgresql column select statement: ") + pgfailure(kr, conn)); + return; + } + if (PQntuples(kr) != 2) { + PQclear(kr); + mkfailure<bool>(string("Couldn't find postgresql table key and value column names")); + return; + } + kname = PQgetvalue(kr, 0, 0); + vname = PQgetvalue(kr, 1, 0); + PQclear(kr); + } + + PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) { + debug("pgsql::pgsql::copy"); + } + + const PGSql& operator=(const PGSql& c) { + debug("pgsql::pgsql::operator="); + if(this == &c) + return *this; + owner = false; + conn = c.conn; + conninfo = c.conninfo; + table = c.table; + return *this; + } + + ~PGSql() { + debug("pgsql::~pgsql"); + if (!owner) + return; + if (conn == NULL) + return; + PQfinish(conn); + } + +private: + bool owner; + PGconn *conn; + string conninfo; + string table; + string kname; + string vname; + + 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 if necessary. + */ +const failable<bool> setup(const PGSql& pgsql) { + debug("pgsql::setup"); + if (PQstatus(pgsql.conn) == CONNECTION_OK) + return true; + debug("pgsql::setup::reset"); + PQreset(pgsql.conn); + if (PQstatus(pgsql.conn) != CONNECTION_OK) + return mkfailure<bool>(string("Couldn't reconnect to postgresql database: ") + PQerrorMessage(pgsql.conn)); + return true; +} + +/** + * 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 = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Couldn't 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 = PQexecParams(pgsql.conn, c_str(string("update ") + pgsql.table + string(" set ") + pgsql.vname + string(" = $2 where ") + pgsql.kname + string(" = $1;")), 2, NULL, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Couldn't 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 = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0); + if (PQresultStatus(pr) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Couldn't 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 = PQexecParams(pgsql.conn, c_str(string("select * from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_TUPLES_OK) + return mkfailure<value>(string("Couldn't execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); + if (PQntuples(r) < 1) { + PQclear(r); + ostringstream os; + os << "Couldn't get postgresql entry: " << key; + return mkfailure<value>(str(os), 404, false); + } + 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 = PQexecParams(pgsql.conn, c_str(string("delete from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Couldn't 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/sca-cpp/branches/lightweight-sca/components/sqldb/server-test b/sca-cpp/branches/lightweight-sca/components/sqldb/server-test new file mode 100755 index 0000000000..db756ec1c4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/server-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 +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +./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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb-test b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb-test new file mode 100755 index 0000000000..cb023fec3a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb-test @@ -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. + +# Setup +rm -rf tmp +./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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.componentType b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.componentType new file mode 100644 index 0000000000..bd024213bd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=6432 dbname=db</property> + <property name="table" type=xsd:string"/> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.composite b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.composite new file mode 100644 index 0000000000..9e102893b5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.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" + targetNamespace="http://tuscany.apache.org/xmlns/sca/components" + name="sqldb"> + + <component name="sqldb"> + <implementation.cpp path="." library="libsqldb"/> + <property name="conninfo">host=localhost port=6432 dbname=db</property> + <property name="table">test</property> + <service name="sqldb"> + <binding.http uri="sqldb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.cpp b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.cpp new file mode 100644 index 0000000000..9925897693 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/sqldb.cpp @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "parallel.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>(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>(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>(val); + return value(content(val)); +} + +/** + * Component implementation lambda function. + */ +class applySqldb { +public: + applySqldb(const perthread_ptr<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 mkfailure<value>(); + } + +private: + const perthread_ptr<pgsql::PGSql> pg; +}; + +/** + * Lambda function that creates a new database connection. + */ +class newPGSql { +public: + newPGSql(const string& conninfo, const string& table) : conninfo(conninfo), table(table) { + } + + const gc_ptr<pgsql::PGSql> operator()() const { + return new (gc_new<pgsql::PGSql>()) pgsql::PGSql(conninfo, table); + } + +private: + const string conninfo; + const string table; +}; + +/** + * Start the component. + */ +const failable<value> start(unused const list<value>& params) { + // Connect to the configured database and table + const value conninfo = ((lambda<value(const list<value>&)>)car(params))(list<value>()); + const value table = ((lambda<value(const list<value>&)>)cadr(params))(list<value>()); + const perthread_ptr<pgsql::PGSql> pg(lambda<gc_ptr<pgsql::PGSql>()>(newPGSql(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/sca-cpp/branches/lightweight-sca/components/sqldb/standby-test b/sca-cpp/branches/lightweight-sca/components/sqldb/standby-test new file mode 100755 index 0000000000..3c91e477e4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/sqldb/standby-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 +rm -rf tmp +../../modules/http/httpd-conf tmp/master localhost 8090 tmp/master/htdocs +../../modules/http/httpd-event-conf tmp +./pgsql-conf tmp/master 5432 +./pgsql-start tmp/master +./pgsql localhost 6432 "drop table test;" 1>/dev/null 2>&1 +./pgsql localhost 6432 "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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/webservice/Makefile.am b/sca-cpp/branches/lightweight-sca/components/webservice/Makefile.am new file mode 100644 index 0000000000..242b97dce8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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${libsuffix} libwebservice-listener${libsuffix} libaxis2-dispatcher${libsuffix} libaxis2-service${libsuffix} + +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${libsuffix}: + ln -s .libs/libwebservice-client${libsuffix} + +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${libsuffix}: + ln -s .libs/libwebservice-listener${libsuffix} + +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${libsuffix}: + ln -s .libs/libaxis2-dispatcher${libsuffix} + +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${libsuffix}: + ln -s .libs/libaxis2-service${libsuffix} + +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/sca-cpp/branches/lightweight-sca/components/webservice/axiom-test.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/axiom-test.cpp new file mode 100644 index 0000000000..75ce2452fd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/axiom-test.cpp @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>"; + +const string echo("<ns1:echoString xmlns:ns1=\"http://ws.apache.org/axis2/services/echo\">\n" + " <text>Hello World!</text>\n" + "</ns1:echoString>"); + +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) == echo); + 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/sca-cpp/branches/lightweight-sca/components/webservice/axis2-conf b/sca-cpp/branches/lightweight-sca/components/webservice/axis2-conf new file mode 100755 index 0000000000..c302737ae9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +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/sca-cpp/branches/lightweight-sca/components/webservice/axis2-dispatcher.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/axis2-dispatcher.cpp new file mode 100644 index 0000000000..dafa6fd229 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/axis2-dispatcher.cpp @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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/sca-cpp/branches/lightweight-sca/components/webservice/axis2-service.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/axis2-service.cpp new file mode 100644 index 0000000000..4df0543370 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/axis2-service.cpp @@ -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. + */ + +/* $Rev$ $Date$ */ + +/** + * Axis2/C service implementation that dispatches requests to SCA Web service components. + */ + +#define WANT_HTTPD_LOG 1 +#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; + debug_httpdRequest(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/sca-cpp/branches/lightweight-sca/components/webservice/axis2-test.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/axis2-test.cpp new file mode 100644 index 0000000000..d7c2f3b671 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/axis2.hpp b/sca-cpp/branches/lightweight-sca/components/webservice/axis2.hpp new file mode 100644 index 0000000000..9bad109ff0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/axis2.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_webservice_hpp +#define tuscany_webservice_hpp + +/** + * Web service invocation functions using Axis2. + */ +#include "config.hpp" + +// Ignore redundant declarations in Axiom headers +#ifdef WANT_MAINTAINER_WARNINGS +#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_WARNINGS +#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) { + debug("webservice::axis2context"); + } + + Axis2Context(const Axis2Context& ax) : env(ax.env), owner(false) { + debug("webservice::axis2context::copy"); + } + + const Axis2Context& operator=(const Axis2Context& ax) { + debug("webservice::axis2context::operator="); + if(this == &ax) + return *this; + env = ax.env; + owner = false; + return *this; + } + + Axis2Context(const axutil_env_t* env) : env(const_cast<axutil_env_t*>(env)), owner(false) { + debug("webservice::axis2context::env"); + } + + ~Axis2Context() { + debug("webservice::~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*>(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> >(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>(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>(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/sca-cpp/branches/lightweight-sca/components/webservice/axis2.xml b/sca-cpp/branches/lightweight-sca/components/webservice/axis2.xml new file mode 100644 index 0000000000..ea9b6d2194 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/client-test.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/client-test.cpp new file mode 100644 index 0000000000..16dd659b22 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/echo-test b/sca-cpp/branches/lightweight-sca/components/webservice/echo-test new file mode 100755 index 0000000000..1056a6c668 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/webservice/module.xml b/sca-cpp/branches/lightweight-sca/components/webservice/module.xml new file mode 100644 index 0000000000..8f6ba5018f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/server-test b/sca-cpp/branches/lightweight-sca/components/webservice/server-test new file mode 100755 index 0000000000..cb12accbfb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/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 +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/http/httpd-event-conf tmp +../../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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/components/webservice/server-test.scm b/sca-cpp/branches/lightweight-sca/components/webservice/server-test.scm new file mode 100644 index 0000000000..44e4eee92a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/services.xml b/sca-cpp/branches/lightweight-sca/components/webservice/services.xml new file mode 100644 index 0000000000..0adf136f4f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/webservice-client.componentType b/sca-cpp/branches/lightweight-sca/components/webservice/webservice-client.componentType new file mode 100644 index 0000000000..043087fe98 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/webservice-client.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/webservice-client.cpp new file mode 100644 index 0000000000..76d4905bf8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/webservice-client.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$ */ + +/** + * Web service client component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#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/sca-cpp/branches/lightweight-sca/components/webservice/webservice-listener.componentType b/sca-cpp/branches/lightweight-sca/components/webservice/webservice-listener.componentType new file mode 100644 index 0000000000..ecd46b3c90 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/components/webservice/webservice-listener.cpp b/sca-cpp/branches/lightweight-sca/components/webservice/webservice-listener.cpp new file mode 100644 index 0000000000..29ebef4bcb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/webservice-listener.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$ */ + +/** + * Web service listener component implementation. + */ + +#define WANT_HTTPD_LOG 1 +#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), rcode(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)); + debug_httpdRequest(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 + return redirectToAxis2(string("/axis2") + r->uri + r->args != NULL? string("?") + r->args : string(""), 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/sca-cpp/branches/lightweight-sca/components/webservice/webservice.composite b/sca-cpp/branches/lightweight-sca/components/webservice/webservice.composite new file mode 100644 index 0000000000..7b7c76b632 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/components/webservice/webservice.composite @@ -0,0 +1,47 @@ +<?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" + 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"> + <binding.jsonrpc uri="echo-client"/> + </service> + </component> + + <component name="webservice-listener"> + <implementation.cpp path="." library="libwebservice-listener"/> + <service name="webservice-listener"> + <binding.http uri="echo-listener"/> + </service> + <reference name="relay" target="echo"/> + </component> + + <component name="echo"> + <implementation.scheme script="server-test.scm"/> + <service name="echo"> + <binding.jsonrpc uri="echo"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/configure.ac b/sca-cpp/branches/lightweight-sca/configure.ac new file mode 100644 index 0000000000..e3f3de7e61 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/configure.ac @@ -0,0 +1,1151 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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]) +if test "${CXX}" = ""; then + AC_MSG_CHECKING([for clang++]) + if test -x "/usr/bin/clang++"; then + # Use CLang++/LLVM if available + CXX=/usr/bin/clang++ + CC=/usr/bin/clang + AC_MSG_RESULT(/usr/bin/clang++) + AM_CONDITIONAL([WANT_LLVM], true) + AC_DEFINE([WANT_LLVM], 1, [compile with clang++/llvm]) + else + AM_CONDITIONAL([WANT_LLVM], false) + fi +else + AM_CONDITIONAL([WANT_LLVM], 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. +cxxname=`basename ${CXX}` +if test "${cxxname}" = "clang++"; then + cxxtype="clang" +else + cxxtype="gcc" +fi +#cxxflags="${CXXFLAGS}" +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) + libsuffix=".dylib" + AC_SUBST([libsuffix],[".dylib"]) + AM_CONDITIONAL([DARWIN], true) +else + AC_MSG_RESULT(no) + libsuffix=".so" + 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} -ggdb -g3 -Werror -Wall -Wextra -Wno-ignored-qualifiers -Wno-strict-aliasing -Winit-self -Wmissing-include-dirs -Wcast-qual -Wcast-align -Wwrite-strings -Wpointer-arith -Waddress -Wredundant-decls -std=c++0x -fmessage-length=0" + if test "${cxxtype}" = "clang"; then + cxxflags="${cxxflags} -O1 -stdlib=libc++" + else + cxxflags="${cxxflags} -O2 -Wlogical-op -Wconversion" + fi + AM_CONDITIONAL([WANT_MAINTAINER_MODE], true) + AC_DEFINE([WANT_MAINTAINER_MODE], 1, [compile with debugging and compile-time warnings]) +else + cxxflags="${cxxflags} -g -std=c++0x -fmessage-length=0" + if test "${cxxtype}" = "clang"; then + cxxflags="${cxxflags} -O1 -stdlib=libc++" + else + cxxflags="${cxxflags} -O2" + fi + 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 memory checking with electric fence. +AC_MSG_CHECKING([whether to enable electric fence]) +AC_ARG_ENABLE(efence, [AS_HELP_STRING([--enable-efence], [link with electric fence [default=no]])], +[ case "${enableval}" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + want_efence=true + ;; + esac ], +[ AC_MSG_RESULT(no)]) +if test "${want_efence}" = "true"; then + ldflags="${ldflags} -lefence" + AM_CONDITIONAL([WANT_EFENCE], true) + AC_DEFINE([WANT_EFENCE], 1, [link with electric fence]) +else + AM_CONDITIONAL([WANT_EFENCE], false) +fi + +# Enable usage of mmap for memory allocation. +AC_MSG_CHECKING([whether to use mmap for memory allocation]) +AC_ARG_ENABLE(malloc-mmap, [AS_HELP_STRING([--enable-malloc-mmap], [use mmap for memory allocation [default=no]])], +[ case "${enableval}" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + want_malloc_mmap=true + ;; + esac ], +[ AC_MSG_RESULT(no)]) +if test "${want_malloc_mmap}" = "true"; then + AM_CONDITIONAL([WANT_MALLOC_MMAP], true) + AC_DEFINE([WANT_MALLOC_MMAP], 1, [use mmap for memory allocation]) +else + AM_CONDITIONAL([WANT_MALLOC_MMAP], 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_DEFINE_UNQUOTED([CURL_PREFIX], "${CURL_PREFIX}", [path to installed curl]) +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]) +AC_ARG_WITH([js-include], [AC_HELP_STRING([--with-js-include=PATH], [path to installed SpiderMonkey include dir + [default=/usr/include]])], [ + JS_INCLUDE="${withval}" + AC_MSG_RESULT("${withval}") +], [ + JS_INCLUDE="/usr/include" + AC_MSG_RESULT(/usr/include) +]) +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]])], [ + JS_LIB="${withval}" + AC_MSG_RESULT("${withval}") +], [ + JS_LIB="/usr/lib" + AC_MSG_RESULT(/usr/lib) +]) +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-1" + APR_LIB="${withval}/lib" + AC_MSG_RESULT("${withval}") +], [ + APR_INCLUDE="/usr/include/apr-1" + 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 apr-util]) +AC_ARG_WITH([apr-util], [AC_HELP_STRING([--with-apr-util=PATH], [path to installed Apache APR util [default=/usr]])], [ + APRUTIL_INCLUDE="${withval}/include/apr-1" + APRUTIL_LIB="${withval}/lib" + AC_MSG_RESULT("${withval}") +], [ + APRUTIL_INCLUDE="/usr/include/apr-1" + APRUTIL_LIB="/usr/lib" + AC_MSG_RESULT(/usr) +]) +AC_SUBST(APRUTIL_INCLUDE) +AC_SUBST(APRUTIL_LIB) +LIBS="-L${APRUTIL_LIB} ${defaultlibs}" +AC_CHECK_LIB([aprutil-1], [apr_memcache_server_create], [], [AC_MSG_ERROR([couldn't find a suitable libaprutil-1, use --with-apr-util=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_DEFINE_UNQUOTED([HTTPD_PREFIX], "${HTTPD_PREFIX}", [path to installed Apache HTTPD]) +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_DEFINE_UNQUOTED([MEMCACHED_PREFIX], "${MEMCACHED_PREFIX}", [path to installed memcached]) +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_DEFINE_UNQUOTED([TINYCDB_PREFIX], "${TINYCDB_PREFIX}", [path to installed tinycdb]) +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${APRUTIL_INCLUDE} -I${HTTPD_INCLUDE} -I${LIBXML2_INCLUDE} -I${JS_INCLUDE} -I${LIBCURL_INCLUDE}" +ldflags="${ldflags} -ldl -L${APR_LIB} -R${APR_LIB} -lapr-1 -L${APRUTIL_LIB} -R${APRUTIL_LIB} -laprutil-1" +ldflags="${ldflags} -L${LIBCURL_LIB} -R${LIBCURL_LIB} -L${JS_LIB} -R${JS_LIB} -L${LIBXML2_LIB} -R${LIBXML2_LIB}" + +# Enable Python 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 includes and lib. + AC_MSG_CHECKING([for python]) + AC_ARG_WITH([python], [AC_HELP_STRING([--with-python=PATH], [path to installed Python [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_DEFINE_UNQUOTED([PYTHON_PREFIX], "${PYTHON_PREFIX}", [path to installed Python]) + AC_SUBST(PYTHON_INCLUDE) + AC_SUBST(PYTHON_LIB) + LIBS="-L${PYTHON_LIB} ${defaultlibs}" + if test -f "${PYTHON_LIB}/libpython2.7${libsuffix}"; then + PYTHON_VERSION="2.7" + AC_DEFINE([PYTHON_VERSION], 27, [Python version]) + else + PYTHON_VERSION="2.6" + AC_DEFINE([PYTHON_VERSION], 26, [Python version]) + fi + AC_SUBST(PYTHON_VERSION) + AC_CHECK_LIB([python${PYTHON_VERSION}], [Py_Initialize], [], [AC_MSG_ERROR([couldn't find a suitable libpython, use --with-python=PATH])]) + AM_CONDITIONAL([WANT_PYTHON], true) + AC_DEFINE([WANT_PYTHON], 1, [enable Python support]) + +else + AM_CONDITIONAL([WANT_PYTHON], false) +fi + +# Configure path to Page Speed. +AC_MSG_CHECKING([for pagespeed]) +AC_ARG_WITH([pagespeed], [AC_HELP_STRING([--with-pagespeed=PATH], [path to installed Page Speed [default=/usr/bin]])], [ + PAGESPEED_PREFIX="${withval}" + AC_MSG_RESULT("${withval}") +], [ + PAGESPEED_PREFIX="/usr/bin" + AC_MSG_RESULT(/usr/bin) +]) +AC_SUBST(PAGESPEED_PREFIX) + +# Enable Page Speed optimizations. +AC_MSG_CHECKING([whether to run Page Speed optimizations]) +AC_ARG_ENABLE(pagespeed, [AS_HELP_STRING([--enable-pagespeed], [run Page Speed optimizations [default=no]])], +[ case "${enableval}" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + want_pagespeed=true + ;; + esac ], +[ AC_MSG_RESULT(no)]) +if test "${want_pagespeed}" = "true"; then + AC_PATH_PROG(MINIFY_HTML, minify_html_bin, , ${PAGESPEED_PREFIX}) + if test "${MINIFY_HTML}" = ""; then + AC_MSG_ERROR([could not find Page Speed minify_html_bin]) + fi + AC_PATH_PROG(MINIFY_JS, jsmin_bin, , ${PAGESPEED_PREFIX}) + if test "${MINIFY_JS}" = ""; then + AC_MSG_ERROR([could not find Page Speed jsmin_bin]) + fi + AM_CONDITIONAL([WANT_PAGESPEED], true) + AC_DEFINE([WANT_PAGESPEED], 1, [run Page Speed optimizations]) + AC_DEFINE_UNQUOTED([PAGESPEED_PREFIX], "${PAGESPEED_PREFIX}", [path to installed Page Speed]) +else + AM_CONDITIONAL([WANT_PAGESPEED], false) +fi + +# Enable OpenCL support. +AC_MSG_CHECKING([whether to enable OpenCL support]) +AC_ARG_ENABLE(opencl, [AS_HELP_STRING([--enable-opencl], [enable OpenCL support [default=no]])], +[ case "${enableval}" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + want_opencl=true + ;; + esac ], +[ AC_MSG_RESULT(no)]) +if test "${want_opencl}" = "true"; then + + # Configure path to OpenCL includes and lib. + AC_MSG_CHECKING([for opencl]) + AC_ARG_WITH([opencl-include], [AC_HELP_STRING([--with-opencl-include=PATH], [path to installed OpenCL 1.1 include dir [default=/usr/include]])], [ + OPENCL_INCLUDE="${withval}" + AC_MSG_RESULT("${withval}") + ], [ + OPENCL_INCLUDE="/usr/include" + AC_MSG_RESULT(/usr/include) + ]) + AC_SUBST(OPENCL_INCLUDE) + AC_ARG_WITH([opencl-lib], [AC_HELP_STRING([--with-opencl-lib=PATH], [path to installed OpenCL 1.1 lib dir [default=/usr/lib]])], [ + OPENCL_LIB="${withval}" + AC_MSG_RESULT("${withval}") + ], [ + OPENCL_LIB="/usr/lib" + AC_MSG_RESULT(/usr/lib) + ]) + AC_SUBST(OPENCL_LIB) + if test "${UNAME}" != "Darwin"; then + LIBS="-L${OPENCL_LIB} ${defaultlibs}" + AC_CHECK_LIB([OpenCL], [clGetDeviceIDs], [], [AC_MSG_ERROR([couldn't find a suitable libOpenCL, use --with-opencl=PATH])]) + fi + AM_CONDITIONAL([WANT_OPENCL], true) + AC_DEFINE([WANT_OPENCL], 1, [enable OpenCL support]) + +else + AM_CONDITIONAL([WANT_OPENCL], 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_DEFINE_UNQUOTED([JAVA_PREFIX], "${JAVA_PREFIX}", [path to installed Java]) + 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/local]])], [ + MODAUTHOPENID_PREFIX="${withval}" + AC_MSG_RESULT("${withval}") + ], [ + MODAUTHOPENID_PREFIX="/usr/local/" + AC_MSG_RESULT(/usr/local) + ]) + AC_SUBST(MODAUTHOPENID_PREFIX) + AC_DEFINE_UNQUOTED([MODAUTHOPENID_PREFIX], "${MODAUTHOPENID_PREFIX}", [path to installed mod-auth-openid]) + + 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 modsecurity. +AC_MSG_CHECKING([whether to enable mod-security support]) +AC_ARG_ENABLE(mod-security, [AS_HELP_STRING([--enable-mod-security], [enable mod-security support [default=no]])], +[ case "${enableval}" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + want_modsecurity=true + ;; + esac ], +[ AC_MSG_RESULT(no)]) +if test "${want_modsecurity}" = "true"; then + + # Configure path to mod-security + AC_MSG_CHECKING([for mod-security]) + AC_ARG_WITH([mod-security], [AC_HELP_STRING([--with-mod-security=PATH], [path to installed mod-security [default=/usr/local]])], [ + MODSECURITY_PREFIX="${withval}" + AC_MSG_RESULT("${withval}") + ], [ + MODSECURITY_PREFIX="/usr/local/" + AC_MSG_RESULT(/usr/local) + ]) + AC_SUBST(MODSECURITY_PREFIX) + AC_DEFINE_UNQUOTED([MODSECURITY_PREFIX], "${MODSECURITY_PREFIX}", [path to installed mod-security]) + + AM_CONDITIONAL([WANT_MODSECURITY], true) + AC_DEFINE([WANT_MODSECURITY], 1, [enable mod-security support]) + +else + AM_CONDITIONAL([WANT_MODSECURITY], 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/python${PYTHON_VERSION}/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_DEFINE_UNQUOTED([AXIS2C_PREFIX], "${AXIS2C_PREFIX}", [path to installed Axis2C]) + 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_DEFINE_UNQUOTED([PGSQL_PREFIX], "${PGSQL_PREFIX}", [path to installed PostgreSQL]) + AC_SUBST(PGSQL_INCLUDE) + AC_SUBST(PGSQL_LIB) + + # Configure path to PgBouncer. + AC_MSG_CHECKING([for pgbouncer]) + AC_ARG_WITH([pgbouncer], [AC_HELP_STRING([--with-pgbouncer=PATH], [path to installed PgBouncer [default=/usr/local]])], [ + PGBOUNCER_PREFIX="${withval}" + AC_MSG_RESULT("${withval}") + ], [ + PGBOUNCER_PREFIX="/usr/local" + AC_MSG_RESULT(/usr/local) + ]) + AC_SUBST(PGBOUNCER_PREFIX) + AC_DEFINE_UNQUOTED([PGBOUNCER_PREFIX], "${PGBOUNCER_PREFIX}", [path to installed PgBouncer]) + + 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_DEFINE_UNQUOTED([QPIDC_PREFIX], "${QPIDC_PREFIX}", [path to installed Qpid/C++]) + 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_DEFINE_UNQUOTED([THRIFT_PREFIX], "${THRIFT_PREFIX}", [path to installed Apache Thrift]) + 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_DEFINE_UNQUOTED([SCRIBE_PREFIX], "${SCRIBE_PREFIX}", [path to installed Facebook Scribe]) + 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/opencl/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/constdb/Makefile + components/filedb/Makefile + components/http/Makefile + components/smtp/Makefile + components/queue/Makefile + components/sqldb/Makefile + components/webservice/Makefile + hosting/Makefile + hosting/server/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-constdb/Makefile + samples/store-vhost/Makefile + samples/store-cluster/Makefile + samples/relay-python/Makefile + samples/relay-gae/Makefile + doc/Makefile + doc/Doxyfile + macos/Makefile + ubuntu/Makefile + ]) +AC_OUTPUT + diff --git a/sca-cpp/branches/lightweight-sca/doc/Doxyfile.in b/sca-cpp/branches/lightweight-sca/doc/Doxyfile.in new file mode 100644 index 0000000000..ba02d58a2a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/doc/Makefile.am b/sca-cpp/branches/lightweight-sca/doc/Makefile.am new file mode 100644 index 0000000000..c5f29b0d6b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/etc/Makefile.am b/sca-cpp/branches/lightweight-sca/etc/Makefile.am new file mode 100644 index 0000000000..c34e48d351 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = svn-config svn-ignore + +dist_noinst_SCRIPTS = httpd-ipcrm memgrind + diff --git a/sca-cpp/branches/lightweight-sca/etc/httpd-ipcrm b/sca-cpp/branches/lightweight-sca/etc/httpd-ipcrm new file mode 100755 index 0000000000..860b724296 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/etc/httpd-ipcrm @@ -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. + +# Remove ipcs created by httpd + +id=`id -un` +ipcs -s | grep "$id" | grep "0x" | awk '{ print $2 }' | xargs -i -t ipcrm -s {} + diff --git a/sca-cpp/branches/lightweight-sca/etc/memgrind b/sca-cpp/branches/lightweight-sca/etc/memgrind new file mode 100755 index 0000000000..312058cc85 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/etc/memgrind @@ -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. + +# Run valgrind to analyze memory usage and track memory leaks +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=50 --track-fds=yes --trace-children=yes --suppressions=$here/../../Python-2.6.6/Misc/valgrind-python.supp --suppressions=$here/valgrind-apr.supp $* 2>&1 | tee memgrind.log + diff --git a/sca-cpp/branches/lightweight-sca/etc/svn-config b/sca-cpp/branches/lightweight-sca/etc/svn-config new file mode 100644 index 0000000000..4f8cb41685 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/etc/svn-ignore b/sca-cpp/branches/lightweight-sca/etc/svn-ignore new file mode 100644 index 0000000000..e93f10efc4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/etc/valgrind-apr.supp b/sca-cpp/branches/lightweight-sca/etc/valgrind-apr.supp new file mode 100644 index 0000000000..9a58600ee7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/etc/valgrind-apr.supp @@ -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. + +# This is a valgrind suppression file. + +{ + Suppress APR pool cleanup registrations. + Memcheck:Leak + fun:malloc + fun:apr_palloc + fun:apr_pool_cleanup_register +} + diff --git a/sca-cpp/branches/lightweight-sca/hosting/Makefile.am b/sca-cpp/branches/lightweight-sca/hosting/Makefile.am new file mode 100644 index 0000000000..36d24d4ffa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/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 = server + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/Makefile.am b/sca-cpp/branches/lightweight-sca/hosting/server/Makefile.am new file mode 100644 index 0000000000..d6e15f819b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/Makefile.am @@ -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. + +if WANT_PYTHON + +moddir = $(prefix)/hosting/server +dist_mod_SCRIPTS = start stop ssl-start mkapplinks config-backup data-backup put-auth get-auth delete-auth + +not_minified = htdocs/public/iframe.html htdocs/create/index.html htdocs/page/index.html htdocs/login/index.html htdocs/public/notfound/index.html htdocs/public/oops/index.html htdocs/proxy/public/oops/index.html htdocs/graph/index.html htdocs/public/notauth/index.html htdocs/account/index.html htdocs/home/index.html htdocs/index.html htdocs/public/notyet/index.html htdocs/clone/index.html htdocs/delete/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/store/index.html htdocs/config.js htdocs/public/config.js htdocs/cache-template.cmf htdocs/app/cache-template.cmf htdocs/cache-template.cmf htdocs/app/cache-template.cmf + +minified = htdocs/public/iframe-min.html htdocs/create/index-min.html htdocs/page/index-min.html htdocs/login/index-min.html htdocs/public/notfound/index-min.html htdocs/public/oops/index-min.html htdocs/proxy/public/oops/index-min.html htdocs/graph/index-min.html htdocs/public/notauth/index-min.html htdocs/account/index-min.html htdocs/home/index-min.html htdocs/index-min.html htdocs/public/notyet/index-min.html htdocs/clone/index-min.html htdocs/delete/index-min.html htdocs/stats/index-min.html htdocs/app/index-min.html htdocs/store/index-min.html htdocs/config-min.js htdocs/public/config-min.js + +js_minified = ../../modules/js/htdocs/all-min.js ../../modules/js/htdocs/ui-min.css + +resources = server.composite *.py data/palettes/*/palette.composite data/accounts/*/*.account data/apps/*/app.composite data/apps/*/app.stats data/apps/*/htdocs/app.html data/dashboards/*/user.apps data/store/*/store.apps htdocs/cache-manifest.cmf htdocs/app/cache-manifest.cmf htdocs/*.ico htdocs/home/*.png htdocs/home/*.b64 htdocs/*.txt htdocs/public/*.png htdocs/public/*.b64 ${minified} + +nobase_dist_mod_DATA = ${resources} +EXTRA_DIST = ${resources} ${not_minified} + +SUFFIXES = -min.html -min.js +.html-min.html: + ../../modules/http/minify-html $< $@ + +.js-min.js: + ../../modules/http/minify-js $< $@ + +htdocs/cache-manifest.cmf: htdocs/cache-template.cmf ${minified} ${js_minified} + ../../modules/http/cache-manifest htdocs $^ + +htdocs/app/cache-manifest.cmf: htdocs/app/cache-template.cmf ${minified} ${js_minified} + ../../modules/http/cache-manifest htdocs/app $^ + +nuvem: + ln -s "../../../nuvem/nuvem-parallel/nuvem" "nuvem" + +lib: + ln -s "../../components" "lib" + +install-data-hook: + cd $(moddir); rm -f nuvem; ln -s "../../../nuvem/nuvem-parallel/nuvem" "nuvem" + cd $(moddir); rm -f lib; ln -s "../../components" "lib" + +CLEANFILES = ${minified} nuvem lib htdocs/cache-manifest.cmf htdocs/app/cache-manifest.cmf + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +dist_noinst_SCRIPTS = logic-test server-test test.py +noinst_PROGRAMS = client-test +TESTS = logic-test + +endif diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/accounts.py b/sca-cpp/branches/lightweight-sca/hosting/server/accounts.py new file mode 100644 index 0000000000..3587f5fb65 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/accounts.py @@ -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. + +# Accounts collection implementation +from time import strftime +from util import * + +# Convert a particular user id to an account id +def accountid(user): + return ('accounts', user.get(()), 'user.account') + +# Get the current user's account +def get(id, user, cache): + account = cache.get(accountid(user)) + if isNil(account) or account is None: + return (("'entry", ("'title", user.get(())), ("'id", user.get(())), ("'updated", strftime('%b %d, %Y'))),) + return account + +# Update the user's account +def put(id, account, user, cache): + return cache.put(accountid(user), account) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/apps.py b/sca-cpp/branches/lightweight-sca/hosting/server/apps.py new file mode 100644 index 0000000000..064701a7df --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/apps.py @@ -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. + +# App collection implementation +from time import strftime +from util import * +from sys import debug + +# Convert an id to an app id +def appid(id): + return ("apps", car(id), "app.stats") + +# Put an app into the apps db +def put(id, app, user, cache, dashboard, store, composites, pages): + debug('apps.py::put::id', id) + debug('apps.py::put::app', app) + + # Update an app + eid = cadr(assoc("'id", car(app))) + if car(id) == eid: + # Check app author + eapp = cache.get(appid(id)); + if (not (isNil(eapp) or eapp is None)) and (cadr(assoc("'author", car(eapp))) != user.get(())): + debug('apps.py::put', 'different author', cadr(assoc("'author", car(eapp)))) + return False + + # Update the app in the apps db + appentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y')), assoc("'content", car(app))),) + debug('apps.py::put::appentry', appentry) + cache.put(appid(id), appentry) + dashboard.put(id, appentry) + + # Create new page and composite if necessary + if isNil(eapp) or eapp is None: + comp = (("'entry", ("'title", car(id)), ("'id", car(id))),) + composites.put(id, comp); + page = (("'entry", ("'title", car(id)), ("'id", car(id))),) + pages.put(id, comp); + return True + return True + + # Check app author + eapp = cache.get(appid(id)); + if (not (isNil(eapp) or eapp is None)) and (cadr(assoc("'author", car(eapp))) != user.get(())): + debug('apps.py::put', 'different author', cadr(assoc("'author", car(eapp)))) + return False + + # Clone an app + appentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y')), assoc("'content", car(app))),) + debug('apps.py::put::appentry', appentry) + cache.put(appid(id), appentry) + composites.put(id, composites.get((eid,))) + pages.put(id, pages.get((eid,))) + dashboard.put(id, appentry) + return True + +# Get an app from the apps db +def get(id, user, cache, dashboard, store, composites, pages): + debug('apps.py::get::id', id) + if isNil(id): + return (("'feed", ("'title", "Apps"), ("'id", "apps")),) + + # Get the requested app + app = cache.get(appid(id)); + if isNil(app) or app is None: + debug('apps.py::get', 'app not found', id) + + # Return a default new app + return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y')), ("'content", ("'stats", ("'description", '')))),) + + # Return the app + debug('apps.py::get::app', app) + return app + +# Delete an app from the apps db +def delete(id, user, cache, dashboard, store, composites, pages): + debug('apps.py::delete::id', id) + + # Get the requested app + app = cache.get(appid(id)); + if isNil(app) or app is None: + debug('apps.py::delete', 'app not found', id) + return False + + # Check app author + author = cadr(assoc("'author", car(app))) + if author != user.get(()): + debug('apps.py::delete', 'different author', author) + return False + + # Delete the app, its composite and page + dashboard.delete(id) + composites.delete(id) + pages.delete(id) + cache.delete(appid(id)) + return True + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/authn.py b/sca-cpp/branches/lightweight-sca/hosting/server/authn.py new file mode 100644 index 0000000000..4d4f34b9fb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/authn.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. + +# User authenticator implementation +from time import strftime +from util import * + +# Convert a particular user id to an authentication id +def authnid(id): + return append(append(('authn',), id), ('user.authn',)) + +# Get a user's authentication +def get(id, cache): + authn = cache.get(authnid(id)) + if isNil(authn) or authn is None: + return None + return authn + +# Update a user's authentication +def put(id, authn, cache): + return cache.put(authnid(id), authn) + +# Delete a user's authentication +def delete(id, cache): + return cache.delete(authnid(id)) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/client-test.cpp b/sca-cpp/branches/lightweight-sca/hosting/server/client-test.cpp new file mode 100644 index 0000000000..c0a01b5237 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/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(const int argc, const char** argv) { + tuscany::cout << "Testing..." << tuscany::endl; + tuscany::server::testURI = argc > 1? argv[1] : "https://jane:jane@www.example.com:8453"; + + tuscany::server::testServer(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/client-test.hpp b/sca-cpp/branches/lightweight-sca/hosting/server/client-test.hpp new file mode 100644 index 0000000000..7d85fc99a6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/client-test.hpp @@ -0,0 +1,436 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 "../../modules/http/http.hpp" + +namespace tuscany { +namespace server { + +string testURI = "http://localhost:8090"; +bool testBlobs = true; + +ostream* curlWriter(const string& s, ostream* os) { + (*os) << s; + return os; +} + +const bool testGetDoc() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + { + ostringstream os; + const failable<list<ostream*> > r = http::get<ostream*>(curlWriter, &os, testURI + "/", ch); + assert(hasContent(r)); + assert(contains(str(os), "HTTP/1.1 200") || contains(str(os), "HTTP/1.0 200")); + assert(contains(str(os), "<base href=\"/\"/>")); + } + { + const failable<value> r = http::getcontent(testURI + "/", ch); + assert(hasContent(r)); + assert(contains(car(list<value>(content(r))), "<base href=\"/\"/>")); + } + return true; +} + +struct getDocLoop { + http::CURLSession& ch; + getDocLoop(http::CURLSession& ch) : ch(ch) { + } + const bool operator()() const { + const failable<value> r = http::getcontent(testURI + "/", ch); + assert(hasContent(r)); + assert(contains(car(list<value>(content(r))), "<base href=\"/\"/>")); + return true; + } +}; + +const bool testGetDocPerf() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + const lambda<bool()> gl = getDocLoop(ch); + cout << "GET doc test " << time(gl, 10, 50) << " ms" << endl; + return true; +} + +struct getCompositeLoop { + http::CURLSession& ch; + getCompositeLoop(http::CURLSession& ch) : ch(ch) { + } + const bool operator()() const { + const failable<value> r = http::getcontent(testURI + "/r/Editor/composites/test", ch); + assert(hasContent(r)); + return true; + } +}; + +const bool testGetCompositePerf() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + const lambda<bool()> gl = getCompositeLoop(ch); + cout << "GET composite test " << time(gl, 10, 50) << " ms" << endl; + return true; +} + +struct getPageLoop { + http::CURLSession& ch; + getPageLoop(http::CURLSession& ch) : ch(ch) { + } + const bool operator()() const { + const failable<value> r = http::getcontent(testURI + "/r/Editor/pages/test", ch); + assert(hasContent(r)); + return true; + } +}; + +const bool testGetPagePerf() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + const lambda<bool()> gl = getPageLoop(ch); + cout << "GET page test " << time(gl, 10, 50) << " ms" << endl; + return true; +} + +struct getAppLoop { + http::CURLSession& ch; + getAppLoop(http::CURLSession& ch) : ch(ch) { + } + const bool operator()() const { + const failable<value> r = http::getcontent(testURI + "/r/Editor/apps/test", ch); + assert(hasContent(r)); + return true; + } +}; + +const bool testGetAppPerf() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + const lambda<bool()> gl = getAppLoop(ch); + cout << "GET app test " << time(gl, 10, 50) << " ms" << endl; + return true; +} + +const bool testEval() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + const failable<value> r = http::evalExpr(mklist<value>(string("echo"), string("Hello")), testURI, ch); + assert(hasContent(r)); + assert(content(r) == 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 failable<value> r = http::evalExpr(mklist<value>(string("echo"), string("Hello")), uri, ch); + assert(hasContent(r)); + assert(content(r) == 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 failable<value> r = content(http::evalExpr(mklist<value>(string("echo"), blobs), uri, ch)); + assert(hasContent(r)); + assert(content(r) == blobs); + return true; + } +}; + +const bool testEvalPerf() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + http::CURLSession ch("", "", "", "", 0); + 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("", "", "", "", 0); + { + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "blob1" + blob) + + (list<value>() + "blob2" + blob) + + (list<value>() + "price" + string("$2.99"))); + const list<value> val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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("", "", "", "", 0); + 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; + worker& w; + const int threads; + postThreadLoop(const lambda<bool()>& l, worker& w, const int threads) : l(l), w(w), threads(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; + worker w(threads); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const value val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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, w, 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("", "", "", "", 0); + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const value val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + http::CURLSession ch("", "", "", "", 0); + 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("", "", "", "", 0); + value rc = content(http::del(testURI + "/111", ch)); + assert(rc == value(true)); + return true; +} + +const bool testServer() { + tuscany::server::testGetDoc(); +#ifdef FOO + tuscany::server::testPost(); + tuscany::server::testPut(); + tuscany::server::testDel(); + tuscany::server::testEval(); +#endif + tuscany::server::testGetDocPerf(); + tuscany::server::testGetCompositePerf(); + tuscany::server::testGetPagePerf(); + tuscany::server::testGetAppPerf(); +#ifdef FOO + tuscany::server::testPostPerf(); +#ifdef WANT_THREADS + tuscany::server::testPostThreadPerf(); +#else + tuscany::server::testPostForkPerf(); +#endif + tuscany::server::testEvalPerf(); +#endif + return true; +} + +} +} diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/composites.py b/sca-cpp/branches/lightweight-sca/hosting/server/composites.py new file mode 100644 index 0000000000..970bc98a5c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/composites.py @@ -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. + +# App composites collection implementation +from time import strftime +from util import * +from sys import debug + +# Convert an id to a composite id +def compid(id): + return ("apps", car(id), "app.composite") + +# Put a composite into the composite db +def put(id, comp, user, cache, apps): + debug('composites.py::put::id', id) + debug('composites.py::put::comp', comp) + + # Get the requested app + app = apps.get(id); + if isNil(app) or app is None: + debug('composites.py::put', 'app not found', id) + return False + + # Check app author + author = cadr(assoc("'author", car(app))) + if author != user.get(()): + debug('composites.py::put', 'different author', author) + return False + + # Update the composite in the composite db + compentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y')), assoc("'content", car(comp))),) + debug('composites.py::put::compentry', compentry) + return cache.put(compid(id), compentry) + +# Get a composite from the composite db +def get(id, user, cache, apps): + debug('composites.py::get::id', id) + if isNil(id): + return (("'feed", ("'title", "Composites"), ("'id", "composites")),) + + # Get the requested app + app = apps.get(id) + if isNil(app) or app is None: + debug('composites.py::get', 'app not found', id) + + # Return a default new composite + return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y'))),) + + # Get the requested composite + comp = cache.get(compid(id)); + if isNil(comp) or comp is None: + debug('composites.py::get', 'composite not found', id) + + # Return a default new composite + return (("'entry", ("'title", car(id)), ("'id", car(id)), assoc("'author", car(app)), assoc("'updated", car(app))),) + + # Return the composite + def updated(u): + return assoc("'updated", car(app)) if isNil(u) or u is None else u + + compentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), assoc("'author", car(app)), updated(assoc("'updated", car(comp))), assoc("'content", car(comp))),) + debug('composites.py::get::compentry', compentry) + return compentry + +# Delete a composite from the composite db +def delete(id, user, cache, apps): + debug('composites.py::delete::id', id) + + # Get the requested app + app = apps.get(id); + if isNil(app) or app is None: + debug('composites.py::delete', 'app not found', id) + return False + + # Check app author + author = cadr(assoc("'author", car(app))) + if author != user.get(()): + debug('composites.py::delete', 'different author', author) + return False + + # Delete the composite + return cache.delete(compid(id)) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/config-backup b/sca-cpp/branches/lightweight-sca/hosting/server/config-backup new file mode 100755 index 0000000000..5e09008fb0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/config-backup @@ -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. + +cd ../../ +tar czf ../config-backup.tar.gz hosting/server/*start hosting/server/*stop hosting/server/htdocs/*.js hosting/server/htdocs/public/*.js hosting/server/htdocs/home/*.b64 hosting/server/htdocs/home/*.png + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/dashboards.py b/sca-cpp/branches/lightweight-sca/hosting/server/dashboards.py new file mode 100644 index 0000000000..d6281d0454 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/dashboards.py @@ -0,0 +1,105 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Dashboards collection implementation +from util import * +from sys import debug + +# Convert a particular user id to a dashboard id +def dashboardid(user): + return ("dashboards", user.get(()), "user.apps") + +# Get a dashboard from the cache +def getdashboard(id, cache): + debug('dashboards.py::getdashboard::id', id) + val = cache.get(id) + if isNil(val) or val is None: + return () + dashboard = cdddr(car(val)) + if not isNil(dashboard) and isList(car(cadr(car(dashboard)))): + # Expand list of entries + edashboard = tuple(map(lambda e: cons("'entry", e), cadr(car(dashboard)))) + debug('dashboards.py::getdashboard::edashboard', edashboard) + return edashboard + + debug('dashboards.py::getdashboard::dashboard', dashboard) + return dashboard + +# Put a dashboard into the cache +def putdashboard(id, dashboard, cache): + debug('dashboards.py::putdashboard::id', id) + debug('dashboards.py::putdashboard::dashboard', dashboard) + val = ((("'feed", ("'title", "Your Apps"), ("'id", cadr(id))) + dashboard),) + return cache.put(id, val) + +# Put an app into the user's dashboard +def put(id, app, user, cache, apps): + debug('dashboards.py::put::id', id) + debug('dashboards.py::put::app', app) + + def putapp(id, app, dashboard): + if isNil(dashboard): + return app + if car(id) == cadr(assoc("'id", car(dashboard))): + return cons(car(app), cdr(dashboard)) + return cons(car(dashboard), putapp(id, app, cdr(dashboard))) + + appentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), ("'author", user.get(())), assoc("'updated", car(app)), assoc("'content", car(app))),) + debug('dashboards.py::put::appentry', appentry) + + dashboard = putapp(id, appentry, getdashboard(dashboardid(user), cache)) + return putdashboard(dashboardid(user), dashboard, cache) + +# Get apps from the user's dashboard +def get(id, user, cache, apps): + debug('dashboards.py::get::id', id) + + def findapp(id, dashboard): + if isNil(dashboard): + return None + if car(id) == cadr(assoc("'id", car(dashboard))): + return (car(dashboard),) + return findapp(id, cdr(dashboard)) + + if isNil(id): + dashboard = ((("'feed", ("'title", "Your Apps"), ("'id", user.get(()))) + getdashboard(dashboardid(user), cache)),) + debug('dashboards.py::get::dashboard', dashboard) + return dashboard + + app = findapp(id, getdashboard(dashboardid(user), cache)) + debug('dashboards.py::get::app', app) + return app + +# Delete apps from the user's dashboard +def delete(id, user, cache, apps): + debug('dashboards.py::delete::id', id) + if isNil(id): + return cache.delete(dashboardid(user)) + + def deleteapp(id, dashboard): + if isNil(dashboard): + return () + if car(id) == cadr(assoc("'id", car(dashboard))): + return cdr(dashboard) + return cons(car(dashboard), deleteapp(id, cdr(dashboard))) + + dashboard = getdashboard(dashboardid(user), cache) + deleted = deleteapp(id, dashboard) + if deleted == dashboard: + return False + return putdashboard(dashboardid(user), deleted, cache) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data-backup b/sca-cpp/branches/lightweight-sca/hosting/server/data-backup new file mode 100755 index 0000000000..f66e947f84 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data-backup @@ -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. + +cd ../../ +tar czf ../data-backup.tar.gz hosting/server/data + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/admin/user.account b/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/admin/user.account new file mode 100644 index 0000000000..4f4a754a92 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/admin/user.account @@ -0,0 +1 @@ +((entry (title "Admin") (id "admin"))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/jane/user.account b/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/jane/user.account new file mode 100644 index 0000000000..a3cf7e2c3d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/jane/user.account @@ -0,0 +1 @@ +((entry (title "Jane Doe") (id "jane") (content (account (description "This is Jane") (keys (key (((@name "key1") (@value "value1")) ((@name "key2") (@value "value2")) ((@name "key3") (@value "value3")) ((@name "") (@value "")) ((@name "") (@value ""))))))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/john/user.account b/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/john/user.account new file mode 100644 index 0000000000..9989daa228 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/accounts/john/user.account @@ -0,0 +1 @@ +((entry (title "John Doe") (id "john") (content (account (description "This is John") (keys (key (((@name "key1") (@value "value1")) ((@name "key2") (@value "value2")) ((@name "key3") (@value "value3")) ((@name "key4") (@value "value4")) ((@name "key5") (@value "value5"))))))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/app.composite new file mode 100644 index 0000000000..95c5f78f7e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/app.composite @@ -0,0 +1,100 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">me360</title> + <id>me360</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="start" promote="start"/> + <component name="bzprofile" title="buzz profile" color="blue1"> + <implementation.python script="nuvem/bzprofile.py"/> + <service name="bzprofile"/> + <reference target="text4" name="id"/> + <reference name="bz" visible="false"> + <binding.http uri="https://www.googleapis.com/buzz/v1/people"/> + </reference> + </component> + <component x="130" y="30" name="fbprofile" title="facebook profile" color="blue1"> + <implementation.python script="nuvem/fbprofile.py"/> + <service name="fbprofile"/> + <reference target="text" name="id"/> + <reference name="fb" visible="false"> + <binding.http uri="https://graph.facebook.com"/> + </reference> + </component> + <component x="90" y="170" name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="fbprofile" name="value"/> + <property>fbprofile</property> + </component> + <component x="90" y="190" name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="twprofile" name="value"/> + <property>twitprofile</property> + </component> + <component x="90" y="210" name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="bzprofile" name="value"/> + <property>buzzprofile</property> + </component> + <component x="60" y="30" name="list31" title="list" color="yellow1"> + <implementation.python script="nuvem/triple.py"/> + <service name="list3"/> + <reference target="item" name="first"/> + <reference target="item2" name="second"/> + <reference target="item3" name="third"/> + </component> + <component x="10" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list31" name="content"/> + </component> + <component x="220" y="170" name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component x="220" y="200" name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component x="220" y="230" name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component name="twprofile" title="twitter profile" color="blue1"> + <implementation.python script="nuvem/twprofile.py"/> + <service name="twprofile"/> + <reference target="text2" name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/users/show.json"/> + </reference> + </component> + </composite> + </content> + <link href="me360"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/app.stats new file mode 100644 index 0000000000..31695e59d7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/app.stats @@ -0,0 +1 @@ +((entry (title "Check my public social data") (id "me360") (author "admin@example.com") (updated "Apr 28, 2012") (content (stats (description "Sample app")))))
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/htdocs/app.html new file mode 100644 index 0000000000..4ba163b6c9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/me360/htdocs/app.html @@ -0,0 +1,82 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">me360</title> + <id>me360</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Me360</H2> + </SPAN> + <SPAN id="page:section" class="section" style="position: absolute; top: 27px; width: 100%; left: 2px; "> + <SPAN>Facebook</SPAN> + </SPAN> + <SPAN id="fbprofile" class="table" style="position: absolute; top: 63px; width: 100%; left: 2px; "> + <TABLE class="datatable" style="width: 100%;"> + <TBODY> + <TR> + <TD>=fbprofile</TD> + <TD>...</TD> + </TR> + <TR> + <TD>...</TD> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + <SPAN id="page:section" class="section" style="position: absolute; top: 288px; width: 100%; left: 2px; "> + <SPAN>Twitter</SPAN> + </SPAN> + <SPAN id="twitprofile" class="table" style="position: absolute; top: 324px; width: 100%; left: 2px; "> + <TABLE class="datatable" style="width: 100%;"> + <TBODY> + <TR> + <TD>=twitprofile</TD> + <TD>...</TD> + </TR> + <TR> + <TD>...</TD> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + <SPAN id="page:section" class="section" style="position: absolute; top: 1368px; width: 100%; left: 2px; "> + <SPAN>Buzz</SPAN> + </SPAN> + <SPAN id="buzzprofile" class="table" style="position: absolute; top: 1404px; width: 100%; left: 2px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=buzzprofile</TD> + <TD>...</TD> + </TR> + <TR> + <TD>...</TD> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + </DIV> + </content> + <link href="me360"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/app.composite new file mode 100644 index 0000000000..0d25e1b533 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/app.composite @@ -0,0 +1,451 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">nearme</title> + <id>nearme</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="getlocs" promote="getlocs"/> + <service name="location" promote="location"/> + <service name="map" promote="map"/> + <service name="nearme" promote="nearme"/> + <service name="start2" promote="start2"/> + <service name="timer" promote="timer"/> + <component name="append" title="+" color="yellow1"> + <implementation.python script="nuvem/append.py"/> + <service name="append"/> + <reference target="params" name="first"/> + <reference target="call2" name="second"/> + </component> + <component x="130" y="530" name="call" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call2" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name2" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call3" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name4" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call4" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name3" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="filedb" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="210" y="120" name="filedb1" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component name="filedb10" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component name="filedb11" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component xmlns="" name="filedb4" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component xmlns="" name="filedb5" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component xmlns="" name="filedb6" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component xmlns="" name="filedb8" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component xmlns="" name="filedb9" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="AppDataFileCache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="190" y="120" name="get1" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb1" name="collection"/> + <reference target="user4" name="id"/> + </component> + <component name="get10" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb11" name="collection"/> + <reference target="param5" name="id"/> + </component> + <component xmlns="" name="get3" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb4" name="collection"/> + <reference target="param3" name="id"/> + </component> + <component xmlns="" name="get4" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb5" name="collection"/> + <reference target="param4" name="id"/> + </component> + <component xmlns="" name="get5" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb6" name="collection"/> + <reference target="param2" name="id"/> + </component> + <component xmlns="" name="get7" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb8" name="collection"/> + <reference target="param7" name="id"/> + </component> + <component xmlns="" name="get8" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb9" name="collection"/> + <reference target="param6" name="id"/> + </component> + <component name="get9" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb10" name="collection"/> + <reference target="user5" name="id"/> + </component> + <component x="310" y="270" name="getlocs" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list4" name="content"/> + </component> + <component x="80" y="610" name="gmap1" title="map" color="blue1"> + <implementation.python script="nuvem/gmap.py"/> + <service name="gmap"/> + <reference target="call" name="locations"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.google.com/maps/api/staticmap"/> + </reference> + </component> + <component x="110" y="90" name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="user3" name="value"/> + <property>me</property> + </component> + <component x="110" y="390" name="item10" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="url" name="value"/> + <property>mapimg</property> + </component> + <component x="660" y="350" name="item11" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="get9" name="value"/> + <property>x</property> + </component> + <component x="660" y="400" name="item12" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="get10" name="value"/> + <property>1</property> + </component> + <component x="660" y="460" name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="get3" name="value"/> + <property>2</property> + </component> + <component x="660" y="530" name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="get4" name="value"/> + <property>3</property> + </component> + <component x="110" y="330" name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="last4" name="value"/> + <property>time3</property> + </component> + <component x="110" y="260" name="item7" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="last3" name="value"/> + <property>time2</property> + </component> + <component x="100" y="200" name="item8" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="last2" name="value"/> + <property>time1</property> + </component> + <component x="100" y="120" name="item9" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="last" name="value"/> + <property>mytime</property> + </component> + <component name="last" title="last" color="yellow1"> + <implementation.python script="nuvem/last.py"/> + <service name="last"/> + <reference target="get1" name="list"/> + </component> + <component name="last2" title="last" color="yellow1"> + <implementation.python script="nuvem/last.py"/> + <service name="last"/> + <reference target="get5" name="list"/> + </component> + <component x="160" y="220" name="last3" title="last" color="yellow1"> + <implementation.python script="nuvem/last.py"/> + <service name="last"/> + <reference target="get8" name="list"/> + </component> + <component name="last4" title="last" color="yellow1"> + <implementation.python script="nuvem/last.py"/> + <service name="last"/> + <reference target="get7" name="list"/> + </component> + <component name="list1" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item" name="item" clonable="true"/> + <reference target="item9" name="item" clonable="true"/> + <reference target="item8" name="item" clonable="true"/> + <reference target="item7" name="item" clonable="true"/> + <reference target="item6" name="item" clonable="true"/> + <reference target="item10" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text7" name="item" clonable="true"/> + <reference target="param10" name="item" clonable="true"/> + <reference target="param" name="item" clonable="true"/> + <reference target="now" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list4" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item11" name="item" clonable="true"/> + <reference target="item12" name="item" clonable="true"/> + <reference target="item4" name="item" clonable="true"/> + <reference target="item5" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="310" y="80" name="location" title="location" color="green1"> + <implementation.python script="nuvem/location.py"/> + <service name="location" visible="false"> + <binding.http uri="location"/> + </service> + <reference target="put" name="content"/> + </component> + <component x="10" y="460" name="map" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="gmap1" name="content"/> + </component> + <component name="name" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>getlocs</property> + </component> + <component name="name2" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>getlocs</property> + </component> + <component name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>nearme</property> + </component> + <component name="name4" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>nearme</property> + </component> + <component x="10" y="60" name="nearme" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list1" name="content"/> + </component> + <component x="500" y="250" name="now" title="now" color="orange1"> + <implementation.python script="nuvem/now.py"/> + <service name="now"/> + <reference target="text" name="format"/> + </component> + <component xmlns="" name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5000</property> + </component> + <component x="500" y="220" name="param" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>longitude</property> + <property name="query" visible="false"/> + </component> + <component x="500" y="200" name="param10" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>latitude</property> + <property name="query" visible="false"/> + </component> + <component name="param2" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>friend1</property> + <property name="query" visible="false"/> + </component> + <component name="param3" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>friend2</property> + <property name="query" visible="false"/> + </component> + <component name="param4" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>friend3</property> + <property name="query" visible="false"/> + </component> + <component name="param5" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>friend1</property> + <property name="query" visible="false"/> + </component> + <component name="param6" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>friend2</property> + <property name="query" visible="false"/> + </component> + <component name="param7" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>friend3</property> + <property name="query" visible="false"/> + </component> + <component xmlns="" name="params" title="?params" color="green1"> + <implementation.python script="nuvem/params.py"/> + <service name="params"/> + <property name="query" visible="false"/> + </component> + <component xmlns="" name="put" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference target="filedb" name="collection"/> + <reference target="user" name="id"/> + <reference target="list2" name="value"/> + </component> + <component x="10" y="10" name="start2" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="call4" name="content"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>%a %b %d, %I:%M %p</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>/components/map</property> + </component> + <component xmlns="" x="500" y="170" name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>green</property> + </component> + <component x="310" y="10" name="timer" title="timer" color="green1"> + <implementation.python script="nuvem/timer.py"/> + <service name="timer" visible="false"> + <binding.http uri="timer"/> + </service> + <reference target="number" name="n"/> + <reference target="call3" name="content"/> + </component> + <component name="url" title="url" color="green1"> + <implementation.python script="nuvem/url.py"/> + <service name="url"/> + <reference target="text2" name="address"/> + <reference target="append" name="args"/> + </component> + <component xmlns="" name="user" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component xmlns="" name="user3" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component xmlns="" x="210" y="150" name="user4" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component name="user5" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + </composite> + </content> + <link href="nearme"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/app.stats new file mode 100644 index 0000000000..5bc3a2ed3c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/app.stats @@ -0,0 +1 @@ +((entry (title "nearme") (id "nearme") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/htdocs/app.html new file mode 100644 index 0000000000..a7ac45d507 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme/htdocs/app.html @@ -0,0 +1,61 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">nearme</title> + <id>nearme</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Nearme</H2> + </SPAN> + <SPAN id="me" class="h2" style="position: absolute; top: 0px; left: 101px; "> + <H2>=me</H2> + </SPAN> + <SPAN style="position: absolute; top: 0px; left: 182px; " class="text" id="mytime"> + <SPAN>=mytime</SPAN> + </SPAN> + <SPAN id="page:section" class="section" style="position: absolute; top: 27px; width: 100%; left: 2px; "> + <SPAN>My friends</SPAN> + </SPAN> + <SPAN style="position: absolute; top: 54px; left: 2px; " class="entry" id="friend1"> + <INPUT type="text" size="20" value="=friend1" autocapitalize="off"/> + </SPAN> + <SPAN style="position: absolute; top: 54px; left: 182px; " class="text" id="time1"> + <SPAN>=time1</SPAN> + </SPAN> + <SPAN style="position: absolute; top: 81px; left: 2px; " class="entry" id="friend2"> + <INPUT type="text" size="20" value="=friend2" autocapitalize="off"/> + </SPAN> + <SPAN style="position: absolute; top: 81px; left: 182px; " class="text" id="time2"> + <SPAN>=time2</SPAN> + </SPAN> + <SPAN style="position: absolute; top: 108px; left: 2px; " class="entry" id="friend3"> + <INPUT type="text" size="20" value="=friend3" autocapitalize="off"/> + </SPAN> + <SPAN style="position: absolute; top: 108px; left: 182px; " class="text" id="time3"> + <SPAN>=time3</SPAN> + </SPAN> + <SPAN style="position: absolute; top: 135px; left: 2px; " class="img" id="mapimg"> + <IMG src="/public/img.png"/> + </SPAN> + </DIV> + </content> + <link href="nearme"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/app.composite new file mode 100644 index 0000000000..cf41a420a5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/app.composite @@ -0,0 +1,198 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">nearme2</title> + <id>nearme2</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="location" promote="location"/> + <service name="start1" promote="start1"/> + <service name="timer" promote="timer"/> + <component x="250" y="230" name="append1" title="+" color="yellow1"> + <implementation.python script="nuvem/append.py"/> + <service name="append"/> + <reference target="text5" name="first"/> + <reference target="get3" name="second"/> + </component> + <component x="250" y="330" name="append2" title="+" color="yellow1"> + <implementation.python script="nuvem/append.py"/> + <service name="append"/> + <reference target="text6" name="first"/> + <reference target="get4" name="second"/> + </component> + <component x="120" y="10" name="filedb2" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="410" y="260" name="filedb4" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="400" y="370" name="filedb5" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="270" y="260" name="get3" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb4" name="collection"/> + <reference target="text2" name="id"/> + </component> + <component x="270" y="350" name="get4" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb5" name="collection"/> + <reference target="text8" name="id"/> + </component> + <component x="200" y="230" name="gmap1" title="map" color="blue1"> + <implementation.python script="nuvem/gmap.py"/> + <service name="gmap"/> + <reference target="list21" name="locations"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.google.com/maps/api/staticmap"/> + </reference> + </component> + <component x="150" y="230" name="htinline2" title="inline" color="white1"> + <implementation.python script="nuvem/htinline.py"/> + <service name="htinline"/> + <reference target="gmap1" name="value"/> + </component> + <component x="40" y="150" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="user1" name="value"/> + <property>me</property> + </component> + <component x="50" y="210" name="item10" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htinline2" name="value"/> + <property>img</property> + </component> + <component x="290" y="90" name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="append1" name="value"/> + <property>S</property> + </component> + <component x="290" y="190" name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="append2" name="value"/> + <property>C</property> + </component> + <component x="190" y="240" name="list21" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="item2" name="first"/> + <reference target="item3" name="second"/> + </component> + <component x="100" y="110" name="list24" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="param10" name="first"/> + <reference target="param" name="second"/> + </component> + <component x="10" y="50" name="location" title="location" color="green1"> + <implementation.python script="nuvem/location.py"/> + <service name="location" visible="false"> + <binding.http uri="location"/> + </service> + <reference target="put1" name="content"/> + </component> + <component xmlns="" name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>10000</property> + </component> + <component x="280" y="90" name="param" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>longitude</property> + <property name="query" visible="false"/> + </component> + <component x="280" y="70" name="param10" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>latitude</property> + <property name="query" visible="false"/> + </component> + <component x="70" y="60" name="put1" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference target="filedb2" name="collection"/> + <reference target="user" name="id"/> + <reference target="list24" name="value"/> + </component> + <component x="10" y="10" name="start1" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="item1" name="content"/> + </component> + <component x="410" y="290" name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>john</property> + </component> + <component x="270" y="230" name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>blue</property> + </component> + <component x="270" y="320" name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>pink</property> + </component> + <component x="410" y="400" name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jane</property> + </component> + <component x="10" y="170" name="timer" title="timer" color="green1"> + <implementation.python script="nuvem/timer.py"/> + <service name="timer" visible="false"> + <binding.http uri="timer"/> + </service> + <reference target="number" name="n"/> + <reference target="item10" name="content"/> + </component> + <component xmlns="" x="120" y="30" name="user" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component x="80" y="20" name="user1" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + </composite> + </content> + <link href="nearme2"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/app.stats new file mode 100644 index 0000000000..c6d99481ae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/app.stats @@ -0,0 +1 @@ +((entry (title "nearme2") (id "nearme2") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/htdocs/app.html new file mode 100644 index 0000000000..6e7cb49f94 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/nearme2/htdocs/app.html @@ -0,0 +1,37 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">nearme2</title> + <id>nearme2</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Hello</H1> + </SPAN> + <SPAN id="me" class="h1" style="position: absolute; top: 0px; left: 56px; "> + <H1>=me</H1> + </SPAN> + <SPAN id="img" class="img" style="position: absolute; top: 36px; left: 2px; "> + <IMG src="/public/img.png"/> + </SPAN> + </DIV> + </content> + <link href="nearme2"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/app.composite new file mode 100644 index 0000000000..f8bc48efa3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/app.composite @@ -0,0 +1,59 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">new</title> + <id>new</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="comment1" promote="comment1"/> + <service name="start1" promote="start1"/> + <component x="10" y="0" name="comment1" title="{propval}" color="white"> + <implementation.python script="nuvem/comment.py"/> + <service name="comment" visible="false"/> + <property>Change this example to do what you want</property> + </component> + <component x="80" y="40" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="user1" name="value"/> + <property>me</property> + </component> + <component name="list1" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item1" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="10" y="40" name="start1" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list1" name="content"/> + </component> + <component name="user1" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + </composite> + </content> + <link href="new"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/app.stats new file mode 100644 index 0000000000..7c0571bf2b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/app.stats @@ -0,0 +1 @@ +((entry (title "An empty app template") (id "new") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/htdocs/app.html new file mode 100644 index 0000000000..58f8f82331 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/new/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">new</title> + <id>new</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 0px; "> + <H1>Hello</H1> + </SPAN> + <SPAN id="me" class="h1" style="position: absolute; top: 0px; left: 56px; "> + <H1>=me</H1> + </SPAN> + </DIV> + </content> + <link href="new"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/app.composite new file mode 100644 index 0000000000..57ea520209 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/app.composite @@ -0,0 +1,170 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">ourphotos</title> + <id>ourphotos</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="start" promote="start"/> + <component name="append" title="+" color="yellow1"> + <implementation.python script="nuvem/append.py"/> + <service name="append"/> + <reference target="values" name="first"/> + <reference target="values2" name="second"/> + </component> + <component name="flkalbum" title="flicker album" color="blue1"> + <implementation.python script="nuvem/flkalbum.py"/> + <service name="flkalbum"/> + <reference target="text7" name="id"/> + <reference name="flk" visible="false"> + <binding.http uri="http://api.flickr.com/services/feeds/photos_public.gne"/> + </reference> + </component> + <component x="200" y="70" name="htattrs1" title="attrs:" color="white1"> + <implementation.python script="nuvem/htattrs.py"/> + <service name="htattrs"/> + <reference target="list12" name="value"/> + </component> + <component x="140" y="40" name="htimg2" title="img" color="white1"> + <implementation.python script="nuvem/htimg.py"/> + <service name="htimg"/> + <reference target="list21" name="value"/> + </component> + <component x="260" y="70" name="htstyle2" title="style" color="white1"> + <implementation.python script="nuvem/htstyle.py"/> + <service name="htstyle"/> + <reference target="item1" name="value"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="map2" name="value"/> + <property>images</property> + </component> + <component x="310" y="70" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="pixels1" name="value"/> + <property>width</property> + </component> + <component x="240" y="70" name="list12" title="list" color="yellow1"> + <implementation.python script="nuvem/single.py"/> + <service name="list1"/> + <reference target="htstyle2" name="value"/> + </component> + <component x="170" y="40" name="list21" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="valueof2" name="first"/> + <reference target="htattrs1" name="second"/> + </component> + <component name="map2" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference target="name5" name="item"/> + <reference target="htimg2" name="transform"/> + <reference target="shuffle" name="list"/> + </component> + <component name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>src</property> + </component> + <component name="name4" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>m</property> + </component> + <component name="name5" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>image</property> + </component> + <component x="420" y="70" name="number1" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>320</property> + </component> + <component name="picalbum" title="picasa album" color="blue1"> + <implementation.python script="nuvem/picalbum.py"/> + <service name="picalbum"/> + <reference target="text5" name="id"/> + <reference name="pic" visible="false"> + <binding.http uri="https://picasaweb.google.com/data/feed/api/user"/> + </reference> + </component> + <component x="280" y="70" name="pixels1" title="pixels" color="white1"> + <implementation.python script="nuvem/pixels.py"/> + <service name="pixels"/> + <reference target="number1" name="value"/> + </component> + <component name="select" title="select" color="yellow1"> + <implementation.python script="nuvem/select.py"/> + <service name="select"/> + <reference target="name3" name="path"/> + <reference target="picalbum" name="list"/> + </component> + <component name="select2" title="select" color="yellow1"> + <implementation.python script="nuvem/select.py"/> + <service name="select"/> + <reference target="name4" name="path"/> + <reference target="flkalbum" name="list"/> + </component> + <component x="180" y="180" name="shuffle" title="shuffle" color="yellow1"> + <implementation.python script="nuvem/shuffle_.py"/> + <service name="shuffle"/> + <reference target="append" name="list"/> + </component> + <component x="10" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="item" name="content"/> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>61049883@N06</property> + </component> + <component x="470" y="30" name="valueof2" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>image</property> + </component> + <component name="values" title="values" color="yellow1"> + <implementation.python script="nuvem/values.py"/> + <service name="values"/> + <reference target="select" name="list"/> + </component> + <component name="values2" title="values" color="yellow1"> + <implementation.python script="nuvem/values.py"/> + <service name="values"/> + <reference target="select2" name="list"/> + </component> + </composite> + </content> + <link href="ourphotos"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/app.stats new file mode 100644 index 0000000000..6986fbea1b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/app.stats @@ -0,0 +1 @@ +((entry (title "Our photos of an event") (id "ourphotos") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/htdocs/app.html new file mode 100644 index 0000000000..a226d6daaf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/ourphotos/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">ourphotos</title> + <id>ourphotos</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Our Photos</H2> + </SPAN> + <SPAN id="images" class="list" style="position: absolute; top: 27px; width: 100%; left: 2px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=images</TD> + </TR> + <TR> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + </DIV> + </content> + <link href="ourphotos"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/app.composite new file mode 100644 index 0000000000..235566c7f2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/app.composite @@ -0,0 +1,603 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">shoppingcart</title> + <id>shoppingcart</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="Add to cart" promote="Add to cart"/> + <service name="Check out" promote="Check out"/> + <service name="Empty" promote="Empty"/> + <service name="carthtml" promote="carthtml"/> + <service name="catalog" promote="catalog"/> + <service name="cataloghtml" promote="cataloghtml"/> + <service name="getcart" promote="getcart"/> + <service name="order" promote="order"/> + <service name="start" promote="start"/> + <service name="total" promote="total"/> + <component x="290" y="290" name="Add to cart" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list33" name="content"/> + </component> + <component x="10" y="590" name="Check out" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list3" name="content"/> + </component> + <component x="10" y="450" name="Empty" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list32" name="content"/> + </component> + <component name="append" title="+" color="yellow1"> + <implementation.python script="nuvem/append.py"/> + <service name="append"/> + <reference target="call2" name="first"/> + <reference target="lookup" name="second"/> + </component> + <component name="call10" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name12" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call11" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name16" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call12" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name13" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call13" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name17" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call14" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name19" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call15" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name20" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="250" y="630" name="call16" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name21" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call17" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name4" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call2" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name5" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call3" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name6" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="370" y="590" name="call4" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name15" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="call5" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name8" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="370" y="620" name="call6" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name10" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="250" y="590" name="call7" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name9" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="500" y="690" name="call8" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name11" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="210" y="280" name="call9" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name2" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="10" y="320" name="carthtml" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="item6" name="content"/> + </component> + <component x="290" y="10" name="catalog" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list31" name="content"/> + </component> + <component x="10" y="160" name="cataloghtml" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="item" name="content"/> + </component> + <component name="delete2" title="delete" color="pink1"> + <implementation.python script="nuvem/delete.py"/> + <service name="delete"/> + <reference target="filedb2" name="collection"/> + <reference target="user2" name="id"/> + </component> + <component name="filedb" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component name="filedb2" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component name="filedb3" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="130" y="420" name="format1" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text6" name="pattern"/> + <reference target="valueof2" name="values"/> + </component> + <component x="280" y="350" name="format2" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text5" name="pattern"/> + <reference target="valueof" name="values"/> + </component> + <component x="300" y="610" name="format3" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text4" name="pattern"/> + <reference target="call8" name="values"/> + </component> + <component name="get" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb" name="collection"/> + <reference target="user" name="id"/> + </component> + <component x="470" y="10" name="getcart" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="get" name="content"/> + </component> + <component x="160" y="250" name="htcheck2" title="checkbox" color="white1"> + <implementation.python script="nuvem/htcheck.py"/> + <service name="htcheck"/> + <reference target="list22" name="value"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="map" name="value"/> + <property>catalog</property> + </component> + <component x="410" y="170" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference name="value" target="total1"/> + <property>total</property> + </component> + <component x="530" y="80" name="item10" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number4" name="value"/> + <property>Kiwi</property> + </component> + <component x="250" y="530" name="item11" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="delete2" name="value"/> + <property>delresult</property> + </component> + <component name="item12" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="sendgtalk" name="value"/> + <property>sendresult</property> + </component> + <component name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="call11" name="value"/> + <property>message</property> + </component> + <component name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text2" name="value"/> + <property>message</property> + </component> + <component name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="map2" name="value"/> + <property>cart</property> + </component> + <component x="380" y="390" name="item7" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="put" name="value"/> + <property>putresult</property> + </component> + <component x="530" y="20" name="item8" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number" name="value"/> + <property>Mango</property> + </component> + <component x="540" y="50" name="item9" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number2" name="value"/> + <property>Passion</property> + </component> + <component x="220" y="250" name="list22" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="text8" name="first"/> + <reference target="format2" name="second"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item4" name="item" clonable="true"/> + <reference target="item12" name="item" clonable="true"/> + <reference target="call3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="360" y="20" name="list31" title="list" color="yellow1"> + <implementation.python script="nuvem/triple.py"/> + <service name="list3"/> + <reference target="item8" name="first"/> + <reference target="item9" name="second"/> + <reference target="item10" name="third"/> + </component> + <component x="50" y="540" name="list32" title="list" color="yellow1"> + <implementation.python script="nuvem/triple.py"/> + <service name="list3"/> + <reference target="item11" name="first"/> + <reference target="call7" name="second"/> + <reference target="call16" name="third"/> + </component> + <component x="350" y="390" name="list33" title="list" color="yellow1"> + <implementation.python script="nuvem/triple.py"/> + <service name="list3"/> + <reference target="item7" name="first"/> + <reference target="call4" name="second"/> + <reference target="call6" name="third"/> + </component> + <component name="list4" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item5" name="item" clonable="true"/> + <reference target="call5" name="item" clonable="true"/> + <reference target="call13" name="item" clonable="true"/> + <reference target="call14" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="lookup" title="lookup" color="yellow1"> + <implementation.python script="nuvem/lookup.py"/> + <service name="lookup"/> + <reference target="second1" name="name"/> + <reference target="call15" name="list"/> + </component> + <component name="map" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference target="name" name="item"/> + <reference target="htcheck2" name="transform"/> + <reference target="call9" name="list"/> + </component> + <component name="map2" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference target="name3" name="item"/> + <reference target="format1" name="transform"/> + <reference target="call10" name="list"/> + </component> + <component name="name" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>fruit</property> + </component> + <component name="name10" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>total</property> + </component> + <component name="name11" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>total</property> + </component> + <component name="name12" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>getcart</property> + </component> + <component name="name13" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>order</property> + </component> + <component name="name15" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>carthtml</property> + </component> + <component name="name16" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>order</property> + </component> + <component name="name17" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>carthtml</property> + </component> + <component name="name19" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>total</property> + </component> + <component name="name2" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>catalog</property> + </component> + <component name="name20" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>catalog</property> + </component> + <component name="name21" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>total</property> + </component> + <component name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>fruit</property> + </component> + <component name="name4" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>getcart</property> + </component> + <component name="name5" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>getcart</property> + </component> + <component name="name6" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>emptyCart</property> + </component> + <component name="name8" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>cataloghtml</property> + </component> + <component name="name9" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>carthtml</property> + </component> + <component name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>2.99</property> + </component> + <component name="number2" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3.55</property> + </component> + <component x="650" y="340" name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>2</property> + </component> + <component name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>1.55</property> + </component> + <component x="300" y="550" name="order" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="format3" name="content"/> + </component> + <component x="580" y="370" name="param" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>fruit</property> + <property name="query" visible="false"/> + </component> + <component name="put" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference target="filedb3" name="collection"/> + <reference target="user3" name="id"/> + <reference target="append" name="value"/> + </component> + <component x="650" y="450" name="second1" title="second" color="yellow1"> + <implementation.python script="nuvem/second.py"/> + <service name="second"/> + <reference target="split2" name="list"/> + </component> + <component name="sendgtalk" title="gtalk" color="blue1"> + <implementation.cpp path="lib/chat" library="libchat-sender2"/> + <service name="sendgtalk"/> + <reference target="text" name="jid"/> + <reference target="text7" name="pass"/> + <reference target="text3" name="to"/> + <reference target="call12" name="msg"/> + </component> + <component x="580" y="480" name="split2" title="split" color="cyan1"> + <implementation.python script="nuvem/split.py"/> + <service name="split"/> + <reference target="text1" name="separator"/> + <reference target="param" name="string"/> + </component> + <component x="10" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list4" name="content"/> + </component> + <component x="650" y="360" name="sum1" title="sum" color="cyan1"> + <implementation.python script="nuvem/sum_.py"/> + <service name="sum"/> + <reference target="values" name="l"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xmppsca.1@gmail.com</property> + </component> + <component x="580" y="330" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property> - </property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Welcome to my online store</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino@gmail.com</property> + </component> + <component x="500" y="660" name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Your order has been processed. Your total: ${1}</property> + </component> + <component x="450" y="280" name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>${1} - {0}</property> + </component> + <component x="220" y="550" name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>${1} - {0}</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xmpp4sca</property> + </component> + <component x="280" y="320" name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>fruit</property> + </component> + <component x="330" y="120" name="total" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="item1" name="content"/> + </component> + <component name="total1" x="600" y="130" title="round" color="cyan1"> + <implementation.python script="nuvem/round_.py"/> + <service name="round"/> + <reference target="number3" name="n"/> + <reference target="sum1" name="x"/> + </component> + <component name="user" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component name="user2" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component name="user3" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component x="440" y="310" name="valueof" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>fruit</property> + </component> + <component x="210" y="580" name="valueof2" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>fruit</property> + </component> + <component x="790" y="320" name="values" title="values" color="yellow1"> + <implementation.python script="nuvem/values.py"/> + <service name="values"/> + <reference target="call17" name="list"/> + </component> + </composite> + </content> + <link href="shoppingcart"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/app.stats new file mode 100644 index 0000000000..b4c696fbe1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/app.stats @@ -0,0 +1 @@ +((entry (title "My online store") (id "shoppingcart") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/htdocs/app.html new file mode 100644 index 0000000000..dbca542ac9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/shoppingcart/htdocs/app.html @@ -0,0 +1,79 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">shoppingcart</title> + <id>shoppingcart</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Shopping Cart</H2> + </SPAN> + <SPAN id="message" class="text" style="position: absolute; top: 36px; left: 2px; "> + <SPAN>Welcome</SPAN> + </SPAN> + <SPAN id="page:section" class="section" style="position: absolute; top: 63px; width: 100%; left: 2px; "> + <SPAN>Catalog</SPAN> + </SPAN> + <SPAN id="page:button" class="button" style="position: absolute; top: 63px; left: 146px; "> + <INPUT type="button" value="Add to cart" class="graybutton"/> + </SPAN> + <SPAN id="catalog" class="list" style="position: absolute; top: 99px; width: 100%; left: 2px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=catalog</TD> + </TR> + <TR> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + <SPAN id="page:section" class="section" style="position: absolute; top: 180px; width: 100%; left: 2px; "> + <SPAN>Your cart:</SPAN> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 180px; left: 83px; "> + <SPAN>$</SPAN> + </SPAN> + <SPAN id="total" class="text" style="position: absolute; top: 180px; left: 92px; "> + <SPAN>=total</SPAN> + </SPAN> + <SPAN id="page:button" class="button" style="position: absolute; top: 180px; left: 146px; "> + <INPUT type="button" value="Check out" class="graybutton"/> + </SPAN> + <SPAN id="page:button" class="button" style="position: absolute; top: 180px; left: 245px; "> + <INPUT type="button" value="Empty" class="graybutton"/> + </SPAN> + <SPAN id="cart" class="list" style="position: absolute; top: 216px; width: 100%; left: 2px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=cart</TD> + </TR> + <TR> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + </DIV> + </content> + <link href="shoppingcart"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/app.composite new file mode 100644 index 0000000000..b36b561a84 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/app.composite @@ -0,0 +1,511 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">slice</title> + <id>slice</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="animation1" promote="animation1"/> + <service name="bounce" promote="bounce"/> + <service name="feather" promote="feather"/> + <service name="gnu" promote="gnu"/> + <service name="score" promote="score"/> + <service name="sprite" promote="sprite"/> + <service name="start" promote="start"/> + <component x="350" y="120" name="add1" title="+" color="cyan1"> + <implementation.python script="nuvem/add.py"/> + <service name="add"> + <documentation>+</documentation> + </service> + <reference target="number10" name="value1"/> + <reference target="get1" name="value2"/> + </component> + <component x="10" y="90" name="animation1" title="animation" color="green1"> + <implementation.python script="nuvem/animation.py"/> + <service name="animation" visible="false"> + <binding.http uri="animation"/> + </service> + <reference target="number6" name="n"/> + <reference target="true2" name="loop"/> + <reference target="map1" name="content"/> + </component> + <component x="360" y="10" name="bounce" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list1" name="content"/> + </component> + <component x="170" y="150" name="call1" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name5" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="820" y="360" name="call2" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name9" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="750" y="210" name="call3" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name4" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="750" y="330" name="call4" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name10" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="200" y="80" name="call5" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name11" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="10" y="360" name="feather" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list22" name="content"/> + </component> + <component x="240" y="100" name="filedb1" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="270" y="150" name="filedb2" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="890" y="350" name="filedb3" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="1100" y="190" name="filedb4" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="710" y="160" name="frames1" title="frames" color="white1"> + <implementation.python script="nuvem/frames.py"/> + <service name="frames"/> + <reference target="number1" name="msec"/> + <reference target="number12" name="loop"/> + <reference target="call3" name="content"/> + </component> + <component x="380" y="140" name="get1" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb2" name="collection"/> + <reference target="user2" name="id"/> + </component> + <component x="860" y="360" name="get2" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb3" name="collection"/> + <reference target="user4" name="id"/> + </component> + <component x="10" y="550" name="gnu" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list23" name="content"/> + </component> + <component x="360" y="160" name="htstyle2" title="style" color="white1"> + <implementation.python script="nuvem/htstyle.py"/> + <service name="htstyle"/> + <reference target="frames1" name="value"/> + </component> + <component x="950" y="180" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="put1" name="value"/> + <property>r</property> + </component> + <component x="210" y="40" name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="user3" name="value"/> + <property>me</property> + </component> + <component x="930" y="400" name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="get2" name="value"/> + <property>score</property> + </component> + <component x="1050" y="210" name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="put2" name="value"/> + <property>r</property> + </component> + <component name="list1" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="list28" name="item" clonable="true"/> + <reference target="list21" name="item" clonable="true"/> + <reference target="list29" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="120" y="160" name="list11" title="list" color="yellow1"> + <implementation.python script="nuvem/single.py"/> + <service name="list1"/> + <reference target="list27" name="value"/> + </component> + <component x="620" y="110" name="list14" title="list" color="yellow1"> + <implementation.python script="nuvem/single.py"/> + <service name="list1"/> + <reference target="htstyle2" name="value"/> + </component> + <component name="list2" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="name6" name="item" clonable="true"/> + <reference target="name7" name="item" clonable="true"/> + <reference target="name2" name="item" clonable="true"/> + <reference target="name8" name="item" clonable="true"/> + <reference target="name3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="670" y="130" name="list21" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="number5" name="first"/> + <reference target="transform1" name="second"/> + </component> + <component x="780" y="200" name="list22" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="item1" name="first"/> + <reference target="call2" name="second"/> + </component> + <component x="1030" y="210" name="list23" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="item4" name="first"/> + <reference target="call4" name="second"/> + </component> + <component x="60" y="10" name="list24" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="item2" name="first"/> + <reference target="call5" name="second"/> + </component> + <component x="140" y="210" name="list27" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="call1" name="first"/> + <reference target="list14" name="second"/> + </component> + <component x="110" y="270" name="list28" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="number20" name="first"/> + <reference target="transform2" name="second"/> + </component> + <component x="670" y="250" name="list29" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="number24" name="first"/> + <reference target="transform3" name="second"/> + </component> + <component x="80" y="140" name="map1" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference target="name1" name="item"/> + <reference target="list11" name="transform"/> + <reference target="range1" name="list"/> + </component> + <component x="110" y="140" name="name1" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>i</property> + </component> + <component x="780" y="330" name="name10" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>score</property> + </component> + <component x="230" y="80" name="name11" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>score</property> + </component> + <component x="840" y="70" name="name2" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>feather2</property> + </component> + <component x="850" y="120" name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>feather3</property> + </component> + <component x="780" y="220" name="name4" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>bounce</property> + </component> + <component x="200" y="160" name="name5" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>sprite</property> + </component> + <component x="400" y="90" name="name6" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>feather1</property> + </component> + <component x="390" y="180" name="name7" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>gnu1</property> + </component> + <component x="840" y="90" name="name8" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>gnu2</property> + </component> + <component x="840" y="360" name="name9" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>score</property> + </component> + <component x="770" y="170" name="number1" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3000</property> + </component> + <component x="380" y="110" name="number10" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>1</property> + </component> + <component x="710" y="240" name="number11" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>200</property> + </component> + <component x="280" y="230" name="number12" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>10</property> + </component> + <component x="1120" y="250" name="number13" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="930" y="170" name="number2" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>100</property> + </component> + <component x="820" y="230" name="number20" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="940" y="80" name="number22" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="950" y="110" name="number23" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="890" y="220" name="number24" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>100</property> + </component> + <component x="940" y="250" name="number25" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>240</property> + </component> + <component x="940" y="280" name="number26" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="940" y="310" name="number27" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>720</property> + </component> + <component x="670" y="210" name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>-400</property> + </component> + <component x="920" y="230" name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>360</property> + </component> + <component x="700" y="130" name="number5" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>50</property> + </component> + <component x="80" y="150" name="number6" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>4000</property> + </component> + <component x="150" y="300" name="number7" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="150" y="330" name="number8" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>20</property> + </component> + <component x="580" y="40" name="number9" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>-200</property> + </component> + <component x="880" y="260" name="put1" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference target="filedb1" name="collection"/> + <reference target="user1" name="id"/> + <reference target="add1" name="value"/> + </component> + <component x="1080" y="210" name="put2" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference target="filedb4" name="collection"/> + <reference target="user5" name="id"/> + <reference target="number13" name="value"/> + </component> + <component x="720" y="60" name="random1" title="rand" color="cyan1"> + <implementation.python script="nuvem/random_.py"/> + <service name="random"/> + <reference target="list2" name="range"/> + </component> + <component x="540" y="40" name="random2" title="rand" color="cyan1"> + <implementation.python script="nuvem/random_.py"/> + <service name="random"/> + <reference target="number9" name="range"/> + </component> + <component x="670" y="240" name="random3" title="rand" color="cyan1"> + <implementation.python script="nuvem/random_.py"/> + <service name="random"/> + <reference target="number11" name="range"/> + </component> + <component x="120" y="300" name="range1" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference target="number7" name="first"/> + <reference target="number8" name="last"/> + </component> + <component x="180" y="10" name="score" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="item3" name="content"/> + </component> + <component x="360" y="400" name="sprite" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="random1" name="content"/> + </component> + <component x="10" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list24" name="content"/> + </component> + <component x="550" y="190" name="subtract1" title="-" color="cyan1"> + <implementation.python script="nuvem/subtract.py"/> + <service name="subtract"> + <documentation>-</documentation> + </service> + <reference target="number3" name="value1"/> + <reference target="random3" name="value2"/> + </component> + <component x="700" y="160" name="transform1" title="transform" color="white1"> + <implementation.python script="nuvem/transform.py"/> + <service name="transform"/> + <reference target="number2" name="x"/> + <reference target="subtract1" name="y"/> + <reference target="number4" name="d"/> + </component> + <component x="820" y="250" name="transform2" title="transform" color="white1"> + <implementation.python script="nuvem/transform.py"/> + <service name="transform"/> + <reference target="random2" name="x"/> + <reference target="number22" name="y"/> + <reference target="number23" name="d"/> + </component> + <component x="890" y="250" name="transform3" title="transform" color="white1"> + <implementation.python script="nuvem/transform.py"/> + <service name="transform"/> + <reference target="number25" name="x"/> + <reference target="number26" name="y"/> + <reference target="number27" name="d"/> + </component> + <component x="80" y="110" name="true2" title="true" color="orange1"> + <implementation.python script="nuvem/true_.py"/> + <service name="true"/> + </component> + <component x="240" y="130" name="user1" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component x="390" y="140" name="user2" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component x="110" y="40" name="user3" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component x="890" y="390" name="user4" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + <component x="1110" y="210" name="user5" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + </composite> + </content> + <link href="slice"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/app.stats new file mode 100644 index 0000000000..bebfcbbaf9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/app.stats @@ -0,0 +1 @@ +((entry (title "Slice") (id "slice") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/htdocs/app.html new file mode 100644 index 0000000000..c02f2fa399 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/slice/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">slice</title> + <id>slice</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Hello</H2> + </SPAN> + <SPAN id="me" class="h2" style="position: absolute; top: 0px; left: 47px; "> + <H2>=me</H2> + </SPAN> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 227px; "> + <H2>Score:</H2> + </SPAN> + <SPAN id="score" class="h2" style="position: absolute; top: 0px; left: 281px; "> + <H2>0</H2> + </SPAN> + <SPAN id="feather2" class="link" style="position: absolute; top: 486px; left: 2px; "> + <A href="link:feather"> + <SPAN> + <IMG src="http://www.apache.org/images/feather-small.gif"/> + </SPAN> + </A> + </SPAN> + <SPAN id="gnu1" class="link" style="position: absolute; top: 549px; left: 2px; "> + <A href="link:gnu"> + <SPAN> + <IMG src="http://www.gnu.org/graphics/lgplv3-147x51.png"/> + </SPAN> + </A> + </SPAN> + <SPAN id="feather1" class="link" style="position: absolute; top: 612px; left: 2px; "> + <A href="link:feather"> + <SPAN> + <IMG src="http://www.apache.org/images/feather-small.gif"/> + </SPAN> + </A> + </SPAN> + <SPAN id="gnu2" class="link" style="position: absolute; top: 666px; left: 2px; "> + <A href="link:gnu"> + <SPAN> + <IMG src="http://www.gnu.org/graphics/lgplv3-147x51.png"/> + </SPAN> + </A> + </SPAN> + <SPAN id="feather3" class="link" style="position: absolute; top: 729px; left: 2px; "> + <A href="link:feather"> + <SPAN> + <IMG src="http://www.apache.org/images/feather-small.gif"/> + </SPAN> + </A> + </SPAN> + </DIV> + </content> + <link href="slice"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/app.composite new file mode 100644 index 0000000000..7a4344df4d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/app.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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">test</title> + <id>test</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="comment1" promote="comment1"/> + <service name="start1" promote="start1"/> + <component x="10" y="10" name="comment1" title="{propval}" color="white"> + <implementation.python script="nuvem/comment.py"/> + <service name="comment" visible="false"/> + <property>Change this example to do what you want</property> + </component> + <component x="80" y="40" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="user1" name="value"/> + <property>me</property> + </component> + <component x="70" y="70" name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="now1" name="value"/> + <property>time</property> + </component> + <component x="50" y="40" name="list21" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="item1" name="first"/> + <reference target="item2" name="second"/> + </component> + <component x="120" y="70" name="now1" title="now" color="orange1"> + <implementation.python script="nuvem/now.py"/> + <service name="now"/> + <reference name="format"/> + </component> + <component x="10" y="50" name="start1" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list21" name="content"/> + </component> + <component name="user1" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + </composite> + </content> + <link href="test"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/app.stats new file mode 100644 index 0000000000..8c9b3792ed --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/app.stats @@ -0,0 +1 @@ +((entry (title "An empty test app") (id "test") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/htdocs/app.html new file mode 100644 index 0000000000..81ab3d3e46 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/test/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">test</title> + <id>test</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 0px; "> + <H1>Hello</H1> + </SPAN> + <SPAN id="me" class="h1" style="position: absolute; top: 0px; left: 74px; "> + <H1>=me</H1> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 36px; left: 2px; "> + <SPAN>The time is:</SPAN> + </SPAN> + <SPAN id="time" class="text" style="position: absolute; top: 36px; left: 74px; "> + <SPAN>=time</SPAN> + </SPAN> + </DIV> + </content> + <link href="test"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/app.composite new file mode 100644 index 0000000000..5dd4c61a53 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/app.composite @@ -0,0 +1,176 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testanimation</title> + <id>testanimation</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="animation1" promote="animation1"/> + <service name="start1" promote="start1"/> + <component x="10" y="60" name="animation1" title="animation" color="green1"> + <implementation.python script="nuvem/animation.py"/> + <service name="animation" visible="false"> + <binding.http uri="animation"/> + </service> + <reference target="number4" name="n"/> + <reference target="number6" name="loop"/> + <reference target="map1" name="content"/> + </component> + <component x="220" y="180" name="htattrs2" title="attrs:" color="white1"> + <implementation.python script="nuvem/htattrs.py"/> + <service name="htattrs"/> + <reference target="htstyle2" name="value"/> + </component> + <component x="240" y="120" name="htstyle2" title="style" color="white1"> + <implementation.python script="nuvem/htstyle.py"/> + <service name="htstyle"/> + <reference target="list21" name="value"/> + </component> + <component x="160" y="180" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htattrs2" name="value"/> + <property>testdynimg</property> + </component> + <component x="80" y="10" name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text1" name="value"/> + <property>testdynimg</property> + </component> + <component x="320" y="170" name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="pixels2" name="value"/> + <property>width</property> + </component> + <component x="120" y="180" name="list11" title="list" color="yellow1"> + <implementation.python script="nuvem/single.py"/> + <service name="list1"/> + <reference target="item1" name="value"/> + </component> + <component x="290" y="180" name="list21" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="item4" name="first"/> + <reference target="transform1" name="second"/> + </component> + <component x="100" y="150" name="map1" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference target="name1" name="item"/> + <reference target="list11" name="transform"/> + <reference target="range1" name="list"/> + </component> + <component x="400" y="190" name="multiply1" title="*" color="cyan1"> + <implementation.python script="nuvem/multiply.py"/> + <service name="multiply"> + <documentation>*</documentation> + </service> + <reference target="valueof1" name="value1"/> + <reference target="number3" name="value2"/> + </component> + <component x="380" y="290" name="multiply2" title="*" color="cyan1"> + <implementation.python script="nuvem/multiply.py"/> + <service name="multiply"> + <documentation>*</documentation> + </service> + <reference target="valueof2" name="value1"/> + <reference target="number5" name="value2"/> + </component> + <component x="150" y="110" name="name1" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>t</property> + </component> + <component x="140" y="110" name="number1" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="150" y="140" name="number2" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>121</property> + </component> + <component x="690" y="290" name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3</property> + </component> + <component x="100" y="90" name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>20</property> + </component> + <component x="680" y="340" name="number5" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>6</property> + </component> + <component x="110" y="120" name="number6" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component x="370" y="180" name="pixels2" title="pixels" color="white1"> + <implementation.python script="nuvem/pixels.py"/> + <service name="pixels"/> + <reference target="multiply1" name="value"/> + </component> + <component x="150" y="400" name="range1" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference target="number1" name="first"/> + <reference target="number2" name="last"/> + </component> + <component x="10" y="10" name="start1" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="item2" name="content"/> + </component> + <component x="150" y="10" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://tuscany.apache.org/images/TuscanyLogo.jpg</property> + </component> + <component x="300" y="240" name="transform1" title="transform" color="white1"> + <implementation.python script="nuvem/transform.py"/> + <service name="transform"/> + <reference name="x"/> + <reference name="y"/> + <reference target="multiply2" name="d"/> + </component> + <component x="680" y="260" name="valueof1" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>t</property> + </component> + <component x="680" y="310" name="valueof2" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>t</property> + </component> + </composite> + </content> + <link href="testanimation"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/app.stats new file mode 100644 index 0000000000..0b6f8bda73 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/app.stats @@ -0,0 +1 @@ +((entry (title "Test animation components") (id "testanimation") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/htdocs/app.html new file mode 100644 index 0000000000..02094d84c7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testanimation/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testanimation</title> + <id>testanimation</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test animation component</H2> + </SPAN> + <SPAN id="testdynimg" class="img" style="position: absolute; top: 36px; left: 11px; "> + <IMG src="/public/img.png"/> + </SPAN> + </DIV> + </content> + <link href="testanimation"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/app.composite new file mode 100644 index 0000000000..e2af18e24b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/app.composite @@ -0,0 +1,106 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testdb</title> + <id>testdb</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="delete" promote="delete"/> + <service name="get" promote="get"/> + <service name="put" promote="put"/> + <component x="150" y="10" name="delete" title="delete" color="pink1"> + <implementation.python script="nuvem/delete.py"/> + <service name="delete"/> + <reference target="filedb2" name="collection"/> + <reference target="list3" name="id"/> + </component> + <component name="filedb" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component name="filedb2" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component name="filedb3" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="20" y="120" name="get" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference target="filedb3" name="collection"/> + <reference target="list2" name="id"/> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text4" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="13" y="1" name="put" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference target="filedb" name="collection"/> + <reference target="list" name="id"/> + <reference target="text2" name="value"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>testkey</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>testvalue</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>testkey</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>testkey</property> + </component> + </composite> + </content> + <link href="testdb"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/app.stats new file mode 100644 index 0000000000..e33dc221a5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/app.stats @@ -0,0 +1 @@ +((entry (title "Test database components") (id "testdb") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/htdocs/app.html new file mode 100644 index 0000000000..a9e77b1012 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testdb/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testdb</title> + <id>testdb</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Test db components</H1> + </SPAN> + </DIV> + </content> + <link href="testdb"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/app.composite new file mode 100644 index 0000000000..3d6e2eb687 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/app.composite @@ -0,0 +1,202 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testevents</title> + <id>testevents</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="Cancel" promote="Cancel"/> + <service name="OK" promote="OK"/> + <service name="call" promote="call"/> + <service name="call2" promote="call2"/> + <service name="call3" promote="call3"/> + <service name="compabc" promote="compabc"/> + <service name="compxyz" promote="compxyz"/> + <service name="location" promote="location"/> + <service name="start" promote="start"/> + <service name="timer3" promote="timer3"/> + <component x="190" y="10" name="Cancel" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="prop2" name="content"/> + </component> + <component x="190" y="60" name="OK" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="list" name="content"/> + </component> + <component name="abc" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abc</property> + </component> + <component x="190" y="150" name="call" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name2" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="20" y="180" name="call2" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="190" y="190" name="call3" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="text5" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="10" y="230" name="compabc" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="abc" name="content"/> + </component> + <component x="20" y="270" name="compxyz" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="text12" name="content"/> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text4" name="value"/> + <property>status</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text" name="value"/> + <property>status</property> + </component> + <component name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text2" name="value"/> + <property>status</property> + </component> + <component name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="param" name="value"/> + <property>testtext</property> + </component> + <component name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="params2" name="value"/> + <property>location</property> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item5" name="item" clonable="true"/> + <reference target="item4" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="10" y="130" name="location" title="location" color="green1"> + <implementation.python script="nuvem/location.py"/> + <service name="location" visible="false"> + <binding.http uri="location"/> + </service> + <reference target="item6" name="content"/> + </component> + <component name="name" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>compxyz</property> + </component> + <component name="name2" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>https://testhttp.example.com:8453/components/property</property> + </component> + <component name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3000</property> + </component> + <component name="param" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>testfield</property> + <property name="query" visible="false"/> + </component> + <component name="params2" title="?params" color="green1"> + <implementation.python script="nuvem/params.py"/> + <service name="params"/> + <property name="query" visible="false"/> + </component> + <component name="prop2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text3" name="value"/> + <property>status</property> + </component> + <component x="15" y="3" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="item3" name="content"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>page opens</property> + </component> + <component name="text12" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xyz</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>ok button clicked</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>cancel button clicked</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>timer fired</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>https://testhttp.example.com:8453/components/property</property> + </component> + <component x="13" y="58" name="timer3" title="timer" color="green1"> + <implementation.python script="nuvem/timer.py"/> + <service name="timer" visible="false"> + <binding.http uri="timer"/> + </service> + <reference target="number" name="n"/> + <reference target="item2" name="content"/> + </component> + </composite> + </content> + <link href="testevents"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/app.stats new file mode 100644 index 0000000000..9c14040cd0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/app.stats @@ -0,0 +1 @@ +((entry (title "Test event components") (id "testevents") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/htdocs/app.html new file mode 100644 index 0000000000..3178459f47 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testevents/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testevents</title> + <id>testevents</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Test events</H1> + </SPAN> + <SPAN id="testfield" class="entry" style="position: absolute; top: 54px; left: 11px; "> + <INPUT type="text" value="=testfield" size="10" autocapitalize="off"/> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 90px; left: 11px; "> + <SPAN>Status:</SPAN> + </SPAN> + <SPAN id="status" class="text" style="position: absolute; top: 90px; left: 92px; "> + <SPAN>=status</SPAN> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 117px; left: 11px; "> + <SPAN>Field value:</SPAN> + </SPAN> + <SPAN id="testtext" class="text" style="position: absolute; top: 117px; left: 92px; "> + <SPAN>=testtext</SPAN> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 144px; left: 11px; "> + <SPAN>Longitude:</SPAN> + </SPAN> + <SPAN id="longitude" class="text" style="position: absolute; top: 144px; left: 92px; "> + <SPAN>=longitude</SPAN> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 171px; left: 11px; "> + <SPAN>Latitude:</SPAN> + </SPAN> + <SPAN id="latitude" class="text" style="position: absolute; top: 171px; left: 92px; "> + <SPAN>=latitude</SPAN> + </SPAN> + <SPAN id="page:button" class="button" style="position: absolute; top: 207px; left: 2px; "> + <INPUT type="button" value="OK" class="graybutton"/> + </SPAN> + <SPAN id="page:button" class="button" style="position: absolute; top: 207px; left: 47px; "> + <INPUT type="button" value="Cancel" class="graybutton"/> + </SPAN> + </DIV> + </content> + <link href="testevents"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/app.composite new file mode 100644 index 0000000000..aa78b576d0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/app.composite @@ -0,0 +1,287 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testhttp</title> + <id>testhttp</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="call" promote="call"/> + <service name="get" promote="get"/> + <service name="get2" promote="get2"/> + <service name="get3" promote="get3"/> + <service name="get4" promote="get4"/> + <service name="get5" promote="get5"/> + <service name="get6" promote="get6"/> + <service name="item" promote="property"/> + <service name="parse" promote="parse"/> + <component x="20" y="180" name="call" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference target="name" name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component name="first" title="first" color="yellow1"> + <implementation.python script="nuvem/first.py"/> + <service name="first"/> + <reference target="rest" name="list"/> + </component> + <component x="750" y="320" name="format1" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text12" name="pattern"/> + <reference target="list2" name="values"/> + </component> + <component x="20" y="10" name="get" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text" name="url"/> + </component> + <component x="20" y="60" name="get2" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text2" name="url"/> + </component> + <component x="20" y="100" name="get3" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text3" name="url"/> + </component> + <component x="310" y="10" name="get4" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text4" name="url"/> + </component> + <component x="200" y="10" name="get5" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text5" name="url"/> + </component> + <component x="20" y="140" name="get6" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text6" name="url"/> + </component> + <component name="get7" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text7" name="url"/> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="user" name="value"/> + <property>user</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="params" name="value"/> + <property>name</property> + </component> + <component name="join" title="join" color="cyan1"> + <implementation.python script="nuvem/join.py"/> + <service name="join"/> + <reference target="text9" name="separator"/> + <reference target="first" name="list"/> + </component> + <component x="570" y="350" name="keychain1" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name1" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="710" y="290" name="keychain2" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name2" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="720" y="310" name="keychain3" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name3" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list1" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="keychain1" name="item" clonable="true"/> + <reference target="text10" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text11" name="item" clonable="true"/> + <reference target="text13" name="item" clonable="true"/> + <reference target="text14" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list4" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="format1" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="name" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>https://testhttp.example.com:8453/components/property</property> + </component> + <component x="630" y="350" name="name1" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>twilliosid</property> + </component> + <component x="780" y="280" name="name2" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>twilliosid</property> + </component> + <component x="780" y="320" name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>twilliotoken</property> + </component> + <component name="params" title="?params" color="green1"> + <implementation.python script="nuvem/params.py"/> + <service name="params"/> + <property name="query" visible="false"/> + </component> + <component x="340" y="180" name="parse" title="parse" color="cyan1"> + <implementation.python script="nuvem/parse.py"/> + <service name="parse"/> + <reference target="text8" name="regexp"/> + <reference target="join" name="string"/> + </component> + <component x="20" y="220" name="property" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list" name="value"/> + <property>test</property> + </component> + <component name="rest" title="rest" color="yellow1"> + <implementation.python script="nuvem/rest.py"/> + <service name="rest"/> + <reference target="get7" name="list"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://www.google.com</property> + </component> + <component x="530" y="320" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>https://api.twilio.com/2010-04-01/Accounts/</property> + </component> + <component x="570" y="390" name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>SMS/Messages</property> + </component> + <component x="580" y="480" name="text11" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>+14155992671</property> + </component> + <component x="550" y="450" name="text12" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>From={0}&To={1}&Body={2}</property> + </component> + <component x="700" y="340" name="text13" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>+16508632924</property> + </component> + <component x="690" y="370" name="text14" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>This is a text message</property> + </component> + <component x="710" y="290" name="text15" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>application/x-www-form-urlencoded</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://maps.googleapis.com/maps/api/directions/json?origin=Boston,MA&destination=Concord,MA&waypoints=Charlestown,MA|Lexington,MA&sensor=false</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdXMLclient.php?whichClient=NDFDgen&lat=38.99&lon=-77.01&listLatLon=&lat1=&lon1=&lat2=&lon2=&resolutionSub=&listLat1=&listLon1=&listLat2=&listLon2=&resolutionList=&endPoint1Lat=&endPoint1Lon=&endPoint2Lat=&endPoint2Lon=&listEndPoint1Lat=&listEndPoint1Lon=&listEndPoint2Lat=&listEndPoint2Lon=&zipCodeList=&listZipCodeList=&centerPointLat=&centerPointLon=&distanceLat=&distanceLon=&resolutionSquare=&listCenterPointLat=&listCenterPointLon=&listDistanceLat=&listDistanceLon=&listResolutionSquare=&citiesLevel=&listCitiesLevel=&sector=&gmlListLatLon=&featureType=&requestedTime=&startTime=&endTime=&compType=&propertyName=&product=time-series&begin=2004-01-01T00%3A00%3A00&end=2015-03-10T00%3A00%3A00&maxt=maxt&Submit=Submit</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://feedproxy.google.com/TechCrunch</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>cnn.com</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>https://chart.googleapis.com/chart?cht=p3&chs=250x100&chd=60,40&chl=Hello|World</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>cnn.com</property> + </component> + <component name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>(CNN)</property> + </component> + <component name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property name="property"/> + </component> + <component name="user" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> + </composite> + </content> + <link href="testhttp"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/app.stats new file mode 100644 index 0000000000..f55f07105b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/app.stats @@ -0,0 +1 @@ +((entry (title "Test HTTP components") (id "testhttp") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/htdocs/app.html new file mode 100644 index 0000000000..bf306c3c37 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testhttp/htdocs/app.html @@ -0,0 +1,38 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testhttp</title> + <id>testhttp</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Test HTTP components</H1> + </SPAN> + <SPAN id="iframe" class="iframe" style="position: absolute; top: 234px; left: 11px; "> + <A href="/public/iframe.html"> + <SPAN class="fakeframe"> + <SPAN>frame ...</SPAN> + </SPAN> + </A> + </SPAN> + </DIV> + </content> + <link href="testhttp"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/app.composite new file mode 100644 index 0000000000..d838773839 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/app.composite @@ -0,0 +1,209 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testlogic</title> + <id>testlogic</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="cos" promote="cos"/> + <service name="eval" promote="eval"/> + <service name="eval2" promote="eval2"/> + <service name="exec" promote="exec"/> + <service name="exec2" promote="exec2"/> + <service name="if" promote="if"/> + <service name="random1" promote="random1"/> + <service name="randoms1" promote="randoms1"/> + <service name="randoms2" promote="randoms2"/> + <service name="sin" promote="sin"/> + <component x="20" y="170" name="cos" title="cos" color="cyan1"> + <implementation.python script="nuvem/cos_.py"/> + <service name="cos"/> + <reference target="number7" name="x"/> + </component> + <component x="150" y="10" name="eval" title="expr" color="cyan1"> + <implementation.python script="nuvem/eval_.py"/> + <service name="eval"/> + <reference target="text3" name="py"/> + <reference name="ref"/> + </component> + <component x="170" y="70" name="eval2" title="expr" color="cyan1"> + <implementation.python script="nuvem/eval_.py"/> + <service name="eval"/> + <reference target="text4" name="py"/> + <reference target="number3" name="ref"/> + </component> + <component x="150" y="210" name="exec" title="script" color="cyan1"> + <implementation.python script="nuvem/exec_.py"/> + <service name="exec"/> + <reference target="get" name="py"/> + <reference target="number4" name="ref"/> + </component> + <component x="150" y="140" name="exec2" title="script" color="cyan1"> + <implementation.python script="nuvem/exec_.py"/> + <service name="exec"/> + <reference target="text6" name="py"/> + <reference target="number5" name="ref"/> + </component> + <component name="get" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text5" name="url"/> + </component> + <component name="greater" title="gt" color="cyan1"> + <implementation.python script="nuvem/greater.py"/> + <service name="greater"/> + <reference target="number2" name="value1"/> + <reference target="number" name="value2"/> + </component> + <component x="19" y="9" name="if" title="if" color="cyan1"> + <implementation.python script="nuvem/if_.py"/> + <service name="if"/> + <reference target="greater" name="condition"/> + <reference target="text" name="then"/> + <reference target="text2" name="else"/> + </component> + <component name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component x="390" y="10" name="number1" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3</property> + </component> + <component x="480" y="90" name="number10" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component x="530" y="120" name="number11" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component x="520" y="140" name="number12" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>100</property> + </component> + <component name="number2" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3</property> + </component> + <component name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component name="number5" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component name="number6" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0.5</property> + </component> + <component name="number7" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0.5</property> + </component> + <component x="490" y="0" name="number8" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>5</property> + </component> + <component x="480" y="40" name="number9" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3</property> + </component> + <component x="310" y="10" name="random1" title="rand" color="cyan1"> + <implementation.python script="nuvem/random_.py"/> + <service name="random"/> + <reference target="number1" name="range"/> + </component> + <component x="390" y="10" name="randoms1" title="rands" color="cyan1"> + <implementation.python script="nuvem/randoms.py"/> + <service name="randoms"/> + <reference target="number8" name="n"/> + <reference target="number9" name="range"/> + </component> + <component x="390" y="100" name="randoms2" title="rands" color="cyan1"> + <implementation.python script="nuvem/randoms.py"/> + <service name="randoms"/> + <reference target="number10" name="n"/> + <reference target="range1" name="range"/> + </component> + <component x="480" y="120" name="range1" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference target="number11" name="first"/> + <reference target="number12" name="last"/> + </component> + <component x="20" y="130" name="sin" title="sin" color="cyan1"> + <implementation.python script="nuvem/sin_.py"/> + <service name="sin"/> + <reference target="number6" name="x"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>greater than 5</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>not greater than 5</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>3.14116 * 5 * 5</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>3.14116 * ref.get(r) * ref.get(r)</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://people.apache.org/~jsdelfino/tuscany/test/surface.py</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>val = 3.14116 * ref.get(r) * ref.get(r)</property> + </component> + </composite> + </content> + <link href="testlogic"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/app.stats new file mode 100644 index 0000000000..018a42a91f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/app.stats @@ -0,0 +1 @@ +((entry (title "Test logic components") (id "testlogic") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/htdocs/app.html new file mode 100644 index 0000000000..1e02755d80 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testlogic/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testlogic</title> + <id>testlogic</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test logic components</H2> + </SPAN> + </DIV> + </content> + <link href="testlogic"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/app.composite new file mode 100644 index 0000000000..6c2ba82131 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/app.composite @@ -0,0 +1,248 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testsearch</title> + <id>testsearch</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="bingsearch" promote="bingsearch"/> + <service name="gaddress1" promote="gaddress1"/> + <service name="get" promote="get"/> + <service name="ggeopos1" promote="ggeopos1"/> + <service name="googlemap" promote="googlemap"/> + <service name="googlemap2" promote="googlemap2"/> + <service name="googlesearch" promote="googlesearch"/> + <service name="weather" promote="weather"/> + <service name="weather2" promote="weather2"/> + <service name="yahoosearch" promote="yahoosearch"/> + <component x="330" y="10" name="bingsearch" title="bing" color="pink1"> + <implementation.python script="nuvem/bsearch.py"/> + <service name="bingsearch"/> + <reference target="text10" name="query"/> + <reference name="s" visible="false"> + <binding.http uri="http://www.bing.com/search"/> + </reference> + </component> + <component x="330" y="50" name="gaddress1" title="address" color="pink1"> + <implementation.python script="nuvem/gaddress.py"/> + <service name="gaddress"/> + <reference target="text1" name="address"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.googleapis.com/maps/api/geocode/json"/> + </reference> + </component> + <component x="20" y="250" name="get" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference target="text3" name="url"/> + </component> + <component x="490" y="10" name="ggeopos1" title="geo position" color="pink1"> + <implementation.python script="nuvem/ggeopos.py"/> + <service name="ggeopos"/> + <reference target="number1" name="latitude"/> + <reference target="number4" name="longitude"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.googleapis.com/maps/api/geocode/json"/> + </reference> + </component> + <component x="310" y="100" name="googlemap" title="google map" color="pink1"> + <implementation.python script="nuvem/gmap.py"/> + <service name="googlemap"/> + <reference target="list2" name="locations"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.google.com/maps/api/staticmap"/> + </reference> + </component> + <component x="15" y="96" name="googlemap2" title="google map" color="pink1"> + <implementation.python script="nuvem/gmap.py"/> + <service name="googlemap"/> + <reference target="list3" name="locations"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.google.com/maps/api/staticmap"/> + </reference> + </component> + <component x="20" y="10" name="googlesearch" title="google" color="pink1"> + <implementation.python script="nuvem/gsearch.py"/> + <service name="googlesearch"/> + <reference target="text" name="query"/> + <reference name="s" visible="false"> + <binding.http uri="http://ajax.googleapis.com/ajax/services/search/web"/> + </reference> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list" name="value"/> + <property>A</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list24" name="value"/> + <property>A</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list25" name="value"/> + <property>B</property> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text4" name="item" clonable="true"/> + <reference target="number2" name="item" clonable="true"/> + <reference target="number3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list24" title="list2" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="text7" name="name"/> + <reference target="text5" name="value"/> + </component> + <component name="list25" title="list2" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="text8" name="name"/> + <reference target="text6" name="value"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>94070</property> + </component> + <component x="730" y="80" name="number1" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>37.507156</property> + </component> + <component name="number2" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>37.507156</property> + </component> + <component name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>-122.260526</property> + </component> + <component x="730" y="120" name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>-122.260526</property> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>apache tuscany</property> + </component> + <component x="710" y="20" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>San Carlos, CA</property> + </component> + <component name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>apache tuscany</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>94070</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://maps.google.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=14&size=512x512&maptype=roadmap%20&markers=color:blue|label:S|40.702147,-74.015794&markers=color:green|label:G|40.711614,-74.012318%20&markers=color:red|color:red|label:C|40.718217,-73.998284&sensor=false</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>green</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>San Francisco, CA</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>San Carlos, CA</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>yellow</property> + </component> + <component name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>green</property> + </component> + <component name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>apache tuscany</property> + </component> + <component x="18" y="49" name="weather" title="weather" color="pink1"> + <implementation.python script="nuvem/gweather.py"/> + <service name="weather"/> + <reference target="number" name="zip"/> + <reference name="ws" visible="false"> + <binding.http uri="http://www.google.com/ig/api"/> + </reference> + </component> + <component x="190" y="51" name="weather2" title="weather" color="pink1"> + <implementation.python script="nuvem/gweather.py"/> + <service name="weather"/> + <reference target="text2" name="zip"/> + <reference name="ws" visible="false"> + <binding.http uri="http://www.google.com/ig/api"/> + </reference> + </component> + <component x="180" y="10" name="yahoosearch" title="yahoo" color="pink1"> + <implementation.python script="nuvem/ysearch.py"/> + <service name="yahoosearch"/> + <reference target="text9" name="query"/> + <reference name="s" visible="false"> + <binding.http uri="http://search.yahooapis.com/WebSearchService/V1/webSearch"/> + </reference> + </component> + </composite> + </content> + <link href="testsearch"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/app.stats new file mode 100644 index 0000000000..23679affa8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/app.stats @@ -0,0 +1 @@ +((entry (title "Test search components") (id "testsearch") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/htdocs/app.html new file mode 100644 index 0000000000..ff52414ec8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsearch/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testsearch</title> + <id>testsearch</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Test search components</H1> + </SPAN> + </DIV> + </content> + <link href="testsearch"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/app.composite new file mode 100644 index 0000000000..ad36e93e7f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/app.composite @@ -0,0 +1,105 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testsms</title> + <id>testsms</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="item" promote="property"/> + <service name="twsms1" promote="twsms1"/> + <component x="180" y="30" name="keychain1" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name1" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="190" y="70" name="keychain3" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name3" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="190" y="100" name="keychain4" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name5" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="180" y="140" name="keychain5" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name4" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text14" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="630" y="350" name="name1" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>twiliosid</property> + </component> + <component x="780" y="320" name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>twiliotoken</property> + </component> + <component x="250" y="140" name="name4" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>tophone</property> + </component> + <component x="520" y="270" name="name5" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>fromphone</property> + </component> + <component x="180" y="170" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Hello Again!</property> + </component> + <component x="550" y="450" name="text12" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>From={0}&To={1}&Body={2}</property> + </component> + <component x="250" y="340" name="text14" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Hello there</property> + </component> + <component x="20" y="10" name="twsms1" title="sms" color="blue1"> + <implementation.python script="nuvem/twsms.py"/> + <service name="twsms"/> + <reference target="keychain1" name="sid"/> + <reference target="keychain3" name="token"/> + <reference target="keychain4" name="from"/> + <reference target="keychain5" name="to"/> + <reference target="text1" name="msg"/> + <reference name="s" wiredByImpl="true" visible="false"/> + </component> + </composite> + </content> + <link href="testsms"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/app.stats new file mode 100644 index 0000000000..f55f07105b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/app.stats @@ -0,0 +1 @@ +((entry (title "Test HTTP components") (id "testhttp") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/htdocs/app.html new file mode 100644 index 0000000000..78f52015fc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsms/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testsms</title> + <id>testsms</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Test SMS API</H1> + </SPAN> + </DIV> + </content> + <link href="testsms"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/app.composite new file mode 100644 index 0000000000..69a9ec6396 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/app.composite @@ -0,0 +1,186 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testsocial</title> + <id>testsocial</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="sendgtalk" promote="sendgtalk"/> + <service name="start" promote="start"/> + <component name="fbprofile" title="facebook profile" color="blue1"> + <implementation.python script="nuvem/fbprofile.py"/> + <service name="fbprofile"/> + <reference target="text" name="id"/> + <reference name="fb" visible="false"> + <binding.http uri="https://graph.facebook.com"/> + </reference> + </component> + <component name="format" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text7" name="pattern"/> + <reference target="list" name="values"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="twprofile" name="value"/> + <property>twitprofile</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="fbprofile" name="value"/> + <property>name</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="twtimeline" name="value"/> + <property>twittimeline</property> + </component> + <component name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="twfriends" name="value"/> + <property>twitfriends</property> + </component> + <component name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="twfollowers" name="value"/> + <property>twitfollowers</property> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="now" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference target="item4" name="item" clonable="true"/> + <reference target="item5" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="now" title="now" color="orange1"> + <implementation.python script="nuvem/now.py"/> + <service name="now"/> + </component> + <component x="20" y="210" name="sendgtalk" title="gtalk" color="blue1"> + <implementation.cpp path="lib/chat" library="libchat-sender2"/> + <service name="sendgtalk"/> + <reference target="text8" name="jid"/> + <reference target="text9" name="pass"/> + <reference target="text6" name="to"/> + <reference target="format" name="msg"/> + </component> + <component x="10" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list3" name="content"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>100001053301307</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>jsdelfino</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xmppsca.2@gmail.com</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Hello, the time is {0}</property> + </component> + <component name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xmppsca.1@gmail.com</property> + </component> + <component name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xmpp4sca</property> + </component> + <component name="twfollowers" title="twitter followers" color="blue1"> + <implementation.python script="nuvem/twfollowers.py"/> + <service name="twfollowers"/> + <reference target="text5" name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/statuses/followers.json"/> + </reference> + </component> + <component name="twfriends" title="twitter friends" color="blue1"> + <implementation.python script="nuvem/twfriends.py"/> + <service name="twfriends"/> + <reference target="text4" name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/statuses/friends.json"/> + </reference> + </component> + <component name="twprofile" title="twitter profile" color="blue1"> + <implementation.python script="nuvem/twprofile.py"/> + <service name="twprofile"/> + <reference target="text3" name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/users/show.json"/> + </reference> + </component> + <component name="twtimeline" title="twitter timeline" color="blue1"> + <implementation.python script="nuvem/twtimeline.py"/> + <service name="twtimeline"/> + <reference target="text2" name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.json"/> + </reference> + </component> + </composite> + </content> + <link href="testsocial"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/app.stats new file mode 100644 index 0000000000..e386c0528c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/app.stats @@ -0,0 +1 @@ +((entry (title "Test social components") (id "testsocial") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/htdocs/app.html new file mode 100644 index 0000000000..7c76d53162 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testsocial/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testsocial</title> + <id>testsocial</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>Test social components</H1> + </SPAN> + </DIV> + </content> + <link href="testsocial"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/app.composite new file mode 100644 index 0000000000..2ae776527b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/app.composite @@ -0,0 +1,223 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testtext</title> + <id>testtext</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="contains" promote="contains"/> + <service name="format" promote="format"/> + <service name="format2" promote="format2"/> + <service name="join" promote="join"/> + <service name="lowercase" promote="lowercase"/> + <service name="parse" promote="parse"/> + <service name="replace" promote="replace"/> + <service name="split" promote="split"/> + <service name="uppercase" promote="uppercase"/> + <component x="19" y="7" name="contains" title="contains" color="cyan1"> + <implementation.python script="nuvem/contains.py"/> + <service name="contains"/> + <reference target="text10" name="search"/> + <reference target="text9" name="string"/> + </component> + <component x="150" y="110" name="format" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text13" name="pattern"/> + <reference target="list" name="values"/> + </component> + <component x="310" y="130" name="format2" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text14" name="pattern"/> + <reference target="list3" name="values"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text17" name="value"/> + <property>a</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text18" name="value"/> + <property>b</property> + </component> + <component x="300" y="10" name="join" title="join" color="cyan1"> + <implementation.python script="nuvem/join.py"/> + <service name="join"/> + <reference target="text6" name="separator"/> + <reference target="list2" name="list"/> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text15" name="item" clonable="true"/> + <reference target="text16" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text7" name="item" clonable="true"/> + <reference target="text8" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item" name="item" clonable="true"/> + <reference target="item2" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="20" y="226" name="lowercase" title="lower" color="cyan1"> + <implementation.python script="nuvem/lowercase.py"/> + <service name="lowercase"/> + <reference target="text2" name="string"/> + </component> + <component x="150" y="230" name="parse" title="parse" color="cyan1"> + <implementation.python script="nuvem/parse.py"/> + <service name="parse"/> + <reference target="text19" name="regexp"/> + <reference target="text20" name="string"/> + </component> + <component x="150" y="10" name="replace" title="replace" color="cyan1"> + <implementation.python script="nuvem/replace.py"/> + <service name="replace"/> + <reference target="text4" name="from"/> + <reference target="text5" name="to"/> + <reference target="text3" name="string"/> + </component> + <component x="23" y="89" name="split" title="split" color="cyan1"> + <implementation.python script="nuvem/split.py"/> + <service name="split"/> + <reference target="text11" name="separator"/> + <reference target="text12" name="string"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abc</property> + </component> + <component name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>cd</property> + </component> + <component name="text11" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>x</property> + </component> + <component name="text12" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abcxdefxghi</property> + </component> + <component name="text13" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>The {0} brown {1}</property> + </component> + <component name="text14" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>The {a} brown {b}</property> + </component> + <component name="text15" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>quick</property> + </component> + <component name="text16" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>fox</property> + </component> + <component name="text17" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>quick</property> + </component> + <component name="text18" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>fox</property> + </component> + <component name="text19" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>city (.*) state (.*)</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>ABC</property> + </component> + <component name="text20" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>city San Francisco state CA</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abcxdefxghi</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>x</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>y</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>x</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abc</property> + </component> + <component name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>def</property> + </component> + <component name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abcdef</property> + </component> + <component x="20" y="172" name="uppercase" title="upper" color="cyan1"> + <implementation.python script="nuvem/uppercase.py"/> + <service name="uppercase"/> + <reference target="text" name="string"/> + </component> + </composite> + </content> + <link href="testtext"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/app.stats new file mode 100644 index 0000000000..4b06f1dbba --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/app.stats @@ -0,0 +1 @@ +((entry (title "Test text processing components") (id "testtext") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/htdocs/app.html new file mode 100644 index 0000000000..e74618df2c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testtext/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testtext</title> + <id>testtext</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test text processing components</H2> + </SPAN> + </DIV> + </content> + <link href="testtext"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/app.composite new file mode 100644 index 0000000000..caa976386a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/app.composite @@ -0,0 +1,159 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testurl</title> + <id>testurl</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="app1" promote="app1"/> + <service name="email" promote="email"/> + <service name="host" promote="host"/> + <service name="keychain1" promote="keychain1"/> + <service name="keychain2" promote="keychain2"/> + <service name="params" promote="params"/> + <service name="path" promote="path"/> + <service name="realm" promote="realm"/> + <service name="url" promote="url"/> + <service name="user" promote="user"/> + <component x="260" y="100" name="app1" title="app" color="green1"> + <implementation.python script="nuvem/app.py"/> + <service name="app"/> + <property name="app" visible="false"/> + </component> + <component x="17" y="223" name="email" title="email" color="green1"> + <implementation.python script="nuvem/email.py"/> + <service name="email"/> + <property name="email"/> + </component> + <component x="20" y="10" name="host" title="host" color="green1"> + <implementation.python script="nuvem/host.py"/> + <service name="host"/> + <property name="host"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text4" name="value"/> + <property>parmx</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text5" name="value"/> + <property>parmy</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number" name="value"/> + <property>parmn</property> + </component> + <component x="260" y="50" name="keychain1" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="text1" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="260" y="10" name="keychain2" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference target="name1" name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text2" name="item" clonable="true"/> + <reference target="text3" name="item" clonable="true"/> + <reference target="item" name="item" clonable="true"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="400" y="10" name="name1" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>key2</property> + </component> + <component name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>123</property> + </component> + <component x="16" y="91" name="params" title="?params" color="green1"> + <implementation.python script="nuvem/params.py"/> + <service name="params"/> + <property name="params"/> + </component> + <component x="20" y="50" name="path" title="path" color="green1"> + <implementation.python script="nuvem/path.py"/> + <service name="path"/> + <property name="path"/> + </component> + <component x="14" y="177" name="realm" title="realm" color="green1"> + <implementation.python script="nuvem/realm.py"/> + <service name="realm"/> + <property name="realm"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://example.com/</property> + </component> + <component x="400" y="10" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>key2</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>path</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xx</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>yy</property> + </component> + <component x="90" y="10" name="url" title="url" color="green1"> + <implementation.python script="nuvem/url.py"/> + <service name="url"/> + <reference target="text" name="address"/> + <reference target="list" name="args"/> + </component> + <component x="16" y="134" name="user" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user"/> + </component> + </composite> + </content> + <link href="testurl"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/app.stats new file mode 100644 index 0000000000..5683bd4a2a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/app.stats @@ -0,0 +1 @@ +((entry (title "Test URL components") (id "testurl") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/htdocs/app.html new file mode 100644 index 0000000000..4c2534a325 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testurl/htdocs/app.html @@ -0,0 +1,31 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testurl</title> + <id>testurl</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test url components</H2> + </SPAN> + </DIV> + </content> + <link href="testurl"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/app.composite new file mode 100644 index 0000000000..74fff1f91f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/app.composite @@ -0,0 +1,498 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testvalues</title> + <id>testvalues</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="empty" promote="empty"/> + <service name="false" promote="false"/> + <service name="first" promote="first"/> + <service name="itemnb" promote="itemnb"/> + <service name="list8" promote="list8"/> + <service name="list9" promote="list9"/> + <service name="name" promote="name"/> + <service name="nothing" promote="nothing"/> + <service name="reduce2" promote="reduce2"/> + <service name="rest" promote="rest"/> + <service name="second" promote="second"/> + <service name="shuffle" promote="shuffle"/> + <service name="start" promote="start"/> + <service name="true" promote="true"/> + <service name="values" promote="values"/> + <service name="values2" promote="values2"/> + <component name="add" title="+" color="cyan1"> + <implementation.python script="nuvem/add.py"/> + <service name="add"> + <documentation>+</documentation> + </service> + <reference target="valueof2" name="value1"/> + <reference target="valueof3" name="value2"/> + </component> + <component x="17" y="269" name="empty" title="empty" color="yellow1"> + <implementation.python script="nuvem/empty.py"/> + <service name="empty"/> + </component> + <component x="21" y="170" name="false" title="false" color="orange1"> + <implementation.python script="nuvem/false_.py"/> + <service name="false"/> + </component> + <component x="110" y="10" name="first" title="first" color="yellow1"> + <implementation.python script="nuvem/first.py"/> + <service name="first"/> + <reference target="list7" name="list"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text3" name="value"/> + <property>a</property> + </component> + <component name="item10" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list6" name="value"/> + <property>a</property> + </component> + <component name="item11" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text7" name="value"/> + <property>entry</property> + </component> + <component name="item12" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list10" name="value"/> + <property>entry</property> + </component> + <component name="item13" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text9" name="value"/> + <property>test</property> + </component> + <component name="item14" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text10" name="value"/> + <property>d</property> + </component> + <component name="item15" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text11" name="value"/> + <property>x</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text4" name="value"/> + <property>d</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text5" name="value"/> + <property>ccc</property> + </component> + <component name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text2" name="value"/> + <property>b</property> + </component> + <component name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text8" name="value"/> + <property>c</property> + </component> + <component name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number11" name="value"/> + <property>c</property> + </component> + <component name="item7" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text6" name="value"/> + <property>b</property> + </component> + <component name="item8" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list4" name="value"/> + <property>a</property> + </component> + <component name="item9" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list5" name="value"/> + <property>x</property> + </component> + <component x="110" y="100" name="itemnb" title="item #" color="yellow1"> + <implementation.python script="nuvem/itemnb.py"/> + <service name="itemnb"/> + <reference target="number8" name="index"/> + <reference target="map" name="list"/> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="number" name="item" clonable="true"/> + <reference target="number7" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list10" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item13" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item" name="item" clonable="true"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item14" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item10" name="item" clonable="true"/> + <reference target="item9" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list4" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item7" name="item" clonable="true"/> + <reference target="item6" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list5" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item8" name="item" clonable="true"/> + <reference target="item5" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list6" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item3" name="item" clonable="true"/> + <reference target="item4" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list7" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="number2" name="item" clonable="true"/> + <reference target="number3" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="357" y="208" name="list8" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item11" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="268" y="279" name="list9" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item12" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="lookup" title="lookup" color="yellow1"> + <implementation.python script="nuvem/lookup.py"/> + <service name="lookup"/> + <reference target="name3" name="name"/> + <reference target="list2" name="list"/> + </component> + <component name="map" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference target="name2" name="item"/> + <reference target="multiply" name="transform"/> + <reference target="reverse" name="list"/> + </component> + <component name="multiply" title="*" color="cyan1"> + <implementation.python script="nuvem/multiply.py"/> + <service name="multiply"> + <documentation>*</documentation> + </service> + <reference target="valueof" name="value1"/> + <reference target="number6" name="value2"/> + </component> + <component x="21" y="70" name="name" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>abc</property> + </component> + <component name="name2" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>nb</property> + </component> + <component name="name3" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>d</property> + </component> + <component name="name6" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>sum</property> + </component> + <component name="name7" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>i</property> + </component> + <component name="name8" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>a.b</property> + </component> + <component x="19" y="219" name="nothing" title="nothing" color="orange1"> + <implementation.python script="nuvem/nothing.py"/> + <service name="nothing"/> + </component> + <component name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>12</property> + </component> + <component name="number10" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>10</property> + </component> + <component name="number11" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>123</property> + </component> + <component name="number12" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component name="number13" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>10</property> + </component> + <component name="number14" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component name="number2" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>123</property> + </component> + <component name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>456</property> + </component> + <component name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component name="number5" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>10</property> + </component> + <component name="number6" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>2</property> + </component> + <component name="number7" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>34</property> + </component> + <component name="number8" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>3</property> + </component> + <component name="number9" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>0</property> + </component> + <component name="range" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference target="number4" name="first"/> + <reference target="number5" name="last"/> + </component> + <component name="range2" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference target="number9" name="first"/> + <reference target="number10" name="last"/> + </component> + <component name="range3" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference target="number12" name="first"/> + <reference target="number13" name="last"/> + </component> + <component x="360" y="10" name="reduce2" title="reduce" color="yellow1"> + <implementation.python script="nuvem/reduce_.py"/> + <service name="reduce"/> + <reference target="name6" name="item"/> + <reference target="name7" name="accum"/> + <reference target="add" name="transform"/> + <reference target="number14" name="init"/> + <reference target="range2" name="list"/> + </component> + <component x="240" y="10" name="rest" title="rest" color="yellow1"> + <implementation.python script="nuvem/rest.py"/> + <service name="rest"/> + <reference target="list" name="list"/> + </component> + <component name="reverse" title="reverse" color="yellow1"> + <implementation.python script="nuvem/reverse.py"/> + <service name="reverse"/> + <reference target="range" name="list"/> + </component> + <component x="830" y="170" name="second" title="second" color="yellow1"> + <implementation.python script="nuvem/second.py"/> + <service name="second"/> + <reference target="item15" name="list"/> + </component> + <component name="select" title="select" color="yellow1"> + <implementation.python script="nuvem/select.py"/> + <service name="select"/> + <reference target="name8" name="path"/> + <reference target="list3" name="list"/> + </component> + <component x="110" y="290" name="shuffle" title="shuffle" color="yellow1"> + <implementation.python script="nuvem/shuffle_.py"/> + <service name="shuffle"/> + <reference target="range3" name="list"/> + </component> + <component x="15" y="11" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="text" name="content"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xyz</property> + </component> + <component name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>xyz</property> + </component> + <component name="text11" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>y</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>bbb</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abc</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>def</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>ccc</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>BBB</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>hello</property> + </component> + <component name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>CCC</property> + </component> + <component name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>abc</property> + </component> + <component x="23" y="120" name="true" title="true" color="orange1"> + <implementation.python script="nuvem/true_.py"/> + <service name="true"/> + </component> + <component name="valueof" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>nb</property> + </component> + <component name="valueof2" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>sum</property> + </component> + <component name="valueof3" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>i</property> + </component> + <component x="830" y="10" name="values" title="values" color="yellow1"> + <implementation.python script="nuvem/values.py"/> + <service name="values"/> + <reference target="lookup" name="list"/> + </component> + <component x="530" y="10" name="values2" title="values" color="yellow1"> + <implementation.python script="nuvem/values.py"/> + <service name="values"/> + <reference target="select" name="list"/> + </component> + </composite> + </content> + <link href="testvalues"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/app.stats new file mode 100644 index 0000000000..88f63235f8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/app.stats @@ -0,0 +1 @@ +((entry (title "Test values and lists") (id "testvalues") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/htdocs/app.html new file mode 100644 index 0000000000..80f6f622f9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testvalues/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testvalues</title> + <id>testvalues</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test values and lists</H2> + </SPAN> + <SPAN id="value" class="text" style="position: absolute; top: 36px; left: 29px; "> + <SPAN>=value</SPAN> + </SPAN> + </DIV> + </content> + <link href="testvalues"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/app.composite new file mode 100644 index 0000000000..d334b152bd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/app.composite @@ -0,0 +1,196 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testwidgets</title> + <id>testwidgets</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="start" promote="start"/> + <component x="170" y="330" name="htattrs1" title="html attrs:" color="cyan1"> + <implementation.python script="nuvem/htattrs.py"/> + <service name="htattrs"/> + <reference target="list2" name="value"/> + </component> + <component name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text9" name="value"/> + <property>testpath2</property> + </component> + <component x="100" y="340" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htattrs1" name="value"/> + <property>testattrs</property> + </component> + <component name="item10" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text" name="value"/> + <property>testh1</property> + </component> + <component x="270" y="370" name="item11" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text10" name="value"/> + <property>onclick</property> + </component> + <component x="280" y="330" name="item12" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text1" name="value"/> + <property>value</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="item" name="value"/> + <property>testpath1</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text6" name="value"/> + <property>testimg</property> + </component> + <component name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text8" name="value"/> + <property>testtext</property> + </component> + <component name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text4" name="value"/> + <property>testlink</property> + </component> + <component name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text5" name="value"/> + <property>testcheckbox</property> + </component> + <component name="item7" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text3" name="value"/> + <property>testentry</property> + </component> + <component name="item8" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text2" name="value"/> + <property>testbutton</property> + </component> + <component name="item9" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text7" name="value"/> + <property>testsection</property> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item10" name="item" clonable="true"/> + <reference target="item9" name="item" clonable="true"/> + <reference target="item8" name="item" clonable="true"/> + <reference target="item7" name="item" clonable="true"/> + <reference target="item6" name="item" clonable="true"/> + <reference target="item5" name="item" clonable="true"/> + <reference target="item4" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item1" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item12" name="item" clonable="true"/> + <reference target="item11" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="17" y="3" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list" name="content"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test header 1</property> + </component> + <component x="320" y="340" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test html attrs</property> + </component> + <component x="370" y="370" name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>alert('hey')</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test button</property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test entry field</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://tuscany.apache.org</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test checkbox</property> + </component> + <component name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://tuscany.apache.org/images/TuscanyLogo.jpg</property> + </component> + <component name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test section</property> + </component> + <component name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test text</property> + </component> + <component name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test path</property> + </component> + </composite> + </content> + <link href="testwidgets"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/app.stats new file mode 100644 index 0000000000..f9a11815a5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/app.stats @@ -0,0 +1 @@ +((entry (title "Test widgets") (id "testwidgets") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/htdocs/app.html new file mode 100644 index 0000000000..857b6bfad3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets/htdocs/app.html @@ -0,0 +1,61 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testwidgets</title> + <id>testwidgets</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="testh1" class="h1" style="position: absolute; top: 9px; left: 11px; "> + <H1>=testh1</H1> + </SPAN> + <SPAN id="testsection" class="section" style="position: absolute; top: 45px; width: 100%; left: 11px; "> + <SPAN>=testsection</SPAN> + </SPAN> + <SPAN id="testimg" class="img" style="position: absolute; top: 90px; left: 263px; "> + <IMG src="/public/img.png"/> + </SPAN> + <SPAN id="testbutton" class="button" style="position: absolute; top: 99px; left: 11px; "> + <INPUT type="button" value="=testbutton" class="graybutton"/> + </SPAN> + <SPAN id="testentry" class="entry" style="position: absolute; top: 144px; left: 11px; "> + <INPUT type="text" value="=testentry" size="20" autocapitalize="off"/> + </SPAN> + <SPAN id="testcheckbox" class="checkbox" style="position: absolute; top: 180px; left: 11px; "> + <INPUT type="checkbox" value="=testcheckbox"/> + <SPAN>=testcheckbox</SPAN> + </SPAN> + <SPAN id="testlink" class="link" style="position: absolute; top: 216px; left: 11px; "> + <A href="=testlink"> + <SPAN>=testlink</SPAN> + </A> + </SPAN> + <SPAN id="testattrs" class="text" style="position: absolute; top: 216px; left: 272px; "> + <SPAN>=testattrs</SPAN> + </SPAN> + <SPAN id="testtext" class="text" style="position: absolute; top: 243px; left: 11px; "> + <SPAN>=testtext</SPAN> + </SPAN> + <SPAN id="testpath1.testpath2" class="text" style="position: absolute; top: 270px; left: 11px; "> + <SPAN>=testpath1.testpath2</SPAN> + </SPAN> + </DIV> + </content> + <link href="testwidgets"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/app.composite new file mode 100644 index 0000000000..200da5e6fb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/app.composite @@ -0,0 +1,154 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testwidgets2</title> + <id>testwidgets2</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="start" promote="start"/> + <component x="100" y="310" name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text5" name="value"/> + <property>testframe</property> + </component> + <component x="100" y="290" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text1" name="value"/> + <property>testselect</property> + </component> + <component name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list3" name="value"/> + <property>testlink</property> + </component> + <component name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text2" name="value"/> + <property>testhtml</property> + </component> + <component name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text" name="value"/> + <property>testlist1</property> + </component> + <component name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="list4" name="value"/> + <property>testlist2</property> + </component> + <component name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number3" name="value"/> + <property>a</property> + </component> + <component name="item7" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="number4" name="value"/> + <property>b</property> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item4" name="item" clonable="true"/> + <reference target="item5" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference target="item2" name="item" clonable="true"/> + <reference target="item1" name="item" clonable="true"/> + <reference target="item" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="text3" name="item" clonable="true"/> + <reference target="text4" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list4" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item6" name="item" clonable="true"/> + <reference target="item7" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="number3" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>1</property> + </component> + <component name="number4" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>2</property> + </component> + <component x="13" y="8" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list" name="content"/> + </component> + <component name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test value</property> + </component> + <component x="170" y="280" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>test select</property> + </component> + <component name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property><b>test bold text</b></property> + </component> + <component name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://www.apache.org/</property> + </component> + <component name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Apache</property> + </component> + <component name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://www.cnn.com</property> + </component> + <component x="760" y="170" name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>dynamic checkbox</property> + </component> + </composite> + </content> + <link href="testwidgets2"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/app.stats new file mode 100644 index 0000000000..e375415f6f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/app.stats @@ -0,0 +1 @@ +((entry (title "Test more widgets") (id "testwidgets2") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/htdocs/app.html new file mode 100644 index 0000000000..06274d38b0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets2/htdocs/app.html @@ -0,0 +1,93 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testwidgets2</title> + <id>testwidgets2</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test widget components</H2> + </SPAN> + <SPAN id="testlist1" class="table" style="position: absolute; top: 36px; width: 100%; left: 20px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=testlist1</TD> + <TD>...</TD> + </TR> + <TR> + <TD>...</TD> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + <SPAN id="testlist2" class="table" style="position: absolute; top: 90px; width: 100%; left: 20px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=testlist2</TD> + <TD>...</TD> + </TR> + <TR> + <TD>...</TD> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + <SPAN id="b" class="table" style="position: absolute; top: 171px; width: 100%; left: 20px; "> + <TABLE class="datatable" style="width: 100%; "> + <TBODY> + <TR> + <TD>=b</TD> + <TD>...</TD> + </TR> + <TR> + <TD>...</TD> + <TD>...</TD> + </TR> + </TBODY> + </TABLE> + </SPAN> + <SPAN id="testhtml" class="text" style="position: absolute; top: 234px; left: 20px; "> + <SPAN>=testhtml</SPAN> + </SPAN> + <SPAN id="testselect" class="select" style="position: absolute; top: 234px; left: 155px; "> + <SELECT> + <OPTION>=testselect</OPTION> + </SELECT> + </SPAN> + <SPAN id="testlink" class="link" style="position: absolute; top: 270px; left: 20px; "> + <A href="=testlink"> + <SPAN>=testlink</SPAN> + </A> + </SPAN> + <SPAN id="testframe" class="iframe" style="position: absolute; top: 306px; left: 20px; "> + <A href="/public/iframe.html"> + <SPAN class="fakeframe"> + <SPAN>frame ...</SPAN> + </SPAN> + </A> + </SPAN> + </DIV> + </content> + <link href="testwidgets2"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/app.composite new file mode 100644 index 0000000000..5e5739c3ff --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/app.composite @@ -0,0 +1,213 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testwidgets3</title> + <id>testwidgets3</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="start" promote="start"/> + <component x="260" y="220" name="htattrs1" title="html attrs:" color="cyan1"> + <implementation.python script="nuvem/htattrs.py"/> + <service name="htattrs"/> + <reference target="list1" name="value"/> + </component> + <component x="190" y="80" name="htbutton1" title="html button" color="cyan1"> + <implementation.python script="nuvem/htbutton.py"/> + <service name="htbutton"/> + <reference target="text8" name="value"/> + </component> + <component x="210" y="180" name="htcheck1" title="html checkbox" color="cyan1"> + <implementation.python script="nuvem/htcheck.py"/> + <service name="htcheck"/> + <reference target="text9" name="value"/> + </component> + <component x="180" y="10" name="htimg1" title="html img" color="cyan1"> + <implementation.python script="nuvem/htimg.py"/> + <service name="htimg"/> + <reference target="text1" name="value"/> + </component> + <component x="190" y="230" name="htimg2" title="html img" color="cyan1"> + <implementation.python script="nuvem/htimg.py"/> + <service name="htimg"/> + <reference target="htattrs1" name="value"/> + </component> + <component x="180" y="50" name="htlink1" title="html link" color="cyan1"> + <implementation.python script="nuvem/htlink.py"/> + <service name="htlink"/> + <reference target="list21" name="value"/> + </component> + <component x="400" y="330" name="htstyle1" title="html style" color="cyan1"> + <implementation.python script="nuvem/htstyle.py"/> + <service name="htstyle"/> + <reference target="list2" name="value"/> + </component> + <component x="100" y="10" name="item1" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htimg1" name="value"/> + <property>testdynimg</property> + </component> + <component x="100" y="170" name="item10" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htcheck1" name="value"/> + <property>testdyncheckbox</property> + </component> + <component x="110" y="230" name="item2" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htimg2" name="value"/> + <property>teststyledimg</property> + </component> + <component x="400" y="300" name="item3" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text3" name="value"/> + <property>onclick</property> + </component> + <component x="510" y="290" name="item4" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text4" name="value"/> + <property>width</property> + </component> + <component x="510" y="320" name="item5" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text5" name="value"/> + <property>height</property> + </component> + <component x="400" y="220" name="item6" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text10" name="value"/> + <property>id</property> + </component> + <component x="400" y="260" name="item7" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="text2" name="value"/> + <property>src</property> + </component> + <component x="90" y="50" name="item8" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htlink1" name="value"/> + <property>testdynlink</property> + </component> + <component x="90" y="120" name="item9" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference target="htbutton1" name="value"/> + <property>testdynbutton</property> + </component> + <component name="list" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item1" name="item" clonable="true"/> + <reference target="item8" name="item" clonable="true"/> + <reference target="item9" name="item" clonable="true"/> + <reference target="item10" name="item" clonable="true"/> + <reference target="item2" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list1" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item6" name="item" clonable="true"/> + <reference target="item7" name="item" clonable="true"/> + <reference target="item3" name="item" clonable="true"/> + <reference target="htstyle1" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="item4" name="item" clonable="true"/> + <reference target="item5" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="240" y="50" name="list21" title="list2" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="text6" name="name"/> + <reference target="text7" name="value"/> + </component> + <component x="20" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference target="list" name="content"/> + </component> + <component x="240" y="10" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://tuscany.apache.org/images/TuscanyLogo.jpg</property> + </component> + <component x="430" y="220" name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>testimg</property> + </component> + <component x="440" y="260" name="text2" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://tuscany.apache.org/images/TuscanyLogo.jpg</property> + </component> + <component x="430" y="250" name="text3" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>alert('hey')</property> + </component> + <component x="560" y="280" name="text4" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>320px</property> + </component> + <component x="560" y="320" name="text5" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>60px</property> + </component> + <component x="280" y="50" name="text6" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>http://www.apache.org/</property> + </component> + <component x="280" y="80" name="text7" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>Apache</property> + </component> + <component x="270" y="80" name="text8" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>dynamic button</property> + </component> + <component x="300" y="180" name="text9" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>dynamic checkbox</property> + </component> + </composite> + </content> + <link href="testwidgets3"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/app.stats new file mode 100644 index 0000000000..d08847ca3d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/app.stats @@ -0,0 +1 @@ +((entry (title "Test HTML generator components") (id "testwidgets3") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/htdocs/app.html new file mode 100644 index 0000000000..94018e994c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/testwidgets3/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">testwidgets3</title> + <id>testwidgets3</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h2" class="h2" style="position: absolute; top: 0px; left: 2px; "> + <H2>Test widget components</H2> + </SPAN> + <SPAN id="testdynimg" class="text" style="position: absolute; top: 36px; left: 2px; "> + <SPAN>=testdynimg</SPAN> + </SPAN> + <SPAN id="testdynlink" class="text" style="position: absolute; top: 135px; left: 2px; "> + <SPAN>=testdynlink</SPAN> + </SPAN> + <SPAN id="testdynbutton" class="text" style="position: absolute; top: 171px; left: 2px; "> + <SPAN>=testdynbutton</SPAN> + </SPAN> + <SPAN id="testdyncheckbox" class="text" style="position: absolute; top: 207px; left: 2px; "> + <SPAN>=testdyncheckbox</SPAN> + </SPAN> + <SPAN id="teststyledimg" class="text" style="position: absolute; top: 243px; left: 2px; "> + <SPAN>=teststyledimg</SPAN> + </SPAN> + </DIV> + </content> + <link href="testwidgets3"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/app.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/app.composite new file mode 100644 index 0000000000..e8b2e27584 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/app.composite @@ -0,0 +1,137 @@ +<?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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">twsms</title> + <id>twsms</id> + <content type="application/xml"> + <composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" name="app" targetNamespace="http://app"> + <service name="item" promote="property"/> + <service name="send" promote="send"/> + <component x="280" y="260" name="format2" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text12" name="pattern"/> + <reference target="list31" name="values"/> + </component> + <component x="100" y="10" name="format4" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference target="text1" name="pattern"/> + <reference target="list6" name="values"/> + </component> + <component x="180" y="330" name="list11" title="list" color="yellow1"> + <implementation.python script="nuvem/single.py"/> + <service name="list1"/> + <reference target="format2" name="value"/> + </component> + <component x="110" y="180" name="list21" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference target="text15" name="first"/> + <reference target="list11" name="second"/> + </component> + <component x="410" y="310" name="list31" title="list" color="yellow1"> + <implementation.python script="nuvem/triple.py"/> + <service name="list3"/> + <reference target="param4" name="first"/> + <reference target="param5" name="second"/> + <reference target="param6" name="third"/> + </component> + <component name="list6" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference target="param1" name="item" clonable="true"/> + <reference target="param3" name="item" clonable="true"/> + <reference target="param2" name="item" clonable="true"/> + <reference target="text10" name="item" clonable="true"/> + <reference name="item" clonable="true"/> + </component> + <component x="480" y="200" name="param1" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>sid</property> + <property name="query" visible="false"/> + </component> + <component x="480" y="250" name="param2" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>sid</property> + <property name="query" visible="false"/> + </component> + <component x="490" y="220" name="param3" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>token</property> + <property name="query" visible="false"/> + </component> + <component x="430" y="310" name="param4" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>from</property> + <property name="query" visible="false"/> + </component> + <component x="430" y="330" name="param5" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>to</property> + <property name="query" visible="false"/> + </component> + <component x="440" y="370" name="param6" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>msg</property> + <property name="query" visible="false"/> + </component> + <component x="80" y="10" name="post1" title="post" color="green1"> + <implementation.cpp path="lib/http" library="libhttppost"/> + <service name="post"/> + <property name="timeout" visible="false"/> + <reference target="format4" name="url"/> + <reference target="list21" name="content"/> + </component> + <component x="10" y="10" name="send" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference target="post1" name="content"/> + </component> + <component x="430" y="80" name="text1" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>https://{0}:{1}@api.twilio.com/2010-04-01/Accounts/{2}/SMS/Messages</property> + </component> + <component x="490" y="270" name="text10" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>SMS/Messages</property> + </component> + <component x="410" y="280" name="text12" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>From={0}&To={1}&Body={2}</property> + </component> + <component x="180" y="300" name="text15" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>application/x-www-form-urlencoded</property> + </component> + </composite> + </content> + <link href="twsms"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/app.stats b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/app.stats new file mode 100644 index 0000000000..4a0584174c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/app.stats @@ -0,0 +1 @@ +((entry (title "SMS send service") (id "twsms") (author "admin@example.com") (updated "Jan 01, 2012") (content (stats (description "Sample app"))))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/htdocs/app.html b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/htdocs/app.html new file mode 100644 index 0000000000..66addc1a1a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/apps/twsms/htdocs/app.html @@ -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. +--> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">twsms</title> + <id>twsms</id> + <content type="application/xml"> + <DIV id="page"> + <SPAN id="page:h1" class="h1" style="position: absolute; top: 0px; left: 2px; "> + <H1>SMS Send Service</H1> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 36px; left: 2px; "> + <SPAN>To send an SMS use a URL like this:</SPAN> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 63px; left: 2px; "> + <SPAN>http://twsms..../?sid=...&token=...&from=...</SPAN> + </SPAN> + <SPAN id="page:text" class="text" style="position: absolute; top: 81px; left: 2px; "> + <SPAN>&to=...&msg=...</SPAN> + </SPAN> + </DIV> + </content> + <link href="twsms"/> +</entry> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/jane@example.com/user.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/jane@example.com/user.apps new file mode 100644 index 0000000000..6126c4b88c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/jane@example.com/user.apps @@ -0,0 +1 @@ +((feed (title "Your Apps") (id "jane@example.com") (entry (title "An empty test app") (id "test")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/jane@localhost/user.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/jane@localhost/user.apps new file mode 100644 index 0000000000..c62dbfb6b8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/jane@localhost/user.apps @@ -0,0 +1 @@ +((feed (title "Your Apps") (id "jane@localhost") (entry (title "An empty test app") (id "test")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/john@example.com/user.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/john@example.com/user.apps new file mode 100644 index 0000000000..bc4d3f64fa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/john@example.com/user.apps @@ -0,0 +1 @@ +((feed (title "Your Apps") (id "john@example.com") (entry (title "An empty test app") (id "test")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/john@localhost/user.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/john@localhost/user.apps new file mode 100644 index 0000000000..ee20c1c2c5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/dashboards/john@localhost/user.apps @@ -0,0 +1 @@ +((feed (title "Your Apps") (id "john@localhost") (entry (title "An empty test app") (id "test")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/animation/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/animation/palette.composite new file mode 100644 index 0000000000..75cbf497b6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/animation/palette.composite @@ -0,0 +1,103 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="frames" promote="frames"/> + <service name="htattrs" promote="htattrs"/> + <service name="htbutton" promote="htbutton"/> + <service name="htcheck" promote="htcheck"/> + <service name="htimg" promote="htimg"/> + <service name="htinline" promote="htinline"/> + <service name="htlink" promote="htlink"/> + <service name="htstyle" promote="htstyle"/> + <service name="left" promote="left"/> + <service name="pixels" promote="pixels"/> + <service name="top" promote="top"/> + <service name="transform" promote="transform"/> + <service name="transition" promote="transition"/> + <component x="170" y="160" name="frames" title="frames" color="white1"> + <implementation.python script="nuvem/frames.py"/> + <service name="frames"/> + <reference name="msec"/> + <reference name="loop"/> + <reference name="content"/> + </component> + <component x="140" y="60" name="htattrs" title="attrs:" color="white1"> + <implementation.python script="nuvem/htattrs.py"/> + <service name="htattrs"/> + <reference name="value"/> + </component> + <component x="130" y="10" name="htbutton" title="button" color="white1"> + <implementation.python script="nuvem/htbutton.py"/> + <service name="htbutton"/> + <reference name="value"/> + </component> + <component x="250" y="10" name="htcheck" title="checkbox" color="white1"> + <implementation.python script="nuvem/htcheck.py"/> + <service name="htcheck"/> + <reference name="value"/> + </component> + <component x="80" y="10" name="htimg" title="img" color="white1"> + <implementation.python script="nuvem/htimg.py"/> + <service name="htimg"/> + <reference name="value"/> + </component> + <component x="80" y="60" name="htinline" title="inline" color="white1"> + <implementation.python script="nuvem/htinline.py"/> + <service name="htinline"/> + <reference name="value"/> + </component> + <component x="200" y="10" name="htlink" title="link" color="white1"> + <implementation.python script="nuvem/htlink.py"/> + <service name="htlink"/> + <reference name="value"/> + </component> + <component x="200" y="60" name="htstyle" title="style" color="white1"> + <implementation.python script="nuvem/htstyle.py"/> + <service name="htstyle"/> + <reference name="value"/> + </component> + <component x="230" y="110" name="left" title="left" color="white1"> + <implementation.python script="nuvem/left.py"/> + <service name="left"/> + <reference name="value"/> + </component> + <component x="260" y="60" name="pixels" title="pixels" color="white1"> + <implementation.python script="nuvem/pixels.py"/> + <service name="pixels"/> + <reference name="value"/> + </component> + <component x="170" y="110" name="top" title="top" color="white1"> + <implementation.python script="nuvem/top.py"/> + <service name="top"/> + <reference name="value"/> + </component> + <component x="80" y="160" name="transform" title="transform" color="white1"> + <implementation.python script="nuvem/transform.py"/> + <service name="transform"/> + <reference name="x"/> + <reference name="y"/> + <reference name="d"/> + </component> + <component x="80" y="110" name="transition" title="transition" color="white1"> + <implementation.python script="nuvem/transition.py"/> + <service name="transition"/> + <reference name="value"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/control/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/control/palette.composite new file mode 100644 index 0000000000..f89cae2c5d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/control/palette.composite @@ -0,0 +1,86 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="animation" promote="animation"/> + <service name="call" promote="call"/> + <service name="location" promote="location"/> + <service name="schedule" promote="schedule"/> + <service name="service" promote="service"/> + <service name="start" promote="start"/> + <service name="stop" promote="stop"/> + <service name="timer" promote="timer"/> + <component x="160" y="60" name="animation" title="animation" color="green1"> + <implementation.python script="nuvem/animation.py"/> + <service name="animation" visible="false"> + <binding.http uri="animation"/> + </service> + <reference name="n"/> + <reference name="loop"/> + <reference name="content"/> + </component> + <component x="190" y="10" name="call" title="call" color="green1"> + <implementation.python script="nuvem/call.py"/> + <service name="call"/> + <reference name="name"/> + <reference name="proxy" wiredByImpl="true" visible="false"/> + </component> + <component x="80" y="60" name="location" title="location" color="green1"> + <implementation.python script="nuvem/location.py"/> + <service name="location" visible="false"> + <binding.http uri="location"/> + </service> + <reference name="content"/> + </component> + <component x="240" y="60" name="schedule" title="schedule" color="green1"> + <implementation.python script="nuvem/schedule.py"/> + <service name="schedule" visible="false"> + <binding.http uri="schedule"/> + </service> + <reference name="n"/> + <reference name="content"/> + </component> + <component x="240" y="10" name="service" title="{compname}" color="green1"> + <implementation.python script="nuvem/service.py"/> + <service name="service" visible="false"/> + <reference name="content"/> + </component> + <component x="80" y="10" name="start" title="start" color="green1"> + <implementation.python script="nuvem/start.py"/> + <service name="start" visible="false"> + <binding.http uri="start"/> + </service> + <reference name="content"/> + </component> + <component x="130" y="10" name="stop" title="stop" color="green1"> + <implementation.python script="nuvem/stop.py"/> + <service name="stop" visible="false"> + <binding.http uri="stop"/> + </service> + <reference name="content"/> + </component> + <component x="80" y="110" name="timer" title="timer" color="green1"> + <implementation.python script="nuvem/timer.py"/> + <service name="timer" visible="false"> + <binding.http uri="timer"/> + </service> + <reference name="n"/> + <reference name="content"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/database/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/database/palette.composite new file mode 100644 index 0000000000..926fb3fa14 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/database/palette.composite @@ -0,0 +1,72 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="delete" promote="delete"/> + <service name="filedb" promote="filedb"/> + <service name="get" promote="get"/> + <service name="nosqldb" promote="nosqldb"/> + <service name="post" promote="post"/> + <service name="put" promote="put"/> + <service name="sqldb" promote="sqldb"/> + <component x="270" y="60" name="delete" title="delete" color="pink1"> + <implementation.python script="nuvem/delete.py"/> + <service name="delete"/> + <reference name="collection"/> + <reference name="id"/> + </component> + <component x="80" y="10" name="filedb" title="file" color="pink1"> + <implementation.python script="nuvem/filedb.py"/> + <service name="filedb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="80" y="60" name="get" title="get" color="pink1"> + <implementation.python script="nuvem/get.py"/> + <service name="get"/> + <reference name="collection"/> + <reference name="id"/> + </component> + <component x="140" y="10" name="nosqldb" title="index **" color="pink1"> + <implementation.python script="nuvem/nosqldb.py"/> + <service name="nosqldb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> + <component x="200" y="60" name="post" title="post" color="pink1"> + <implementation.python script="nuvem/post.py"/> + <service name="post"/> + <reference name="collection"/> + <reference name="id"/> + <reference name="value"/> + </component> + <component x="140" y="60" name="put" title="put" color="pink1"> + <implementation.python script="nuvem/put.py"/> + <service name="put"/> + <reference name="collection"/> + <reference name="id"/> + <reference name="value"/> + </component> + <component x="210" y="10" name="sqldb" title="sql **" color="pink1"> + <implementation.python script="nuvem/sqldb.py"/> + <service name="sqldb"/> + <reference name="db" target="Cache" visible="false"/> + <property name="host" visible="false"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/http/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/http/palette.composite new file mode 100644 index 0000000000..f4d0c2bdf5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/http/palette.composite @@ -0,0 +1,116 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="app" promote="app"/> + <service name="delete" promote="delete"/> + <service name="email" promote="email"/> + <service name="get" promote="get"/> + <service name="host" promote="host"/> + <service name="keychain" promote="keychain"/> + <service name="param" promote="param"/> + <service name="params" promote="params"/> + <service name="patch" promote="patch"/> + <service name="path" promote="path"/> + <service name="post" promote="post"/> + <service name="put" promote="put"/> + <service name="url" promote="url"/> + <service name="user" promote="user"/> + <component x="80" y="10" name="app" title="app" color="green1"> + <implementation.python script="nuvem/app.py"/> + <service name="app"/> + <property name="app" visible="false"/> + </component> + <component x="80" y="220" name="delete" title="delete" color="green1"> + <implementation.cpp path="lib/http" library="libhttpdelete"/> + <service name="delete"/> + <property name="timeout" visible="false"/> + <reference name="url"/> + </component> + <component x="140" y="110" name="email" title="email" color="green1"> + <implementation.python script="nuvem/email.py"/> + <service name="email"/> + <property name="email" visible="false"/> + </component> + <component x="80" y="170" name="get" title="get" color="green1"> + <implementation.cpp path="lib/http" library="libhttpget"/> + <service name="get"/> + <property name="timeout" visible="false"/> + <reference name="url"/> + </component> + <component x="130" y="10" name="host" title="host" color="green1"> + <implementation.python script="nuvem/host.py"/> + <service name="host"/> + <property name="host" visible="false"/> + </component> + <component x="210" y="110" name="keychain" title="keychain" color="green1"> + <implementation.python script="nuvem/keychain.py"/> + <service name="keychain"/> + <reference name="name"/> + <reference name="account" target="Accounts" visible="false"/> + </component> + <component x="150" y="60" name="param" title="?param" color="green1"> + <implementation.python script="nuvem/param.py"/> + <service name="param"/> + <property>x</property> + <property name="query" visible="false"/> + </component> + <component x="80" y="60" name="params" title="?params" color="green1"> + <implementation.python script="nuvem/params.py"/> + <service name="params"/> + <property name="query" visible="false"/> + </component> + <component x="260" y="170" name="patch" title="patch" color="green1"> + <implementation.cpp path="lib/http" library="libhttppatch"/> + <service name="patch"/> + <property name="timeout" visible="false"/> + <reference name="url"/> + <reference name="content"/> + </component> + <component x="190" y="10" name="path" title="path" color="green1"> + <implementation.python script="nuvem/path.py"/> + <service name="path"/> + <property name="path" visible="false"/> + </component> + <component x="200" y="170" name="post" title="post" color="green1"> + <implementation.cpp path="lib/http" library="libhttppost"/> + <service name="post"/> + <property name="timeout" visible="false"/> + <reference name="url"/> + <reference name="content"/> + </component> + <component x="140" y="170" name="put" title="put" color="green1"> + <implementation.cpp path="lib/http" library="libhttpput"/> + <service name="put"/> + <property name="timeout" visible="false"/> + <reference name="url"/> + <reference name="content"/> + </component> + <component x="250" y="10" name="url" title="url" color="green1"> + <implementation.python script="nuvem/url.py"/> + <service name="url"/> + <reference name="address"/> + <reference name="args"/> + </component> + <component x="80" y="110" name="user" title="user" color="green1"> + <implementation.python script="nuvem/user.py"/> + <service name="user"/> + <property name="user" visible="false"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/lists/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/lists/palette.composite new file mode 100644 index 0000000000..2f4051d7b9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/lists/palette.composite @@ -0,0 +1,131 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="append" promote="append"/> + <service name="empty" promote="empty"/> + <service name="first" promote="first"/> + <service name="insert" promote="insert"/> + <service name="itemnb" promote="itemnb"/> + <service name="last" promote="last"/> + <service name="list" promote="list"/> + <service name="list1" promote="list1"/> + <service name="list2" promote="list2"/> + <service name="list3" promote="list3"/> + <service name="lookup" promote="lookup"/> + <service name="names" promote="names"/> + <service name="range" promote="range"/> + <service name="rest" promote="rest"/> + <service name="second" promote="second"/> + <service name="select" promote="select"/> + <service name="values" promote="values"/> + <component x="140" y="70" name="append" title="+" color="yellow1"> + <implementation.python script="nuvem/append.py"/> + <service name="append"/> + <reference name="first"/> + <reference name="second"/> + </component> + <component x="80" y="70" name="empty" title="empty" color="yellow1"> + <implementation.python script="nuvem/empty.py"/> + <service name="empty"/> + </component> + <component x="80" y="130" name="first" title="first" color="yellow1"> + <implementation.python script="nuvem/first.py"/> + <service name="first"/> + <reference name="list"/> + </component> + <component x="200" y="70" name="insert" title="insert" color="yellow1"> + <implementation.python script="nuvem/insert.py"/> + <service name="insert"/> + <reference name="value"/> + <reference name="list"/> + </component> + <component x="80" y="180" name="itemnb" title="item #" color="yellow1"> + <implementation.python script="nuvem/itemnb.py"/> + <service name="itemnb"/> + <reference name="index"/> + <reference name="list"/> + </component> + <component x="200" y="130" name="last" title="last" color="yellow1"> + <implementation.python script="nuvem/last.py"/> + <service name="last"/> + <reference name="list"/> + </component> + <component x="80" y="10" name="list" title="list.." color="yellow1"> + <implementation.python script="nuvem/list_.py"/> + <service name="list"/> + <reference name="item" clonable="true"/> + </component> + <component x="140" y="10" name="list1" title="list" color="yellow1"> + <implementation.python script="nuvem/single.py"/> + <service name="list1"/> + <reference name="value"/> + </component> + <component x="200" y="10" name="list2" title="list" color="yellow1"> + <implementation.python script="nuvem/pair.py"/> + <service name="list2"/> + <reference name="first"/> + <reference name="second"/> + </component> + <component x="260" y="10" name="list3" title="list" color="yellow1"> + <implementation.python script="nuvem/triple.py"/> + <service name="list3"/> + <reference name="first"/> + <reference name="second"/> + <reference name="third"/> + </component> + <component x="160" y="180" name="lookup" title="lookup" color="yellow1"> + <implementation.python script="nuvem/lookup.py"/> + <service name="lookup"/> + <reference name="name"/> + <reference name="list"/> + </component> + <component x="80" y="250" name="names" title="names" color="yellow1"> + <implementation.python script="nuvem/names.py"/> + <service name="names"/> + <reference name="list"/> + </component> + <component x="240" y="250" name="range" title="range" color="yellow1"> + <implementation.python script="nuvem/range_.py"/> + <service name="range"/> + <reference name="first"/> + <reference name="last"/> + </component> + <component x="140" y="130" name="rest" title="rest" color="yellow1"> + <implementation.python script="nuvem/rest.py"/> + <service name="rest"/> + <reference name="list"/> + </component> + <component x="250" y="130" name="second" title="second" color="yellow1"> + <implementation.python script="nuvem/second.py"/> + <service name="second"/> + <reference name="list"/> + </component> + <component x="240" y="180" name="select" title="select" color="yellow1"> + <implementation.python script="nuvem/select.py"/> + <service name="select"/> + <reference name="path"/> + <reference name="list"/> + </component> + <component x="160" y="250" name="values" title="values" color="yellow1"> + <implementation.python script="nuvem/values.py"/> + <service name="values"/> + <reference name="list"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/logic/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/logic/palette.composite new file mode 100644 index 0000000000..4d84272fd5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/logic/palette.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" name="palette" targetNamespace="http://palette"> + <service name="and" promote="and"/> + <service name="equals" promote="equals"/> + <service name="greater" promote="greater"/> + <service name="if" promote="if"/> + <service name="lesser" promote="lesser"/> + <service name="not" promote="not"/> + <service name="or" promote="or"/> + <component x="140" y="10" name="and" title="and" color="green1"> + <implementation.python script="nuvem/and_.py"/> + <service name="and"/> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="80" y="100" name="equals" title="=" color="green1"> + <implementation.python script="nuvem/equals.py"/> + <service name="equals"/> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="200" y="100" name="greater" title="gt" color="green1"> + <implementation.python script="nuvem/greater.py"/> + <service name="greater"/> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="80" y="10" name="if" title="if" color="green1"> + <implementation.python script="nuvem/if_.py"/> + <service name="if"/> + <reference name="condition"/> + <reference name="then"/> + <reference name="else"/> + </component> + <component x="140" y="100" name="lesser" title="lt" color="green1"> + <implementation.python script="nuvem/lesser.py"/> + <service name="lesser"/> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="260" y="10" name="not" title="not" color="green1"> + <implementation.python script="nuvem/not_.py"/> + <service name="not"/> + <reference name="value"/> + </component> + <component x="200" y="10" name="or" title="or" color="green1"> + <implementation.python script="nuvem/or_.py"/> + <service name="or"/> + <reference name="value1"/> + <reference name="value2"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/math/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/math/palette.composite new file mode 100644 index 0000000000..7dc4e88f2f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/math/palette.composite @@ -0,0 +1,138 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="add" promote="add"/> + <service name="ceil" promote="ceil"/> + <service name="cos" promote="cos"/> + <service name="distance" promote="distance"/> + <service name="divide" promote="divide"/> + <service name="floor" promote="floor"/> + <service name="max" promote="max"/> + <service name="min" promote="min"/> + <service name="mod" promote="mod"/> + <service name="multiply" promote="multiply"/> + <service name="pi" promote="pi"/> + <service name="random" promote="random"/> + <service name="randoms" promote="randoms"/> + <service name="round" promote="round"/> + <service name="sin" promote="sin"/> + <service name="subtract" promote="subtract"/> + <service name="sum" promote="sum"/> + <component x="80" y="10" name="add" title="+" color="cyan1"> + <implementation.python script="nuvem/add.py"/> + <service name="add"> + <documentation>+</documentation> + </service> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="270" y="130" name="ceil" title="ceil" color="cyan1"> + <implementation.python script="nuvem/ceil_.py"/> + <service name="ceil"/> + <reference name="x"/> + </component> + <component x="210" y="190" name="cos" title="cos" color="cyan1"> + <implementation.python script="nuvem/cos_.py"/> + <service name="cos"/> + <reference name="x"/> + </component> + <component x="80" y="240" name="distance" title="distance **" color="cyan1"> + <implementation.python script="nuvem/distance.py"/> + <service name="distance"/> + <reference name="location1"/> + <reference name="location2"/> + </component> + <component x="270" y="10" name="divide" title="/" color="cyan1"> + <implementation.python script="nuvem/divide.py"/> + <service name="divide"> + <documentation>/</documentation> + </service> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="210" y="130" name="floor" title="floor" color="cyan1"> + <implementation.python script="nuvem/floor_.py"/> + <service name="floor"/> + <reference name="x"/> + </component> + <component x="150" y="80" name="max" title="max" color="cyan1"> + <implementation.python script="nuvem/max_.py"/> + <service name="max"/> + <reference name="l"/> + </component> + <component x="210" y="80" name="min" title="min" color="cyan1"> + <implementation.python script="nuvem/min_.py"/> + <service name="min"/> + <reference name="l"/> + </component> + <component x="80" y="130" name="mod" title="mod" color="cyan1"> + <implementation.python script="nuvem/mod.py"/> + <service name="mod"/> + <reference name="n"/> + <reference name="x"/> + </component> + <component x="210" y="10" name="multiply" title="*" color="cyan1"> + <implementation.python script="nuvem/multiply.py"/> + <service name="multiply"> + <documentation>*</documentation> + </service> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="80" y="190" name="pi" title="pi" color="cyan1"> + <implementation.python script="nuvem/pi_.py"/> + <service name="pi"/> + </component> + <component x="170" y="240" name="random" title="rand" color="cyan1"> + <implementation.python script="nuvem/random_.py"/> + <service name="random"/> + <reference name="range"/> + </component> + <component x="230" y="240" name="randoms" title="rands" color="cyan1"> + <implementation.python script="nuvem/randoms.py"/> + <service name="randoms"/> + <reference name="n"/> + <reference name="range"/> + </component> + <component x="150" y="130" name="round" title="round" color="cyan1"> + <implementation.python script="nuvem/round_.py"/> + <service name="round"/> + <reference name="n"/> + <reference name="x"/> + </component> + <component x="150" y="190" name="sin" title="sin" color="cyan1"> + <implementation.python script="nuvem/sin_.py"/> + <service name="sin"/> + <reference name="x"/> + </component> + <component x="150" y="10" name="subtract" title="-" color="cyan1"> + <implementation.python script="nuvem/subtract.py"/> + <service name="subtract"> + <documentation>-</documentation> + </service> + <reference name="value1"/> + <reference name="value2"/> + </component> + <component x="80" y="80" name="sum" title="sum" color="cyan1"> + <implementation.python script="nuvem/sum_.py"/> + <service name="sum"/> + <reference name="l"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/python/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/python/palette.composite new file mode 100644 index 0000000000..2cc03ae365 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/python/palette.composite @@ -0,0 +1,35 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="eval" promote="eval"/> + <service name="exec" promote="exec"/> + <component x="80" y="10" name="eval" title="expr" color="green1"> + <implementation.python script="nuvem/eval_.py"/> + <service name="eval"/> + <reference name="py"/> + <reference name="ref"/> + </component> + <component x="150" y="10" name="exec" title="script" color="green1"> + <implementation.python script="nuvem/exec_.py"/> + <service name="exec"/> + <reference name="py"/> + <reference name="ref"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/search/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/search/palette.composite new file mode 100644 index 0000000000..db58cdcd08 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/search/palette.composite @@ -0,0 +1,100 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="bsearch" promote="bsearch"/> + <service name="gaddress" promote="gaddress"/> + <service name="ggeopos" promote="ggeopos"/> + <service name="gimages" promote="gimages"/> + <service name="gmap" promote="gmap"/> + <service name="gsearch" promote="gsearch"/> + <service name="gweather" promote="gweather"/> + <service name="traffic" promote="traffic"/> + <service name="ysearch" promote="ysearch"/> + <component x="240" y="10" name="bsearch" title="bing" color="blue1"> + <implementation.python script="nuvem/bsearch.py"/> + <service name="bsearch"/> + <reference name="query"/> + <reference name="s" visible="false"> + <binding.http uri="http://www.bing.com/search"/> + </reference> + </component> + <component x="140" y="60" name="gaddress" title="address" color="blue1"> + <implementation.python script="nuvem/gaddress.py"/> + <service name="gaddress"/> + <reference name="address"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.googleapis.com/maps/api/geocode/json"/> + </reference> + </component> + <component x="220" y="60" name="ggeopos" title="geo position" color="blue1"> + <implementation.python script="nuvem/ggeopos.py"/> + <service name="ggeopos"/> + <reference name="latitude"/> + <reference name="longitude"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.googleapis.com/maps/api/geocode/json"/> + </reference> + </component> + <component x="80" y="120" name="gimages" title="images" color="blue1"> + <implementation.python script="nuvem/gimages.py"/> + <service name="gimages"/> + <reference name="query"/> + <reference name="s" visible="false"> + <binding.http uri="https://ajax.googleapis.com/ajax/services/search/images"/> + </reference> + </component> + <component x="80" y="60" name="gmap" title="map" color="blue1"> + <implementation.python script="nuvem/gmap.py"/> + <service name="gmap"/> + <reference name="locations"/> + <reference name="s" visible="false"> + <binding.http uri="http://maps.google.com/maps/api/staticmap"/> + </reference> + </component> + <component x="80" y="10" name="gsearch" title="google" color="blue1"> + <implementation.python script="nuvem/gsearch.py"/> + <service name="gsearch"/> + <reference name="query"/> + <reference name="s" visible="false"> + <binding.http uri="http://ajax.googleapis.com/ajax/services/search/web"/> + </reference> + </component> + <component x="150" y="120" name="gweather" title="weather" color="blue1"> + <implementation.python script="nuvem/gweather.py"/> + <service name="gweather"/> + <reference name="zip"/> + <reference name="ws" visible="false"> + <binding.http uri="http://www.google.com/ig/api"/> + </reference> + </component> + <component x="230" y="120" name="traffic" title="traffic **" color="blue1"> + <implementation.python script="nuvem/traffic.py"/> + <service name="traffic"/> + <reference name="location"/> + </component> + <component x="160" y="10" name="ysearch" title="yahoo" color="blue1"> + <implementation.python script="nuvem/ysearch.py"/> + <service name="ysearch"/> + <reference name="query"/> + <reference name="s" visible="false"> + <binding.http uri="http://search.yahooapis.com/WebSearchService/V1/webSearch"/> + </reference> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/social/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/social/palette.composite new file mode 100644 index 0000000000..5e02303857 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/social/palette.composite @@ -0,0 +1,120 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="bzprofile" promote="bzprofile"/> + <service name="fbalbums" promote="fbalbums"/> + <service name="fbfriends" promote="fbfriends"/> + <service name="fbgroups" promote="fbgroups"/> + <service name="fbprofile" promote="fbprofile"/> + <service name="flkalbum" promote="flkalbum"/> + <service name="picalbum" promote="picalbum"/> + <service name="twfollowers" promote="twfollowers"/> + <service name="twfriends" promote="twfriends"/> + <service name="twprofile" promote="twprofile"/> + <service name="twtimeline" promote="twtimeline"/> + <component x="80" y="260" name="bzprofile" title="buzz profile" color="blue1"> + <implementation.python script="nuvem/bzprofile.py"/> + <service name="bzprofile"/> + <reference name="id"/> + <reference name="bz" visible="false"> + <binding.http uri="https://www.googleapis.com/buzz/v1/people"/> + </reference> + </component> + <component x="190" y="60" name="fbalbums" title="facebook albums" color="blue1"> + <implementation.python script="nuvem/fbalbums.py"/> + <service name="fbalbums"/> + <reference name="id"/> + <reference name="fb" visible="false"> + <binding.http uri="https://graph.facebook.com"/> + </reference> + </component> + <component x="190" y="10" name="fbfriends" title="facebook friends" color="blue1"> + <implementation.python script="nuvem/fbfriends.py"/> + <service name="fbfriends"/> + <reference name="id"/> + <reference name="fb" visible="false"> + <binding.http uri="https://graph.facebook.com"/> + </reference> + </component> + <component x="80" y="60" name="fbgroups" title="facebook groups" color="blue1"> + <implementation.python script="nuvem/fbgroups.py"/> + <service name="fbgroups"/> + <reference name="id"/> + <reference name="fb" visible="false"> + <binding.http uri="https://graph.facebook.com"/> + </reference> + </component> + <component x="80" y="10" name="fbprofile" title="facebook profile" color="blue1"> + <implementation.python script="nuvem/fbprofile.py"/> + <service name="fbprofile"/> + <reference name="id"/> + <reference name="fb" visible="false"> + <binding.http uri="https://graph.facebook.com"/> + </reference> + </component> + <component x="80" y="210" name="flkalbum" title="flicker album" color="blue1"> + <implementation.python script="nuvem/flkalbum.py"/> + <service name="flkalbum"/> + <reference name="id"/> + <reference name="flk" visible="false"> + <binding.http uri="http://api.flickr.com/services/feeds/photos_public.gne"/> + </reference> + </component> + <component x="190" y="210" name="picalbum" title="picasa album" color="blue1"> + <implementation.python script="nuvem/picalbum.py"/> + <service name="picalbum"/> + <reference name="id"/> + <reference name="pic" visible="false"> + <binding.http uri="https://picasaweb.google.com/data/feed/api/user"/> + </reference> + </component> + <component x="80" y="160" name="twfollowers" title="twitter followers" color="blue1"> + <implementation.python script="nuvem/twfollowers.py"/> + <service name="twfollowers"/> + <reference name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/statuses/followers.json"/> + </reference> + </component> + <component x="190" y="160" name="twfriends" title="twitter friends" color="blue1"> + <implementation.python script="nuvem/twfriends.py"/> + <service name="twfriends"/> + <reference name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/statuses/friends.json"/> + </reference> + </component> + <component x="80" y="110" name="twprofile" title="twitter profile" color="blue1"> + <implementation.python script="nuvem/twprofile.py"/> + <service name="twprofile"/> + <reference name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/users/show.json"/> + </reference> + </component> + <component x="190" y="110" name="twtimeline" title="twitter timeline" color="blue1"> + <implementation.python script="nuvem/twtimeline.py"/> + <service name="twtimeline"/> + <reference name="id"/> + <reference name="tw" visible="false"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.json"/> + </reference> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/talk/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/talk/palette.composite new file mode 100644 index 0000000000..90a48291ca --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/talk/palette.composite @@ -0,0 +1,55 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="sendemail" promote="sendemail"/> + <service name="sendgtalk" promote="sendgtalk"/> + <service name="twsms" promote="twsms"/> + <service name="voicecall" promote="voicecall"/> + <component x="150" y="10" name="sendemail" title="email **" color="blue1"> + <implementation.python script="nuvem/sendemail.py"/> + <service name="sendemail"/> + <reference name="from"/> + <reference name="to"/> + <reference name="msg"/> + </component> + <component x="80" y="10" name="sendgtalk" title="gtalk" color="blue1"> + <implementation.cpp path="lib/chat" library="libchat-sender2"/> + <service name="sendgtalk"/> + <reference name="jid"/> + <reference name="pass"/> + <reference name="to"/> + <reference name="msg"/> + </component> + <component x="230" y="10" name="twsms" title="sms" color="blue1"> + <implementation.python script="nuvem/twsms.py"/> + <service name="twsms"/> + <reference name="sid"/> + <reference name="token"/> + <reference name="from"/> + <reference name="to"/> + <reference name="msg"/> + <reference name="s" wiredByImpl="true" visible="false"/> + </component> + <component x="80" y="120" name="voicecall" title="voice **" color="blue1"> + <implementation.python script="nuvem/voicecall.py"/> + <service name="voicecall"/> + <reference name="to"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/text/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/text/palette.composite new file mode 100644 index 0000000000..6b9214f6e4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/text/palette.composite @@ -0,0 +1,76 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="contains" promote="contains"/> + <service name="format" promote="format"/> + <service name="join" promote="join"/> + <service name="lowercase" promote="lowercase"/> + <service name="parse" promote="parse"/> + <service name="replace" promote="replace"/> + <service name="split" promote="split"/> + <service name="uppercase" promote="uppercase"/> + <component x="80" y="10" name="contains" title="contains" color="cyan1"> + <implementation.python script="nuvem/contains.py"/> + <service name="contains"/> + <reference name="search"/> + <reference name="string"/> + </component> + <component x="80" y="90" name="format" title="format" color="cyan1"> + <implementation.python script="nuvem/format_.py"/> + <service name="format"/> + <reference name="pattern"/> + <reference name="values"/> + </component> + <component x="280" y="10" name="join" title="join" color="cyan1"> + <implementation.python script="nuvem/join.py"/> + <service name="join"/> + <reference name="separator"/> + <reference name="list"/> + </component> + <component x="210" y="90" name="lowercase" title="lower" color="cyan1"> + <implementation.python script="nuvem/lowercase.py"/> + <service name="lowercase"/> + <reference name="string"/> + </component> + <component x="150" y="90" name="parse" title="parse" color="cyan1"> + <implementation.python script="nuvem/parse.py"/> + <service name="parse"/> + <reference name="regexp"/> + <reference name="string"/> + </component> + <component x="150" y="10" name="replace" title="replace" color="cyan1"> + <implementation.python script="nuvem/replace.py"/> + <service name="replace"/> + <reference name="from"/> + <reference name="to"/> + <reference name="string"/> + </component> + <component x="220" y="10" name="split" title="split" color="cyan1"> + <implementation.python script="nuvem/split.py"/> + <service name="split"/> + <reference name="separator"/> + <reference name="string"/> + </component> + <component x="270" y="90" name="uppercase" title="upper" color="cyan1"> + <implementation.python script="nuvem/uppercase.py"/> + <service name="uppercase"/> + <reference name="string"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/transform/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/transform/palette.composite new file mode 100644 index 0000000000..566278c44b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/transform/palette.composite @@ -0,0 +1,59 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="filter" promote="filter"/> + <service name="map" promote="map"/> + <service name="reduce" promote="reduce"/> + <service name="reverse" promote="reverse"/> + <service name="shuffle" promote="shuffle"/> + <component x="160" y="10" name="filter" title="filter" color="yellow1"> + <implementation.python script="nuvem/filter_.py"/> + <service name="filter"/> + <reference name="item"/> + <reference name="condition"/> + <reference name="list"/> + </component> + <component x="80" y="10" name="map" title="map" color="yellow1"> + <implementation.python script="nuvem/map_.py"/> + <service name="map"/> + <reference name="item"/> + <reference name="transform"/> + <reference name="list"/> + </component> + <component x="80" y="90" name="reduce" title="reduce" color="yellow1"> + <implementation.python script="nuvem/reduce_.py"/> + <service name="reduce"/> + <reference name="item"/> + <reference name="accum"/> + <reference name="transform"/> + <reference name="init"/> + <reference name="list"/> + </component> + <component x="220" y="10" name="reverse" title="reverse" color="yellow1"> + <implementation.python script="nuvem/reverse.py"/> + <service name="reverse"/> + <reference name="list"/> + </component> + <component x="160" y="90" name="shuffle" title="shuffle" color="yellow1"> + <implementation.python script="nuvem/shuffle_.py"/> + <service name="shuffle"/> + <reference name="list"/> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/values/palette.composite b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/values/palette.composite new file mode 100644 index 0000000000..4cd3a9d14e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/palettes/values/palette.composite @@ -0,0 +1,79 @@ +<?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" name="palette" targetNamespace="http://palette"> + <service name="comment" promote="comment"/> + <service name="false" promote="false"/> + <service name="item" promote="item"/> + <service name="name" promote="name"/> + <service name="nothing" promote="nothing"/> + <service name="now" promote="now"/> + <service name="number" promote="number"/> + <service name="text" promote="text"/> + <service name="true" promote="true"/> + <service name="valueof" promote="valueof"/> + <component x="210" y="110" name="comment" title="{propval}" color="white"> + <implementation.python script="nuvem/comment.py"/> + <service name="comment" visible="false"/> + <property>comment</property> + </component> + <component x="260" y="10" name="false" title="false" color="orange1"> + <implementation.python script="nuvem/false_.py"/> + <service name="false"/> + </component> + <component x="80" y="60" name="item" title="{propval}:" color="orange1"> + <implementation.python script="nuvem/item.py"/> + <service name="item"/> + <reference name="value"/> + <property>name</property> + </component> + <component x="150" y="60" name="name" title="" color="orange1"> + <implementation.python script="nuvem/name.py"/> + <service name="name"/> + <property>name</property> + </component> + <component x="80" y="110" name="nothing" title="nothing" color="orange1"> + <implementation.python script="nuvem/nothing.py"/> + <service name="nothing"/> + </component> + <component x="150" y="110" name="now" title="now" color="orange1"> + <implementation.python script="nuvem/now.py"/> + <service name="now"/> + <reference name="format"/> + </component> + <component x="140" y="10" name="number" title="#" color="orange1"> + <implementation.python script="nuvem/number.py"/> + <service name="number"/> + <property>123</property> + </component> + <component x="80" y="10" name="text" title=" '{propval}'" color="orange1"> + <implementation.python script="nuvem/text.py"/> + <service name="text"/> + <property>text</property> + </component> + <component x="200" y="10" name="true" title="true" color="orange1"> + <implementation.python script="nuvem/true_.py"/> + <service name="true"/> + </component> + <component x="210" y="60" name="valueof" title="valueof" color="orange1"> + <implementation.python script="nuvem/valueof.py"/> + <service name="valueof"/> + <property>name</property> + </component> +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/store/all/store.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/all/store.apps new file mode 100644 index 0000000000..cb12aa05c7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/all/store.apps @@ -0,0 +1 @@ +((feed (title "App Store") (id "all") (entry (title "Check my public social data") (id "me360") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme2") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Our photos of an event") (id "ourphotos") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Slice") (id "slice") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "My online store") (id "shoppingcart") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "SMS send service") (id "twsms") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "An empty test app") (id "test") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test values and lists") (id "testvalues") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test social components") (id "testsocial") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test URL components") (id "testurl") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test logic components") (id "testlogic") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test text processing components") (id "testtext") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test HTTP components") (id "testhttp") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test SMS API") (id "testsms") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test widgets") (id "testwidgets") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test more widgets") (id "testwidgets2") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test event components") (id "testevents") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test search components") (id "testsearch") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test database components") (id "testdb") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test HTML generator components") (id "testwidgets3") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Test animation components") (id "testanimation") (author "admin@example.com") (updated "Jan 01, 2012")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/store/featured/store.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/featured/store.apps new file mode 100644 index 0000000000..adfcf5e10d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/featured/store.apps @@ -0,0 +1 @@ +((feed (title "App Store") (id "featured") (entry (title "Check my public social data") (id "me360") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme2") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Our photos of an event") (id "ourphotos") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Slice") (id "slice") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "My online store") (id "shoppingcart") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "SMS send service") (id "twsms") (author "admin@example.com") (updated "Jan 01, 2012")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/store/new/store.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/new/store.apps new file mode 100644 index 0000000000..b444d7f73c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/new/store.apps @@ -0,0 +1 @@ +((feed (title "App Store") (id "new") (entry (title "Check my public social data") (id "me360") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme2") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Our photos of an event") (id "ourphotos") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Slice") (id "slice") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "My online store") (id "shoppingcart") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "SMS send service") (id "twsms") (author "admin@example.com") (updated "Jan 01, 2012")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/data/store/top/store.apps b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/top/store.apps new file mode 100644 index 0000000000..63a7b34d46 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/data/store/top/store.apps @@ -0,0 +1 @@ +((feed (title "App Store") (id "top") (entry (title "Check my public social data") (id "me360") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Where are my friends") (id "nearme2") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Our photos of an event") (id "ourphotos") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "Slice") (id "slice") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "My online store") (id "shoppingcart") (author "admin@example.com") (updated "Jan 01, 2012")) (entry (title "SMS send service") (id "twsms") (author "admin@example.com") (updated "Jan 01, 2012")))) diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/delete-auth b/sca-cpp/branches/lightweight-sca/hosting/server/delete-auth new file mode 100755 index 0000000000..407d730c80 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/delete-auth @@ -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. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +admin=$2 +apass=$3 +user=$4 + +httpd_prefix=`cat $here/../../modules/http/httpd.prefix` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + scheme="http" + addr=`echo $conf | awk '{ print $7 }'` + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +else + scheme="https" + ssladdr=`echo $sslconf | awk '{ print $6 }'` + host=`$here/../../modules/http/httpd-addr ip $ssladdr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $ssladdr` +fi + +# Compute user id +slash=`echo $user | grep "/"` +if [ "$slash" = "" ]; then + id="\"$user\"" + upath=$user +else + id=`echo $user | awk -F "/" '{ printf "\"%s\" \"%s\"", $2, $3 }'` + upath=`echo $user | awk -F "/" '{ printf "%s/%s", $2, $3 }'` +fi + +# Delete user auth +curl -k -L -u $admin:$apass -X DELETE -H "X-Forwarded-Server: $host" $scheme://$host:$port/c/Authenticator/$upath + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/get-auth b/sca-cpp/branches/lightweight-sca/hosting/server/get-auth new file mode 100755 index 0000000000..2be546f91f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/get-auth @@ -0,0 +1,62 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +admin=$2 +apass=$3 +user=$4 + +httpd_prefix=`cat $here/../../modules/http/httpd.prefix` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + scheme="http" + addr=`echo $conf | awk '{ print $7 }'` + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +else + scheme="https" + ssladdr=`echo $sslconf | awk '{ print $6 }'` + host=`$here/../../modules/http/httpd-addr ip $ssladdr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $ssladdr` +fi + +# Compute user id +slash=`echo $user | grep "/"` +if [ "$slash" = "" ]; then + id="\"$user\"" + upath=$user +else + id=`echo $user | awk -F "/" '{ printf "\"%s\" \"%s\"", $2, $3 }'` + upath=`echo $user | awk -F "/" '{ printf "%s/%s", $2, $3 }'` +fi + +# Get user auth +curl -k -L -u $admin:$apass -H "X-Forwarded-Server: $host" $scheme://$host:$port/c/Authenticator/$upath + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/account/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/account/index.html new file mode 100644 index 0000000000..a0c2e78c31 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/account/index.html @@ -0,0 +1,222 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div class="viewform"> + +<form id="userForm"> +<table style="width: 100%;"> +<tr><tr><td><b>Photo:</b></td></tr> +<tr><td><img id="userimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Name:</b></td></tr> +<tr><td><input type="text" id="userTitle" class="flatentry" size="30" placeholder="Enter your name" style="width: 300px;"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>About Me:</b></td></tr> +<tr><td><textarea id="userDescription" class="flatentry" cols="40" rows="3" placeholder="Enter a short description of yourself" style="width: 300px;"></textarea></td></tr> +</table> + +<br/> +<table style="width: 100%;"> +<tr> +<th class="thl thr" style="padding-top: 4px; padding-bottom: 4px; padding-left: 2px; padding-right: 2px; ">Calendar</th> +</tr> +</table> + +<table> +<tr><td style="padding-right: 2px;"><input type="text" id="sched1" class="flatentry" size="10" placeholder="Schedule" style="width: 80px;"/></td><td><input type="text" id="service1" class="flatentry" size="2048" placeholder="Service URL" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="sched2" class="flatentry" size="10" placeholder="Schedule" style="width: 80px;"/></td><td><input type="text" id="service2" class="flatentry" size="2048" placeholder="Service URL" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="sched3" class="flatentry" size="10" placeholder="Schedule" style="width: 80px;"/></td><td><input type="text" id="service3" class="flatentry" size="2048" placeholder="Service URL" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="sched4" class="flatentry" size="10" placeholder="Schedule" style="width: 80px;"/></td><td><input type="text" id="service4" class="flatentry" size="2048" placeholder="Service URL" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="sched5" class="flatentry" size="10" placeholder="Schedule" style="width: 80px;"/></td><td><input type="text" id="service5" class="flatentry" size="2048" placeholder="Service URL" style="width: 200px;"/></td></tr> +</table> +<br/> + +<table style="width: 100%;"> +<tr> +<th class="thl thr" style="padding-top: 4px; padding-bottom: 4px; padding-left: 2px; padding-right: 2px; ">Key chain</th> +</tr> +</table> + +<table> +<tr><td style="padding-right: 2px;"><input type="text" id="name1" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value1" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name2" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value2" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name3" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value3" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name4" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value4" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name5" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value5" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name6" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value6" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name7" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value7" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name8" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value8" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name9" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value9" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +<tr><td style="padding-right: 2px;"><input type="text" id="name10" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value10" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> +</table> +</form> + +</div> + +<script type="text/javascript"> +(function() { + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var user= sca.defun(sca.reference(editorComp, "user")); +var accounts = sca.reference(editorComp, "accounts"); + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Account'; +$('viewhead').innerHTML = '<span class="cmenu">' + username + '</span>'; + +/** + * Set images. + */ +$('userimg').src = ui.b64img(appcache.get('/public/user.b64')); + +/** + * The current account entry and corresponding saved XML content. + */ +var accountentry; +var savedaccountentryxml = ''; + +/** + * Get and display the user's account. + */ +function getaccount() { + showStatus('Loading'); + + return accounts.get('', function(doc) { + + // Stop now if we didn't get an account + if (doc == null) { + showError('Account info not available'); + return false; + } + showOnlineStatus(); + + accountentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + $('userTitle').value = cadr(assoc("'title", cdr(accountentry))); + + var content = cadr(assoc("'content", cdr(accountentry))); + var acct = isNil(content)? mklist() : cdr(content); + + var desc = assoc("'description", acct); + $('userDescription').innerHTML = isNil(desc) || isNil(cdr(desc))? '' : cadr(desc); + + var cal = assoc("'calendar", acct); + reduce(function(i, evt) { + var sched = assoc("'@schedule", evt); + var svc = assoc("'@service", evt); + $('sched' + i).value = isNil(sched)? '' : cadr(sched); + $('service' + i).value = isNil(svc)? '' : cadr(svc); + return i + 1; + }, 1, isNil(cal)? mklist() : cadr(cadr(cal))); + + var keys = assoc("'keys", acct); + reduce(function(i, key) { + var kn = assoc("'@name", key); + var kv = assoc("'@value", key); + $('name' + i).value = isNil(kn)? '' : cadr(kn); + $('value' + i).value = isNil(kv)? '' : cadr(kv); + return i + 1; + }, 1, isNil(keys)? mklist() : cadr(cadr(keys))); + + savedaccountentryxml = car(atom.writeATOMEntry(valuesToElements(mklist(accountentry)))); + return true; + }); +} + +/** + * Save the user's account. + */ +function save(entryxml) { + if (isNil(username)) + return false; + showStatus('Saving'); + savedaccountentryxml = entryxml; + accounts.put('', savedaccountentryxml, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + + showStatus('Saved'); + return true; + }); + return true; +} + +/** + * Handle a change event + */ +function onaccountchange() { + var title = $('userTitle').value; + var desc = $('userDescription').value; + var cal = map(function(i) { + var sched = $('sched' + i).value; + var svc = $('service' + i).value; + return mklist("'event", mklist("'@schedule", sched), mklist("'@service", svc)); + }, range(1, 6)); + var keys = map(function(i) { + var kn = $('name' + i).value; + var kv = $('value' + i).value; + return mklist("'key", mklist("'@name", kn), mklist("'@value", kv)); + }, range(1, 11)); + + var accountentry = mklist("'entry", mklist("'title", title != ''? title : username), mklist("'id", username), + mklist("'content", mklist("'account", mklist("'description", desc), cons("'keys", keys), cons("'calendar", cal)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(accountentry)))); + if (savedaccountentryxml == entryxml) + return false; + + showStatus('Modified'); + return save(entryxml); +} + +$('userTitle').onchange = onaccountchange; +$('userDescription').onchange = onaccountchange; +map(function(i) { + $('sched' + i).onchange = onaccountchange; + $('service' + i).onchange = onaccountchange; + return true; +}, range(1, 6)); +map(function(i) { + $('name' + i).onchange = onaccountchange; + $('value' + i).onchange = onaccountchange; + return true; +}, range(1, 11)); + +/** + * Handle a form submit event. + */ +$('userForm').onsubmit = function() { + onaccountchange(); + return false; +}; + +/** + * Get the user's account. + */ +getaccount(); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/app/cache-template.cmf b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/app/cache-template.cmf new file mode 100644 index 0000000000..5881cf83dd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/app/cache-template.cmf @@ -0,0 +1,17 @@ +CACHE MANIFEST + +# Version SHA1 + +# App resources +/favicon.ico +/public/iframe-min.html +/public/img.png +/public/notauth/ +/public/notfound/ +/public/notyet/ +/public/oops/ +/public/touchicon.png + +NETWORK: +* + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/app/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/app/index.html new file mode 100644 index 0000000000..cddf4fb477 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/app/index.html @@ -0,0 +1,1012 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 manifest="cache-manifest.cmf"> +<head> +<title></title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<link rel="apple-touch-icon" href="/public/touchicon.png"/> +<base href="/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + // Redirect to login page if not signed in + document.location = '/login/'; + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + // Redirect to login page if not signed in + if (http.status == 403) + document.location = '/login/'; + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +})(); + +/** + * Redirect to login page if not signed in. + */ +(function() { + +if (document.location.protocol == 'https:' && !hasauthcookie()) + document.location = '/login/'; + +})(); + +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/config-min.js'))); + +})(); +</script> +</div> + +<div id="content"> +</div> + +<script type="text/javascript"> +(function() { + +/** + * Get the app name + */ +var appname = location.pathname.split('/')[1]; + +/** + * Set page title. + */ +document.title = appname; + +/** + * The main page div. + */ +var contentdiv = $('content'); + +/** + * The main app composite and page definitions. + */ +var appcomposite = null; +var apppage = null; + +/** + * Initialize the app HTTP clients. + */ +var appComp = sca.component('App'); +var pagecomp = sca.reference(appComp, 'pages'); +var composcomp = sca.reference(appComp, 'composites'); +var startcomp = sca.httpclient('start', '/' + appname + '/start'); +var stopcomp = sca.httpclient('stop', '/' + appname + '/stop'); +var timercomp = sca.httpclient('timer', '/' + appname + '/timer'); +var animationcomp = sca.httpclient('animation', '/' + appname + '/animation'); +var locationcomp = sca.httpclient('location', '/' + appname + '/location'); + +/** + * Pre-fetch app resources. + */ +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/config-min.js'], + ['/public/config-min.js'] +]; + +/** + * Handle application cache events. + */ +applicationCache.addEventListener('checking', function(e) { + //debug('appcache checking', e); +}, false); +applicationCache.addEventListener('error', function(e) { + //debug('appcache error', e); +}, false); +applicationCache.addEventListener('noupdate', function(e) { + //debug('appcache noupdate', e); +}, false); +applicationCache.addEventListener('downloading', function(e) { + //debug('appcache downloading', e); +}, false); +applicationCache.addEventListener('progress', function(e) { + //debug('appcache progress', e); +}, false); +applicationCache.addEventListener('updateready', function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + //debug('appcache swapped', e); +}, false); +applicationCache.addEventListener('cached', function(e) { + //debug('appcache cached', e); + map(function(res) { + appcache.get(res[0]); + }, appresources); +}, false); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); +}, false); + +//debug(navigator.onLine? 'online' : 'offline'); + +/** + * Find a named value in a tree of elements. The value name is given + * as a list of ids. + */ +function namedvalue(l, id) { + if (isNil(l)) + return null; + var e = car(l); + + // Element matches id segment + if (car(id) == elementName(e)) { + + // Found element matching the whole id path + if (isNil(cdr(id))) + return e; + + // Search for next id segments in child elements + if (!elementHasValue(e)) { + var v = namedvalue(elementChildren(e), cdr(id)); + if (v != null) + return v; + } + } + + // Search for id through the whole element tree + if (!elementHasValue(e)) { + var v = namedvalue(elementChildren(e), id); + if (v != null) + return v; + } + return namedvalue(cdr(l), id); +} + +/** + * Return the value of an input element. + */ +function inputvalue(e) { + if (e.className == 'entry' || e.className == 'password') { + return car(childElements(e)).value; + } + if (e.className == 'button') { + return car(childElements(e)).value; + } + if (e.className == 'checkbox') { + if (!car(childElements(e)).checked) + return null; + return car(childElements(e)).value; + } + if (e.className == 'select') { + return car(childElements(car(childElements(e)))).value; + } + return null; +}; + +/** + * Set a value into a widget. + */ +function setwidgetvalue(e, dv) { + var htattrs = namedElementChild("'htattrs", dv); + + function attr(ce) { + return mklist(elementName(ce) == "'htstyle"? 'style' : elementName(ce).substring(1), elementHasValue(ce)? elementValue(ce) : elementChildren(ce)); + } + + function vattr(dv) { + return (elementHasValue(dv) && !isNil(elementValue(dv)))? mklist(mklist('value', isNil(elementValue(dv))? '' : elementValue(dv))) : mklist(); + } + + function sattr(dv) { + var s = namedElementChild("'htstyle", dv); + return isNil(s)? mklist() : mklist(mklist('style', elementHasValue(s)? elementValue(s) : elementChildren(s))) + } + + var attrs = append(append(isNil(htattrs)? mklist() : map(attr, elementChildren(htattrs)), vattr(dv)), sattr(dv)); + + // Set the attributes of the widget + function setattrs(vsetter, attrs, ce) { + return map(function(a) { + if (car(a) == 'value') + return vsetter(a, ce); + + if (car(a) == 'style') { + // Split a style property between a style attribute + // and a stylesheet definition in the document's head + + function prop(s) { + if (s == ';') + return ''; + var i = s.indexOf('<style>'); + if (i == -1) + return s; + var j = s.indexOf('</style>'); + return s.substring(0, i) + prop(s.substring(j + 8)); + } + + function sheet(s) { + var i = s.indexOf('<style>'); + if (i == -1) + return ''; + var j = s.indexOf('</style>'); + return s.substring(i + 7, j) + sheet(s.substring(j + 8)); + } + + var st = cadr(a).replace(new RegExp('{id}', 'g'), e.id); + var p = prop(st); + var s = sheet(st); + + // Define the stylesheet + if (s != '') { + var esheet = ui.elementByID(contentdiv, 'style_' + e.id); + if (isNil(esheet)) { + var nesheet = document.createElement('style'); + nesheet.id = 'style_' + e.id; + nesheet.type = 'text/css'; + document.head.appendChild(nesheet); + nesheet.innerHTML = s; + } else { + esheet.innerHTML = s; + } + } + + var aname = ce.style.webkitAnimationName; + + // Set the style attribute + ce.setAttribute('style', p); + + // Restart current animation if necessary + if (!isNil(aname) && ce.style.webkitAnimationName == aname) { + ce.style.webkitAnimationName = ''; + setTimeout(function() { + ce.style.webkitAnimationName = aname; + }, 0); + } + return a; + } + + ce.setAttribute(car(a), cadr(a)); + return a; + }, attrs); + } + + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + var ce = car(childElements(e)); + return setattrs(function(a, ce) { ce.innerHTML = cadr(a); }, attrs, ce); + } + if (e.className == 'entry' || e.className == 'password') { + var ce = car(childElements(e)); + return setattrs(function(a, ce) { ce.defaultValue = cadr(a); }, attrs, ce); + } + if (e.className == 'button') { + var ce = car(childElements(e)); + return setattrs(function(a, ce) { ce.value = cadr(a); }, attrs, ce); + } + if (e.className == 'checkbox') { + var ce = car(childElements(e)); + + function setcheckvalue(a, ce) { + var v = cadr(a); + ce.value = v; + map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = v; return n; }, nodeList(e.childNodes)); + return true; + } + + return setattrs(setcheckvalue, attrs, ce); + } + if (e.className == 'select') { + var ce = car(childElements(car(childElements(e)))); + + function setselectvalue(a, ce) { + var v = cadr(a); + ce.value = v; + ce.innerHTML = v; + return true; + } + + return setattrs(setselectvalue, attrs, ce); + } + if (e.className == 'list') { + var dl = ui.datalist(isNil(dv)? mklist() : mklist(dv)); + e.innerHTML = dl; + return dl; + } + if (e.className == 'table') { + var dl = ui.datatable(isNil(dv)? mklist() : mklist(dv)); + e.innerHTML = dl; + return dl; + } + if (e.className == 'link') { + var ce = car(childElements(e)); + + function setlinkvalue(a, ce) { + var v = cadr(a); + if (isList(v)) { + ce.href = car(v); + ce.innerHTML = cadr(v); + return true; + } + ce.href = v; + ce.innerHTML = v; + return true; + } + + return setattrs(setlinkvalue, attrs, ce); + } + if (e.className == 'img') { + var ce = car(childElements(e)); + return setattrs(function(a, ce) { ce.setAttribute('src', cadr(a)); }, attrs, ce); + } + if (e.className == 'iframe') { + var ce = car(childElements(e)); + return setattrs(function(a, ce) { ce.setAttribute('src', cadr(a)); }, attrs, ce); + } + return ''; +}; + +/** + * Update the app page with the given app data. + */ +function updatepage(l) { + if (isNil(l)) + return true; + + // Update the widgets values + function updatewidget(e) { + var dv = namedvalue(l, map(function(t) { return "'" + t; }, e.id.split('.'))); + if (dv == null || isNil(dv)) + return e; + setwidgetvalue(e, dv); + return e; + } + + map(updatewidget, filter(function(e) { return !isNil(e.id) && e.id.substring(0, 5) != 'page:'; }, nodeList(ui.elementByID(contentdiv, 'page').childNodes))); + return true; +} + +/** + * Convert a document to application data. + */ +function docdata(doc) { + if (isNil(doc)) + return null; + + if (json.isJSON(mklist(doc))) + return json.readJSON(mklist(doc)); + + if (atom.isATOMEntry(mklist(doc))) + return atom.readATOMEntry(mklist(doc)); + + if (atom.isATOMFeed(mklist(doc))) + return atom.readATOMFeed(mklist(doc)); + + return doc; +} + +/** + * Bind a handler to a widget. + */ +function bindwidgethandler(e, appname) { + if (e.className == 'button') { + var b = car(childElements(e)); + b.name = e.id; + b.onclick = function() { return buttonClickHandler(b.value, appname); }; + return e; + } + if (e.className == 'link') { + var l = car(childElements(e)); + var hr = l.href; + if (hr.substring(0, 5) == 'link:' && hr.indexOf('://') == -1) { + var f = function(e) { + e.preventDefault(); + return buttonClickHandler(hr.substring(5), appname); + }; + l.ontouchstart = l.onclick = f; + l.href = 'javascript:void()'; + } + return e; + } + if (e.className == 'entry' || e.className == 'password' || e.className == 'checkbox') { + car(childElements(e)).name = e.id; + return e; + } + if (e.className == 'select') { + var ce = car(childElements(car(childElements(e)))); + ce.name = e.id; + return e; + } + return e; +} + +/** + * Initial fixup of a widget. + */ +function fixupwidget(e) { + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + if (e.className == 'section') + e.style.width = '100%'; + var ce = car(childElements(e)); + if (ce.innerHTML == '=' + e.id) + ce.innerHTML = ''; + return e; + } + if (e.className == 'entry' || e.className == 'password') { + var ce = car(childElements(e)); + if (ce.defaultValue == '=' + e.id) + ce.defaultValue = ''; + return e; + } + if (e.className == 'button') { + var ce = car(childElements(e)); + if (ce.value == '=' + e.id) + ce.value = ''; + return e; + } + if (e.className == 'checkbox') { + var ce = car(childElements(e)); + if (ce.value == '=' + e.id) { + ce.value = ''; + map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = ''; return n; }, nodeList(e.childNodes)); + } + return e; + } + if (e.className == 'select') { + var ce = car(childElements(car(childElements(e)))); + if (ce.value == '=' + e.id) { + ce.value = ''; + ce.innerHTML = ''; + } + return e; + } + if (e.className == 'list') { + car(childElements(e)).innerHTML = ''; + e.style.width = '100%'; + car(childElements(e)).style.width = '100%'; + return e; + } + if (e.className == 'table') { + car(childElements(e)).innerHTML = ''; + e.style.width = '100%'; + car(childElements(e)).style.width = '100%'; + return e; + } + if (e.className == 'link') { + var ce = car(childElements(e)); + if (ce.innerHTML == '=' + e.id) + ce.innerHTML = ''; + return e; + } + if (e.className == 'img') { + var ce = car(childElements(e)); + return e; + } + if (e.className == 'iframe') { + var ce = car(childElements(e)); + e.innerHTML = '<iframe src="' + ce.href + '" frameborder="no" scrolling="no"></iframe>'; + return e; + } + return e; +} + +/** + * Set initial value of a widget. + */ +function initwidget(e) { + if (!isNil(e.id) && e.id.substring(0, 5) != 'page:') + setwidgetvalue(e, mklist()); + return e; +} + +/** + * Return the component bound to a uri. + */ +function isbound(uri, comps) { + return !isNil(filter(function(comp) { + return !isNil(filter(function(svc) { + return !isNil(filter(function(b) { + return uri == scdl.uri(b); + }, scdl.bindings(svc))); + }, scdl.services(comp))); + }, comps)); +} + +/** + * Get app data from the main app page component. + */ +function getappdata(appname, page, compos) { + try { + + // Eval a component init script + function evalcompinit(doc) { + if (isNil(doc)) + return true; + var js = car(json.readJSON(mklist(doc))); + if (!elementHasValue(js)) + return true; + eval(elementValue(js)); + return true; + } + + // Initial setup of a widget + function setupwidget(e) { + initwidget(e); + fixupwidget(e); + bindwidgethandler(e, appname); + } + + // Setup the widgets + map(setupwidget, filter(function(e) { return !isNil(e.id); }, nodeList(ui.elementByID(contentdiv, 'page').childNodes))); + + // Get the app components + var comps = scdl.components(compos); + + // Get the component app data + if (isbound("start", comps)) { + startcomp.get(location.search, function(doc, e) { + if (isNil(doc)) { + debug('error on get(start, ' + location.search + ')', e); + return false; + } + + // Display data on the page + updatepage(docdata(doc)); + }); + } + + // Get and eval the optional timer, animation and location watch setup scripts + if (isbound("timer", comps)) { + timercomp.get('setup', function(doc, e) { + if (isNil(doc)) { + debug('error on get(timer, setup)', e); + return false; + } + + // Evaluate the component init expression + return evalcompinit(doc); + }); + } + + if (isbound("animation", comps)) { + animationcomp.get('setup', function(doc, e) { + if (isNil(doc)) { + debug('error on get(animation, setup)', e); + return false; + } + + // Evaluate the component init expression + return evalcompinit(doc); + }); + } + + if (isbound("location", comps)) { + locationcomp.get('setup', function(doc, e) { + if (isNil(doc)) { + debug('error on get(location, setup)', e); + return false; + } + + // Evaluate the component init expression + return evalcompinit(doc); + }); + } + + return true; + + } catch(e) { + debug('error in getappdata()', e); + return true; + } +} + +/** + * Return the page in an ATOM entry. + */ +function atompage(doc) { + var entry = atom.readATOMEntry(mklist(doc)); + if (isNil(entry)) + return mklist(); + var content = namedElementChild("'content", car(entry)); + if (content == null) + return mklist(); + return elementChildren(content); +} + +/** + * Get the app page. + */ +function getapppage(appname, compos) { + pagecomp.get(appname, function(doc, e) { + //debug('page get'); + if (isNil(doc)) { + debug('error in getapppage', e); + return false; + } + + // Set the app HTML page into the content div + var page = atompage(doc); + contentdiv.innerHTML = writeStrings(writeXML(page, false)); + apppage = page; + + // Merge in the app data + if (!isNil(appcomposite)) + getappdata(appname, apppage, appcomposite); +}); + +} + +/** + * Build a query string from the values of the page's input fields. + */ +function compquery() { + function queryarg(e) { + return e.id + '=' + inputvalue(e); + } + + function childrenList(n) { + return append(nodeList(n.childNodes), reduce(append, mklist(), map(childrenList, nodeList(n.childNodes)))); + } + + var args = map(queryarg, filter(function(e) { return !isNil(e.id) && !isNil(inputvalue(e)); }, childrenList(ui.elementByID(contentdiv, 'page')))); + + // Append current location properties if known + if (!isNil(geoposition)) { + var g = geoposition; + args = append(args, mklist('latitude=' + g.coords.latitude, 'longitude=' + g.coords.longitude, 'altitude=' + g.coords.altitude, + 'accuracy=' + g.coords.accuracy, 'altitudeAccuracy=' + g.coords.altitudeAccuracy, 'heading=' + g.coords.heading, + 'speed=' + g.coords.speed)); + } + + return '?' + args.join('&'); +} + +/** + * Handle a button click event. + */ +function buttonClickHandler(id, appname) { + try { + var uri = compquery(); + return sca.component(id, appname).get(uri, function(doc, e) { + if (isNil(doc)) { + debug('error on get(button, ' + uri + ')', e); + return false; + } + + // Inject data into the page + updatepage(docdata(doc)); + }); + } catch(e) { + debug('error in buttonClickHandler()', e); + return true; + } +} + +/** + * Handle a timer interval event. + */ +function intervalHandler() { + try { + var uri = compquery(); + return timercomp.get(uri, function(doc, e) { + if (isNil(doc)) { + debug('error on get(timer, ' + uri + ')', e); + return false; + } + + // Inject data into the page + updatepage(docdata(doc)); + }); + } catch(e) { + debug('error in intervalHandler()', e); + return true; + } +} + +/** + * Setup an interval timer. + */ +function setupIntervalHandler(msec) { + intervalHandler(); + try { + return setInterval(intervalHandler, msec); + } catch(e) { + debug('error in setupIntervalHandler()', e); + return true; + } +} + +/** + * Handle an animation event. + */ +var animationData = null; +var gettingAnimationData = false; +var currentAnimationData = null; +var animationLoop = 0; +var currentAnimationLoop = 0; + +function animationHandler() { + try { + function applyAnimation() { + // Update page with current animation data + updatepage(car(currentAnimationData)); + + // End of animation? + if (isNil(cdr(currentAnimationData))) { + if (currentAnimationLoop == -1) { + // Repeat current animation forever + currentAnimationData = animationData; + return true; + } + + currentAnimationLoop = currentAnimationLoop - 1; + if (currentAnimationLoop <= 0) { + // Get next animation data + currentAnimationData = null; + animationData = null; + return true; + } + + // Repeat animation + currentAnimationData = animationData; + return true; + } + + // Move to the next animation frame + currentAnimationData = cdr(currentAnimationData); + return true; + } + + // Get new animation data if necessary + if (isNil(animationData)) { + if (gettingAnimationData) + return true; + var uri = compquery(); + return animationcomp.get(uri, function(doc, e) { + if (isNil(doc)) { + debug('error on get(animation, ' + uri + ')', e); + return false; + } + + // Apply the new animation + currentAnimationData = docdata(doc); + currentAnimationLoop = animationLoop; + gettingAnimationData = false; + applyAnimation(); + }); + } + + // Apply the current animation + return applyAnimation(); + + } catch(e) { + debug('error in animationHandler()', e); + return true; + } +} + +/** + * Setup an animation. + */ +function setupAnimationHandler(msec, loop) { + animationLoop = loop; + animationHandler(); + try { + return setInterval(animationHandler, msec); + } catch(e) { + debug('error in setupAnimationHandler()', e); + return true; + } +} + +/** + * Handle a location watch event. + */ +var locationWatch = null; +var geoposition = null; + +function locationHandler(pos) { + try { + geoposition = pos; + var uri = compquery(); + return locationcomp.get(uri, function(doc, e) { + if (isNil(doc)) { + debug('error on get(location, ' + uri + ')', e); + return false; + } + + // Inject data into the page + updatepage(docdata(doc)); + }); + } catch(e) { + return locationErrorHandler(e); + } +} + +function locationErrorHandler(e) { + debug('location error', e); + if (!isNil(locationWatch)) { + try { + navigator.geolocation.clearWatch(locationWatch); + } catch(e) {} + locationWatch = null; + } + return true; +} + +/** + * Setup a location watch handler. + */ +function setupLocationHandler() { + function installLocationHandler() { + if (!isNil(locationWatch)) + return true; + try { + locationWatch = navigator.geolocation.watchPosition(locationHandler, locationErrorHandler); + } catch(e) { + debug('error in installLocationHandler()', e); + } + return true; + } + + installLocationHandler(); + setInterval(installLocationHandler, 10000); + return true; +} + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + + return true; +}; + +/** + * Return the composite in an ATOM entry. + */ +function atomcomposite(doc) { + var entry = atom.readATOMEntry(mklist(doc)); + if (isNil(entry)) + return mklist(); + var content = namedElementChild("'content", car(entry)); + if (content == null) + return mklist(); + return elementChildren(content); +} + +/** + * Get the app composite. + */ +function getappcomposite(appname) { + return composcomp.get(appname, function(doc, e) { + //debug('page get'); + if (isNil(doc)) { + debug('error in getappcomposite', e); + return false; + } + + var compos = atomcomposite(doc); + if (isNil(compos)) { + + // Create a default empty composite if necessary + var x = '<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" ' + + 'targetNamespace="http://app" name="app"></composite>'; + compos = readXML(mklist(x)); + } + appcomposite = compos; + + // Merge in the app data + if (!isNil(apppage)) + getappdata(appname, apppage, appcomposite); + }); +} + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + + // Show the page + document.body.style.visibility = 'visible'; + + // Initialize the app composite + getappcomposite(appname); + + // Initialize the app page + getapppage(appname); + + return true; +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/cache-template.cmf b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/cache-template.cmf new file mode 100644 index 0000000000..8d9aa26f7d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/cache-template.cmf @@ -0,0 +1,18 @@ +CACHE MANIFEST + +# Version SHA1 + +# App resources +/ +/favicon.ico +/public/iframe-min.html +/public/img.png +/public/notauth/ +/public/notfound/ +/public/notyet/ +/public/oops/ +/public/touchicon.png + +NETWORK: +* + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/clone/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/clone/index.html new file mode 100644 index 0000000000..0a2f7733bc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/clone/index.html @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div class="viewform"> + +<form id="cloneAppForm"> +<table style="width: 100%;"> +<tr><td><b>New App Name:</b></td></tr> +<tr><td><input type="text" id="appName" class="flatentry" size="15" autocapitalize="off" placeholder="Your app name"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Icon:</b></td></tr> +<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Title:</b></td></tr> +<tr><td><input type="text" id="appTitle" class="flatentry" size="30" placeholder="Enter the title of your app" style="width: 300px;"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> +<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" placeholder="Enter a short description of your app" style="width: 300px;"></textarea></td></tr> +<tr><td> +<input id="cloneAppOKButton" type="submit" class="graybutton bluebutton" style="font-weight: bold;" value="Clone" title="Clone the app"/> +<input id="cloneAppCancelButton" type="button" class="graybutton" value="Cancel"/> +</td></tr> +</table> +</form> + +</div> + +<script type="text/javascript"> +(function() { + +/** + * Get the app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - ' + config.clone() + ' - ' + appname; +$('viewhead').innerHTML = '<span class="smenu">' + config.clone() + ' ' + appname + '</span>'; +$('cloneAppOKButton').value = config.clone(); +$('cloneAppOKButton').title = config.clone() + ' this app'; + +/** + * Set images. + */ +$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var apps = sca.reference(editorComp, "apps"); + +/** + * The current app entry and corresponding saved XML content. + */ +var appentry; +var savedappentryxml = ''; + +/** + * Get and display an app. + */ +function getapp(name) { + if (isNil(name)) + return false; + showStatus('Loading'); + + return apps.get(name, function(doc) { + + // Stop now if we didn't get the app + if (doc == null) { + showError('App not available'); + return false; + } + showOnlineStatus(); + + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); + $('appTitle').value = cadr(assoc("'title", cdr(appentry))); + var content = cadr(assoc("'content", cdr(appentry))); + var description = assoc("'description", content); + $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); + savedappentryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + return true; + }); +} + +/** + * Save an app. + */ +function save(name, entryxml) { + showStatus('Saving'); + savedappentryxml = entryxml; + apps.put(name, savedappentryxml, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + showStatus('Saved'); + + // Open it in the page editor + ui.navigate('/#view=page&app=' + name, '_view'); + return false; + }); + return false; +} + +/** + * Clone an app. + */ +$('cloneAppForm').onsubmit = function() { + var name = $('appName').value; + if (name == '') { + showError('Missing app name'); + return false; + } + showStatus('Saving'); + + // Clone the app + var title = $('appTitle').value; + var description = $('appDescription').value; + appentry = mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", appname), mklist("'content", mklist("'stats", mklist("'description", description)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + return save(name, entryxml); +}; + +/** + * Cancel cloning an app. + */ +$('cloneAppCancelButton').onclick = function() { + history.back(); +}; + +/** + * Get the current app. + */ +getapp(appname); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/config.js b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/config.js new file mode 100644 index 0000000000..70d3ea1195 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/config.js @@ -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. + */ + +if (isNil(config)) + config = {}; + +/** + * UI configuration. + */ +config.windowtitle = function() { + return 'App Builder'; +}; + +config.pagetitle = function() { + return '<span style="font-weight: bold;">App Builder</span>'; +}; + +config.hometitle = function() { + return '<br/><span style="font-weight: bold;">Create SCA Composite Apps</span><br/><br/>'; +}; + +config.clone = function() { + return 'Clone'; +}; + +config.logic = function() { + return 'Logic'; +}; + +config.viewfoot = function() { + return ui.menubar(mklist(ui.menu('menuabout', 'About', '/', '_view', 'note')), mklist()); +}; + +config.appresources = function() { + return mklist(); +}; + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/create/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/create/index.html new file mode 100644 index 0000000000..d8d2b30f3c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/create/index.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div class="viewform"> + +<form id="createAppForm"> +<table style="width: 100%;"> +<tr><td><b>App Name:</b></td></tr> +<tr><td><input type="text" id="appName" class="flatentry" size="15" autocapitalize="off" placeholder="Your app name"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr> +<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>App Title:</b></td></tr> +<tr><td><input type="text" id="appTitle" class="flatentry" size="30" placeholder="Enter the title of your app" style="width: 300px;"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> +<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" placeholder="Enter a short description of your app" style="width: 300px;"></textarea></td></tr> +<tr><td> +<input id="createAppOKButton" type="submit" class="graybutton bluebutton" style="font-weight: bold;" value="Create" title="Create the app"/> +<input id="createAppCancelButton" type="button" class="graybutton" value="Cancel"/> +</td></tr> +</table> +</form> + +</div> + +<script type="text/javascript"> +(function() { + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Create App'; +$('viewhead').innerHTML = '<span class="smenu">Create an App</span>'; + +/** + * Set images. + */ +$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var apps = sca.reference(editorComp, "apps"); + +/** + * The current app entry and corresponding saved XML content. + */ +var appentry; +var savedappentryxml = ''; + +/** + * Save an app. + */ +function save(name, entryxml) { + showStatus('Saving'); + savedappentryxml = entryxml; + apps.put(name, savedappentryxml, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + showStatus('Saved'); + + // Open it in the page editor + ui.navigate('/#view=page&app=' + name, '_view'); + return false; + }); + return false; +} + +/** + * Create an app. + */ +$('createAppForm').onsubmit = function() { + var name = $('appName').value; + if (name == '') { + showError('Missing app name'); + return false; + } + showStatus('Modified'); + + // Clone the 'new' app template + var title = $('appTitle').value; + var description = $('appDescription').value; + appentry = mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", 'new'), mklist("'content", mklist("'stats", mklist("'description", description)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + return save(name, entryxml); +}; + +/** + * Cancel creating an app. + */ +$('createAppCancelButton').onclick = function() { + history.back(); +}; + +/** + * Show the status. + */ +showOnlineStatus(); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/delete/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/delete/index.html new file mode 100644 index 0000000000..5a668af401 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/delete/index.html @@ -0,0 +1,139 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div class="viewform"> + +<form id="deleteAppForm"> +<table style="width: 100%;"> +<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr> +<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>App Title:</b></td></tr> +<tr><td><input type="text" id="appTitle" class="flatentry" size="30" readonly="readonly" style="width: 300px;"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Author:</b></td></tr> +<tr><td><span id="appAuthor"></span></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Updated:</b></td></tr> +<tr><td><span id="appUpdated"></span></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> +<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" readonly="readonly" style="width: 300px;"></textarea></td></tr> +<tr><td> +<input id="deleteAppOKButton" type="submit" class="graybutton bluebutton" style="font-weight: bold;" value="Delete" title="Delete the app"/> +<input id="deleteAppCancelButton" type="button" class="graybutton" value="Cancel"/> +</td></tr> +</table> +</form> + +</div> + +<script type="text/javascript"> +(function() { + +/** + * Get the app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - ' + 'Delete' + ' - ' + appname; +$('viewhead').innerHTML = '<span class="smenu">Delete ' + appname + '</span>'; + +/** + * Set images. + */ +$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var apps = sca.reference(editorComp, "apps"); + +/** + * The current app entry and corresponding saved XML content. + */ +var appentry; + +/** + * Get and display an app. + */ +function getapp(name) { + if (isNil(name)) + return false; + showStatus('Loading'); + + return apps.get(name, function(doc) { + + // Stop now if we didn't get the app + if (doc == null) { + showError('App not available'); + return false; + } + showOnlineStatus(); + + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); + $('appTitle').value = cadr(assoc("'title", cdr(appentry))); + $('appAuthor').innerHTML = cadr(assoc("'author", cdr(appentry))); + $('appUpdated').innerHTML = cadr(assoc("'updated", cdr(appentry))); + var content = cadr(assoc("'content", cdr(appentry))); + var description = assoc("'description", content); + $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); + return true; + }); +} + +/** + * Delete an app. + */ +$('deleteAppForm').onsubmit = function() { + showStatus('Deleting'); + + // Delete the app + apps.del(appname, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + showOnlineStatus(); + + // Return to the app store + ui.navigate('/#view=store', '_view'); + return false; + }); + return false; +}; + +/** + * Cancel cloning an app. + */ +$('deleteAppCancelButton').onclick = function() { + history.back(); +}; + +/** + * Get the current app. + */ +getapp(appname); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/favicon.ico b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/favicon.ico Binary files differnew file mode 100644 index 0000000000..a7b502b9e1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/favicon.ico diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/graph/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/graph/index.html new file mode 100644 index 0000000000..d360336375 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/graph/index.html @@ -0,0 +1,2100 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div id="contentdiv" class="viewcontent" style="width: 2500px;"> +<div id="graphdiv" class="graphdiv" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"></div> +<div id="playdiv" style="position: absolute; top: 0x; left: 0px; width: 2500px; height: 5000px; visibility: hidden"></div> +</div> + +<script type="text/javascript"> +(function() { + +/** + * Get the current app name. + */ +var appname = ui.fragmentParams(location)['app']; +var ispalette = false; +if (isNil(appname)) { + appname = ui.fragmentParams(location)['palette']; + + // Edit a palette instead of a regular app + if (!isNil(appname)) + ispalette = true; +} + +/** + * Set page title. + */ +document.title = config.windowtitle() + ' - ' + config.logic() + ' - ' + appname; + +/** + * Set header div. + */ +$('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + +'<input type="button" id="deleteCompButton" title="Delete a component" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + +'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="compValue" type="text" value="" class="flatentry" title="Component value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; visibility: hidden;" readonly="readonly"/></span>' + +'<input type="button" id="playCompButton" title="View component value" class="graybutton plusminus" style="position: absolute; top: 4px; right: 75px;" disabled="true" value=">"/>' + +'<input type="button" id="copyCompButton" title="Copy a component" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 40px;" disabled="true" value="C"/>' + +'<input type="button" id="addCompButton" title="Add a component" class="graybutton bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + +/** + * Track the current app composite, author, and saved XML content. + */ +var author = ''; +var editable = false; +var composite; +var savedcomposxml = ''; + +/** + * Component value field, add, delete and play buttons. + */ +var cvalue = $('compValue'); +var atitle = $('appTitle'); +var cadd = $('addCompButton'); +var cdelete = $('deleteCompButton'); +var ccopy = $('copyCompButton'); +var cplay = $('playCompButton'); + +/** + * Init componnent references. + */ +var editorComp = sca.component("Editor"); +var palettes = sca.reference(editorComp, "palettes"); +var composites = sca.reference(editorComp, ispalette? "palettes" : "composites"); + +/** + * Composite rendering functions. + */ +var graph = {}; + +/** + * Basic colors + */ +graph.colors = {}; +graph.colors.black = '#000000'; +graph.colors.blue = '#0000ff'; +graph.colors.cyan = '#00ffff'; +graph.colors.gray = '#808080' +graph.colors.lightgray = '#dcdcdc' +graph.colors.green = '#00ff00'; +graph.colors.magenta = '#ff00ff'; +graph.colors.orange = '#ffa500'; +graph.colors.pink = '#ffc0cb'; +graph.colors.purple = '#800080'; +graph.colors.red = '#ff0000'; +graph.colors.white = '#ffffff'; +graph.colors.yellow = '#ffff00'; +graph.colors.link = '#357ae8'; + +graph.colors.orange1 = '#ffd666'; +graph.colors.green1 = '#bbe082'; +graph.colors.blue1 = '#66dbdf'; +graph.colors.yellow1 = '#fdf57a'; +graph.colors.cyan1 = '#e6eafb'; +graph.colors.lightgray1 = '#eaeaea' +graph.colors.pink1 = '#ffd9e0'; +graph.colors.red1 = '#d03f41'; +graph.colors.white1 = '#ffffff'; + +graph.colors.orange2 = '#ffbb00'; +graph.colors.green2 = '#96d333'; +//graph.colors.blue2 = '#0d7cc1'; +graph.colors.blue2 = '#00c3c9'; +graph.colors.red2 = '#d03f41'; +graph.colors.yellow2 = '#fcee21'; +graph.colors.magenta2 = '#c0688a'; +graph.colors.cyan2 = '#d5dcf9'; +graph.colors.lightgray2 = '#dcdcdc' +graph.colors.pink2 = '#ffc0cb'; +graph.colors.white2 = '#ffffff'; + +graph.colors.orange3 = '#ffc700'; +graph.colors.green3 = '#92e120'; +graph.colors.blue3 = '#008fd1'; +graph.colors.yellow3 = '#fdf400'; +graph.colors.cyan3 = '#b4d3fd'; +graph.colors.lightgray3 = '#e3e3e3' +graph.colors.pink3 = '#da749b'; +graph.colors.red3 = '#ed3f48'; +graph.colors.white3 = '#ffffff'; + +/** + * Default positions and sizes. + */ +graph.palcx = 2500; +graph.proxcx = 20; +graph.proxcy = 20; +graph.buttoncx = 55; +graph.buttoncy = 23; +graph.curvsz = 4; +graph.tabsz = 2; +graph.titlex = 4; +graph.titley = 0; + +/** + * Make a composite graph editor. + */ +graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onchange, onselect) { + + // Track element dragging and selection + graph.dragging = null; + graph.dragged = false; + graph.selected = null; + cvalue.readOnly = true; + cvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; + ccopy.disabled = true; + cdelete.disabled = true; + cadd.disabled = !editable; + + // Register event listeners + graph.oncomposchange = onchange; + graph.oncompselect = onselect; + + /** + * Find the first draggable element in a hierarchy of elements. + */ + function draggable(n) { + //debug('draggable', n); + if (n == graphdiv || n == null) + return null; + if (n.className == 'g' && !isNil(n.id) && n.id != '') + return n; + return draggable(n.parentNode); + } + + /** + * Handle a mouse down or touch start event. + */ + function onmousedown(e) { + + // Remember mouse or touch position + var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + graph.downX = pos.screenX; + graph.downY = pos.screenY; + graph.moveX = pos.screenX; + graph.moveY = pos.screenY; + + // Engage the click component selection right away + // on mouse controlled devices + if (typeof e.touches == 'undefined') + onclick(e); + + // Find and remember draggable component + var dragging = draggable(e.target); + if (dragging == null || dragging != graph.selected) + return true; + graph.dragging = dragging; + graph.dragged = false; + + // Remember current drag position + graph.dragX = pos.screenX; + graph.dragY = pos.screenY; + + e.preventDefault(); + return true; + }; + + if (!ui.isMobile()) { + graphdiv.onmousedown = function(e) { + //debug('onmousedown'); + return onmousedown(e); + } + } else { + graphdiv.ontouchstart = function(e) { + //debug('ontouchstart'); + return onmousedown(e); + } + } + + /** + * Handle a mouse up or touch end event. + */ + function onmouseup(e) { + + // Engage the click component selection now on touch devices + if (ui.isMobile()) { + if (!graph.dragged && graph.moveX == graph.downX && graph.moveY == graph.downY) + return onclick(e); + } + + // Stop here if the component was not dragged + if (graph.dragging == null) + return true; + if (!graph.dragged) { + graph.dragging = null; + return true; + } + + if (graph.dragging.parentNode == graphdiv && graph.dragging.id.substring(0, 8) != 'palette:') { + + // Add new dragged component to the composite + if (isNil(graph.dragging.compos)) { + var compos = scdl.composite(graphdiv.compos); + setElement(compos, graph.sortcompos(graph.addcomps(mklist(graph.dragging.comp), compos))); + graph.dragging.compos = graphdiv.compos; + } + + // Update component position + setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.draggingg))); + + // Wire component to neighboring reference + if (!isNil(graph.dragging.svcpos)) { + var compos = scdl.composite(graphdiv.compos); + setElement(compos, graph.sortcompos(graph.clonerefs(graph.wire(graph.dragging, compos, graphdiv)))); + } + + // Snap top level component position to grid + if (graph.dragging.parentNode == graphdiv) { + var gpos = graph.relpos(graph.dragging); + setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().pos(graph.gridsnap(gpos.x), graph.gridsnap(gpos.y)))); + } + } + + // Forget current dragged component + graph.dragging = null; + graph.dragged = false; + + // Refresh the composite + //debug('onmouseup refresh'); + var nodes = graph.refresh(graphdiv); + + // Reselect the previously selected component + if (!isNil(graph.selected)) { + graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); + + // Trigger component select event + graph.oncompselect(graph.selected); + } + + // Trigger composite change event + graph.oncomposchange(false); + return true; + }; + + if (!ui.isMobile()) { + graphdiv.onmouseup = function(e) { + //debug('onmouseup'); + return onmouseup(e); + } + } else { + graphdiv.ontouchend = function(e) { + //debug('ontouchend'); + return onmouseup(e); + } + } + + /** + * Handle a mouse or touch click event. + */ + function onclick(e) { + //debug('onclick logic'); + + // Find selected component + var selected = draggable(e.target); + if (selected == null) { + if (graph.selected != null) { + + // Reset current selection + graph.compselect(graph.selected, false, atitle, cvalue, ccopy, cdelete); + graph.selected = null; + + // Trigger component select event + graph.oncompselect(null); + } + + // Dismiss the palette + if (e.target == graphdiv && ui.numpos(graphdiv.style.left) != (graph.palcx * -1)) + graphdiv.style.left = ui.pixpos(graph.palcx * -1); + + return true; + } + + + // Ignore duplicate click events + if (selected == graph.selected) + return true; + if (selected.id.substring(0, 8) == 'palette:' && ui.numpos(graphdiv.style.left) != 0) + return true; + + // Deselect previously selected component + graph.compselect(graph.selected, false, atitle, cvalue, ccopy, cdelete); + + // Clone component from the palette + if (selected.id.substring(0, 8) == 'palette:') { + var compos = scdl.composite(graphdiv.compos); + var comp = graph.clonepalette(selected, compos); + setElement(compos, graph.sortcompos(graph.addcomps(mklist(comp), compos))); + + // Move into the editing area and hide the palette + graphdiv.style.left = ui.pixpos(graph.palcx * -1); + + // Refresh the composite + //debug('onclick refresh'); + var nodes = graph.refresh(graphdiv); + + // Reselect the previously selected component + graph.selected = graph.findcompnode(scdl.name(comp), nodes); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); + + // Trigger component select event + graph.oncompselect(graph.selected); + + // Trigger composite change event + graph.oncomposchange(true); + + } else { + graph.selected = selected; + + // Select the component + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); + + // Trigger component select event + graph.oncompselect(graph.selected); + } + + //debug('comp selected'); + + e.preventDefault(); + return true; + } + + if (!ui.isMobile()) { + graphdiv.onclick = function(e) { + //debug('onclick'); + return onclick(e); + } + } else { + graphdiv.onclick = function(e) { + //debug('onclick'); + return onclick(e); + } + } + + /** + * Handle a mouse or touch move event. + */ + function onmousemove(e) { + if (graph.dragging == null) + return true; + + // Ignore duplicate mouse move events + if (graph.moveX == graph.dragX && graph.moveY == graph.dragY) + return true; + + // Remember that the component was dragged + graph.dragged = true; + + // Cut wire to component + if (graph.dragging.parentNode != graphdiv) { + var compos = scdl.composite(graphdiv.compos); + setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, graphdiv))); + + // Bring component to the top + graph.bringtotop(graph.dragging, graphdiv); + } + + // Calculate new position of dragged element + var gpos = graph.relpos(graph.dragging); + var newX = gpos.x + (graph.moveX - graph.dragX); + var newY = gpos.y + (graph.moveY - graph.dragY); + if (newX >= graph.palcx) + graph.dragX = graph.moveX + else + newX = graph.palcx; + if (newY >= 0) + graph.dragY = graph.moveY; + else + newY = 0; + + // Move the dragged element + graph.move(graph.dragging, graph.mkpath().pos(newX, newY)); + + return false; + }; + + if (!ui.isMobile()) { + window.onmousemove = function(e) { + //debug('onmousemove'); + + // Remember mouse position + graph.moveX = e.screenX; + graph.moveY = e.screenY; + + return onmousemove(e); + } + } else { + graphdiv.ontouchmove = function(e) { + //debug('ontouchmove'); + + // Remember touch position + var pos = e.touches[0]; + if (graph.moveX == pos.screenX && graph.moveY == pos.screenY) + return true; + graph.moveX = pos.screenX; + graph.moveY = pos.screenY; + if (graph.moveX == graph.dragX && graph.moveY == graph.dragY) + return true; + + return onmousemove(e); + } + } + + /** + * Handle field on change events. + */ + function onvaluechange() { + if (graph.selected == null) + return false; + if (graphdiv.parentNode.style.visibility == 'hidden') + return false; + + // Change component name and refactor references to it + function changename() { + var compos = scdl.composite(graphdiv.compos); + cvalue.value = graph.ucid(cvalue.value, compos, false); + graph.selected.id = cvalue.value; + setElement(compos, graph.sortcompos(graph.renamecomp(graph.selected.comp, compos, cvalue.value))); + + // Refresh the composite + //debug('onchangename refresh'); + var nodes = graph.refresh(graphdiv); + + // Reselected the previously selected component + graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); + + // Trigger component select event + graph.oncompselect(graph.selected); + + // Trigger composite change event + graph.oncomposchange(true); + return false; + } + + // Change the component property value + function changeprop() { + graph.setproperty(graph.selected.comp, cvalue.value); + var hasprop = graph.hasproperty(graph.selected.comp); + cvalue.readOnly = (hasprop? false : true) || !editable; + cvalue.style.visibility = hasprop? 'visible' : 'hidden'; + atitle.style.visibility = hasprop? 'hidden' : 'visible'; + cvalue.value = graph.property(graph.selected.comp); + + // Refresh the composite + //debug('onchangeprop refresh'); + var nodes = graph.refresh(graphdiv); + + // Reselected the previously selected component + graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); + + // Trigger component select event + graph.oncompselect(graph.selected); + + // Trigger composite change event + graph.oncomposchange(true); + return false; + } + + return graph.hasproperty(graph.selected.comp)? changeprop() : changename(); + }; + + cvalue.onchange = function() { + return onvaluechange(); + } + + // Handle delete event + function ondeleteclick() { + if (graph.selected == null) + return false; + if (graph.selected.id.substring(0, 8) != 'palette:') { + + // Remove selected component + var compos = scdl.composite(graphdiv.compos); + if (isNil(graph.selected.compos)) + setElement(compos, graph.sortcompos(graph.cutwire(graph.selected, compos, graphdiv))); + setElement(compos, graph.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.selected.comp, compos))))); + + // Reset current selection + graph.compselect(graph.selected, false, atitle, cvalue, ccopy, cdelete); + graph.selected = null; + + // Refresh the composite + //debug('ondelete refresh'); + graph.refresh(graphdiv); + + // Trigger component select event + graph.oncompselect(null); + + // Trigger composite change event + graph.oncomposchange(true); + } + return false; + }; + + cdelete.onclick = function() { + return ondeleteclick(); + }; + + // Handle copy event + function oncopyclick() { + if (graph.selected == null) + return false; + if (graph.selected.id.substring(0, 8) == 'palette:') + return false; + + // Clone the selected component + var compos = scdl.composite(graphdiv.compos); + var comps = graph.clonecomp(graph.selected, compos); + setElement(compos, graph.sortcompos(graph.addcomps(comps, compos))); + + // Refresh the composite + //debug('oncopyclick refresh'); + var nodes = graph.refresh(graphdiv); + + // Select the component clone + graph.selected = graph.findcompnode(scdl.name(car(comps)), nodes); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); + + // Trigger component select event + graph.oncompselect(graph.selected); + + // Trigger composite change event + graph.oncomposchange(true); + + return false; + }; + + ccopy.onclick = function() { + return oncopyclick(); + }; + + // Handle add event + cadd.onclick = function() { + + // Show the palette + graphdiv.style.left = ui.pixpos(0); + return false; + }; + + // Create a hidden SVG element to help compute the width + // of component and reference titles + graph.offtitles = document.createElement('span'); + graph.offtitles.style.visibility = 'hidden'; + graph.offtitles.position = 'absolute'; + graph.offtitles.top = -500; + graph.offtitles.width = 500; + graph.offtitles.height = 50; + graphdiv.appendChild(graph.offtitles); + + return graphdiv; +}; + +/** + * Point class. + */ +graph.Point = function(x, y) { + this.x = x; + this.y = y; +}; + +graph.mkpoint = function(x, y) { + return new graph.Point(x, y); +}; + +/** + * Path class. + */ +graph.Path = function() { + this.x = 0; + this.y = 0; + this.xmin = null; + this.xmax = null; + this.xmin = -8; + this.ymax = null; + this.draw = function(ctx) { + return ctx; + }; +} +graph.Path.prototype.pos = function(x, y) { + this.x = x; + this.y = y; + if (this.xmin == null || x < this.xmin) this.xmin = x; + if (this.xmax == null || x > this.xmax) this.xmax = x; + if (this.ymin == null || y < this.ymin) this.ymin = y; + if (this.ymax == null || y > this.ymax) this.ymax = y; + return this; +}; +graph.Path.prototype.rmove = function(x, y) { + return this.move(this.x + x, this.y + y); +}; +graph.Path.prototype.rline = function(x, y) { + return this.line(this.x + x, this.y + y); +}; +graph.Path.prototype.rcurve = function(x1, y1, x, y) { + return this.curve(this.x + x1, this.y + y1, this.x + x1 + x, this.y + y1 + y); +}; +graph.Path.prototype.clone = function() { + return graph.mkpath().pos(this.x, this.y); +}; +graph.Path.prototype.move = function(x, y) { + var d = this.draw; + this.draw = function(ctx) { + d(ctx); + ctx.moveTo(x, y); + return ctx; + }; + return this.pos(x, y); +}; +graph.Path.prototype.line = function(x, y) { + var d = this.draw; + this.draw = function(ctx) { + d(ctx); + ctx.lineTo(x, y); + return ctx; + }; + return this.pos(x, y); +}; +graph.Path.prototype.curve = function(x1, y1, x, y) { + var d = this.draw; + this.draw = function(ctx) { + d(ctx); + ctx.quadraticCurveTo(x1, y1, x, y); + return ctx; + }; + return this.pos(x, y); +}; +graph.Path.prototype.end = function() { + var d = this.draw; + this.draw = function(ctx) { + ctx.beginPath(); + d(ctx); + ctx.fill(); + ctx.beginPath(); + d(ctx); + ctx.stroke(); + }; + return this; +}; +graph.Path.prototype.bounds = function() { + var width = this.xmin == null || this.xmax == null? 0 : this.xmax - this.xmin + 1; + var height = this.ymin == null || this.ymax == null? 0 : this.ymax - this.ymin + 1; + return graph.mkpath().pos(width, height); +}; + +graph.mkpath = function() { + return new graph.Path(); +}; + +/** + * Translate the position of an element. + */ +graph.translate = function(g, x, y) { + var t = 'translate(' + ui.pixpos(x) + ',' + ui.pixpos(y) + ')'; + g.style.setProperty('-webkit-transform', t, null); + g.style.setProperty('-moz-transform', t, null); + g.style.setProperty('-o-transform', t, null); + g.style.setProperty('transform', t, null); + g.ctmx = x; + g.ctmy = y; + return g; +}; + +/** + * Apply a path to an element. + */ +graph.drawshape = function(g) { + // Set shape element size + var b = g.path.bounds(); + g.width = b.x + 4; + g.height = b.y + 4; + + // Get canvas context + var ctx = g.getContext('2d'); + ctx.save(); + + // Apply translation + ctx.translate((g.path.xmin * -1) + 2, (g.path.ymin * -1) + 2); + + // Draw the shape + ctx.fillStyle = g.fillStyle; + ctx.strokeStyle = !isNil(g.strokeStyle)? g.strokeStyle : graph.colors.gray; + ctx.lineWidth = !isNil(g.lineWidth)? g.lineWidth : 1; + g.path.draw(ctx); + + // Reset canvas context + ctx.restore(); + return g; +} + +/** + * Return an element representing a title. + */ +graph.mktitle = function(t, x, y) { + var title = document.createElement('span'); + title.className = 'gtitle'; + title.style.left = ui.pixpos(x); + title.style.top = ui.pixpos(y); + title.appendChild(document.createTextNode(t)); + graph.offtitles.appendChild(title); + title.style.width = ui.pixpos(title.clientWidth + 2); + title.style.height = ui.pixpos(title.clientHeight + 2); + return title; +}; + +/** + * Return an element representing the title of a component. + */ +graph.comptitle = function(comp) { + return memo(comp, 'title', function() { + var ct = graph.title(comp); + var pt = graph.propertytitle(comp); + if (ct == '' && pt == '') + return null; + return graph.mktitle((ct != '' && pt != '')? ct + ' ' + pt : ct + pt, graph.titlex, graph.titley); + }); +}; + +/** + * Return the width of the title of a component. + */ +graph.comptitlewidth = function(comp) { + var title = graph.comptitle(comp); + if (isNil(title)) + return 0; + return title.clientWidth; +}; + +/** + * Draw a component shape selection. + */ +graph.compselect = function(g, s, atitle, cvalue, ccopy, cdelete) { + if (isNil(g) || !s) { + cvalue.value = ''; + cvalue.readOnly = true; + cvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; + ccopy.disabled = true; + cdelete.disabled = true; + if (isNil(g)) + return true; + g.shape.strokeStyle = null; + g.shape.lineWidth = null; + graph.drawshape(g.shape); + return true; + } + + cvalue.value = graph.hasproperty(g.comp)? graph.property(g.comp) : g.id; + cvalue.readOnly = false || !editable; + cvalue.style.visibility = 'visible'; + atitle.style.visibility = 'hidden'; + ccopy.disabled = false || !editable; + cdelete.disabled = false || !editable; + + g.shape.strokeStyle = graph.colors.link; + g.shape.lineWidth = 2; + graph.drawshape(g.shape); + g.parentNode.appendChild(g); + return true; +}; + +/** + * Draw a palette shape selection. + */ +graph.paletteselect = function(g, s) { + if (isNil(g)) + return true; + if (!s) { + g.shape.strokeStyle = null; + g.shape.lineWidth = null; + graph.drawshape(g.shape); + return true; + } + + g.shape.strokeStyle = graph.colors.link; + g.shape.lineWidth = 2; + graph.drawshape(g.shape); + g.parentNode.appendChild(g); + return true; +}; + +/** + * Return a node representing a component. + */ +graph.compnode = function(comp, cassoc, pos) { + //debug('compnode', graph.title(comp)); + + // Create the component shape + var shape = document.createElement('canvas'); + shape.className = 'path'; + shape.fillStyle = graph.color(comp); + shape.path = graph.comppath(comp, cassoc); + graph.drawshape(shape); + + // Make the component title element + var title = graph.comptitle(comp); + + // Create a span group element and add the shape and title to it + var g = document.createElement('span'); + g.className = 'g'; + g.comp = comp; + g.id = scdl.name(comp); + graph.translate(g, pos.x, pos.y); + g.pos = pos.clone(); + g.appendChild(shape); + g.shape = shape; + g.style.width = ui.pixpos(shape.width); + g.style.height = ui.pixpos(shape.height); + if (!isNil(title)) { + title.style.left = ui.pixpos(shape.path.xmin * -1); + g.appendChild(title); + } + + // Store the positions of the services and references + g.refpos = reverse(shape.path.refpos); + g.svcpos = reverse(shape.path.svcpos); + + return g; +}; + +/** + * Find the node representing a component. + */ +graph.findcompnode = function(name, nodes) { + if (isNil(nodes)) + return null; + if (isNil(car(nodes).comp)) + return graph.findcompnode(name, cdr(nodes)); + if (name == scdl.name(car(nodes).comp)) + return car(nodes); + var node = graph.findcompnode(name, nodeList(car(nodes).childNodes)); + if (!isNil(node)) + return node; + return graph.findcompnode(name, cdr(nodes)); +} + +/** + * Return a graphical group. + */ +graph.mkgroup = function(pos) { + var g = document.createElement('div'); + g.className = 'g'; + graph.translate(g, pos.x, pos.y); + g.pos = pos.clone(); + return g; +}; + +/** + * Return a node representing a button. + */ +graph.mkbutton = function(t, pos) { + + // Create the main button shape + var shape = document.createElement('canvas'); + shape.className = 'path'; + shape.fillStyle = graph.colors.lightgray1; + shape.path = graph.buttonpath(); + graph.drawshape(shape); + + // Make the button title + var title = graph.mktitle(t, graph.titlex, graph.titley); + + // Create a group and add the button shape and title to it + var g = document.createElement('span'); + g.className = 'g'; + graph.translate(g, pos.x, pos.y); + g.pos = pos.clone(); + g.appendChild(shape); + g.appendChild(title); + + // Store the button shape in the group + g.shape = shape; + + return g; +}; + +/** + * Return the position of a node relative to its parent. + */ +graph.relpos = function(g) { + var curX = g.ctmx? g.ctmx : 0; + var curY = g.ctmy? g.ctmy : 0; + return graph.mkpath().pos(curX, curY); +}; + +/** + * Move a node. + */ +graph.move = function(g, pos) { + g.pos = pos.clone(); + graph.translate(g, g.pos.x, g.pos.y); + return g; +}; + +/** + * Return the absolute position of a component node. + */ +graph.abspos = function(e) { + if (isNil(e) || e == graphdiv) + return graph.mkpath(); + var gpos = graph.relpos(e); + var pgpos = graph.abspos(e.parentNode); + return graph.mkpath().pos(gpos.x + pgpos.x, gpos.y + pgpos.y); +}; + +/** + * Bring a component node to the top. + */ +graph.bringtotop = function(n, g) { + if (n == g) + return null; + graph.move(n, graph.abspos(n)); + g.appendChild(n); +} + +/** + * Return the title of a SCDL element. + */ +graph.title = function(e) { + var t = scdl.title(e); + if (t != null) { + if (t == 'gt') + return '>' + if (t == 'lt') + return '<'; + if (t.indexOf('{propval}') != -1) + return ''; + if (t.indexOf('{compname}') == -1) + return t; + return t.replace('{compname}', scdl.name(e)); + } + return scdl.name(e); +}; + +/** + * Return the property value of a SCDL component. + */ +graph.property = function(e) { + var p = scdl.properties(e); + if (isNil(p)) + return ''; + if (scdl.visible(car(p)) == 'false') + return ''; + var pv = scdl.propertyValue(car(p)); + return pv; +}; + +/** + * Return the title of a property of a SCDL component. + */ +graph.propertytitle = function(e) { + var pv = graph.property(e); + var t = scdl.title(e); + if (t.indexOf('{propval}') == -1) + return pv; + return t[0] == ' '? t.substr(1).replace('{propval}', pv) : t.replace('{propval}', pv); +}; + +/** + * Return true if a SCDL component has a property. + */ +graph.hasproperty = function(e) { + var p = scdl.properties(e); + if (isNil(p)) + return false; + if (scdl.visible(car(p)) == 'false') + return false; + return true; +}; + +/** + * Change the property value of a SCDL component. + */ +graph.setproperty = function(e, value) { + var p = scdl.properties(e); + if (isNil(p)) + return ''; + if (scdl.visible(car(p)) == 'false') + return ''; + var name = scdl.name(car(p)); + setElement(car(p), mklist(element, "'property", mklist(attribute, "'name", name != null? name : "property"), value)); + return value; +}; + +/** + * Return the color of a SCDL component. + */ +graph.color = function(comp) { + return memo(comp, 'color', function() { + var c = scdl.color(comp); + return c == null? graph.colors.blue1 : graph.colors[c]; + }); +}; + +/** + * Return the services on the left side of a component. + */ +graph.lsvcs = function(comp) { + return memo(comp, 'lsvcs', function() { + var svcs = scdl.services(comp); + if (isNil(svcs)) + return mklist(mklist("'element","'service","'attribute","'name",scdl.name(comp))); + var l = filter(function(s) { + var a = scdl.align(s); + var v = scdl.visible(s); + return (a == null || a == 'left') && v != 'false'; + }, svcs); + if (isNil(l)) + return mklist(); + return mklist(car(l)); + }); +}; + +/** + * Return the references on the right side of a component. + */ +graph.rrefs = function(comp) { + return memo(comp, 'rrefs', function() { + return filter(function(r) { + var a = scdl.align(r); + var v = scdl.visible(r); + return (a == null || a == 'right') && v != 'false'; + }, scdl.references(comp)); + }); +}; + +/** + * Return the height of a reference on the right side of a component. + */ +graph.rrefheight = function(ref, cassoc) { + return memo(ref, 'rheight', function() { + var target = assoc(scdl.target(ref), cassoc); + if (isNil(target)) + return graph.tabsz * 8; + return graph.compclosureheight(cadr(target), cassoc); + }); +}; + +/** + * Return the total height of the references on the right side of a component. + */ +graph.rrefsheight = function(refs, cassoc) { + if (isNil(refs)) + return 0; + return graph.rrefheight(car(refs), cassoc) + graph.rrefsheight(cdr(refs), cassoc); +}; + +/** + * Return the height of a component node. + */ +graph.compheight = function(comp, cassoc) { + return memo(comp, 'height', function() { + var lsvcs = graph.lsvcs(comp); + var lsvcsh = Math.max(1, length(lsvcs)) * (graph.tabsz * 8) + (graph.tabsz * 4); + var rrefs = graph.rrefs(comp); + var rrefsh = graph.rrefsheight(rrefs, cassoc) + (graph.tabsz * 2); + return Math.max(lsvcsh, rrefsh); + }); +}; + +/** + * Return the height of a component and the components wired to its bottom side. + */ +graph.compclosureheight = function(comp, cassoc) { + return memo(comp, 'closureheight', function() { + return graph.compheight(comp, cassoc); + }); +}; + +/** + * Return the max width of the references on the right side of a component. + */ +graph.rrefswidth = function(refs, cassoc) { + if (isNil(refs)) + return 0; + return Math.max(graph.rrefwidth(car(refs), cassoc), graph.rrefswidth(cdr(refs), cassoc)); +}; + +/** + * Return the width of a component. + */ +graph.compwidth = function(comp, cassoc) { + return memo(comp, 'width', function() { + var ctw = graph.comptitlewidth(comp); + var rrefsw = (isNil(graph.rrefs(comp))? 0 : (graph.tabsz * 4)); + var twidth = (graph.titlex * 2) + ctw + rrefsw; + var width = Math.max(twidth, (graph.tabsz * 8) + (graph.tabsz * 4)); + return width; + }); +}; + +/** + * Return a path representing a reference positioned to the right of a component. + */ +graph.rrefpath = function(ref, cassoc, path, maxheight) { + var height = graph.rrefheight(ref, cassoc); + + // Record reference position in the path + var xpos = path.x; + var ypos = path.y; + path.refpos = cons(mklist(ref, graph.mkpath().pos(xpos, ypos + (graph.tabsz * 5))), path.refpos); + + // Compute the reference path + return path.rline(0,graph.tabsz * 2).rcurve(0,graph.tabsz,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,-graph.tabsz/2.0).rcurve(0,-graph.tabsz/2.0,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,graph.tabsz/2.0).rline(0,graph.tabsz * 3).rcurve(0,graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,-graph.tabsz/2.0).rcurve(0,-graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,graph.tabsz).line(path.x, Math.min(ypos + height, maxheight)); +}; + +/** + * Return a path representing a service positioned to the left of a component. + */ +graph.lsvcpath = function(svc, cassoc, path, minheight) { + var height = graph.tabsz * 8; + + // Record service position in the path + var xpos = path.x; + var ypos = path.y; + path.svcpos = cons(mklist(svc, graph.mkpath().pos(xpos, ypos - (graph.tabsz * 6))), path.svcpos); + + // Compute the service path + return path.rline(0, -(graph.tabsz * 2)).rcurve(0,-graph.tabsz,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,graph.tabsz/2.0).rcurve(0,graph.tabsz/2.0,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,-graph.tabsz/2.0).rline(0,-(graph.tabsz * 3)).rcurve(0,-graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,graph.tabsz/2.0).rcurve(0,graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,-graph.tabsz).line(path.x, Math.max(ypos - height, minheight)); +}; + +/** + * Return a path representing a component node. + */ +graph.comppath = function(comp, cassoc) { + + // Calculate the width and height of the component node + var width = graph.compwidth(comp, cassoc); + var height = graph.compheight(comp, cassoc); + + /** + * Apply a path rendering function to a list of services or references. + */ + function renderpath(x, f, cassoc, path, height) { + if (isNil(x)) + return path; + return renderpath(cdr(x), f, cassoc, f(car(x), cassoc, path, height), height); + } + + var path = graph.mkpath().move(graph.curvsz,0); + + // Store the positions of services and references in the path + path.refpos = mklist(); + path.svcpos = mklist(); + + // Render the references on the right side of the component + var rrefs = graph.rrefs(comp); + path = path.line(width - graph.curvsz,path.y).rcurve(graph.curvsz,0,0,graph.curvsz); + path = renderpath(rrefs, graph.rrefpath, cassoc, path, height - graph.curvsz); + + // Render the references on the bottom side of the component + var boffset = graph.curvsz; + path = path.line(path.x,height - graph.curvsz).rcurve(0,graph.curvsz,graph.curvsz * -1,0).line(boffset, path.y); + + // Render the services on the left side of the component + var lsvcs = graph.lsvcs(comp); + var loffset = graph.curvsz + (length(lsvcs) * (graph.tabsz * 8)); + path = path.line(graph.curvsz,path.y).rcurve(graph.curvsz * -1,0,0,graph.curvsz * -1).line(path.x, loffset); + path = renderpath(lsvcs, graph.lsvcpath, cassoc, path, graph.curvsz); + + // Close the component node path + path = path.line(0,graph.curvsz).rcurve(0,graph.curvsz * -1,graph.curvsz,0); + + return path.end(); +}; + +/** + * Return the position of a component. + */ +graph.comppos = function(comp, pos) { + var x = scdl.x(comp); + var y = scdl.y(comp); + return graph.mkpath().pos(x != null? Number(x) + graph.palcx : pos.x, y != null? Number(y) : pos.y); +}; + +/** + * Return a path representing a button node. + */ +graph.buttonpath = function(t) { + var path = graph.mkpath().move(graph.curvsz,0); + path = path.line(graph.buttoncx - graph.curvsz,path.y).rcurve(graph.curvsz,0,0,graph.curvsz); + path = path.line(path.x,graph.buttoncy - graph.curvsz).rcurve(0,graph.curvsz,-graph.curvsz,0).line(graph.curvsz, path.y); + path = path.line(graph.curvsz,path.y).rcurve(-graph.curvsz,0,0,-graph.curvsz).line(path.x, graph.curvsz); + path = path.line(0,graph.curvsz).rcurve(0,-graph.curvsz,graph.curvsz,0); + return path.end(); +}; + +/** + * Render a SCDL composite into a list of component nodes. + */ +graph.composite = function(compos, pos, aspalette) { + var name = scdl.name(scdl.composite(compos)); + var comps = scdl.components(compos); + var cassoc = scdl.nameToElementAssoc(comps); + var proms = scdl.promotions(compos); + + // Unmemoize any memoized info about components and their references. + map(function(c) { + unmemo(c); + map(function(r) { + unmemo(r); + }, scdl.references(c)); + }, comps); + + /** + * Render a component. + */ + function rendercomp(comp, cassoc, pos) { + + /** + * Render the references on the right side of a component. + */ + function renderrrefs(refs, cassoc, pos, gcomp) { + + /** + * Render a reference on the right side of a component. + */ + function renderrref(ref, cassoc, pos, gcomp) { + var target = assoc(scdl.target(ref), cassoc); + if (isNil(target)) + return null; + + // Render the component target of the reference + return rendercomp(cadr(target), cassoc, pos); + } + + /** + * Move the rendering cursor down below a reference. + */ + function rendermove(ref, cassoc, pos) { + return pos.clone().rmove(0, graph.rrefheight(ref, cassoc)); + } + + if (isNil(refs)) + return mklist(); + + // Return list of (ref, comp rendering) pairs + var grefcomp = renderrref(car(refs), cassoc, pos, gcomp); + return cons(mklist(car(refs), grefcomp), renderrrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos), gcomp)); + } + + // Compute the component shape + var gcomp = graph.compnode(comp, cassoc, pos); + + // Render the components wired to the component references + var rrefs = graph.rrefs(comp); + var rpos = graph.mkpath().rmove(graph.compwidth(comp, cassoc), 0); + var grrefs = renderrrefs(rrefs, cassoc, rpos, gcomp); + + // Store list of (ref, pos, component rendering) triplets in the component + function refposgcomp(refpos, grefs) { + if (isNil(refpos)) + return mklist(); + + // Append component rendering to component + var gref = cadr(car(grefs)); + if (gref != null) + gcomp.appendChild(gref); + return cons(mklist(car(car(refpos)), cadr(car(refpos)), gref), refposgcomp(cdr(refpos), cdr(grefs))); + } + + gcomp.refpos = refposgcomp(gcomp.refpos, grrefs); + + return gcomp; + } + + /** + * Render a list of promoted service components. + */ + function renderproms(svcs, cassoc, pos) { + + /** + * Return the component promoted by a service. + */ + function promcomp(svc, cassoc) { + var c = assoc(scdl.promote(svc), cassoc); + if (isNil(c)) + return mklist(); + return cadr(c); + } + + /** + * Move the rendering cursor down below a component. + */ + function rendermove(comp, cassoc, pos) { + return pos.clone().rmove(0, graph.compclosureheight(comp, cassoc) + Math.max((graph.tabsz * 2), 8)); + } + + if (isNil(svcs)) + return mklist(); + + // Render the first promoted component in the list + // then recurse to render the rest of the list + var comp = promcomp(car(svcs), cassoc); + if (isNil(comp)) + return renderproms(cdr(svcs), cassoc, rendermove(car(svcs), cassoc, pos)); + + var cpos = graph.comppos(comp, pos); + return cons(rendercomp(comp, cassoc, cpos), renderproms(cdr(svcs), cassoc, rendermove(comp, cassoc, cpos))); + } + + // Render the promoted service components + var rproms = renderproms(proms, cassoc, pos.clone().rmove(graph.tabsz * 4, graph.tabsz * 4)); + + if (aspalette) { + + // Prefix ids of palette component elements with 'palette:' and + // move them to the palette area + return map(function(r) { + r.id = 'palette:' + r.id; + var gpos = r.pos; + graph.move(r, graph.mkpath().pos(gpos.x - graph.palcx, gpos.y)); + return r; + }, rproms); + + } else { + + // Link app component elements to the containing composite + return map(function(r) { r.compos = compos; return r; }, rproms); + } +}; + +/** + * Return a component unique id. + */ +graph.ucid = function(prefix, compos1, compos2, clone) { + + // Build an assoc list keyed by component name + var comps = map(function(c) { return mklist(scdl.name(c), c); }, append(namedElementChildren("'component", compos1), namedElementChildren("'component", compos2))); + + if (!clone && isNil(assoc(prefix, comps))) + return prefix; + + /** + * Find a free component id. + */ + function ucid(p, id) { + if (isNil(assoc(p + id, comps))) + return p + id; + return ucid(p, id + 1); + } + + /** + * Remove trailing digits from a prefix. + */ + function untrail(p) { + if (p.length < 2 || p[p.length - 1] < '0' || p[p.length - 1] > '9') + return p; + return untrail(p.substring(0, p.length - 1)); + } + + return ucid(prefix == ''? 'comp' : (clone? untrail(prefix) : prefix), 1); +}; + +/** + * Clone a palette component node. + */ +graph.clonepalette = function(e, compos) { + + // Clone the SCDL component and give it a unique name + var wcomp = append(mklist(element, "'component", mklist(attribute, "'name", graph.ucid(scdl.name(e.comp), compos, compos, true))), + filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e.comp))); + var x = '<composite>' + writeXML(mklist(wcomp), false) + '</composite>'; + var rcompos = scdl.composite(readXML(mklist(x))); + var comp = car(scdl.components(mklist(rcompos))); + + // Update component position + setElement(comp, graph.movecomp(comp, graph.abspos(e).rmove(graph.palcx, 0))); + + return comp; +}; + +/** + * Move a SCDL component to the given position. + */ +graph.movecomp = function(comp, pos) { + if (isNil(pos)) + return append(mklist(element, "'component"), + filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'x" || attributeName(e) == "'y")); }, elementChildren(comp))); + return append(mklist(element, "'component", mklist(attribute, "'x", '' + (pos.x - graph.palcx)), mklist(attribute, "'y", '' + pos.y)), + filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'x" || attributeName(e) == "'y")); }, elementChildren(comp))); +}; + +/** + * Align a pos along a 10pixel grid. + */ +graph.gridsnap = function(x) { + return Math.round(x / 10) * 10; +} + +/** + * Clone a component node and all the components it references. + */ +graph.clonecomp = function(e, compos) { + + // Write the component and the components it references to XML + function collectcomp(e) { + function collectrefs(refpos) { + if (isNil(refpos)) + return mklist(); + var r = car(refpos); + var n = caddr(r); + if (isNil(n)) + return collectrefs(cdr(refpos)); + return append(collectcomp(n), collectrefs(cdr(refpos))); + } + + return cons(e.comp, collectrefs(e.refpos)); + } + + var allcomps = collectcomp(e); + var ls = map(function(e) { return writeXML(mklist(e), false); }, allcomps); + var x = '<composite>' + writeStrings(ls) + '</composite>'; + + // Read them back from XML to clone them + var rcompos = scdl.composite(readXML(mklist(x))); + var comps = scdl.components(mklist(rcompos)); + + // Give them new unique names + map(function(e) { + + // Rename each component + var oname = scdl.name(e); + var name = graph.ucid(oname, compos, rcompos, true); + setElement(e, append(mklist(element, "'component", mklist(attribute, "'name", name)), + filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e)))); + + // Refactor references to the component + map(function(c) { return graph.refactorrefs(scdl.references(c), oname, name); }, comps); + }, comps); + + // Update the top component position + var comp = car(comps); + setElement(comp, graph.movecomp(comp, graph.abspos(e).rmove(10, 10))); + + return comps; +}; + +/** + * Sort elements of a composite. + */ +graph.sortcompos = function(compos) { + return append(mklist(element, "'composite"), elementChildren(compos).sort(function(a, b) { + + // Sort attributes, place them at the top + var aa = isAttribute(a); + var ba = isAttribute(b); + if (aa && !ba) return -1; + if (!aa && ba) return 1; + if (aa && ba) { + var aan = attributeName(a); + var ban = attributeName(b); + if (aan < ban) return -1; + if (aan > ban) return 1; + return 0; + } + + // Sort elements, place services before components + var aen = elementName(a); + var ben = elementName(b); + if (aen == "'service" && ben == "'component") return -1; + if (aen == "'component" && ben == "'service") return 1; + var an = scdl.name(a); + var bn = scdl.name(b); + if (an < bn) return -1; + if (an > bn) return 1; + return 0; + })); +} + +/** + * Add a list of components to a SCDL composite. The first + * component in the list is a promoted component. + */ +graph.addcomps = function(comps, compos) { + var comp = car(comps); + var name = scdl.name(comp); + var prom = mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name)); + return append(mklist(element, "'composite"), append(elementChildren(compos), cons(prom, comps))); +}; + +/** + * Remove a component from a SCDL composite. + */ +graph.removecomp = function(comp, compos) { + var name = scdl.name(comp); + return append(mklist(element, "'composite"), + filter(function(c) { return !(isElement(c) && scdl.name(c) == name); }, elementChildren(compos))); +}; + +/** + * Garbage collect components not referenced or promoted. + */ +graph.gcollect = function(compos) { + + // List the promoted components + var proms = map(function(s) { return mklist(scdl.promote(s), true); }, scdl.promotions(mklist(compos))); + + // List the referenced components + var refs = reduce(function(a, comp) { + return append(a, + map(function(ref) { return mklist(scdl.target(ref), true); }, filter(function(ref) { return scdl.target(ref) != null; }, scdl.references(comp)))); + }, mklist(), scdl.components(mklist(compos))); + + // Filter out the unused components + var used = append(proms, refs); + return append(mklist(element, "'composite"), + filter(function(c) { return !(isElement(c) && elementName(c) == "'component" && isNil(assoc(scdl.name(c), used))); }, elementChildren(compos))); +} + +/** + * Clone and cleanup clonable references. + */ +graph.clonerefs = function(compos) { + return append(mklist(element, "'composite"), + map(function(c) { + if (elementName(c) != "'component") + return c; + + // If the references are clonable + var refs = scdl.references(c); + if (isNil(refs)) + return c; + if (scdl.clonable(car(refs)) != 'true') + return c; + + // Filter out the unwired references and add a fresh unwired + // reference at the end of the list + var cc = append( + filter(function(e) { return !(elementName(e) == "'reference" && scdl.target(e) == null); }, elementChildren(c)), + mklist(mklist(element, "'reference", mklist(attribute, "'name", scdl.name(car(refs))), mklist(attribute, "'clonable", "true")))); + return append(mklist(element, "'component"), cc); + + }, elementChildren(compos))); +} + +/** + * Refactor references to a component. + */ +graph.refactorrefs = function(refs, oname, nname) { + if (isNil(refs)) + return true; + var ref = car(refs); + if (scdl.target(ref) != oname) + return graph.refactorrefs(cdr(refs), oname, nname); + + // Change the reference's target attribute + setElement(ref, append(mklist(element, "'reference"), + append(filter(function(e) { return !(isAttribute(e) && attributeName(e) == "'target"); }, elementChildren(ref)), + mklist(mklist(attribute, "'target", nname))))); + + return graph.refactorrefs(cdr(refs), oname, nname); +}; + +/** + * Rename a component. + */ +graph.renamecomp = function(comp, compos, name) { + + // Refactor all the references to the renamed component + var oname = scdl.name(comp); + map(function(c) { return graph.refactorrefs(scdl.references(c), oname, name); }, namedElementChildren("'component", compos)); + + // Rename the SCDL promoted service and component + var proms = filter(function(s) { return scdl.name(s) == oname }, scdl.services(compos)); + if (!isNil(proms)) + setElement(car(proms), mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name))); + setElement(comp, append(mklist(element, "'component"), + cons(mklist(attribute, "'name", name), + filter(function(e) { return !(isAttribute(e) && attributeName(e) == "'name"); }, elementChildren(comp))))); + + return append(mklist(element, "'composite"), elementChildren(compos)); +}; + +/** + * Cut the wire to a component node and make that node a + * top level component node. + */ +graph.cutwire = function(node, compos, g) { + + /** + * Find the reference wired to a node and cut its wire. + */ + function cutref(refs, node) { + if (isNil(refs)) + return true; + var ref = car(refs); + if (caddr(ref) == node) { + setlist(ref, mklist(car(ref), cadr(ref), null)); + setElement(car(ref), + append(mklist(element, "'reference"), + filter(function(e) { return !(isAttribute(e) && attributeName(e) == "'target"); }, elementChildren(car(ref))))); + } + return cutref(cdr(refs), node); + } + + // Cut any reference wire, if found + cutref(node.parentNode.refpos, node); + + // Make the component node a top level node. + node.compos = g.compos; + + // Update the SCDL composite, add a promote element for + // that component + var comp = node.comp; + var name = scdl.name(comp); + var prom = mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name)); + return append(mklist(element, "'composite"), + append(mklist(prom), filter(function(c) { return !(isElement(c) && elementName(c) == "'service" && scdl.name(c) == name); }, elementChildren(compos)))); +} + +/** + * Wire a component to the closest neighbor reference. + */ +graph.wire = function(n, compos, g) { + + // Compute position of the component's service node + var spos = cadr(car(n.svcpos)); + var aspos = graph.abspos(n).rmove(spos.x, spos.y); + + /** + * Find closest unwired reference node among all the references + * of all the components. + */ + function closecomprefs(nodes, spos, cref) { + + /** + * Find the closest unwired reference node among all the + * references of a node. + */ + function closerefs(npos, refs, spos, cref) { + if (isNil(refs)) + return cref; + var fdist = cadddr(cref); + var ref = car(refs); + + // Skip wired reference + if (!isNil(filter(function(n) { return isAttribute(n) && attributeName(n) == "'target"; }, car(ref)))) + return closerefs(npos, cdr(refs), spos, cref); + + // Compute distance between service node and reference node + var rpos = cadr(ref).clone().rmove(npos.x, npos.y); + var dx = Math.pow(rpos.x - spos.x, 2); + var dy = Math.pow(rpos.y - spos.y, 2); + + // Check for proximity threshold + var rdist = (dx < (graph.proxcx * graph.proxcx) && dy < (graph.proxcy * graph.proxcy))? Math.sqrt(dx + dy) : 25000000; + + // Go through all the references in the component + return closerefs(npos, cdr(refs), spos, fdist < rdist? cref : mklist(car(ref), cadr(ref), caddr(ref), rdist)); + } + + if (isNil(nodes)) + return cref; + + // Skip non-component nodes + var node = car(nodes); + if (isNil(node.comp)) + return closecomprefs(cdr(nodes), spos, cref); + + // Compute the component absolute position + var npos = graph.abspos(node); + + // Go through all the components and their references + return closecomprefs(append(nodeList(node.childNodes), cdr(nodes)), spos, closerefs(npos, node.refpos, spos, cref)); + } + + // Find closest reference node + var cref = closecomprefs(nodeList(g.childNodes), aspos, mklist(null, graph.mkpath(), null, 25000000)); + if (car(cref) == null) + return compos; + if (cadddr(cref) == 25000000) + return compos; + + // Wire component to that reference, un-promote it, and + // update the SCDL reference and composite + setElement(n.comp, graph.movecomp(graph.dragging.comp, null)); + n.compos = null; + setElement(car(cref), append(mklist(element, "'reference", mklist(attribute, "'target", scdl.name(n.comp))), elementChildren(car(cref)))); + var name = scdl.name(n.comp); + return append(mklist(element, "'composite"), + filter(function(c) { return !(isElement(c) && elementName(c) == "'service" && scdl.name(c) == name); }, elementChildren(compos))); +} + +/** + * Display a list of graphical nodes. + */ +graph.display = function(nodes, g) { + + // Append the nodes to the graphical canvas + appendNodes(nodes, g); + return nodes; +}; + +/** + * Hide a graph. + */ +graph.hide = function(g) { + + // Remove nodes from the graph + map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); + return g; +}; + +/** + * Refresh a graph. + */ +graph.refresh = function(g) { + //debug('refresh'); + + // Remove existing nodes from the graph + map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); + + // Redisplay the composite associated with the graph + var nodes = graph.composite(g.compos, graph.mkpath().pos(graph.palcx,0), false); + appendNodes(nodes, g); + return nodes; +}; + +/** + * Display and enable editing of a composite and the graphical + * nodes that represent it. + */ +graph.edit = function(appname, compos, nodes, g) { + + // Store the composite elements, and sort them to allow for change detection later + g.compos = compos; + var scompos = scdl.composite(g.compos); + setElement(scompos, graph.sortcompos(scompos)); + + // Remove existing nodes from the graph + map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); + + // Display the composite nodes + appendNodes(nodes, g); + return nodes; +}; + +/** + * Track the composition graph, whether it's visible or not and the selected component. + */ +var gvisible = true; +var gcomp = null; +var cdiv = $('contentdiv'); +var pdiv = $('playdiv'); +var graphdiv = $('graphdiv'); + +/** + * Track the palettes. + */ +var gpalettes = new Array(); +var spalette = 'control'; +var bpalette = null; + +/** + * Get and display an application composite. + */ +function getapp(name, g) { + if (isNil(name)) + return false; + showStatus('Loading'); + + return composites.get(name, function(doc) { + + // Stop now if we didn't get a composite + if (doc == null) { + showError('App not available'); + return false; + } + + // Get the composite from the ATOM entry + var composentry = car(atom.readATOMEntry(mklist(doc))); + var content = namedElementChild("'content", composentry); + composite = isNil(content)? mklist() : elementChildren(content); + if (isNil(composite)) { + + // Create a default empty composite if necessary + var x = '<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" ' + + 'targetNamespace="http://app" name="app"></composite>'; + composite = readXML(mklist(x)); + } + + // Display the composite + graph.edit(name, composite, graph.composite(composite, graph.mkpath().move(graph.palcx,0), false, g), g); + + // Track the saved composite XML + savedcomposxml = car(writeXML(composite, false)); + + // Enable author to edit the composite + author = elementValue(namedElementChild("'author", composentry)); + editable = author == username; + cadd.disabled = !editable; + showStatus(editable? onlineStatus() : 'Read only'); + return true; + }); +} + +/** + * Display a palette. Get it from the server if needed. + */ +function displaypalette(name, g, palette, gpalettes) { + if (isNil(name)) + return; + if (isNil(gpalettes[name])) { + + // Get the palette from the server + palettes.get(name, function(doc) { + var entry = car(atom.readATOMEntry(mklist(doc))); + var content = namedElementChild("'content", entry); + var compos = isNil(content)? mklist() : elementChildren(content); + gpalettes[name] = graph.composite(compos, graph.mkpath().move(2580,0), true, g); + graph.display(gpalettes[name], g); + }); + return true; + } + graph.display(gpalettes[name], g); + return true; +} + +/** + * Install a palette, including a button to select the palette, and + * the palette content. + */ +function installpalette(name, pos, g, bg, palette, gpalettes) { + var b = graph.mkbutton(name, pos); + graph.display(mklist(b), g); + b.onclick = function(e) { + + // Swap the selected palette + graph.paletteselect(bpalette, false); + displaypalette(spalette, bg, palette, gpalettes); + bpalette = b; + graph.paletteselect(b, true); + spalette = name; + return displaypalette(spalette, g, palette, gpalettes); + }; + + if (name != spalette) { + + // Will get the palette from the server later if needed + gpalettes[name] = null; + return true; + } + + // Display the selected palette + graph.paletteselect(b, true); + displaypalette(name, g, palette, gpalettes); + + return b; +} + +/** + * Save the current composite. + */ +function save(savexml) { + showStatus('Saving'); + savedcomposxml = savexml; + var entry = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title type="text">' + appname + '</title><id>' + appname + '</id><author><email>' + author + '</email></author>' + + '<content type="application/xml">' + savedcomposxml + '</content></entry>'; + composites.put(appname, entry, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + showStatus('Saved'); + return false; + }); + return true; +} + +/** + * Handle a composite change event. + */ +function oncomposchange(prop) { + if (!editable) + return false; + + var newxml = car(writeXML(composite, false)); + if (savedcomposxml == newxml) + return false; + showStatus('Modified'); + + // Save property changes right away + if (prop) + return save(newxml); + + // Autosave other changes after 1 second + showStatus('Modified'); + setTimeout(function() { + if (savedcomposxml == newxml) { + showStatus('Saved'); + return false; + } + return save(newxml); + }, 1000); + return true; +} + +/** + * Return the link to a component. + */ +function complink(appname, cname) { + if (cname == '' || isNil(cname)) + return ''; + var protocol = location.protocol; + var host = location.hostname; + var port = ':' + location.port; + if (port == ':80' || port == ':443' || port == ':') + port = ''; + var link = protocol + '//' + host + port + '/' + appname + '/c/' + cname; + return link; +} + +/** + * Handle a component select event. + */ +function oncompselect(gsel) { + if (gsel == gcomp) + return true; + gcomp = gsel; + + cdelete.disabled = isNil(gsel) || !editable; + ccopy.disabled = isNil(gsel) || !editable; + cplay.disabled = isNil(gsel); + return true; +} + +/** + * Show the result data of a component. + */ +function showdata(gcomp) { + if (!gvisible) + return true; + if (isNil(gcomp)) + return true; + cvalue.value = complink(appname, gcomp.id); + cplay.value = '<'; + gvisible = false; + pdiv.innerHTML = ''; + pdiv.style.visibility = 'visible'; + + // Get the component result data + var comp = sca.component(gcomp.id, appname); + comp.get('', function(doc) { + function displaydata(t, w) { + pdiv.style.width = w; + pdiv.innerHTML = t; + return true; + } + + // Stop now if we didn't get the doc + if (doc == null) + return displaydata('No content', '2500px'); + + // Format data table + if (json.isJSON(mklist(doc))) + return displaydata(ui.datatable(json.readJSON(mklist(doc))), '2500px'); + + if (atom.isATOMEntry(mklist(doc))) + return displaydata(ui.datatable(atom.readATOMEntry(mklist(doc))), '2500px'); + + if (atom.isATOMFeed(mklist(doc))) + return display(ui.datatable(atom.readATOMFeed(mklist(doc))), '2500px'); + + // Insert the doc as is in an iframe + var t = '<table class="datatable" style="width: 100%;">' + + '<tr><td class="datatdltop">' + 'value' + '</td>' + '<td class="datatdr">' + + '<iframe style="width: 100%; height: 5000px;" scrolling="no" frameborder="0" src="' + clink + '"/>' + + '</td></tr></table>' + return displaydata(t, '100%'); + }); + + setTimeout(function() { + graphdiv.style.visibility = 'hidden' + }, 0); + return true; +} + +/** + * Show the composition graph. + */ +function showgraph(gcomp) { + if (gvisible) + return true; + cplay.value = '>'; + graphdiv.style.visibility = 'visible' + gvisible = true; + graph.compselect(gcomp, true, atitle, cvalue, ccopy, cdelete); + setTimeout(function() { + pdiv.style.visibility = 'hidden'; + pdiv.innerHTML = ''; + }, 0); + return true; +} + +/** + * Handle play component button event. + */ +cplay.onclick = function() { + if (gcomp == null) + return false; + if (!gvisible) + return showgraph(gcomp); + return showdata(gcomp); +} + +/** + * Create editor graph area. + */ +graph.mkedit(graphdiv, graph.mkpath().move(-2500,0), atitle, cvalue, cadd, ccopy, cdelete, oncomposchange, oncompselect); + +/** + * Install the palettes. + */ +var bg = graph.mkgroup(graph.mkpath()); +var pos = graph.mkpath().move(0, 0); +bpalette = installpalette('control', pos.rmove(5,2), graphdiv, bg, spalette, gpalettes); +installpalette('values', pos.rmove(0,28), graphdiv, bg, spalette, gpalettes); +installpalette('lists', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('transform', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('text', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('http', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('animation', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('talk', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('social', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('search', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('database', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('logic', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('math', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('python', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); + +/** + * Get and display the current app. + */ +getapp(appname, graphdiv); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/home.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/home.b64 new file mode 100644 index 0000000000..9131135881 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/home.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAAaoAAACRCAIAAAAdJ2t7AAAgAElEQVR42u2d+1NT1/r/99/AD2f68ZfjOOOFGXFwhoLScqgow2E+IAylGUqDCAlBwFgU6yUwMkVyKnKGD7anSvVrcWwZLziVFioUiQJCzIWQkHATwrXCEVQUBP1Uz6d+n7XXTtgJm5ug3J5n3tMuHtfaa+2tefE8a629wrxGQ0NDW5HG4CNAQ0ND/KGhoaEh/tDQ0NAQf2hoaGiIPzQ0NDTEHxoaGhriDw0NDQ3xh4aGhob4Q0NDQ0P8oaGhoSH+0NDQ0BB/aGhoaMsSfy9fvhwbGxsdHX2G9tYMHi88ZHjUS+75L92R4/NchPe4iPA3MNyhsV4pbzz1q/mr4oZM1FsSPN5yS6763qX23obBwcHnz5/T5/981DrQ90NfV9b9zmP3O1MXpWBgWX09F/vvG/kjb3nyNK/5nsJg3KczJGnrUDMUPC5FnfGMpVnf3ePwL2GoZbAxr1+r6Ffv669NWtqCW4AbaTjT36Xn3+Piwl/rv6tKzEpk07sUPHBjR3l/f//w8PDTxxX3O9MWK/UmKq2v9wYdeUnv/b1IvbkJHuD1e230eQ73lPSr9y556glwcG9/y3V6j4sLfxD32dlXYs4sa838rS2zvF2JekuCxwsPGR41PHaIAXu67va0HaVk6e9Kfdyf+nQgdXhwMQoGBsODQQIBIQa8025NUOu4j7HOkGC0JDQ0JZibUTMVPC6jBR4dEBBiwJ62O73VCZQXD9RJT/QJI4aEZ/VLW3ALcCNwO4SAXXog4NxjwPnEH+S8lH1lrcrb9zMr+5SodyB41PDASRbccrqj+SCwD8jyn1HF/40tdsEgYaiQBWdr66TVtcC+RKNF1tYpa+9CvYnaOuEBQhZsvZvdeUsK7HuiT/yzSfa6efkIbgduimTB/f2QBS8W/L18+bK88RSN+5B9C0DAhv9pb063Nqfc7zy6JNhnJ2CP9cT+O2pJVU2Ctg7ZN3cCKrQG6+39nSpJf03CMmOfnYAPdIp+1ua4EjJv+BsbG6NrHZCOTftxVdXHfRYXVNCB5JpEPYcPy33/UXts5k1KGr5qbzoE+BvoPbyQRBved/6gd5Hl4Myb3O84JquqAfzJ6oz2j7G4MNd1x1aXLYnhjXPCgbT2qvvu9IjGhWk+hew3GHYLujgGXUhrCmhhjlfepzV0qGSAv4d3x5HxoibCqpHOFjRv1uod6EmdnOIPsLMo8Dc6Okoz39/apsdfaVkQw7x3ug1JN4naktYwTHxZ2izwZ84E9oEe3j+0kPgbiHVjmBO1B2bepL87TcLiT2ow2T7DdV4Mw6yP9ErLnSMOYorSGWZDqGlhmk+u8Rv8+HomlKCLmKJjtDDHi+/VGYB9oMd2chnDQxgm43L07CjzZq3eiUYMCRR/gJ1Fgb9nz55R/JW3T/9ZLVXBg3X9vgfKx1U9yDvH0BgeSE/yhwwjnw3+fjUrKf4e9S1Y9PfHMER/8fBXm/tG+Iurb7B9hitdGca7pHXuoIkpUTKMf3hLl6ylXfqGzbeGzT/+BG4wpgQ4uCVsHvBXT/E3pI3jeGEhIDtVJJkdZd6s1TvRs3oOf4CdRYm/nuTPXN+L/+kwG8vIw13fi81PIeWOZCjv/3//Db/8wuXvM6z5p+4uZT/DxVVR/q7U9568IBk85bVRH7q6xx50rmkXW8E1PM6dVvjsX0kq1n+xIGQzw9haRRWzzis/cc41YR8Ee7/32dkUwU6dVFT2qb1CfL58ik5nPn7BTq9c5Ya3OeA9+O+BOeOvqSjwI9tD+Czzk0djijHLJyEb132+dyN1HsmP/WMSJzR/VP/JZ5zvL7lF8f/H1dz4Zdpm2zUjnrI1u37lOvoo6C/w3zNzwV9jhZttzGszSsEjOq9cZfccOhfNfsijik6vXU99W30uVtJPfnTZOZtzg/f5Chu/GNfdodTrkVMsdW6+wSuvVDaJk4e/xoDPQyFe26lt57NGojq3er2/m+367uz1WefWtSFbSdc5Fc6XdbxBScXp/1ofE25ywN/EG5kD/mIKgrnukrNF4BkqCRCvow6XU2fBIy2Vr2Y83Q16Qhbrtx4Ms/rnil1OrRB/s4r+vkwLYxhxFHChuPjv5CmGicq5tHfN/xSFEI/rBzmq5K//5QtFueqYqn43ZHyb5R9frP+COuN/UrBxIhipmZPzAYGC6tiEQBIu5Xtad/js2R1QjL16uLyKOINPxF6p/+J0PukdEsnSKhEUPkyNKtDJD8cRvnyYkSTYqQNe2VZr4j6+qEvJOUEG8FnBF4Kdznz8gjXLecOTB5A2U0R/5R3KYvNxUHnHpPgbqw+Ei8i+juyyJqmv+jFsTvpUR5zMRm916z59wd+g+OWv+wSdf1gj4FP60cGgJmtSVb43aX4zmavJeN7Uxd/M8ySk0x0cqyf3GJL5SVurNDeI/PEU0d+zh4r+LiIoTBL9tUZcIsxyO1EgqmqUlLH8yiiIrK0JzTsCZa8ik0x7wQU+u7uzRVWVgYf8ye+VqnZpLXGu2pMtqq3ZmZNIal6qo/hj1ifuLKukTo+LdZKyXMbWPCgjlmDrfI2gkwseG03+u8ll/EpMQuEhuX5olSbsm/3s9TWck4n1zUjfnvfVhMve4t9gTAnkvFtCefgTvJHJYLfH0pKoM4CgMFn013eZ/BuTpQdaaySvKgM3Mcw2mW9LZWR1Nvn9nfVD1GvNTvJXuCtgsIL8y9umCHVqhfibdfJ7rQAen3tBn/L0wTXsv4b3L5Iy4eDPLBT+UU9rHv4MUHU25fsTEA6tOalLKzYriptT4r3Ha57k1XSaESt1qHD8yzDSqrTti6+vJhX3KMvb0q6UfbqGRcnZjDWMa1Ax1zAZfrdtzkgS7LScd33SivG9wv14/B9i+CwG/STU6XczHr9gp9+Sjv7ODa9DPkXya7yX3dZ0GFSt/+pK1fFfjMcF8ffHQFLVr7GPhhVjAwe6asPcWCpRft2wUvQcuRrBMBEhA0JO3dcQIfz1RuuBR93Jj/oSTvxtYs19R1ik6rP/CmR4RAH3WDpF8nu9qTCxuhr0490Ckz6t15omnPy2lK625YZSU83Oi8XRLV0Skymy6DRwwbvIFJ4ByIuN5BCgCTiRG65tZ51bA6tM0dq66LpKry2A5NxdLIkCamnNdj8Y3I7snWkQlyXamrcHwP2uTxd0itnmq7Yw7JXbJ8mOmUDb9f1DeJ1WEWeY0GVjeDdop569IHgjEiH2Fel/vKdKBF29dfbzctVejW7a5NecDj2vKq2IHqqJGtJEZMGvsGC/FxASXvbmgr1g3yFMfudh7q85Dj7QaSo5/MqLL4iCv9LDZUlQDi84zDJrzVlu6ePYYW9mTUbSxX+9z/DNFVLUj39yrHnAVRh/XzdzP17McSWM6zmcdtCdfzE5Bx3fIq7hl1N0ys+vv4cLMjtsrej1Q34S6vTMjMcv2OmZE/yOvpx4p/a4D8BHSQcFwB8InALJ7/C+H9M28vux46+qz5Yd561jNvp3Cznv5m92GORGxi0i6D6p+Vf9AK158MxGgj8TAeXfHnCMO0SdgnEfgI+SDgqAPxAJBifir7F4FYs5FoUav89D+QMBvygHPOkxjiwQ5UQ6DHg94xKSzfJrfO1CdMKfkA7+y+yPauc7laFCTjEXx7H9CoVgFH876xyuH8nGjGHsok240GVjeDc4EX+CNxIjFPcB+CjpoAD4A4FTAH/GsG0AsmtkEaMl29Xh4uuYTcG+I2yOzEbzTJ6dd7xWiL83WPo4dhhCadf3yCpHxzESIrGf9dPNSif8HfAmgRgbZ31gi7OUV8piTxanlDjWlAvj7z07iU7G0UAMLuX6D9UXpZAb9sg3s8n192x4ZeNLSjgzaacq5+hvHH8n5YwNf86dfjvj8Qt2mseP/iZf+oCEl2Kut/0g6KdqJeAPnDcbTzjhz/Q1BGXrinRJTx8DCqUfAf50B1n8/cVOuht77TGds7OWxHSeXTZ4ddVG3qhMeOyIv9yNE6K/yZc+IOGlmJPUakF3dUrAHzjbO76aAn/hGRA9+QeU1MQ0kqiQ+Esa2ZBqv5gDgcl/T6T3xRrWaQ8JuyKLCgILK6PZyTsb/tjojIv+xpEUuAcQoxR0Unru1JoCSfLrH1oniL8NdvyRalz0xy2YhAlddmr8Cd7IxHWbRNsK7/0qotSbNwB/4FTo1YL4o1wzKKBnt24bR7qvBZVejngFhW/t4YK71eLcCvH3Jiu/V/LJbBcTEALpZAENeegM4AT8QSDGTX4djLrSnFbwEwmv1qTuKZ0R/pg14pCC5rTv88k03GdXD7Oke//r+mPlbV98KSepd/C/klX1UWRVQS76vipJzrL4w0k6dbz+x+yU3O6iNu76kKcLdjrz8U9S82N2vjKuqO3wyVT3yeb++FHeo74vDMZMIGCxJtPSZPd/weGPUGlzlfXg2EDS1YN/JfM4+fE0+nOLDWzrO2C6Sqb5jtjm/pyc3Ixe2iddfQfabrIVMqOfCuHvqS6InWSMejCw70bmxsnm/vhRnsTQkKP+BQhobMg8pb/BYdEghD/CgsidtY0SU43/Hm4xQaIi83Rr0y5EmUyhOWRCzU/VSifvVn9+LrLORCfXXA5d56bhQpQRdaZwdurQnczNZZOah0jz8DwyYef6TeUkThZkjWRIa8l1cmOEoj+XCHr9/bbrj+NP8LKyKfEneCNTL3EMaSW3b2cBARVVN+/U/NPmt5FLHwogE6f4t1TGvCghs8Ah8oBuTbT1Bx8ob0oJ5SYEFWGAPPK3Lgt85dgK8fdGG1/MsRB5+eeQ1VJV7ad03YBdT4CPuisffx+ydQoKgtbYfgdtjhNd65lQczL82ScuMmLLybbq2GD7dcS+wRDvx0WR0En16Yes88O4Hf5kMIcFO3UizkV28YS/dCvY6azGL9jpRXYVhQ2RXdn5ymNT4+/50BFa5guc3NyfNVJm6+KjWG8ZcGnvJxzp/sb5ZdmRY2MKQSdcoa3I375G+dHekN+HFWP1QLp1TskvyZcLbI03rmMnGQ9Ojb+4pnsc8ngCpw1/pWttdJDWFtiztVURia7rGWb3OfBHnE+3/6W429Zzwelir7w7V9wCKMmm+SP3XDOu0poiFoW21eQLMZM42eb+FGRRl47Q9RAB/G2xXT+tQOLYSrgv3g2ylXew+OMKgjcyNf7+1xRHy3yB08aL6HyRCyUdWds9673JdvFtu/z6LFGnIO1d50FDwr6zHtx6iGMrxN+87fub8oWHL4ub00o7js+wPreFsEOpaksrdXiN5Hip43WuFPw9+GAUN6/XkbSZv4oybadchWk7nc34BWuyTtWMN7gM9H7BZx/86AidI0/7Djx9fMTuYUm3zvRY8cfAAZIUT+60TSAeeuR4hcnf9yA1/5jxBhep3shnH/w4+WaO9pg6U0zjhJWHltZo8LcIOSdUFrgCV7Nreue0+wobu6SmKVvN8rJT3MhkG1we3pXy2Qc/Or/CYZS8Gt/TJxnSRI8Yp3+jw6EV4u+t42+WmvkLJKpaEZt9+x448Xc2BnQ/3fzWO513TVzigHAPEl6QPe6bQk9rIer9i3pgeue8a+ISB4kBDSQRHo/7lpre2mshb7K9GcI9SHhBvLhveQrxZ4OaOelAxqdXZvb6cJEqNl7+QbD4/dgTn15sPv5uOl1U+PujO/ZMdljX4+mdiL8ZvRSsLfZJOx3ZiPhD/C0E/laanPB3r+PET9VKkMGYKZT8LiI54e+0peKuTgnKUf8yXfKLmh5/Wn1u6s0boNu3swSTX8Qf4m9Z4Q/CPbrxBQQFp6WPxYw/CPfoxhcQFJyXPlCzxB+Ee3TjCwgKE5Y+EH+Iv+WCP7rtGfA3cF9B2XftLpHTxpdFiD+67Rnwt9dYT9nXalaAnDe+oGaGP7rtGfA3oNtL2SevvANy3vhiU8u3XjKRu6rC5tdEFKZ7HZW5HZX7VJdxu1teaUSFCq+ju9wyFP5WvdMhCJF5MtfklMAReuxK2c58pW9Bth+R0rf0WhRbTdqS75chc0uWef18TQyewWuB49XYmgVnw8lyikZUoPBI3uV2NMXXUClB/KGmV7H5eLX+KyBgV9uRu+YTFH/gXAwnvkyDvy7Fj3cLgIBJavUVwyWKP/L+r8CJL6jplagzXL11FgjYVZVYWPM9xV8iOe9+wlsflFYl/nS/C/cihz5M7PD+B5NfFPPaGC5z8Nm2QLOqTmGPnvD0oW/FsTuo+W9WhQL7VCkOzrxr0YYUF8bZvIb0Th2tUtVIEX+oaVTewWW7fAm/9LbI9OyhgiKPL+GX3lAz0B5LC0UeX8IvvTVLDNnj74BS/HXnsns6Pb2sGnHhLsKsbSmhfflste0+3TXhR9lTYbJs5/2NFPlw7T192OhPwh4J43JU4Zuv9Dml8Cq8LH5dE8QS1qWwRGxQrqVM7Lvsf0rhk5fuk690t20sFY1cYzfNbvfuM0b/vIvwMSNfjPhDTa9fjA7sm+zIg0WoXqsD+yY98gA1w/xXo+Ozb9IjD/Shm3iBFsWf9ay3ePvqjG8jyeY+Fm0hirChsrBCpU9pCaSiUnrgFYc/S0Syvf12Fn+WCJaPLoVFkd0VYro3cDCfbJneJAsYaZYOloVVXw7v5p0W86LIlzaH4JHiL4Q9WkYjJ/BNZkeC+EPNKAac9sCrRRsDTnfgFWp2MeC0B169NoqydnkZasT5wbzkd1xRp7YTv1hpO9dPHyajBwJ6eg2yHhVLKLHcI8TGr9eandscste11ZVSg2I137VN5NM3njtHZbG4/LmCJrli9kdmk+cqFs2uZj3O/aHmbz/gUhHi723vB7QpJm/7BPxZxHnBztN8L0r8tjF0wm71zyUxQ9fYtFfk/6o5gkzYbfd9QWYS/QBbm7Z7qK6F5rG5MxPsp09fSyfysnIDTolWsZFgEA0M6YFam2SBNiLT4JFh1nEdlVZIEH8oxB/qbeEv3wl/RhHHIMbNoHFGTB+byTIiv9Pbac7rniXj6CaT+VqNvMoadsrP0+d2+mrKQfbEBDY89PQe4nWdV8StL7ewM4MhKTvJLCT7ljGzK/AV4g+F+EO9E/yxJx0QQnnYWdbCrpAcZafhhi57sX/qnes5YeWWcSk55yP2dJGlh5G9MmV+tGYnPTOVIq8mcJO9bAwnq8zrPPpsg6FpMk236cyjbUUF8YdC/KHecvJrzR0/93QTGwOGpIdxC7KMi0zmSldLknMjXuijhzTRQ/qYkcqgEHZCsFsvfUGRxzAyuQf95hByXpZFRLezbAt2E3sy9nPzuYlCHuAGKVsZl2S5RwjbXJwdgckvCvGHemvRX7Btf1+zpHCX83a8EBLKSTW8LTLJ6TtfOH71pdi+8tssNed62BeUxba90C8qgrhlE7igzH+Qt2mGrvPaJDVke4x3LQ8Ywm3PKMQf6q3hb+ZfcRnDHoc1k5oSNjB02rEsHSFOyZs2R/yhEH+ohcIfvvOL+EP8If4Qf4g/xB/iD/GH+EP8If4Qf4i/RY+/DpVsmePPKEf8oRB/qAn409dbb+8H/D3WLNsTT0caFBR/o6OjiD8U4g9lOwhLb7xXcxLwN6hettHfk9bvKP7GxsYQfyjEH4pTQr25sb68QyX5vTr+z6ZlyL4/m+Mf9Bgo/l6+fIn4QyH+UDb8mZubmpqaNRd6q/c80ScuMwIC+550lVD2DQ4OzpFaiD/EH+JvueGvs7PTbDZ3NFf3N5x5oFM8qZOPGBKe1S9lGeUjDQrIee1xH9jz588RfyjEH8oBf4CGtrY2q9Xav3xteHh47tRC/CH+EH/LEH80NwRbfuCDm5p73If4Q/wtFvzJEH/zJ7mlhb8n7uXLl2NjY6Ojo8+WuMEtwI3Mca0D8Yf4W1z6d3fa/jtq8k3nBhPCa+5SNLXOy5bglWCIP8TfAutBT+pJtZZEf/p6hNfc9V1bB+IP8Yf4Wxp61JdaXm8E/MWrtbK2TuTXXBTf3mXo/R3xh/hD/C0NDQ+mNjU1XdDp96i1iUYLEnAu7Cvp6bUvESD+EH+IvyWAP7pPrbql9YylWaEz7NMa9upA9StR+vpEvTGh3pxgbnZWvRn+CCo4Nflcb0ytN55paFS33rPabHBwcJEsLyD+UIi/qfBH96mVmy3Z2rr9d9R0IXgFCm58f7X6pFpbXm+EiBh+K9A4rqftjvVutvX2fnqUy7TqqZT11ybNWup9/VpFf8OZ/i79PG4uQfyhEH/T4O+HBktctVpaXStZqexz0gWdHiJi+K3QbfqhYwbI43RL2lu9503Y58DBvf0t1+drazHiD4X4mwp/d9qtZOmjVpOkrUvQ1snqjFKDKa6+YQWK3Li+Pl6t3aPWVre03mso77wV11sVD/q9On5QHfdYIx3Sxk3UE51suC5+ju+WjRgSnugTHqhZAnbp5+XFMsQfCvE3Ff4g56X4w6UPTm2d8CjOWJoh54WADiKyd3l4AXQE3ZEseD6OFUD8oRB/U218odueceOLEwEVWgM9uLS/JuEdH9wC3T3QKeblUCnEHwrxN9W2Z+6lN962Z4m2MqKufWpASGuuuu8+FtHoXH8mbedR4sJc1x1bXbYkht3ixiOtKbAPbC7apzXQtY6Hd8fB9KImwjr7Y5zfoNWTOvm8HCmK+EMh/qZ66Y1O9o+/9NZYupphPAqneQcupiSTYdaHmhzrz6zt/KnOi4FRRHql5X58nRtPTNExbmBz/dYOA13QGD+23hgewjAZl6Nnh783ajViSJiXA+URfyjE32xOfGkhCPMuaZ0pKfj1Z9t2rqp0ndAdy+UtYfOAvwnf2WYhIDtVJJnl15a/Sav5+jY1xB8K8Tdz/DX6wYeVNbd/fu++foPXJQ3xm0rd1m/wyKtkQ7wKKPucy/mv9THhJl79nGJeuQJqRpedW7ueOjZ4nyceierc6vVb14ZsBZcrW4dLmYnf3213KK3tnlMsnVA5qui0/WpeeaVkGFxvzNqMUknFaXY8DvibOIA54C+mIJjrLjlbBJ6hkgDxOupwOXUWPNJS+WrG092gJ/yyfuvBMKt/rtjl1Arxh/hD/C2Mnj1U9HcRQWGy6E9cmE1wk3EhQttAcBZxDkgUXXiEfIJDciUQXhWlM8zWoMuQY26BHJNXv5VfltZecGGYVXuyRbU1O3MSwe91qS6mRMmiINY3I92/xMQL2Vj/+sTQKk3YN/uh6HFRw6+8Pe8rgpnd2aKqyqCMWILI87ciLpEKbicKRFWNMSXceOz4ExzAZLDbY2lJ1BlAUJgs+uu77AsXkaUHWmskryoDNzHMNplvS2VkdbY7+LN+iHqt2Un4vytgsCIA/r9NEerUCvGH+EP8LYyuNxUmVleDfrxbYNKn9VrTpk1+xeeBGqER7V2hn29lSRQpImXCwV32IGuS5Dc8wx8oGVhlitbWRddVem2hrQiwAqomziQSf2At/bHdP8S5clgaDCAxkqvfHhABrEyP4XVnp569IDgAiRD7ivQ/3lMlgq7eOvt5uWqvRjdt8mtOh55XlVZED9VEDWkisjwZJtjvBYSEl725YC/YdwiTX8Qf4m+RxH0APko6KAD+QCQYnIi/xuJVwJQiNjSruwoBlF9JKSRyXufPrWUY36JiKLud14znmPz6vLIoJ5Lh23rGJSRbTIjmH9YojL+dddyPohP+QLdIXuVw8DD7o9r5FZQxvO4m4k9wADFCcR+Aj5IOCoA/EDgF8GcM2wYgu0YWMVqyXR0uvo7ZFOw7wubIeZ7EkWfnHa8V4g/xh/hbiDm+LgX3RletFnRXpwT8gbO94ytB/Plw6wmNvjsAHBsAQ+GNjf7c1J5/aF2XE/64+rwyG6/F2uK1rsiigsDCymhCtK0T1yVY/G2w4y9wtz364yqzVxvHX+AeZlr8CQ5AOvGbeW0rvPeriFJv3gD8gVOhVwvij3LNoICe3bpttOq+FlR6OeIVFL51txHR3WpxboX4Q/wh/hZ4iUNiaMhR/wIENDZkntLf4LBosOHPdB0+2WsPnRbVNhJq5JGJNmaHEtLGCBpP0RlAO/749XllSVku1F39+bnIOhOdpHM5dD1mKvwxLhHKiDpTeB6Z+3Pn5v64yjElZFZx9aELUSaugus3lbIp8Sc4gKmXOIa0ktu3s4CAiqqbd2r+afPbyKUPBZCJU/xbKmNelPiRJyEP6NZEW3/wgfKmlFBuQlARBsgjvylkga8cWyH+EH+IvwXGX1zTvYkv+YPTRgSTb8SGcVhoCwjRTpSSrc6q0+yaQw1Zqy0DHu1g2cSv79A24ny6iy0WWrU7V9xCW/lPir8tXGXXtAJJu3NlUd4Re6659tCFGHab4Vob/uzjYUFJByYwgKnx97+muIkHGYDTRqXofJELJR1Z2z3rvcl28W27/PosUacg7V3nQUPCvrMe3HqIYyvEH+IP8bfAG1ykeiOfffCjExQkja3S2WwT4dd3aNvSGl1nimlsn24TtZLNr7ukJqg8xR5DerXZ7OCbbgBOc3wP70r57IMfnV/hMEpeje/pkwxpokeM07/R4dAK8Yf4Q/wt7PZmEgMaSCLMi/sWTOxmmg1zf1VjXrY3Q7gHCS+IF/e9ayH+EH+Iv5WCP6m22CftdGQj4g/xh/hD/L1l/J22VNzVKUE56l8Ek9+VIyf8afW5qTdvgG7fzhJMfhF/iD/U0l76oBtfQFCYsPSxcvEH4R7d+AKCwoSlD8Qf4g+1NPFHtz0D/vYa6yn7Ws0KkPPGl5WHP7rtGfA3oNtL2SevvANy2vjyqjI0S+aWkR70AvGH+EMtrW3PP94tAAImqdVXDJco/sj7vxPf+lhhStQZrt46CwTsqkosrPme4i+R/a47pznBkWte7C4XryHEH+IPtbReeqPI40v4pbcVpj2WFoo8voRferNEGX7YqSkRz4Rfr4zSV4g/xB/ib5Go1+rAvkmPPFiB+a9Gx2ffZEcevKgIlG1fLZYHjFDA1YRliVZz255FXoYabpFk8Jq/7SCsVafyIxB/iCESqGQAAAU2SURBVD/E35I58GrFxoDTHng1co283MZ4+pDkVx8mpojzXCv25F5FMesBkf70BECZzJ2+IX1qtqdDI/4Qf4i/BTvtGTUZ/oo4/EH0Z80lZ61uEvnRU14K2dfaxMpwAzkIiwlJIcsj3ex7b/QgLMQf4g/xh/hbJvgzp68lZxpkc7lti5L8GKIIo37Hs7C8hxB/iD/EH+Jv2eCPnve3aVcAu74hLZWtIvhLDzco2OhPsXPEIukrCsrP9lddi3iF+EP8If4Qf8sGf69rgjZxix7uR0Wr2OJqjcZ+2vOqLKVvMjsnOKuDXhB/iD/EH+JvMeLvRQn51g5muw9d+R0qsq/wQobrqirjjvNr+dbLnviG7PIbxJVfxB/iD/G3pPH3Si9WKdmvlvN0mMt7oY8e0kw4x9QSM8ODsBB/iD/EH+JvsePPkMIdnLpJFoTv/CL+UIi/lYS/XO/kXW5HU/y6jXjkAeIPhfhbYXN/eOIL4g+F+Fsp+OtQyRYMf0Y54g/xh/hD/C0Q/vT11tv7AX+PNQtw4ulIg4Lib3R0FPGH+EP8If7e7UFYeuO9mpOAv0H1AkR/T1q/o/gbGxtD/CH+EH+Iv3eqhHpzY315h0rye3X8n03vlH1/Nsc/6DFQ/L18+RLxh/hD/CH+3i3+zM1NTU3Nmgu91Xue6BPfGQGBfU+6Sij7BgcHXy9fQ/wh/hB/ixd/nZ2dZrO5o7m6v+HMA53iSZ18xJDwrP7tyCgfaVBAzmuP+8CeP3+O+EP8If4QfwuAPwBQW1ub1WrtXwgbHh5+vawN8Yf4Q/wtavzRDBTsXYIPulvecR/iD/G3WPAnQ/wJSW5p4e+8e/ny5djY2Ojo6LO3ZnBx6GIZr3Ug/hB/i0v/7k7bf0dNvuncYELk8aVoal32G48Rf6gVjb8HPakn1VoS/enrEXl8fdfWgfhD/KGWM/4e9aWW1xsBf/FqraytE6lHFd/eZej9HfGH+EMtZ/wND6Y2NTVd0On3qLWJRgsSkLKvpKfXvhCB+EP8oZYt/ujutuqW1jOWZkV9g9zUmNDQlGBuXmmSW1oUza2Q89rjvmW/8w7xh1rp+FvY3W2L2Zb9zjvEHwrxtzC72xazrZCdd4g/1Pzgr73p0NLEX/o73t22mG2l7bxD/KHmA38WZXtzOuDv4f1DSwt/TwdO4gQ/GuIPNRf8ZbY2fgv4e9CzxPA3NFCA+END/KHeXKUtmY3mW+1NKb3th/8zumTY95/R1Af9DYg/NMQf6s0Fj52cDWe51N125HF/6pIgILBv6OFN3N2GhvhDzRV/3Nlw7eq+nov/7sl63H/s6UDq8OAiVPrw4EnIee1xH+5uQ0P8oeaEv6W7ew53t6Eh/lBzxd+S2z2Hu9vQlgn+fjV/hfhbKFVYs5bQ7jnc3Ya2rPAH/6DLG08B/n5ry0QYLYA6vsYFBDS0hcEf/DJX37sE+CtrRfwtgOp6ChF/aGgLgz9IZNp7G0rMyhJz5u37SMB3rY7fzYg/NLSFwR/Y4OCgsaMcCFjWqkQCvks191Xi7jk0tIXE3/Pnz+HjBzEgZME3m0/9du/Eb21kJQT1NlRhzars/AZyXnvch7vn0NAWDH9gw8PDeFQR7p5DQ1uJ+KMxIJ7ahrvn0NBWIv6orfBT23D3HBraysUfGhoaGuIPDQ0NDfGHhoaGhvhDQ0NDQ/yhoaGhIf7Q0NDQEH9oaGhoiD80NDQ0xB8aGhoa4g8NDQ0N8YeGhoaG+ENDQ0ND/KGhoaEh/tDQ0NAQf2hoaGiIPzQ0tJVs/x8Xr6boMQqPwwAAAABJRU5ErkJggg==
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/home.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/home.png Binary files differnew file mode 100644 index 0000000000..8f5a0b0d86 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/home.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/index.html new file mode 100644 index 0000000000..130c05fda0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/home/index.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<div id="hometitle" style="font-size: 28px;"></div> +<br/> + +<!-- +<div id="homeanimation" style="width: 320px; height: 280px; padding: 0px; margin: 0px auto;"></div> +--> + +<input type="button" class="graybutton bluebutton" style="font-size: 21px; padding: 10px; height: 50px;" id="getstarted" title="Get Started" value="Get Started"/> + +<br/><br/> +<div class="note">Requires Safari 5+, Chrome 11+, Firefox 4+, IE 9+</div> + +</div> + +<script type="text/javascript"> +(function() { + +/** + * Set page titles. + */ +document.title = config.windowtitle(); +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +$('hometitle').innerHTML = config.hometitle(); + +$('getstarted').onclick = function() { + return ui.navigate('/#view=store', '_view'); +}; + +/** + * Display animation. + */ +var anim = $('homeanimation'); +if (!isNil(anim)) { + anim.style.background = 'url(\'' + ui.b64img(appcache.get('/home/home.b64')) + '\')'; + var bgpos = 0; + setInterval(function() { + bgpos = bgpos -280; + if (bgpos == -2800) + bgpos = 0; + anim.style.backgroundPosition = '0px ' + ui.pixpos(bgpos); + }, 2000); +} + +/** + * Show the status. + */ +showOnlineStatus(); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/index.html new file mode 100644 index 0000000000..e3e046136d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/index.html @@ -0,0 +1,640 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 manifest="/cache-manifest.cmf"> +<head> +<title></title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<link rel="apple-touch-icon" href="/public/touchicon.png"/> +<base href="/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + //if (window.debug) debug('appcache.get', u); + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + // Redirect to login page if not signed in + document.location = '/login/'; + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + // Redirect to login page if not signed in + if (http.status == 403) + document.location = '/login/'; + return null; +}; + +appcache.remove = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + var ls = window.lstorage || localStorage; + try { ls.removeItem(u); } catch(e) {} + return true; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +// Disable cache for testing +//lstorage.enabled = false; + +})(); + +/** + * Redirect to login page if not signed in. + */ +(function() { + +if (document.location.protocol == 'https:' && !hasauthcookie()) + document.location = '/login/'; + +})(); +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbody"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"></div> + +<div id="viewcontainer"></div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> +<div id="status" class="status fixed" style="visibility: hidden;"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var user= sca.defun(sca.reference(editorComp, "user")); +var accounts = sca.reference(editorComp, "accounts"); + +/** + * Set page title. + */ +document.title = config.windowtitle(); + +/** + * Init div variables. + */ +var bdiv = $('mainbodydiv'); +var mdiv = $('menu'); +var hdiv = $('viewhead'); +var vcontainer = $('viewcontainer'); +vcontainer.className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; +var fdiv = $('viewfoot'); + +/** + * The current user name and account entry. + */ +window.username = 'anonymous'; + +/** + * The current store category. + */ +var storecat = 'top'; +var storeidx = 0; + +/** + * Pre-fetch app resources. + */ +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/account/', 9], + ['/clone/', 3], + ['/create/', 2], + ['/delete/', 3], + ['/graph/', 5], + ['/config-min.js'], + ['/home/', 0], + ['/home/home.b64'], + ['/page/', 4], + ['/public/app.b64'], + ['/public/config-min.js'], + ['/public/grid72.b64'], + ['/public/iframe-min.html'], + ['/public/img.b64'], + ['/public/user.b64'], + ['/stats/', 2], + ['/store/', 1] +]; + +/** + * Show a status message. + */ +window.showStatus = function(s, c) { + //debug('status', s); + var sdiv = $('status'); + if (isNil(sdiv)) + return s; + sdiv.innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + sdiv.className = 'status fixed'; + sdiv.style.visibility = 'visible'; + + function divtransitionend(e) { + e.target.style.visibility = 'hidden'; + e.target.className = 'status fixed'; + } + if (!sdiv.addedTransitionEnd) { + sdiv.addEventListener('webkitTransitionEnd', divtransitionend, false); + sdiv.addEventListener('transitionend', divtransitionend, false); + sdiv.addedTransitionEnd = true; + } + sdiv.className = 'statusout3 fixed'; + return s; +} + +/** + * Show an error message. + */ +window.showError = function(s) { + //debug('error', s); + return showStatus(s, 'errorstatus'); +} + +/** + * Show the online/offline status. + */ +window.showOnlineStatus = function() { + return navigator.onLine? showStatus('Online') : showError('Offline'); +} + +/** + * Handle application cache events. + */ +applicationCache.addEventListener('checking', function(e) { + //debug('appcache checking', e); + showStatus('Checking'); +}, false); +applicationCache.addEventListener('error', function(e) { + //debug('appcache error', e); + showOnlineStatus(); +}, false); +applicationCache.addEventListener('noupdate', function(e) { + //debug('appcache noupdate', e); + showOnlineStatus(); +}, false); +applicationCache.addEventListener('downloading', function(e) { + //debug('appcache downloading', e); + showStatus('Updating'); +}, false); +applicationCache.addEventListener('progress', function(e) { + //debug('appcache progress', e); + showStatus('Updating'); +}, false); +applicationCache.addEventListener('updateready', function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + showOnlineStatus(); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showStatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0]); + }, append(appresources, config.appresources())); + window.location.reload(); +}, false); +applicationCache.addEventListener('cached', function(e) { + //debug('appcache cached', e); + showOnlineStatus(); + + // Install offline resources in local storage + map(function(res) { + showStatus('Installing'); + appcache.remove(res[0]); + appcache.get(res[0]); + }, append(appresources, config.appresources())); +}, false); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showStatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showStatus('Online'); +}, false); + +//debug(navigator.onLine? 'online' : 'offline'); + +/** + * Handle view transitions. + */ +var viewurl = ''; +var viewuri = ''; +var viewidx = 0; +var viewdiv; + +/** + * Record which transitions should be applied to each resource. + */ +var apptransitions = {}; +map(function(res) { + if (res.length > 1) + apptransitions[res[0]] = res[1]; +}, append(appresources, config.appresources())); + +/** + * Return the transition that should be applied to a resource. + */ +function viewtransition(ouri, uri) { + var ot = apptransitions[ouri]; + if (isNil(ot)) + return 'left'; + var t = apptransitions[uri]; + if (isNil(t)) + return 'left'; + return t < ot? 'right' : 'left'; +} + +/** + * Create a new view div. + */ +function mkviewdiv(cname) { + var vdiv = document.createElement('div'); + vdiv.className = cname; + if (!ui.isMobile()) + return vdiv; + + // Handle view transition end + function viewdivtransitionend(e) { + if (e.target.className == 'leftviewunloaded3dm' || e.target.className == 'rightviewunloaded3dm') + e.target.parentNode.removeChild(e.target); + } + vdiv.addEventListener('webkitTransitionEnd', viewdivtransitionend, false); + vdiv.addEventListener('transitionend', viewdivtransitionend, false); + return vdiv; +} + +/** + * Return the last visited location. + */ +function lastvisited() { + if (username != lstorage.getItem('ui.lastvisit.user')) + return null; + return lstorage.getItem('ui.lastvisit.url'); +} + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv, view, appname) { + mdiv.innerHTML = ui.menubar( + append(mklist(ui.menu('menuhome', 'Home', '/', '_view', view == 'home'), + ui.menu('menustore', 'Store', '/#view=store&category=' + storecat + '&idx=' + storeidx, '_view', view === 'store')), + (isNil(appname) || appname == 'undefined')? + mklist() : + mklist( + ui.menu('menustats', 'Stats', '/#view=stats&app=' + appname, '_view', view == 'stats'), + ui.menu('menupage', 'Page', '/#view=page&app=' + appname, '_view', view == 'page'), + ui.menu('menulogic', config.logic(), '/#view=graph&app=' + appname, '_view', view == 'graph'), + ui.menu('menurun', '<span class="greentext" style="font-weight: bold">Run!</span>', '/' + appname + '/', '_blank', false))), + (isNil(appname) || appname == 'undefined')? mklist( + hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false), + ui.menu('menuaccount', 'Account', '/#view=account', '_view', view == 'account')) : + mklist()); + + if (fdiv.innerHTML == '') + fdiv.innerHTML = config.viewfoot(); +} + +/** + * Get the current user's account. + */ +function getaccount() { + var doc = accounts.get(); + + // Stop now if we didn't get an account + if (doc == null) + return false; + + var accountentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + username = cadr(assoc("'id", cdr(accountentry))); + return true; +} + +/** + * Show a view. + */ +function showview(url) { + //debug('showview', url); + + // Save last visited location + lstorage.setItem('ui.lastvisit.user', username); + lstorage.setItem('ui.lastvisit.url', url); + + // Determine the view to show + var params = ui.fragmentParams(url); + var view = isNil(params['view'])? 'home' : params['view'];; + var uri = '/' + view + '/'; + var idx = isNil(params['idx'])? 0 : parseInt(params['idx']); + + // Track store category view + if (view == 'store') { + storecat = isNil(params['category'])? 'top' : params['category']; + storeidx = idx; + } + + // Determine the transition to use + var vtransition = uri == viewuri? (idx >= viewidx? 'left' : 'right') : viewtransition(viewuri, uri); + + // Track current view url and uri + viewurl = url; + viewuri = uri; + viewidx = idx; + + // Show the menu bar + var appname = params['app']; + showmenu(mdiv, view, appname); + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + + // Start to unload the front view and create a new view + if (ui.isMobile()) { + // Prepare current view for transition out + var ovdiv = viewdiv; + if (!isNil(ovdiv)) { + ovdiv.skipNode = true; + ovdiv.className = 'viewunloading3dm'; + } + + // Load the requested doc into a new view + var vdiv = mkviewdiv(vtransition + 'viewloading3dm'); + var vdoc = appcache.get(uri); + vdiv.innerHTML = vdoc; + vcontainer.appendChild(vdiv); + map(ui.evalScript, ui.innerScripts(vdiv)); + + // Make sure the top document is visible + if (document.body.style.visibility != 'visible') + document.body.style.visibility = 'visible'; + + setTimeout(function() { + // Transition the old view out + if (!isNil(ovdiv)) + ovdiv.className = vtransition + 'viewunloaded3dm'; + + // Transition the new view in + vdiv.className = 'viewloaded3dm'; + }, 100); + + } else { + // Prepare current view for transition out + var ovdiv = viewdiv; + if (!isNil(ovdiv)) + ovdiv.skipNode = true; + + // Load the requested doc into the view + var vdiv = mkviewdiv('viewloading3d'); + var vdoc = appcache.get(uri); + vdiv.innerHTML = vdoc; + vcontainer.appendChild(vdiv); + map(ui.evalScript, ui.innerScripts(vdiv)); + + // Make sure the top document is visible + if (document.body.style.visibility != 'visible') + document.body.style.visibility = 'visible'; + + setTimeout(function() { + // Transition the new view in + vdiv.className = 'viewloaded3d'; + + // Transition the old view out + if (!isNil(ovdiv)) + ovdiv.parentNode.removeChild(ovdiv); + }, 100); + } + + // Track the current visible view + viewdiv = vdiv; + + return true; +} + +/** + * Update the browser window location. + */ +function updatelocation(url) { + //debug('updatelocation', url); + + // Add url to the history if necessary + if (url != ui.pathandparams(location)) { + history.pushState(null, null, url); + //debug('pushstate', history.length); + + // Update the location hash if necessary + var f = ui.fragment(url); + if (f != '' && f != location.hash) { + location.hash = f; + //debug('hash', f); + } + } + return url; +} + +/** + * Handle navigations. + */ +window.onnavigate = function(url) { + //debug('onnavigate', url); + + // Update the browser window location + updatelocation(url); + + // Show the specified view + if (url == viewurl) + return true; + return showview(url); +}; + +/** + * Handle login redirect. + */ +window.onloginredirect = function(e) { + document.location = '/login/'; +}; + +/** + * Log the current user out. + */ +window.logout = function() { + // Clear session cookie and user-specific local storage entries + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.location = '/login/'; + return false; +} + +/** + * Handle history. + */ +window.addEventListener('popstate', function(e) { + //debug('onpopstate', history.length); + var furl = ui.fragment(location); + var url = location.pathname + (furl == ''? '' : '#' + furl); + + // Show the current view + if (url == viewurl) + return true; + return showview(url); + +}, false); + +window.addEventListener('hashchange', function(e) { + //debug('onhashchange'); + var furl = ui.fragment(location); + var url = location.pathname + (furl == ''? '' : '#' + furl); + + // Show the current view + if (url == viewurl) + return true; + return showview(url); + +}, false); + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload', history.length); + ui.onload(); + + // Get the current user account + getaccount(); + + // Show the view specified in the given url fragment + var furl = ui.fragment(location); + if (furl != '') { + var url = location.pathname + '#' + furl; + if (url == viewurl) + return true; + return showview(url); + } + + // Show the last visited view + if (ui.isMobile() && (document.referrer == null || document.referrer == '' || + document.referrer.indexOf('//' + location.hostname + '/login/') != -1 || + document.referrer.indexOf('//accounts.google.com/ServiceLogin') != -1 || + document.referrer.indexOf('//www.facebook.com/login.php') != -1)) { + var lv = lastvisited(); + var url = isNil(lv)? location.pathname : lv; + updatelocation(url); + if (url == viewurl) + return true; + return showview(url); + } + + // Show the main home view + var url = location.pathname; + if (url == viewurl) + return true; + return showview(url); +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/login/index.html new file mode 100644 index 0000000000..bf09339927 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/login/index.html @@ -0,0 +1,337 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>Sign in</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<base href="/login/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +})(); + +</script> +</head> +<body class="delayed""> +<div id="mainbodydiv" class="bodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"> +<span class="cmenu">Sign in</span> +</div> + +<div id="viewcontainer"> +<div id="view"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<form id="formSignin" name="formSignin" method="POST" action="/login/dologin" style="width: 100%;"> +<table style="width: 100%;"> +<tr><td><span id="loginprompt" style="font-size: 16px;"></span></tr></td> +<tr><td><input type="text" class="flatentry" name="httpd_username" value="" placeholder="User id"/></td></tr> +<tr><td><input type="password" class="flatentry" name="httpd_password" value="" placeholder="Password"/></td></tr> +<tr><td><input type="submit" class="graybutton bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px" value="Sign in"/></td></tr> +</table> +<input type="hidden" name="httpd_location" value="/"/> +</form> +<br/> + +<form name="facebookOAuth2Form" style="width: 100%;"> +<table style="width: 100%;"> +<tr><td><span style="font-size: 16px;">Sign in with your <span style="font-weight: bold;">Facebook</span> account</span></td></tr> +<tr><td><input type="button" id="facebookOAuth2Signin" value="Sign in" class="graybutton bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px"/></td></tr> +</table> +</form> +<br/> + +<form name="googleOAuth2Form" style="width: 100%;"> +<table style="width: 100%;"> +<tr><td><span style="font-size: 16px;">Sign in with your <span style="font-weight: bold;" >Google</span> account</span></td></tr> +<tr><td><input type="button" id="googleOAuth2Signin" value="Sign in" class="graybutton bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px"/></td></tr> +</table> +</form> +<br/> + +<form name="oauth2Signin" action="/oauth2/authorize/" method="GET"> +<input type="hidden" name="oauth2_authorize" value=""/> +<input type="hidden" name="oauth2_access_token" value=""/> +<input type="hidden" name="oauth2_client_id" value=""/> +<input type="hidden" name="oauth2_info" value=""/> +<input type="hidden" name="oauth2_display" value=""/> +<input type="hidden" name="oauth2_scope" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +</div> +</div> +</div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> +<div id="status" class="status fixed" style="visibility: hidden;"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init div variables. + */ +var mbdiv = $('menubackground'); +var mdiv = $('menu'); +var hdiv = $('viewhead'); +var hbdiv = $('viewheadbackground'); +$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; +$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; +$('loginprompt').innerHTML = config.loginprompt(); +var fdiv = $('viewfoot'); + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Sign in'; +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv) { + mdiv.innerHTML = ui.menubar(mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + fdiv.innerHTML = config.viewfoot(); +} + +showmenu(mdiv); + +/** + * Show a status message. + */ +window.showStatus = function(s, c) { + //debug('status', s); + var sdiv = $('status'); + if (isNil(sdiv)) + return s; + sdiv.innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + sdiv.className = 'status fixed'; + sdiv.style.visibility = 'visible'; + + function divtransitionend(e) { + e.target.style.visibility = 'hidden'; + e.target.className = 'status fixed'; + } + if (!sdiv.addedTransitionEnd) { + sdiv.addEventListener('webkitTransitionEnd', divtransitionend, false); + sdiv.addEventListener('transitionend', divtransitionend, false); + sdiv.addedTransitionEnd = true; + } + sdiv.className = 'statusout3 fixed'; + return s; +} + +/** + * Show an error message. + */ +window.showError = function(s) { + //debug('error', s); + return showStatus(s, 'errorstatus'); +} + +/** + * Parse the query parameeters. + */ +function queryParams() { + var qp = new Array(); + var qs = window.location.search.substring(1).split('&'); + for (var i = 0; i < qs.length; i++) { + var e = qs[i].indexOf('='); + if (e > 0) + qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1)); + } + return qp; +} + +/** + * Show login status. + */ +function showLoginStatus() { + var a = queryParams()['openauth_attempt']; + debug('a', a); + if (typeof(a) != 'undefined' && a == '1') + showError('Incorrect email or password, please try again'); +} + +showLoginStatus(); + +/** + * Return the referrer URL. + */ +function openauthReferrer() { + var r = queryParams()['openauth_referrer']; + if (typeof(r) == 'undefined' || domainname(r) != domainname(window.location.hostname)) + return '/'; + var q = r.indexOf('?'); + if (q > 0) + return r.substring(0, q); + return r; +} + +/** + * Signin with OAuth 2.0. + */ +function submitOAuth2Signin(w) { + parms = w(); + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.oauth2Signin.oauth2_authorize.value = parms[0]; + document.oauth2Signin.oauth2_access_token.value = parms[1]; + document.oauth2Signin.oauth2_client_id.value = parms[2]; + document.oauth2Signin.oauth2_info.value = parms[3]; + document.oauth2Signin.oauth2_scope.value = parms[4]; + document.oauth2Signin.oauth2_display.value = parms[5]; + document.oauth2Signin.openauth_referrer.value = openauthReferrer(); + document.oauth2Signin.action = '/oauth2/authorize/'; + 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', 'email', ui.isMobile()? 'touch' : 'page']; + return parms; +} + +function withGoogle() { + var parms = ['https://accounts.google.com/o/oauth2/auth', 'https://accounts.google.com/o/oauth2/token', 'google.com', 'https://www.googleapis.com/oauth2/v1/userinfo', 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile', '']; + return parms; +} + +$('facebookOAuth2Signin').onclick = function() { + return submitOAuth2Signin(withFacebook); +}; + +$('googleOAuth2Signin').onclick = function() { + return submitOAuth2Signin(withGoogle); +}; + +/** + * Signin with a userid and password. + */ +function submitFormSignin() { + clearauthcookie(); + document.formSignin.httpd_location.value = '/'; + document.formSignin.submit(); +} + +$('formSignin').onsubmit = submitFormSignin; + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + ui.onload(); + + // Show the page + document.body.style.visibility = 'visible'; + return true; +} + +onload(); + +})(); +</script> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html new file mode 100644 index 0000000000..6a6e042c74 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html @@ -0,0 +1,1081 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div id="contentdiv" class="viewcontent" style="width: 2500px;"> +<div id="pagediv" class="pagediv" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"> + +<!-- +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 320px; height: 460px;"></div> +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 480px; height: 300px;"></div> +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 768px; height: 911px;"></div> +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 1024px; height: 655px;"></div> +--> + +<span class="h1" id="palette:h1" style="position: absolute; left: 0px; top: 0px;"><h1>Header Level 1</h1></span> +<span class="h2" id="palette:h2" style="position: absolute; left: 0px; top: 30px;"><h2>Header Level 2</h2></span> +<span class="section" id="palette:section" style="position: absolute; left: 0px; top: 60px; width: 220px;"><span class="Section">Section</span></span> +<span class="text" id="palette:text" style="position: absolute; left: 0px; top: 90px;"><span>Some text</span></span> +<span class="link" id="palette:link" style="position: absolute; left: 80px; top: 90px;"><a href="/"><span>Link</span></a></span> +<span class="button" id="palette:graybutton" style="position: absolute; left: 0px; top: 120px;"><input type="button" value="Button" class="graybutton"/></span> +<span class="button" id="palette:bluebutton" style="position: absolute; left: 80px; top: 120px;"><input type="button" value="Button" class="graybutton bluebutton"/></span> +<span class="button" id="palette:redbutton" style="position: absolute; left: 160px; top: 120px;"><input type="button" value="Button" class="graybutton redbutton"/></span> +<span class="entry" id="palette:entry" style="position: absolute; left: 0px; top: 160px;"><input type="text" value="Entry Field" class="flatentry" size="20" autocapitalize="off"/></span> +<span class="password" id="palette:password" style="position: absolute; left: 0px; top: 190px;"><input type="password" value="Password" class="flatentry" size="20"/></span> +<span class="checkbox" id="palette:checkbox" style="position: absolute; left: 0px; top: 220px;"><input type="checkbox" value="Checkbox" class="flatcheckbox"/><span>Checkbox</span></span> +<!-- +<span class="select" id="palette:select" style="position: absolute; left: 80px; top: 220px;"><select><option value="select">Selection</option></select></span> +--> +<span class="list" id="palette:list" style="position: absolute; left: 0px; top: 250px; width: 220px;"> +<table class="datatable" style="width: 220px;"> +<tr><td class="datatd">List</td></tr> +<tr><td class="datatd">List</td></tr> +<tr><td class="datatd">List</td></tr> +</table> +</span> +<span class="table" id="palette:table" style="position: absolute; left: 0px; top: 320px; width: 220px;"> +<table class="datatable" style="width: 220px;"> +<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +</table> +</span> +<!-- +<span class="iframe fakeframe" id="palette:iframe" style="position: absolute; left: 0px; top: 380px; width: 200px;"><a href="/public/iframe-min.html"><span class="fakeframe"><span>Frame ...</span></span></a></span> +--> +<span class="img" id="palette:img" style="position: absolute; left: 0px; top: 410px;"><img id="imgimg"/></span> +</div> + +<div id="playdiv" style="visibility: hidden; position: absolute; top: 0px; left: 0px; width: 2500px; height: 5000px;"> +</div> + +</div> + +<div id="buffer" style="visibility: hidden; width: 0px; height: 0px"></div> + +<script type="text/javascript"> +(function() { + +/** + * Get the current app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Return the link to an app. + */ +function applink(appname) { + var protocol = location.protocol; + var host = location.hostname; + var port = ':' + location.port; + if (port == ':80' || port == ':443' || port == ':') + port = ''; + var link = protocol + '//' + host + port + '/' + appname + '/'; + return link; +} + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Page - ' + appname; + +/** + * Set header div. + */ +$('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + +'<input type="button" id="deleteWidgetButton" title="Delete a Widget" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + +'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="widgetValue" type="text" value="" class="flatentry" title="Widget value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; visibility: hidden;" readonly="readonly"/></span>' + +'<input type="button" id="playPageButton" title="View page" class="graybutton plusminus" style="position: absolute; top: 4px; right: 75px;" value=">"/>' + +'<input type="button" id="copyWidgetButton" title="Copy a Widget" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 40px; font-size: 16px;" disabled="true" value="C"/>' + +'<input type="button" id="addWidgetButton" title="Add a Widget" class="graybutton bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + +/** + * Track the current page, author, and saved XHTML content. + */ +var author = ''; +var editable = false; +var savedpagexhtml = ''; + +/** + * Page editor area, widget value field, add, delete and play page buttons. + */ +var cdiv = $('contentdiv'); +var pagediv = $('pagediv'); +var evisible = true; +var pdiv = $('playdiv'); +var wadd = $('addWidgetButton'); +var wdelete = $('deleteWidgetButton'); +var wcopy = $('copyWidgetButton'); +var wvalue = $('widgetValue'); +var atitle = $('appTitle'); +var pplay = $('playPageButton'); + +/** + * Set images. + */ +$('imgimg').src = ui.b64img(appcache.get('/public/img.b64')); + +/** + * Init component references. + */ +var editorComp = sca.component('Editor'); +var pages = sca.reference(editorComp, 'pages'); + +/** + * Page editing functions. + */ +var page = {}; + +/** + * Default positions and sizes. + */ +page.palcx = 2500; + +/** + * Init a page editor. + */ +page.mkedit = function(pagediv, atitle, wvalue, wadd, wcopy, wdelete, onchange, onselect) { + + // Track element dragging and selection + page.dragging = null; + page.selected = null; + wvalue.readOnly = true; + wvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; + page.mousemoved = false; + wcopy.disabled = true; + wdelete.disabled = true; + wadd.disabled = !editable; + + // Trigger widget select and page change events + page.onpagechange = onchange; + page.onselectwidget = onselect; + + /** + * Handle a mouse down event. + */ + function onmousedown(e) { + // On mouse controlled devices, run component selection logic right away + var selected = page.selected; + if (typeof e.touches == 'undefined') { + //debug('onmousedown-click'); + onclick(e); + } + + // Find a draggable element + var dragging = page.draggable(e.target, pagediv); + if (dragging == null || dragging != page.selected) + return true; + page.dragging = dragging; + + // Remember mouse position + var pos = typeof e.touches != "undefined"? e.touches[0] : e; + page.mousemoved = false; + page.dragX = pos.screenX; + page.dragY = pos.screenY; + page.moveX = pos.screenX; + page.moveY = pos.screenY; + + // Prevent default behavior on first click on a widget + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + + return true; + } + + if (!ui.isMobile()) { + pagediv.onmousedown = function(e) { + //debug('onmousedown'); + return onmousedown(e); + }; + } else { + pagediv.ontouchstart = function(e) { + //debug('ontouchstart'); + return onmousedown(e); + }; + } + + /** + * Handle a mouse up event. + */ + function onmouseup(e) { + if (page.dragging == null) + return true; + + // Snap to grid + var newX = page.gridsnap(ui.numpos(page.dragging.style.left)); + var newY = page.gridsnap(ui.numpos(page.dragging.style.top)); + page.dragging.style.left = ui.pixpos(newX); + page.dragging.style.top = ui.pixpos(newY); + + // Fixup widget style + page.initwidget(page.dragging); + + // Forget dragged element + page.dragging = null; + + // Trigger page change event + page.onpagechange(false); + + // Simulate onclick event + onclick(e); + + return true; + } + + if (!ui.isMobile()) { + pagediv.onmouseup = function(e) { + //debug('onmouseup'); + return onmouseup(e); + }; + } else { + pagediv.ontouchend = function(e) { + //debug('ontouchend'); + return onmouseup(e); + } + } + + /** + * Handle a mouse move event. + */ + function onmousemove(e) { + + // Track mouse moves + page.mousemoved = true; + + if (page.dragging == null) + return true; + + // Ignore duplicate mouse move events + if (page.moveX == page.dragX && page.moveY == page.dragY) + return true; + + // Compute position of dragged element + var curX = ui.numpos(page.dragging.style.left); + var curY = ui.numpos(page.dragging.style.top); + var newX = curX + (page.moveX - page.dragX); + var newY = curY + (page.moveY - page.dragY); + if (newX >= page.palcx) + page.dragX = page.moveX; + else + newX = page.palcx; + if (newY >= 0) + page.dragY = page.moveY; + else + newY = 0; + + // Move the dragged element + page.dragging.style.left = ui.pixpos(newX); + page.dragging.style.top = ui.pixpos(newY); + page.constrainwidget(page.dragging); + + return true; + } + + if (!ui.isMobile()) { + window.onmousemove = function(e) { + + // Remember mouse position + page.moveX = e.screenX; + page.moveY = e.screenY; + + return onmousemove(e); + }; + } else { + pagediv.ontouchmove = function(e) { + + // Remember touch position + var pos = e.touches[0]; + if (page.moveX == pos.screenX && page.moveY == pos.screenY) + return true; + page.moveX = pos.screenX; + page.moveY = pos.screenY; + if (page.moveX == page.dragX && page.moveY == page.dragY) + return true; + + onmousemove(e); + }; + } + + /** + * Handle a mouse click event. + */ + function onclick(e) { + + // Find selected element + var selected = page.draggable(e.target, pagediv); + if (selected == null) { + if (page.selected != null) { + + // Reset current selection + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + page.selected = null; + + // Trigger widget select event + page.onselectwidget(null); + } + + // Dismiss the palette + if (ui.numpos(pagediv.style.left) != (page.palcx * -1)) + pagediv.style.left = ui.pixpos(page.palcx * -1); + + return true; + } + + // Deselect the previously selected element + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + + // Clone element dragged from palette + if (selected.id.substring(0, 8) == 'palette:') { + page.selected = page.clone(selected); + + // Move into the editing area and hide the palette + page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + page.palcx); + page.initwidget(page.selected); + pagediv.style.left = ui.pixpos(page.palcx * -1); + page.constrainwidget(page.selected); + + // Bring it to the top + page.bringtotop(page.selected); + + // Trigger page change event + page.onpagechange(true); + + // Select the element + page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onselectwidget(page.selected); + + return true; + + } + + // Bring selected element to the top + page.selected = selected; + page.bringtotop(page.selected); + + // Select the element + page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onselectwidget(page.selected); + + return true; + } + + if (!ui.isMobile()) { + pagediv.onclick = function(e) { + //debug('onclick'); + return onclick(e); + }; + } else { + pagediv.onclick = function(e) { + //debug('onclick'); + return onclick(e); + }; + } + + /** + * Handle field on change events. + */ + wvalue.onchange = wvalue.onblur = function() { + if (page.selected == null) + return false; + page.settext(page.selected, wvalue.value); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + + // Handle add widget event. + wadd.onclick = function() { + + // Show the palette + pagediv.style.left = ui.pixpos(0); + return false; + }; + + // Handle delete event. + wdelete.onclick = function() { + if (page.selected == null) + return false; + + // Reset current selection + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + + // Remove selected widget + page.selected.parentNode.removeChild(page.selected); + page.selected = null; + + // Trigger widget select event + page.onselectwidget(null); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + + // Handle copy event. + wcopy.onclick = function() { + if (page.selected == null) + return false; + if (page.selected.id.substring(0, 8) == 'palette:') + return false; + + // Reset current selection + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + + // Clone selected widget + page.selected = page.clone(page.selected); + + // Move 10 pixels down right + page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + 10); + page.selected.style.top = ui.pixpos(ui.numpos(page.selected.style.top) + 10); + page.constrainwidget(page.selected); + + // Bring it to the top + page.bringtotop(page.selected); + + // Select the element + page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onselectwidget(page.selected); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + + return pagediv; +}; + +/** + * Return the text of a widget. + */ +page.text = function(e) { + function formula(e) { + var f = e.id; + if (f.substring(0, 5) != 'page:') + return '=' + f; + return ''; + } + + function constant(e, f) { + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + var t = car(childElements(e)).innerHTML; + return t == f? '' : t; + } + if (e.className == 'button' || e.className == 'checkbox') { + var t = car(childElements(e)).value; + return t == f? '' : t; + } + if (e.className == 'entry' || e.className == 'password') { + var t = car(childElements(e)).defaultValue; + return t == f? '' : t; + } + /* + if (e.className == 'select') { + var t = car(childElements(car(childElements(e)))).value; + return t == f? '' : t; + } + */ + if (e.className == 'link') { + var lhr = car(childElements(e)).href; + var hr = lhr.substring(0, 5) == 'link:'? lhr.substring(5) : ''; + var t = car(childElements(car(childElements(e)))).innerHTML; + return t == f? hr : (t == hr? hr : (t == ''? hr : hr + ',' + t)); + } + if (e.className == 'img') { + var src = car(childElements(e)).src; + return src == location.href? '' : src; + } + /* + if (e.className == 'iframe') { + var hr = car(childElements(e)).href; + return hr == location.href? '' : hr; + } + */ + if (e.className == 'list') + return ''; + if (e.className == 'table') + return ''; + return ''; + } + + var f = formula(e); + var c = constant(e, f); + return f == ''? c : (c == ''? f : f + ',' + c); +}; + +/** + * Return true if a widget has editable text. + */ +page.hastext = function(e) { + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') + return true; + if (e.className == 'button' || e.className == 'checkbox') + return true; + if (e.className == 'entry' || e.className == 'password') + return true; + /* + if (e.className == 'select') + return false; + */ + if (e.className == 'link') + return true; + if (e.className == 'img') + return true; + /* + if (e.className == 'iframe') + return true; + */ + if (e.className == 'list') + return false; + if (e.className == 'table') + return false; + return false; +}; + +/** + * Set the text of a widget. + */ +page.settext = function(e, t) { + function formula(t) { + if (t.length > 1 && t.substring(0, 1) == '=') + return car(t.split(',')); + return ''; + } + + function constant(t) { + return t.length > 1 && t.substring(0, 1) == '='? cdr(t.split(',')) : t.split(','); + } + + var f = formula(t); + var c = constant(t); + + e.id = f != ''? f.substring(1) : ('page:' + e.className); + + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + car(childElements(e)).innerHTML = isNil(c)? f : car(c); + return t; + } + if (e.className == 'button') { + car(childElements(e)).value = isNil(c)? f : car(c); + return t; + } + if (e.className == 'entry' || e.className == 'password') { + car(childElements(e)).defaultValue = isNil(c)? f : car(c); + return t; + } + if (e.className == 'checkbox') { + car(childElements(e)).value = isNil(c)? f : car(c); + map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = isNil(c)? f : car(c); return n; }, nodeList(e.childNodes)); + return t; + } + /* + if (e.className == 'select') { + var ce = car(childElements(car(childElements(e)))); + ce.value = isNil(c)? f : car(c); + ce.innerHTML = isNil(c)? f : car(c); + return t; + } + */ + if (e.className == 'list') { + e.innerHTML = '<table class="datatable" style="width: 100%;;"><tr><td class="datatd">' + (isNil(c)? f : car(c)) + '</td></tr><tr><td class="datatd">...</td></tr></table>'; + return t; + } + if (e.className == 'table') { + e.innerHTML = '<table class="datatable" style="width: 100%;"><tr><td class="datatdl">' + (isNil(c)? f : car(c)) + '</td><td class="datatdr">...</td></tr><tr><td class="datatdl">...</td><td class="datatdr">...</td></tr></table>'; + return t; + } + if (e.className == 'link') { + var ce = car(childElements(e)); + ce.href = isNil(c)? 'link:/index.html' : ('link:' + car(c)); + car(childElements(ce)).innerHTML = isNil(c)? (f != ''? f : '/index.html') : isNil(cdr(c))? (f != ''? f : car(c)) : cadr(c); + return t; + } + if (e.className == 'img') { + car(childElements(e)).src = isNil(c)? '/public/img.png' : car(c); + return t; + } + /* + if (e.className == 'iframe') { + car(childElements(e)).href = isNil(c)? '/public/iframe-min.html' : car(c); + return t; + } + */ + return ''; +}; + +/** + * Initialize a widget. + */ +page.initwidget = function(e) { + + // Add a Webkit transform to leverage hardware acceleration + e.style.setProperty('-webkit-transform', 'translate(0px, 0px)', null); + + /* + if (e.className == 'iframe') { + var f = car(childElements(e)); + //e.innerHTML = '<iframe src="' + f.href + '" frameborder="no" scrolling="no"></iframe>'; + return e; + } + */ + + if (e.className == 'section') { + e.style.width = '100%'; + return e; + } + if (e.className == 'text' || e.className == 'h1' || e.className == 'h2') { + return e; + } + if (e.className == 'button') { + return e; + } + if (e.className == 'checkbox') { + return e; + } + if (e.className == 'list' || e.className == 'table') { + e.style.width = '100%'; + var t = car(childElements(e)); + t.style.width = '100%'; + return e; + } + if (e.className == 'img') { + var i = car(childElements(e)); + if (i.src != '' && i.src.substring(0, 5) == 'data:') + i.src = '/public/img.png'; + return e; + } + if (e.className == 'entry' || e.className == 'password') { + var i = car(childElements(e)); + i.readOnly = true; + i.style.cursor = 'default'; + return e; + } + if (e.className == 'link') { + var l = car(childElements(e)); + l.onclick = function(e) { return false; }; + return e; + } + return e; +} + +/** + * Enforce widget position and style constraints. + */ +page.constrainwidget = function(e) { + if (e.className == 'section' || e.className == 'list' || e.className == 'table') { + e.style.left = ui.pixpos(page.palcx); + return e; + } + return e; +}; + +/** + * Cleanup of a widget before saving it. + */ +page.cleanupwidget = function(e) { + //debug('cleanupwidget', e); + + // Clear outline + e.style.outline = null; + + // Clear the Webkit transform + e.style.removeProperty('-webkit-transform'); + + if (e.className == 'entry' || e.className == 'password') { + var i = car(childElements(e)); + i.readOnly = false; + i.style.cursor = null; + return e; + } + if (e.className == 'link') { + var l = car(childElements(e)); + l.onclick = null; + return e; + } + return e; +} + +/** + * Find a draggable element in a hierarchy of elements. + */ +page.draggable = function(n, e) { + if (n == e) + return null; + if (!isNil(n.id) && n.id != '') + return n; + return page.draggable(n.parentNode, e); +} + +/** + * Align a pos along a 9pixel grid. + */ +page.gridsnap = function(x) { + return Math.round(x / 9) * 9; +} + +/** + * Bring an element and its parent to the top. + */ +page.bringtotop = function(n) { + n.parentNode.appendChild(n); +} + +/** + * Select a widget. + */ +page.selectwidget = function(n, s, atitle, wvalue, wcopy, wdelete) { + //debug('selectwidget', n, s); + if (isNil(n) || !s) { + // Clear the widget value field + wvalue.value = ''; + wvalue.readOnly = true; + wvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; + wcopy.disabled = true; + wdelete.disabled = true; + + // Clear the widget outline + if (!isNil(n)) + n.style.outline = null; + + return true; + } + + // Outline the widget + n.style.outline = '2px solid #598edd'; + + // Update the widget value field + wvalue.value = page.text(n); + wvalue.readOnly = false || !editable; + wvalue.style.visibility = 'visible'; + atitle.style.visibility = 'hidden'; + wcopy.disabled = false || !editable; + wdelete.disabled = false || !editable; + + return true; +}; + +/** + * Clone a palette element. + */ +page.clone = function(e) { + + /** + * Clone an element's HTML. + */ + function mkclone(e) { + var ne = document.createElement('span'); + + // Skip the palette: prefix + ne.id = 'page:' + e.id.substr(8); + + // Copy the class and HTML content + ne.className = e.className; + ne.innerHTML = e.innerHTML; + + // Fixup the widget style + page.initwidget(ne); + + return ne; + } + + /** + * Clone an element's position. + */ + function posclone(ne, e) { + ne.style.position = 'absolute'; + ne.style.left = ui.pixpos(ui.numpos(e.style.left)); + ne.style.top = ui.pixpos(ui.numpos(e.style.top)); + e.parentNode.appendChild(ne); + return ne; + } + + return posclone(mkclone(e), e); +}; + +/** + * Track the current widget. + */ +var widget = null; + +/** + * Get and display an app page. + */ +function getpage(name, pagediv) { + if (isNil(name)) + return false; + showStatus('Loading'); + + return pages.get(name, function(doc) { + + // Stop now if we didn't get a page + if (doc == null) { + showError('App not available'); + return false; + } + + // Get the page from the ATOM entry, convert it to XHTML and place it in a hidden buffer + var pageentry = car(atom.readATOMEntry(mklist(doc))); + var content = namedElementChild("'content", pageentry); + var el = isNil(content)? mklist() : elementChildren(content); + var buffer = $('buffer'); + if (isNil(el)) + buffer.innerHTML = '<div id="page"></div>'; + else + buffer.innerHTML = writeStrings(writeXML(el, false)); + + // Remove any existing page nodes from the editor div + var fnodes = filter(function(e) { + if (isNil(e.id) || e.id == '' || e.id.substr(0, 8) == 'palette:') + return false; + var x = ui.numpos(e.style.left) - 2500; + if (x < 0 || ui.numpos(e.style.top) < 0) + return false; + return true; + }, nodeList(pagediv.childNodes)); + + map(function(e) { + pagediv.removeChild(e); + }, fnodes); + + // Append new page nodes to editor + map(function(e) { + pagediv.appendChild(e); + if (!isNil(e.style)) + e.style.left = ui.pixpos(ui.numpos(e.style.left) + 2500); + page.initwidget(e); + return e; + }, nodeList(buffer.childNodes[0].childNodes)); + + savedpagexhtml = pagexhtml(pagediv); + + // Enable author to edit the page + author = elementValue(namedElementChild("'author", pageentry)); + editable = author == username; + wadd.disabled = !editable; + showStatus(editable? onlineStatus() : 'Read only'); + + return true; + }); +} + +/** + * Handle add widget button click event. + */ +wadd.onclick = function(e) { + // Show the widget palette + pagediv.style.left = ui.pixpos(0); +}; + +/** + * Return the current page XHTML content. + */ +function pagexhtml(pagediv) { + + // Copy page DOM to hidden buffer + var buffer = $('buffer'); + buffer.innerHTML = '<div id="page"></div>' + var div = buffer.childNodes[0]; + + // Capture the nodes inside the page div + div.innerHTML = pagediv.innerHTML; + var nodes = nodeList(div.childNodes); + map(function(e) { + div.removeChild(e); + return e; + }, nodes); + + // Filter out palette and editor artifacts, which are not + // part of the page, as well as nodes positioned out the + // editing area + var fnodes = filter(function(e) { + if (isNil(e.id) || e.id == '' || e.id.substr(0, 8) == 'palette:') + return false; + var x = ui.numpos(e.style.left) - 2500; + if (x < 0 || ui.numpos(e.style.top) < 0) + return false; + return true; + }, nodes); + + // Reposition and cleanup nodes + map(function(e) { + var x = ui.numpos(e.style.left) - 2500; + e.style.left = ui.pixpos(x); + page.cleanupwidget(e); + return e; + }, fnodes); + + // Sort them by position + var snodes = fnodes.sort(function(a, b) { + var ay = ui.numpos(a.style.top); + var by = ui.numpos(b.style.top); + if (ay < by) return -1; + if (ay > by) return 1; + var ax = ui.numpos(a.style.left); + var bx = ui.numpos(b.style.left); + if (ax < bx) return -1; + if (ax > bx) return 1; + return 0; + }); + + // Append the sorted nodes back to the div in order + map(function(e) { + div.appendChild(e); + return e; + }, snodes); + + // Convert the page to XHTML + var lxhtml = readXHTMLElement(div); + var xhtml = writeStrings(writeXML(lxhtml, false)); + return xhtml; +} + +/** + * Save the current page. + */ +function save(newxml) { + showStatus('Saving'); + + // Get the current page XHTML content + savedpagexhtml = newxml; + + // Update the page ATOM entry + var entry = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title type="text">' + appname + '</title><id>' + appname + '</id><author><email>' + author + '</email></author>' + + '<content type="application/xml">' + newxml + '</content></entry>'; + + pages.put(appname, entry, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + showStatus('Saved'); + return false; + }); + return true; +}; + +/** + * Handle a page change event + */ +function onpagechange(prop) { + if (!editable) + return false; + + var newxml = pagexhtml(pagediv); + if (savedpagexhtml == newxml) + return false; + showStatus('Modified'); + + // Save property changes right away + if (prop) + return save(newxml); + + // Autosave other changes after 1 second + setTimeout(function() { + if (savedpagexhtml == newxml) { + showStatus('Saved'); + return false; + } + return save(newxml); + }, 1000); + return true; +} + +/** + * Handle a widget select event. + */ +function onselectwidget(w) { + if (w == widget) + return true; + widget = w; + return true; +} + +/** + * Play page in a frame. + */ +function playpage() { + if (!evisible) + return true; + page.selectwidget(widget, false, atitle, wvalue, wcopy, wdelete); + page.selected = null; + pplay.value = '<'; + evisible = false; + pdiv.style.visibility = 'visible'; + pdiv.innerHTML = ''; + pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="/' + + appname + '"></iframe>'; + setTimeout(function() { + pagediv.style.visibility = 'hidden' + }, 0); + return true; +} + +/** + * Show the page editor. + */ +function showedit() { + if (evisible) + return true; + pplay.value = '>'; + pagediv.style.visibility = 'visible' + evisible = true; + page.selectwidget(widget, true, atitle, wvalue, wcopy, wdelete); + page.selected = widget; + setTimeout(function() { + pdiv.style.visibility = 'hidden'; + pdiv.innerHTML = ''; + }, 0); + return true; +} + +/** + * Handle play page button event. + */ +pplay.onclick = function() { + if (!evisible) + return showedit(); + return playpage(); +} + +/** + * Initialize the page editor. + */ +page.mkedit(pagediv, atitle, wvalue, wadd, wcopy, wdelete, onpagechange, onselectwidget); + +/** + * Get and display the current app page. + */ +getpage(appname, pagediv); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/proxy/public/oops/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/proxy/public/oops/index.html new file mode 100644 index 0000000000..b1d118d59a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/proxy/public/oops/index.html @@ -0,0 +1,193 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>Oops</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<base href="/proxy/public/oops/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/proxy/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/proxy/ui-min.css'))); + +})(); + +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/proxy/public/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"></div> + +<div id="viewcontainer"> +<div id="view"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<div class="hd2">Oops, something went wrong...</div> + +</div> +</div> +</div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init div variables. + */ +var mdiv = $('menu'); +var hdiv = $('viewhead'); +$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; +$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; +var fdiv = $('viewfoot'); + +/** + * Set page title. + */ +document.title = config.windowtitle() + ' - Oops'; +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv) { + mdiv.innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), + mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); + fdiv.innerHTML = config.viewfoot(); +} + +showmenu(mdiv); + +/** + * Log the current user out. + */ +window.logout = function() { + // Clear session cookie and user-specific local storage entries + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.location = '/login/'; + return false; +} + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + ui.onload(); + + // Show the page + document.body.style.visibility = 'visible'; + return true; +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.b64 new file mode 100644 index 0000000000..7ed235aa14 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAxQTFRFyN+N+dR1/PCI////6HjE5gAAADJJREFUKM9j+I8EPjBQifeBAQSY6coLBYN6inhaq0Bg6SDn/f//akB466ExTS6P2ukMAKumzarJO/66AAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.png Binary files differnew file mode 100644 index 0000000000..1f73274b76 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.xcf b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.xcf Binary files differnew file mode 100644 index 0000000000..741b7ff43f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/app.xcf diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/config.js b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/config.js new file mode 100644 index 0000000000..54818f4810 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/config.js @@ -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. + */ + +if (isNil(config)) + config = {}; + +/** + * UI configuration. + */ +config.windowtitle = function() { + return 'App Builder'; +}; + +config.pagetitle = function() { + return '<span style="font-weight: bold;">App Builder</span>'; +}; + +config.loginprompt = function() { + return '<span>Sign in with your userid and password</span>'; +}; + +config.viewfoot = function() { + return ui.menubar(mklist(ui.menu('menuabout', 'About', '/', '_view', 'note')), mklist()); +}; + +config.appresources = function() { + return mklist(); +}; + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.b64 new file mode 100644 index 0000000000..c8137d7ab4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAAXNSR0IArs4c6QAAAAZiS0dEANAAPwBBXloXjQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sEFhQaKzNh4PgAAAMKSURBVEjHxZZPTBNBFMa/maVbWjcUi0YiIHIoNBADTUgsqCWgUUFjwkk5CXLUBKIc9KIXjx64oMSDoiggGC8koImCGDWYkADRIiQQgikWCq0WoXW33R0PpYjSLeWP8btN3sv85s17894QrKNeIBng8gFmJSDZgGIAqJeBjQCkH5AHioGZaHsQNUMP+ByKYB0ByVjvIAxsUkHcrRJI9pggXYBWB1pLQUqxQSlg3X4o9WWAqArpAhL04JoIYMQmxQCPD3JlGbCwBtIFaPXgWrcC+AtUEY6Ihg060NrtACyf3KgDrQ2v6e8kbzwH0URBSnvA56xAKIJ1kRzNbS2ZNhYssjodVj41VbPaxqemaqxOh9XGgkXmtpbMyKDQvqQXSKbg2iKGzfPE0v8uV7BYDIuDg95B66FhJkmM8DyxfHifK+TlGRaHhryDBwuHmSSxyBUnn6Ohh6aSQElin86U26XZWVGwWAxZD5tMAGBufmAS8vIMkssl2s+Uj6gBQuLySS/oTQpyONr9GmxHhAMvnltovJZ+73vjTiyyJSmipHw8WTrkfd33Y52385arAr1EAF00R3HqixRwu38mnT61O35/uh4AJq7Ujc0/affEUGsCDfWi9TXX3uEOeDwBABCnp/3OO42uGPuAgQLUG4urueVRlsZo1ACANiVFZ7rTkBFjMXtpqJtGV9q1q3uNJ47vlpd88kTt5VEWCLLk6gtpeyrP74qheY5wlaB6AhSqOSUUFOzIun8vh8RxZKKmZvRrw20X0WjkxCKbceexo0Z3Z+d8wDUXVIeQdgrIA6rFl5DAmVsfZ1MtT+faO5zOxrtzADB1/Ybj28tX85wgxOU8e5pN9XqqHos8QIuBGQY2GTEPD5tM8en79P7x8aWxqurx1bbPZytGRYfDrzOZBHPzA5PanCkGZki4d3GQG7DNksFdLIFkpwBQAsmugHVvJ0AB6w5PypW79EOpZ4BnOwAM8Pih1P/R6gGgDBB9kCu3Clo1GcU1kGXQgg9yxWavTgHrXp6IC///t/Iv/l2/AGa0Qa2X0eC0AAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.png Binary files differnew file mode 100644 index 0000000000..fb56bae030 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.xcf b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.xcf Binary files differnew file mode 100644 index 0000000000..7691f50cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/delete.xcf diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/grid72.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/grid72.b64 new file mode 100644 index 0000000000..34be13e5ca --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/grid72.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAgMAAAAog1vUAAAABGdBTUEAALGPC/xhBQAAAAlQTFRFwuD84/T+////fj9v9QAAACxJREFUOMtjWLUqa9WsVctWrYQxVjAMCqFQdBDCMOrUUaeOOnXUqYPPqZgAABmg/C7pJC7lAAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/grid72.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/grid72.png Binary files differnew file mode 100644 index 0000000000..cf6008171a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/grid72.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/iframe.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/iframe.html new file mode 100644 index 0000000000..e2b862dbaa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/iframe.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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> +</head> +<body style="margin:3px; padding: 0px; background-color: #dcdcdc;"> + +<div>frame ...</div> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.b64 new file mode 100644 index 0000000000..97dae687a0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAIRQTFRFwdt/w9yEw9+MxN2GxN6NxN+Oxd2Mxd6Nxt6Lx96Lx96Nx9+NyN6MyN+MyN+N8u2I8+2I+NBq+NFr+NFt+NFu+NJz+NN0+dR1+dR3+dZw+dh4+9Fy+9Nz++5++++B+++F/NNz/PCH/PCI/PGW/PKc/fKd/vzp/vzq/v7+/v/z/9Jx////nQZfHwAAAIxJREFUOMtj0CYAGKiiQANdUAPdBAZmFMCIYQUzHwrgpKECblYwYEJ2LYoCHi0FMBCEAmF0E3hkxFGABJICXnYWFhY2aVE4EENTwCWgCARKCCCFoUAJFQw9BYycnBz8eBSA04cqPhNAQIX+CiSFhIRE8CiQ10ROMNgUqKNnHGU5FCCrhqZAg7Z5Ey8AALiBh6brcmloAAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.png Binary files differnew file mode 100644 index 0000000000..2363b25e8e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.xcf b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.xcf Binary files differnew file mode 100644 index 0000000000..ffcc124584 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/img.xcf diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notauth/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notauth/index.html new file mode 100644 index 0000000000..89852393bf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notauth/index.html @@ -0,0 +1,195 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>Sorry</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<base href="/public/notauth/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +})(); + +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"></div> + +<div id="viewcontainer"> +<div id="view"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<div class="hd2">Sorry, you're not authorized to view this page.</div> + +</div> +</div> +</div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init div variables. + */ +var mdiv = $('menu'); +var hdiv = $('viewhead'); +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; +$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; +var fdiv = $('viewfoot'); + +/** + * Set page title. + */ +document.title = config.windowtitle() + ' - Sorry'; +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv) { + mdiv.innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), + mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); + fdiv.innerHTML = config.viewfoot(); +} + +showmenu(mdiv); + +/** + * Log the current user out. + */ +window.logout = function() { + // Clear session cookie and user-specific local storage entries + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.location = '/login/'; + return false; +} + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + ui.onload(); + + // Show the page + document.body.style.visibility = 'visible'; + return true; +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notfound/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notfound/index.html new file mode 100644 index 0000000000..8f0d486854 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notfound/index.html @@ -0,0 +1,194 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>Page not found</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<base href="/public/notfound/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +})(); + +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"></div> + +<div id="viewcontainer"> +<div id="view"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<div class="hd2">Sorry, that page was not found.</div> +<div>You may have clicked an expired link or mistyped the address.</div> + +</div> +</div> +</div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init div variables. + */ +var mdiv = $('menu'); +var hdiv = $('viewhead'); +$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; +$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; +var fdiv = $('viewfoot'); + +/** + * Set page title. + */ +document.title = config.windowtitle() + ' - Page not found'; +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv) { + mdiv.innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), + mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); + fdiv.innerHTML = config.viewfoot(); +} + +showmenu(mdiv); + +/** + * Log the current user out. + */ +window.logout = function() { + // Clear session cookie and user-specific local storage entries + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.location = '/login/'; + return false; +} + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + ui.onload(); + + // Show the page + document.body.style.visibility = 'visible'; + return true; +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notyet/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notyet/index.html new file mode 100644 index 0000000000..e43a992f38 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/notyet/index.html @@ -0,0 +1,194 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>Page not found</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<base href="/public/notyet/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +})(); + +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"></div> + +<div id="viewcontainer"> +<div id="view"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<div class="hd2">Sorry, that page is still under construction.</div> +<div>Please check back later.</div> + +</div> +</div> +</div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init div variables. + */ +var mdiv = $('menu'); +var hdiv = $('viewhead'); +$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; +$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; +var fdiv = $('viewfoot'); + +/** + * Set page title. + */ +document.title = config.windowtitle() + ' - Page not found'; +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv) { + mdiv.innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), + mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); + fdiv.innerHTML = config.viewfoot(); +} + +showmenu(mdiv); + +/** + * Log the current user out. + */ +window.logout = function() { + // Clear session cookie and user-specific local storage entries + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.location = '/login/'; + return false; +} + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + ui.onload(); + + // Show the page + document.body.style.visibility = 'visible'; + return true; +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/oops/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/oops/index.html new file mode 100644 index 0000000000..cc97c5362e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/oops/index.html @@ -0,0 +1,193 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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>Oops</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<base href="/public/oops/"/> +<script type="text/javascript"> +(function() { + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.setRequestHeader("Accept", "*/*"); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (window.debug) debug('http error', u, 'X-Login'); + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (window.debug) debug('http error', u, 'No-Content'); + return null; + } + try { ls.setItem(u, http.responseText); } catch(e) {} + return http.responseText; + } + if (window.debug) debug('http error', u, http.status, http.statusText); + return null; +}; + +})(); + +/** + * Load Javascript and CSS. + */ +(function() { + +var bootjs = document.createElement('script'); +bootjs.type = 'text/javascript'; +bootjs.text = appcache.get('/all-min.js'); +document.head.appendChild(bootjs); +document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); + +})(); + +</script> +</head> +<body class="delayed"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { + +$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); + +})(); +</script> +</div> + +<div id="menubackground" class="tbarbackground fixed"></div> +<div id="menu" class="tbarmenu fixed"></div> + +<div id="viewheadbackground" class="viewheadbackground fixed"></div> +<div id="viewhead" class="viewhead fixed"></div> + +<div id="viewcontainer"> +<div id="view"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> + +<br/> +<div class="hd2">Oops, something went wrong...</div> + +</div> +</div> +</div> + +<div id="viewfootbackground" class="viewfootbackground fixed"></div> +<div id="viewfoot" class="viewfoot fixed"></div> + +<script type="text/javascript"> +(function() { + +/** + * Init div variables. + */ +var mdiv = $('menu'); +var hdiv = $('viewhead'); +$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; +$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; +var fdiv = $('viewfoot'); + +/** + * Set page title. + */ +document.title = config.windowtitle() + ' - Oops'; +$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + +/** + * Build and show the menu bar. + */ +function showmenu(mdiv) { + mdiv.innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), + mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); + fdiv.innerHTML = config.viewfoot(); +} + +showmenu(mdiv); + +/** + * Log the current user out. + */ +window.logout = function() { + // Clear session cookie and user-specific local storage entries + clearauthcookie(); + lstorage.removeItem('/r/Editor/accounts'); + lstorage.removeItem('/r/Editor/dashboards'); + document.location = '/login/'; + return false; +} + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //debug('onorientationchange'); + ui.onorientationchange(e); + + // Resize menu and view header + mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); + return true; +}; + +/** + * Initialize the document. + */ +function onload() { + //debug('onload'); + ui.onload(); + + // Show the page + document.body.style.visibility = 'visible'; + return true; +} + +onload(); + +})(); +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.b64 new file mode 100644 index 0000000000..2239f6ae0f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAADkAAAA5CAIAAAADehTSAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDGxMkCJXGmL8AAAHwSURBVGje7ZpNbhNBEIXf625sCzA/QUhkg8SGiGxZcpDcgRux5hLkEjkE7BAS9gIyk+muxyZIsSeOG09bsXHX0p4pfVNdP8/loSTsiTnsj1XWyrrMutVSG+ic/ftNqe1mIMtSjsPUu9EQJ6H/UdvNLr59cgwFWaM1p8dnLx6dFGYF6RhIXzLVGIChB3VX8Fg0DWrPqqyHxTq4MUnKKEEBoNvIN4uxiqTkofUXpgZKsqtMx3Djpb45lNWAxxbfXf6wtdH9+vkKBLLGrFLz4M1HTk+K5gAIgBCVcaTI1gOK/acazqqbw2PdYzE7tdyh9AFJTL0zNDIJMInAZpKPzBzmIZuUnjoa9QQkOBHAyWbigYDaTslybg/59f7Q4+003pqwhqcbqjLH9H2OXw0Ksl6XsWB/a39lhf1rz8vOnKoHKmtlrayVtbLuuc6SFK1Z2hEZkBwAv1us4zA9PT7rDX3v9dPiOeBxT/uY0A+qd6Pbl2Sax/kXDN9LlcrXO3Rk9k/QWluVtbIe2O5toBGwFum3bLH/pEso7RarrPNHH/D8JbBIpsjJqx2Lq3Xu2Xv61yvXJzf6/b3nK2Htyu8WB9P/XltF/wfVllgFxet9azGL+bjMD5IUYbPSMktwT8hRSdalkizcufKcs77vUlkr61bsD5lbwtgOKPT2AAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.png Binary files differnew file mode 100644 index 0000000000..f22c33d2a0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.xcf b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.xcf Binary files differnew file mode 100644 index 0000000000..fc713b478b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/touchicon.xcf diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/user.b64 b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/user.b64 new file mode 100644 index 0000000000..7ed235aa14 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/user.b64 @@ -0,0 +1 @@ +iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAxQTFRFyN+N+dR1/PCI////6HjE5gAAADJJREFUKM9j+I8EPjBQifeBAQSY6coLBYN6inhaq0Bg6SDn/f//akB466ExTS6P2ukMAKumzarJO/66AAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/user.png b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/user.png Binary files differnew file mode 100644 index 0000000000..1f73274b76 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/public/user.png diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/robots.txt b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/robots.txt new file mode 100644 index 0000000000..1f53798bb4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/stats/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/stats/index.html new file mode 100644 index 0000000000..7c3d9a6434 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/stats/index.html @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div class="viewform"> + +<form id="appForm"> +<table style="width: 100%;"> +<tr><tr><td><b>Icon:</b></td></tr> +<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Title:</b></td></tr> +<tr><td><input type="text" class="flatentry" id="appTitle" size="30" readonly="readonly" placeholder="Enter the title of your app" style="width: 300px;"/></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Author:</b></td></tr> +<tr><td><span id="appAuthor"></span></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Updated:</b></td></tr> +<tr><td><span id="appUpdated"></span></td></tr> +<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> +<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" readonly="readonly" placeholder="Enter a short description of your app" style="width: 300px;"></textarea></td></tr> +</table> +</form> + +</div> + +<script type="text/javascript"> +(function() { + +/** + * Get the app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Stats - ' + appname; +$('viewhead').innerHTML = '<span id="appname" class="cmenu">' + appname + '</span>' + +'<input type="button" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" id="deleteApp" value="-" title="Delete the app" disabled="true"/>' + +'<input type="button" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 5px;" id="cloneApp" value="'+ config.clone() +'" title="' + config.clone() + ' this app"/>'; + +/** + * Set images. + */ +$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var apps = sca.reference(editorComp, "apps"); + +/** + * The current app entry, author and saved XML content. + */ +var savedappentryxml = ''; +var author; +var appentry; + +/** + * Get and display an app. + */ +function getapp(name) { + if (isNil(name)) + return false; + showStatus('Loading'); + + return apps.get(name, function(doc) { + + // Stop now if we didn't get the app + if (doc == null) { + showError('App not available'); + return false; + } + + appentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + $('appTitle').value = cadr(assoc("'title", cdr(appentry))); + author = cadr(assoc("'author", cdr(appentry))); + $('appAuthor').innerHTML = author; + $('appUpdated').innerHTML = cadr(assoc("'updated", cdr(appentry))); + var content = cadr(assoc("'content", cdr(appentry))); + var description = assoc("'description", content); + $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); + savedappentryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + + // Enable author to edit and delete the app + if (username == author) { + $('appTitle').readOnly = false; + $('appDescription').readOnly = false; + $('deleteApp').disabled = false; + $('deleteApp').onclick = function() { + return ui.navigate('/#view=delete&app=' + appname, '_view'); + } + showOnlineStatus(); + } else { + $('appTitle').placeholder = ''; + $('appDescription').placeholder = ''; + showStatus('Read only'); + } + return true; + }); +} + +/** + * Save the current app. + */ +function save(entryxml) { + showStatus('Saving'); + savedappentryxml = entryxml; + apps.put(appname, savedappentryxml, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + + showStatus('Saved'); + return false; + }); + return true; +} + +/** + * Handle a change event + */ +function onappchange() { + if (username != author) + return false; + var title = $('appTitle').value; + var description = $('appDescription').value; + appentry = mklist("'entry", mklist("'title", title != ''? title : appname), mklist("'id", appname), mklist("'content", mklist("'stats", mklist("'description", description)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + if (savedappentryxml == entryxml) + return false; + showStatus('Modified'); + return save(entryxml); +} + +$('appTitle').onchange = onappchange; +$('appDescription').onchange = onappchange; + +/** + * Handle a form submit event. + */ +$('appForm').onsubmit = function() { + onappchange(); + return false; +}; + +/** + * Handle Clone button event. + */ +$('cloneApp').onclick = function() { + return ui.navigate('/#view=clone&app=' + appname, '_view'); +} + +/** + * Get the current app. + */ +getapp(appname); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/store/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/store/index.html new file mode 100644 index 0000000000..1264007fe3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/store/index.html @@ -0,0 +1,170 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div id="apps" class="viewcontent"></div> + +<script type="text/javascript"> +(function() { + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Store'; + +/** + * The store categories + */ +var categories = [ + //['Featured', 'featured', 1], + ['Top', 'top', 2], + ['New', 'new', 3], + ['Search', 'all', 4], + ['My Apps', 'myapps', 5] +]; + +/** + * Find a store category. + */ +function findcategory(name) { + if (isNil(name)) + return findcategory('top'); + var f = filter(function(c) { return cadr(c) == name }, categories); + if (isNil(f)) + return findcategory('top'); + return car(f); +} + +/** + * Get the current store category. + */ +var catname = cadr(findcategory(ui.fragmentParams(location)['category'])); + +/** + * Build the store menu bar + */ +function catmenu() { + function catmenuitem(name, cat, idx) { + var c = cat == catname? 'smenu' : 'amenu'; + return '<span>' + ui.href('storecat_' + cat, '/#view=store&category=' + cat + '&idx=' + idx, '_view', '<span class="' + c + '">' + name + '</span>') + '</span>'; + } + + var m = ''; + map(function(c) { m += catmenuitem(car(c), cadr(c), caddr(c)); }, categories); + m += '<span class="rmenu"><input type="button" class="graybutton bluebutton" id="createApp" title="Create a new app" Value="Create"/></span>'; + return m; +} + +/** + * Build the store menu bar. + */ +$('viewhead').innerHTML = catmenu(); + +/** + * Init service references. + */ +var editorComp = sca.component("Editor"); +var store = sca.reference(editorComp, "store"); +var dashboards = sca.reference(editorComp, "dashboards"); + +/** + * Edit an app. + */ +function editApp(appname) { + return ui.navigate('/#view=page&app=' + appname, '_view'); +} + +/** + * View an app. + */ +function viewApp(appname) { + return ui.navigate('/#view=stats&app=' + appname, '_view'); +} + +/** + * Create an app. + */ +$('createApp').onclick = function() { + return ui.navigate('/#view=create', '_view'); +} + +/** + * Get and display list of apps. + */ +function getapps(catname) { + //debug('catname', catname); + showStatus('Loading'); + + function display(doc) { + + // Stop now if we didn't get the apps + if (doc == null) { + showError('App not available'); + return false; + } + showOnlineStatus(); + + var apps = '<div>'; + var feed = car(elementsToValues(atom.readATOMFeed(mklist(doc)))); + var aentries = assoc("'entry", cdr(feed)); + var entries = isNil(aentries)? mklist() : isList(car(cadr(aentries)))? cadr(aentries) : mklist(cdr(aentries)); + + var appimg = ui.b64img(appcache.get('/public/app.b64')); + + function displayentries(entries) { + if (isNil(entries)) + return apps; + var entry = car(entries); + var title = cadr(assoc("'title", entry)) + var name = cadr(assoc("'id", entry)); + var author = cadr(assoc("'author", entry)); + var updated = cadr(assoc("'updated", entry)); + + apps += '<div class="box">' + apps += '<span class="appicon">' + ui.href('appicon_' + name, '/#view=stats&app=' + name, '_view', '<img src="' + appimg + '" width="50" height="50"></img>') + '</span>'; + apps += '<span>' + apps += '<span class="apptitle">' + ui.href('apptitle_' + name, '/#view=stats&app=' + name, '_view', name) + '</span>'; + if (catname != 'myapps') + apps += '<br/><span>' + 'by ' + author.split('@')[0] + '</span>'; + apps += '</span>'; + apps += '</div>'; + return displayentries(cdr(entries)); + } + + displayentries(entries); + + apps += '</div>'; + $('apps').innerHTML = apps; + } + + if (catname == 'myapps') + return dashboards.get('', display); + return store.get(catname, display); +} + +/** + * Get and display the list of apps. + */ +getapps(catname); + +})(); +</script> + +</div> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/log.py b/sca-cpp/branches/lightweight-sca/hosting/server/log.py new file mode 100644 index 0000000000..8aa3d3bd30 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/log.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. + +# Log service component +from sys import stderr + +# Log a message +def log(msg): + print >> stderr, '[rconsole]', msg + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/logic-test b/sca-cpp/branches/lightweight-sca/hosting/server/logic-test new file mode 100755 index 0000000000..d4767e858f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/logic-test @@ -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. + +# Run Python test cases +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +python_prefix=`cat $here/../../modules/python/python.prefix` +export LD_LIBRARY_PATH=$python_prefix/lib:$LD_LIBRARY_PATH + +$python_prefix/bin/python test.py 2>/dev/null +rc=$? + +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/mkapplinks b/sca-cpp/branches/lightweight-sca/hosting/server/mkapplinks new file mode 100755 index 0000000000..a68a2896ec --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/mkapplinks @@ -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. + +aprefix=$1 +tprefix=$2 +nprefix=$3 + +# Create app links to Nuvem and Tuscany components +cd $1 +for n in `ls apps | awk '{ printf "apps/%s/nuvem\n", $1 }'`; do + if [ ! -e "$n" ]; then + ln -s "$nprefix/nuvem-parallel/nuvem" "$n" + fi +done + +for n in `ls apps | awk '{ printf "apps/%s/lib\n", $1 }'`; do + if [ ! -e "$n" ]; then + ln -s "$tprefix/components" "$n" + fi +done + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/pages.py b/sca-cpp/branches/lightweight-sca/hosting/server/pages.py new file mode 100644 index 0000000000..a4f6d056f9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/pages.py @@ -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. + +# App pages collection implementation +from time import strftime +from util import * +from sys import debug + +# Convert an id to a page id +def pageid(id): + return ("apps", car(id), "htdocs", "app.html") + +# Put a page into the page db +def put(id, page, user, cache, apps): + debug('pages.py::put::id', id) + debug('pages.py::put::page', page) + + # Get the requested app + app = apps.get(id); + if isNil(app) or app is None: + debug('pages.py::put', 'app not found', id) + return False + + # Check app author + author = cadr(assoc("'author", car(app))) + if author != user.get(()): + debug('pages.py::put', 'different author', author) + return False + + # Update the page in the page db + pageentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y')), assoc("'content", car(page))),) + debug('pages.py::put::pageentry', pageentry) + return cache.put(pageid(id), pageentry) + +# Get a page from the page db +def get(id, user, cache, apps): + debug('pages.py::get::id', id) + if isNil(id): + return (("'feed", ("'title", "Pages"), ("'id", "pages")),) + + # Get the requested app + app = apps.get(id) + if isNil(app) or app is None: + debug('pages.py::get', 'app not found', id) + + # Return a default new page + return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'author", user.get(())), ("'updated", strftime('%b %d, %Y'))),) + + # Get the requested page + page = cache.get(pageid(id)) + if isNil(page) or page is None: + debug('pages.py::get', 'page not found', id) + + # Return a default new page + return (("'entry", ("'title", car(id)), ("'id", car(id)), assoc("'author", car(app)), assoc("'updated", car(app))),) + + # Return the page + def updated(u): + return assoc("'updated", car(app)) if isNil(u) or u is None else u + pageentry = (("'entry", assoc("'title", car(app)), ("'id", car(id)), assoc("'author", car(app)), updated(assoc("'updated", car(page))), assoc("'content", car(page))),) + debug('pages.py::get::pageentry', pageentry) + return pageentry + +# Delete a page from the page db +def delete(id, user, cache, apps): + debug('pages.py::delete::id', id) + + # Get the requested app + app = apps.get(id); + if isNil(app) or app is None: + debug('pages.py::delete', 'app not found', id) + return False + + # Check app author + author = cadr(assoc("'author", car(app))) + if author != user.get(()): + debug('pages.py::delete', 'different author', author) + return False + + # Delete the page + return cache.delete(pageid(id)) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/palettes.py b/sca-cpp/branches/lightweight-sca/hosting/server/palettes.py new file mode 100644 index 0000000000..321db3cf46 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/palettes.py @@ -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. + +# Palettes collection implementation +from util import * + +# Convert an id to a palette id +def paletteid(id): + return ("palettes", car(id), "palette.composite") + +# Put a palette into the palettes db +def put(id, palette, cache): + comp = cdr(cadddr(car(palette))) + cache.put(paletteid(id), comp) + return True + +# Get a palette from the palettes db +def get(id, cache): + if isNil(id): + return (("'feed", ("'title", "Palettes"), ("'id", "palettes")),) + return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'content", car(cache.get(paletteid(id))))),) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/proxy-start b/sca-cpp/branches/lightweight-sca/hosting/server/proxy-start new file mode 100755 index 0000000000..f06de9fc01 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/proxy-start @@ -0,0 +1,164 @@ +#!/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 module to work, add the www.example.com domain to your /etc/hosts as +# follows: +# 127.0.0.1 www.example.com + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +# Configure and start logging +if [ -x ../../components/log/scribe-cat ]; then + ../../components/log/scribed-central-conf tmp + ../../components/log/scribed-client-conf tmp localhost + ../../components/log/scribed-central-start tmp + ../../components/log/scribed-client-start tmp +fi + +# Start memcached +../../components/cache/memcached-start tmp 11211 +../../components/cache/memcached-start tmp 11212 + +# Configure server +../../modules/http/httpd-conf tmp www.example.com 9090 htdocs +../../modules/http/httpd-event-conf tmp + +# Configure Python component support +../../modules/server/server-conf tmp +../../modules/python/python-conf tmp + +# Configure server log streaming +if [ -x ../../components/log/scribe-cat ]; then + cat >tmp/conf/log.conf <<EOF +# Generated by: proxy-start $* +LogLevel notice +ErrorLog "|$here/../../components/log/scribe-cat localhost server" +CustomLog "|$here/../../components/log/scribe-cat localhost server" combined + +EOF + +fi +#../../modules/http/httpd-loglevel-conf tmp debug + +# Configure error pages +cat >>tmp/conf/svhost.conf <<EOF +# Generated by: proxy-start $* +# Error pages +ErrorDocument 404 /public/notfound/ +ErrorDocument 401 /public/notauth/ +ErrorDocument 403 /public/notauth/ +ErrorDocument 400 /public/oops/ +ErrorDocument 405 /public/oops/ +ErrorDocument 500 /public/oops/ +ErrorDocument 502 /public/oops/ +ErrorDocument 503 /public/oops/ + +EOF + +# Configure SCA contributions +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: proxy-start $* +# Configure SCA Composite +SCAContribution $here/ +SCAComposite server.composite + +# Configure SCA Composite for mass dynamic virtual Hosting +#SCAVirtualContribution $here/data/apps/ +#SCAVirtualComposite app.composite +SCAVirtualContributor Composites + +# Configure SCA wiring timeout +SCAWiringTimeout 10 + +EOF + +# Configure resource aliases +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: proxy-start $* +Alias /home/home.png $here/htdocs/home/home.png +Alias /home/home.b64 $here/htdocs/home/home.b64 +Alias /proxy/public/config.js $here/htdocs/public/config.js +Alias /proxy/public/config-min.js $here/public/config-min.js + +EOF + +# Configure app resource aliases +cat >>tmp/conf/svhost.conf <<EOF +# Generated by: proxy-start $* +# Map /v/<app-name>/<path> to htdocs/app/<path> +AliasMatch /v/([^/]+)(.*)$ $here/htdocs/app\$2 + +EOF + +# Start server +../../modules/http/httpd-start tmp + +# Clear document cache +rm -rf tmp/proxy/cache + +# Configure proxy balancer +../../modules/http/httpd-conf tmp/proxy www.example.com 8090 tmp/htdocs +../../modules/http/alt-host-conf tmp/proxy ww1.example.com +../../modules/http/alt-host-conf tmp/proxy ww2.example.com +../../modules/http/proxy-conf tmp/proxy +../../modules/js/js-conf tmp/proxy +../../modules/http/httpd-event-conf tmp/proxy +#../../modules/http/cache-conf tmp/proxy + +# Configure proxy balancer members +../../modules/http/proxy-member-conf tmp/proxy localhost 9090 + +# Configure proxy log streaming +if [ -x ../../components/log/scribe-cat ]; then + cat >tmp/proxy/conf/log.conf <<EOF +# Generated by: proxy-start $* +ErrorLog "|$here/../../components/log/scribe-cat www.example.com proxy" +CustomLog "|$here/../../components/log/scribe-cat www.example.com access" combined + +EOF + +fi +#../../modules/http/httpd-loglevel-conf tmp/proxy debug + +# Configure resource aliases +cat >>tmp/proxy/conf/httpd.conf <<EOF +# Generated by: proxy-start $* +Alias /proxy/public/config.js $here/htdocs/public/config.js +Alias /proxy/public/config-min.js $here/htdocs/public/config-min.js + +EOF + +# Configure error pages +cat >>tmp/proxy/conf/vhost.conf <<EOF +# Generated by: proxy-start $* +# Error pages +ErrorDocument 404 /proxy/public/oops/ +ErrorDocument 401 /proxy/public/oops/ +ErrorDocument 403 /proxy/public/oops/ +ErrorDocument 400 /proxy/public/oops/ +ErrorDocument 405 /proxy/public/oops/ +ErrorDocument 500 /proxy/public/oops/ +ErrorDocument 502 /proxy/public/oops/ +ErrorDocument 503 /proxy/public/oops/ + +EOF + +# Start proxy balancer +../../modules/http/httpd-start tmp/proxy + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/put-auth b/sca-cpp/branches/lightweight-sca/hosting/server/put-auth new file mode 100755 index 0000000000..351c9b7d7a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/put-auth @@ -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. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +admin=$2 +apass=$3 +user=$4 +upass=$5 + +httpd_prefix=`cat $here/../../modules/http/httpd.prefix` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + scheme="http" + addr=`echo $conf | awk '{ print $7 }'` + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +else + scheme="https" + ssladdr=`echo $sslconf | awk '{ print $6 }'` + host=`$here/../../modules/http/httpd-addr ip $ssladdr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $ssladdr` +fi + +# Get password hash +rm -f $root/conf/auth.passwd +touch $root/conf/auth.passwd +$httpd_prefix/bin/htpasswd -b $root/conf/auth.passwd "$user" "$upass" 2>/dev/null +hash=`cat $root/conf/auth.passwd | awk -F ":" '{ print $2 }'` +rm -f $root/conf/auth.passwd + +# Compute user id +slash=`echo $user | grep "/"` +if [ "$slash" = "" ]; then + id="\"$user\"" + upath=$user +else + id=`echo $user | awk -F "/" '{ printf "\"%s\" \"%s\"", $2, $3 }'` + upath=`echo $user | awk -F "/" '{ printf "%s/%s", $2, $3 }'` +fi + +# Put user auth +cat >$root/conf/auth.entry <<EOF +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">$user</title> + <id>$user</id> + <content type="application/xml"> + <hash>$hash</hash> + </content> +</entry> +EOF +curl -k -L -u $admin:$apass -X PUT -H "X-Forwarded-Server: $host" --data-binary @$root/conf/auth.entry $scheme://$host:$port/c/Authenticator/$upath +rm $root/conf/auth.entry + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/selector.py b/sca-cpp/branches/lightweight-sca/hosting/server/selector.py new file mode 100644 index 0000000000..7fcdd65a0f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/selector.py @@ -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. + +# App composites collection implementation +from util import * + +# Get the database to use for a particular key +def get(id, db): + if isNil(id): + return db[0] + if cadr(id)[0:1].lower() < 'm': + return db[0] + return db[1] + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/server-test b/sca-cpp/branches/lightweight-sca/hosting/server/server-test new file mode 100755 index 0000000000..4d4d06f338 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/server-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 +./ssl-proxy-start +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +./stop +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/server.composite b/sca-cpp/branches/lightweight-sca/hosting/server/server.composite new file mode 100644 index 0000000000..7e4d7196d0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/server.composite @@ -0,0 +1,149 @@ +<?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" + targetNamespace="http://server" + name="server"> + + <component name="User"> + <implementation.python script="user.py"/> + <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> + <property name="host">?</property> + </component> + + <component name="Editor"> + <implementation.widget location="/index.html"/> + <reference name="user" target="User"/> + <reference name="accounts" target="Accounts"/> + <reference name="dashboards" target="Dashboards"/> + <reference name="apps" target="Apps"/> + <reference name="store" target="AppStore"/> + <reference name="palettes" target="Palettes"/> + <reference name="composites" target="Composites"/> + <reference name="pages" target="Pages"/> + <reference name="log" target="Log"/> + </component> + + <component name="App"> + <implementation.widget location="/app/index.html"/> + <reference name="user" target="User"/> + <reference name="pages" target="Pages"/> + <reference name="composites" target="Composites"/> + <reference name="log" target="Log"/> + </component> + + <component name="Accounts"> + <implementation.python script="accounts.py"/> + <reference name="user" target="User"/> + <reference name="cache" target="Cache"/> + </component> + + <component name="Authenticator"> + <implementation.python script="authn.py"/> + <reference name="cache" target="Cache"/> + </component> + + <component name="Dashboards"> + <implementation.python script="dashboards.py"/> + <reference name="user" target="User"/> + <reference name="cache" target="Cache"/> + <reference name="apps" target="Apps"/> + </component> + + <component name="AppStore"> + <implementation.python script="store.py"/> + <reference name="user" target="User"/> + <reference name="cache" target="Cache"/> + <reference name="apps" target="Apps"/> + </component> + + <component name="Apps"> + <implementation.python script="apps.py"/> + <reference name="user" target="User"/> + <reference name="cache" target="Cache"/> + <reference name="dashboard" target="Dashboards"/> + <reference name="store" target="AppStore"/> + <reference name="composites" target="Composites"/> + <reference name="pages" target="Pages"/> + </component> + + <component name="Composites"> + <implementation.python script="composites.py"/> + <reference name="user" target="User"/> + <reference name="cache" target="Doccache"/> + <reference name="apps" target="Apps"/> + </component> + + <component name="Pages"> + <implementation.python script="pages.py"/> + <reference name="user" target="User"/> + <reference name="cache" target="Doccache"/> + <reference name="apps" target="Apps"/> + </component> + + <component name="Palettes"> + <implementation.python script="palettes.py"/> + <reference name="cache" target="Doccache"/> + </component> + + <component name="Cache"> + <implementation.cpp path="../../components/cache" library="libdatacache"/> + <reference name="l1reader" target="Memcache"/> + <reference name="l1writer" target="Memcache"/> + <reference name="l2reader" target="Database"/> + <reference name="l2writer" target="Database"/> + </component> + + <component name="Doccache"> + <implementation.cpp path="../../components/cache" library="libdatacache"/> + <reference name="l1reader" target="Memcache"/> + <reference name="l1writer" target="Memcache"/> + <reference name="l2reader" target="Documents"/> + <reference name="l2writer" target="Documents"/> + </component> + + <component name="Memcache"> + <implementation.cpp path="../../components/cache" library="libmemcache"/> + <property name="server">localhost:11211</property> + <property name="server">localhost:11212</property> + </component> + + <component name="Database"> + <implementation.cpp path="../../components/filedb" library="libfiledb"/> + <property name="dbname">data</property> + <property name="format">scheme</property> + </component> + + <component name="Documents"> + <implementation.cpp path="../../components/filedb" library="libfiledb"/> + <property name="dbname">data</property> + <property name="format">xml</property> + </component> + + <component name="Log"> + <implementation.python script="log.py"/> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/ssl-proxy-start b/sca-cpp/branches/lightweight-sca/hosting/server/ssl-proxy-start new file mode 100755 index 0000000000..e38f54055b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/ssl-proxy-start @@ -0,0 +1,252 @@ +#!/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 module to work, add the www.example.com domain to your /etc/hosts as +# follows: +# 127.0.0.1 www.example.com + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +# Configure and start logging +if [ -x ../../components/log/scribe-cat ]; then + ../../components/log/scribed-central-conf tmp + ../../components/log/scribed-client-conf tmp localhost + ../../components/log/scribed-central-start tmp + ../../components/log/scribed-client-start tmp +fi + +# Start memcached +../../components/cache/memcached-start tmp 11211 +../../components/cache/memcached-start tmp 11212 + +# Configure server +../../modules/http/httpd-conf tmp www.example.com 9090 htdocs +../../modules/http/httpd-event-conf tmp + +# Configure HTTP basic auth +../../modules/http/basic-auth-conf tmp component + +# Configure OAuth authentication +# Configure your OAuth app keys here +../../modules/oauth/oauth-conf tmp component +../../modules/oauth/oauth-memcached-conf tmp localhost 11212 +../../modules/oauth/oauth2-appkey-conf tmp facebook.com 12345 67890 +../../modules/oauth/oauth2-appkey-conf tmp google.com 12345 67890 + +# Configure form-based authentication +../../modules/http/open-auth-conf tmp component 80b67f38-b79e-4a72-bb5c-22c69fb00820 + +# Configure authorized admins +../../modules/http/passwd-auth-conf tmp admin admin + +# Configure Python component support +../../modules/server/server-conf tmp +../../modules/python/python-conf tmp + +# Configure server log streaming +if [ -x ../../components/log/scribe-cat ]; then + cat >tmp/conf/log.conf <<EOF +# Generated by: ssl-proxy-start $* +LogLevel notice +ErrorLog "|$here/../../components/log/scribe-cat localhost server" +CustomLog "|$here/../../components/log/scribe-cat localhost server" combined + +EOF + +fi +../../modules/http/httpd-loglevel-conf tmp debug + +# Configure error pages +cat >>tmp/conf/svhost.conf <<EOF +# Generated by: ssl-proxy-start $* +# Error pages +ErrorDocument 404 /public/notfound/ +ErrorDocument 401 /public/notauth/ +ErrorDocument 403 /public/notauth/ +ErrorDocument 400 /public/oops/ +ErrorDocument 405 /public/oops/ +ErrorDocument 500 /public/oops/ +ErrorDocument 502 /public/oops/ +ErrorDocument 503 /public/oops/ + +EOF + +# Configure SCA contributions +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: ssl-proxy-start $* +# Configure SCA Composite +SCAContribution $here/ +SCAComposite server.composite + +# Configure SCA Composite for mass dynamic virtual Hosting +SCAVirtualContributor Composites + +# Configure SCA Authenticator component +SCAAuthenticator Authenticator + +# Configure SCA wiring timeout +SCAWiringTimeout 10 + +EOF + +# Configure resource aliases +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: ssl-proxy-start $* +Alias /home/home.png $here/htdocs/home/home.png +Alias /home/home.b64 $here/htdocs/home/home.b64 +Alias /proxy/public/config.js $here/htdocs/public/config.js +Alias /proxy/public/config-min.js $here/public/config-min.js + +EOF + +# Configure app resource aliases +cat >>tmp/conf/svhost-ssl.conf <<EOF +# Generated by: ssl-proxy-start $* +# Map /v/<app-name>/<path> to htdocs/app/<path> +AliasMatch /v/([^/]+)(.*)$ $here/htdocs/app\$2 + +EOF + +# Configure admin access to server status and info +cat >tmp/conf/adminauth.conf <<EOF +# Generated by: ssl-proxy-start $* +# Allow the server admin to view the server status and info +<Location /server-status> +AuthType None +Require all granted +</Location> + +<Location /server-info> +AuthType None +Require all granted +</Location> + +EOF + +# Configure admin access to components +cat >>tmp/conf/locauth-ssl.conf <<EOF +# Generated by: ssl-proxy-start $* +# Allow the server admin to access all components +<Location /c> +Require user admin +</Location> +<Location /r> +Require user admin +</Location> +<Location /r/Editor> +Require valid-user +</Location> +<Location /r/App> +Require valid-user +</Location> +EOF + +# Start server +../../modules/http/httpd-start tmp +sleep 2 + +# Configure authorized users +./put-auth tmp admin admin admin admin +./put-auth tmp admin admin john john +./put-auth tmp admin admin jane jane +# Configure the email addresses associated with your OAuth ids here +./put-auth tmp admin admin /oauth1/john@example.com password +./put-auth tmp admin admin /oauth2/jane@example.com password + +# Clear document cache +rm -rf tmp/proxy/cache + +# Create SSL certificates +../../modules/http/ssl-ca-conf tmp/proxy www.example.com +../../modules/http/ssl-cert-conf tmp/proxy www.example.com server + +# Configure proxy balancer +../../modules/http/httpd-conf tmp/proxy www.example.com 8090 tmp/htdocs +../../modules/http/alt-host-conf tmp/proxy ww1.example.com +../../modules/http/alt-host-conf tmp/proxy ww2.example.com +../../modules/http/proxy-conf tmp/proxy +../../modules/js/js-conf tmp/proxy +../../modules/http/httpd-event-conf tmp/proxy +#../../modules/http/cache-conf tmp/proxy +../../modules/http/httpd-ssl-conf tmp/proxy 8453 +../../modules/http/proxy-ssl-conf tmp/proxy +#../../modules/http/cache-ssl-conf tmp/proxy + +# Configure password authentication +../../modules/http/basic-auth-conf tmp/proxy file /balancer-manager +../../modules/http/basic-auth-conf tmp/proxy file /server-status +../../modules/http/passwd-auth-conf tmp/proxy file admin admin + +# Configure mod-security +../../modules/http/mod-security-conf tmp/proxy +#../../modules/http/mod-security-audit-conf tmp/proxy + +# Configure proxy balancer members +../../modules/http/proxy-ssl-nossl-member-conf tmp/proxy localhost 9090 + +# Configure proxy log streaming +if [ -x ../../components/log/scribe-cat ]; then + cat >tmp/proxy/conf/log.conf <<EOF +# Generated by: ssl-proxy-start $* +ErrorLog "|$here/../../components/log/scribe-cat www.example.com proxy" +CustomLog "|$here/../../components/log/scribe-cat www.example.com access" combined + +EOF + + cat >tmp/proxy/conf/log-ssl.conf <<EOF +# Generated by: ssl-proxy-start $* +CustomLog "|$here/../../components/log/scribe-cat www.example.com access" sslcombined + +EOF + +# cat >tmp/proxy/conf/mod-security-audit-log.conf <<EOF +## Generated by: start $* +#SecAuditLog "|$here/../../components/log/scribe-cat $host secaudit secaudit" +# +#EOF + +fi +../../modules/http/httpd-loglevel-conf tmp/proxy debug + +# Configure resource aliases +cat >>tmp/proxy/conf/httpd.conf <<EOF +# Generated by: ssl-proxy-start $* +Alias /proxy/public/config.js $here/htdocs/public/config.js +Alias /proxy/public/config-min.js $here/htdocs/public/config-min.js + +EOF + +# Configure error pages +cat >>tmp/proxy/conf/vhost-ssl.conf <<EOF +# Generated by: ssl-proxy-start $* +# Error pages +ErrorDocument 404 /proxy/public/oops/ +ErrorDocument 401 /proxy/public/oops/ +ErrorDocument 403 /proxy/public/oops/ +ErrorDocument 400 /proxy/public/oops/ +ErrorDocument 405 /proxy/public/oops/ +ErrorDocument 500 /proxy/public/oops/ +ErrorDocument 502 /proxy/public/oops/ +ErrorDocument 503 /proxy/public/oops/ + +EOF + +# Start proxy balancer +../../modules/http/httpd-start tmp/proxy + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/ssl-start b/sca-cpp/branches/lightweight-sca/hosting/server/ssl-start new file mode 100755 index 0000000000..d699089847 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/ssl-start @@ -0,0 +1,208 @@ +#!/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 module to work, add the www.example.com domain to your /etc/hosts as +# follows: +# 127.0.0.1 www.example.com + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +host=`hostname` + +# Create SSL certificates +../../modules/http/ssl-ca-conf tmp www.example.com +../../modules/http/ssl-cert-conf tmp www.example.com server + +# Configure and start logging +if [ -x ../../components/log/scribe-cat ]; then + ../../components/log/scribed-central-conf tmp + ../../components/log/scribed-client-conf tmp localhost + ../../components/log/scribed-central-start tmp + ../../components/log/scribed-client-start tmp +fi + +# Start memcached +../../components/cache/memcached-start tmp 11211 +../../components/cache/memcached-start tmp 11212 + +# Clear document cache +rm -rf tmp/cache + +# Configure server +../../modules/http/httpd-conf tmp www.example.com 8090 htdocs +../../modules/http/alt-host-conf tmp ww1.example.com +../../modules/http/alt-host-conf tmp ww2.example.com +../../modules/http/httpd-event-conf tmp +#../../modules/http/cache-conf tmp +../../modules/http/httpd-ssl-conf tmp 8453 +#../../modules/http/cache-ssl-conf tmp + +# Configure HTTP basic auth +../../modules/http/basic-auth-conf tmp component + +# Configure OAuth authentication +# Configure your OAuth app keys here +../../modules/oauth/oauth-conf tmp component +../../modules/oauth/oauth-memcached-conf tmp localhost 11212 +../../modules/oauth/oauth2-appkey-conf tmp facebook.com 12345 67890 +../../modules/oauth/oauth2-appkey-conf tmp google.com 12345 67890 + +# Configure form-based authentication +../../modules/http/open-auth-conf tmp component 80b67f38-b79e-4a72-bb5c-22c69fb00820 + +# Configure authorized admins +../../modules/http/passwd-auth-conf tmp admin admin + +# Configure mod-security +#../../modules/http/mod-security-conf tmp + +# Configure Python component support +../../modules/server/server-conf tmp +../../modules/python/python-conf tmp + +# Configure server log streaming +if [ -x ../../components/log/scribe-cat ]; then + cat >tmp/conf/log.conf <<EOF +# Generated by: ssl-start $* +ErrorLog "|$here/../../components/log/scribe-cat $host server" +CustomLog "|$here/../../components/log/scribe-cat $host server" combined + +EOF + + cat >tmp/conf/log-ssl.conf <<EOF +# Generated by: ssl-start $* +CustomLog "|$here/../../components/log/scribe-cat $host server" sslcombined + +EOF + + cat >tmp/conf/mod-security-log.conf <<EOF +# Generated by: ssl-start $* +SecAuditLog "|$here/../../components/log/scribe-cat $host secaudit" + +EOF + +fi +#../../modules/http/httpd-loglevel-conf tmp debug + +# Configure certificate mime type +cat >>tmp/conf/svhost-ssl.conf <<EOF +# Generated by: ssl-start $* +# Certificate mime type +<Location /ca.crt> +ForceType application/x-x509-ca-cert +</Location> + +EOF + +# Configure error pages +cat >>tmp/conf/svhost-ssl.conf <<EOF +# Generated by: ssl-start $* +# Error pages +ErrorDocument 404 /public/notfound/ +ErrorDocument 401 /public/notauth/ +ErrorDocument 403 /public/notauth/ +ErrorDocument 400 /public/oops/ +ErrorDocument 405 /public/oops/ +ErrorDocument 500 /public/oops/ +ErrorDocument 502 /public/oops/ +ErrorDocument 503 /public/oops/ + +EOF + +# Configure SCA contributions +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: ssl-start $* +# Configure SCA Composite +SCAContribution $here/ +SCAComposite server.composite + +# Configure SCA Composite for mass dynamic virtual Hosting +SCAVirtualContributor Composites + +# Configure SCA Authenticator component +SCAAuthenticator Authenticator + +# Configure SCA wiring timeout +SCAWiringTimeout 10 + +EOF + +# Configure resource aliases +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: ssl-start $* +Alias /home/home.png $here/htdocs/home/home.png +Alias /home/home.b64 $here/htdocs/home/home.b64 +Alias /proxy/public/config.js $here/htdocs/public/config.js +Alias /proxy/public/config-min.js $here/public/config-min.js + +EOF + +# Configure app resource aliases +cat >>tmp/conf/svhost-ssl.conf <<EOF +# Generated by: ssl-start $* +# Map /v/<app-name>/<path> to htdocs/app/<path> +AliasMatch /v/([^/]+)(.*)$ $here/htdocs/app\$2 + +EOF + +# Configure admin access to server status and info +cat >tmp/conf/adminauth.conf <<EOF +# Generated by: ssl-start $* +# Allow the server admin to view the server status and info +<Location /server-status> +AuthType None +Require all granted +</Location> + +<Location /server-info> +AuthType None +Require all granted +</Location> + +EOF + +# Configure admin access to components +cat >>tmp/conf/locauth-ssl.conf <<EOF +# Generated by: ssl-start $* +# Allow the server admin to access all components +<Location /c> +Require user admin +</Location> +<Location /r> +Require user admin +</Location> +<Location /r/Editor> +Require valid-user +</Location> +<Location /r/App> +Require valid-user +</Location> +EOF + +# Start server +../../modules/http/httpd-start tmp +sleep 2 + +# Configure authorized users +./put-auth tmp admin admin admin admin +./put-auth tmp admin admin john john +./put-auth tmp admin admin jane jane +# Configure the email addresses associated with your OAuth ids here +./put-auth tmp admin admin /oauth1/john@example.com password +./put-auth tmp admin admin /oauth2/jane@example.com password + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/start b/sca-cpp/branches/lightweight-sca/hosting/server/start new file mode 100755 index 0000000000..d4443cb250 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/start @@ -0,0 +1,126 @@ +#!/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 module to work, add the www.example.com domain to your /etc/hosts as +# follows: +# 127.0.0.1 www.example.com + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +host=`hostname` + +# Configure and start logging +if [ -x ../../components/log/scribe-cat ]; then + ../../components/log/scribed-central-conf tmp + ../../components/log/scribed-client-conf tmp localhost + ../../components/log/scribed-central-start tmp + ../../components/log/scribed-client-start tmp +fi + +# Start memcached +../../components/cache/memcached-start tmp 11211 +../../components/cache/memcached-start tmp 11212 + +# Clear document cache +rm -rf tmp/cache + +# Configure server +../../modules/http/httpd-conf tmp www.example.com 8090 htdocs +../../modules/http/alt-host-conf tmp ww1.example.com +../../modules/http/alt-host-conf tmp ww2.example.com +../../modules/http/httpd-event-conf tmp +#../../modules/http/cache-conf tmp + +# Configure Python component support +../../modules/server/server-conf tmp +../../modules/python/python-conf tmp + +# Configure server log streaming +if [ -x ../../components/log/scribe-cat ]; then + cat >tmp/conf/log.conf <<EOF +# Generated by: start $* +LogLevel notice +ErrorLog "|$here/../../components/log/scribe-cat $host server" +CustomLog "|$here/../../components/log/scribe-cat $host server" combined + +EOF + +else + cat >tmp/conf/log.conf <<EOF +# Generated by: start $* +ErrorLog $here/tmp/logs/error_log +CustomLog $here/tmp/logs/access_log combined + +EOF + +fi +#../../modules/http/httpd-loglevel-conf tmp debug + +# Configure error pages +cat >>tmp/conf/svhost.conf <<EOF +# Generated by: start $* +# Error pages +ErrorDocument 404 /public/notfound/ +ErrorDocument 401 /public/notauth/ +ErrorDocument 403 /public/notauth/ +ErrorDocument 400 /public/oops/ +ErrorDocument 405 /public/oops/ +ErrorDocument 500 /public/oops/ +ErrorDocument 502 /public/oops/ +ErrorDocument 503 /public/oops/ + +EOF + +# Configure SCA contributions +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: start $* +# Configure SCA Composite +SCAContribution $here/ +SCAComposite server.composite + +# Configure SCA Composite for mass dynamic virtual Hosting +#SCAVirtualContribution $here/data/apps/ +#SCAVirtualComposite app.composite +SCAVirtualContributor Composites + +# Configure SCA wiring timeout +SCAWiringTimeout 10 + +EOF + +# Configure resource aliases +cat >>tmp/conf/httpd.conf <<EOF +# Generated by: start $* +Alias /home/home.png $here/htdocs/home/home.png +Alias /home/home.b64 $here/htdocs/home/home.b64 +Alias /proxy/public/config.js $here/htdocs/public/config.js +Alias /proxy/public/config-min.js $here/public/config-min.js + +EOF + +# Configure app resource aliases +cat >>tmp/conf/svhost.conf <<EOF +# Generated by: start $* +# Map /v/<app-name>/<path> to htdocs/app/<path> +AliasMatch /v/([^/]+)(.*)$ $here/htdocs/app\$2 + +EOF + +# Start server +../../modules/http/httpd-start tmp + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/stop b/sca-cpp/branches/lightweight-sca/hosting/server/stop new file mode 100755 index 0000000000..82ecd101ef --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/stop @@ -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-stop tmp/proxy +../../modules/http/httpd-stop tmp + +../../components/cache/memcached-stop tmp 11211 +../../components/cache/memcached-stop tmp 11212 + +if [ -x ../../components/log/scribe-cat ]; then + ../../components/log/scribed-client-stop tmp + ../../components/log/scribed-central-stop tmp +fi + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/store.py b/sca-cpp/branches/lightweight-sca/hosting/server/store.py new file mode 100644 index 0000000000..054f546c2d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/store.py @@ -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. + +# Stores collection implementation +from util import * +from sys import debug + +# Convert a particular store tag to a store id +def storeid(tag): + return ("store", tag, "store.apps") + +# Get a store from the cache +def getstore(id, cache): + debug('store.py::getstore::id', id) + val = cache.get(id) + if isNil(val) or val is None: + return () + store = cdddr(car(val)) + if not isNil(store) and isList(car(cadr(car(store)))): + # Expand list of entries + estore = tuple(map(lambda e: cons("'entry", e), cadr(car(store)))) + debug('store.py::getstore::estore', estore) + return estore + + debug('store.py::getstore::store', store) + return store + +# Put a store into the cache +def putstore(id, store, cache): + debug('store.py::putstore::id', id) + debug('store.py::putstore::store', store) + val = ((("'feed", ("'title", "App Store"), ("'id", cadr(id))) + store),) + return cache.put(id, val) + +# Put an app into a store +def put(id, app, user, cache, apps): + debug('store.py::put::id', id) + debug('store.py::put::app', app) + tag = car(id) + appid = cdr(id) + + def putapp(appid, app, store): + if isNil(store): + return app + if car(appid) == cadr(assoc("'id", car(store))): + return cons(car(app), cdr(store)) + return cons(car(store), putapp(appid, app, cdr(store))) + + appentry = (("'entry", assoc("'title", car(app)), ("'id", car(appid)), ("'author", user.get(())), assoc("'updated", car(app)), assoc("'content", car(app))),) + debug('store.py::put::appentry', appentry) + + store = putapp(appid, appentry, getstore(storeid(tag), cache)) + return putstore(storeid(tag), store, cache) + +# Get apps from a store +def get(id, user, cache, apps): + debug('store.py::get::id', id) + tag = car(id) + appid = cdr(id) + + def findapp(appid, store): + if isNil(store): + return None + if car(appid) == cadr(assoc("'id", car(store))): + return (car(store),) + return findapp(appid, cdr(store)) + + if isNil(appid): + store = ((("'feed", ("'title", "App Store"), ("'id", tag)) + getstore(storeid(tag), cache)),) + debug('store.py::get::store', store) + return store + + app = findapp(appid, getstore(storeid(tag), cache)) + debug('store.py::get::app', app) + return app + +# Delete apps from a store +def delete(id, user, cache, apps): + debug('store.py::delete::id', id) + tag = car(id) + appid = cdr(id) + + if isNil(appid): + return cache.delete(storeid(tag)) + + def deleteapp(appid, store): + if isNil(store): + return () + if car(appid) == cadr(assoc("'id", car(store))): + return cdr(store) + return cons(car(store), deleteapp(appid, cdr(store))) + + store = getstore(storeid(tag), cache) + deleted = deleteapp(appid, store) + if deleted == store: + return False + return putstore(storeid(tag), deleted, cache) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/test.py b/sca-cpp/branches/lightweight-sca/hosting/server/test.py new file mode 100755 index 0000000000..2575fb7b92 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/test.py @@ -0,0 +1,296 @@ +#!/usr/bin/python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Test the hosting server components + +import sys +sys.debug = lambda *l: sys.stderr.write('python::debug ' + repr(l) + '\n') +import time +time.strftime = lambda f: 'Jan 01, 2012' + +import unittest +from test.property import * +from test.reference import * +from test.cache import * + +import user +import accounts +import pages +import composites +import apps +import store +import dashboards + +def testUser(): + # Return current user + assert user.get((), mkprop('user', lambda: 'johndoe'), mkprop('email', lambda: 'jdoe@example.com'), mkprop('nick', lambda: 'jdoe'), mkprop('full', lambda: 'john doe'), mkprop('first', lambda: 'john'), mkprop('last', lambda: 'doe'), mkprop('realm', lambda: 'example.com'), mkprop('host', lambda: 'localhost')) == 'jdoe@example.com' + return True + +def testAccounts(): + # Get default account + defaccount = (("'entry", ("'title", 'jdoe@example.com'), ("'id", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012')),) + assert accounts.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {})) == defaccount + + # Get user's account + jdoe = (("'entry", ("'title", 'John Doe'), ("'id", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'key", 'value'))),) + assert accounts.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('accounts', 'jdoe@example.com', 'user.account') : jdoe})) == jdoe + + # Put and get account + cache1 = mkcache('cache', {}) + assert accounts.put((), jdoe, mkref('user', lambda id: 'jdoe@example.com'), cache1) == True + assert accounts.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1) == jdoe + return True + +def testPages(): + # Get default page + defpage = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012')),) + app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),) + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defpage + defpagefromapp = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012')),) + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: app1)) == defpagefromapp + + # Get a page + page1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ())),) + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('apps', 'app1', 'htdocs', 'app.html') : page1}), mkref('apps', lambda id: app1)) == page1 + + # Put and get a page + cache1 = mkcache('cache', {}) + page1updated = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ())),) + assert pages.put(('app1',), page1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == page1updated + + # Reject put from user other than the author + app1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),) + page1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 02, 2012')),) + assert pages.put(('app1',), page1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False + assert pages.put(('app1',), page1otherauthor, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == page1updated + + # Reject delete from user other than the author + assert pages.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == page1updated + + # Delete a page + assert pages.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True + assert pages.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == defpagefromapp + return True + +def testComposites(): + # Get default composite + defcomposite = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012')),) + app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),) + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defcomposite + defcompositefromapp = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 03, 2012')),) + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: app1)) == defcompositefromapp + + # Get a composite + composite1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ())),) + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('apps', 'app1', 'app.composite') : composite1}), mkref('apps', lambda id: app1)) == composite1 + + # Put and get a composite + cache1 = mkcache('cache', {}) + composite1updated = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ())),) + assert composites.put(('app1',), composite1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == composite1updated + + # Reject put from user other than the author + app1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),) + composite1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 02, 2012')),) + assert composites.put(('app1',), composite1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False + assert composites.put(('app1',), composite1otherauthor, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == composite1updated + + # Reject delete from user other than the author + assert composites.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1otherauthor)) == False + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == composite1updated + + # Delete a composite + assert composites.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == True + assert composites.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: app1)) == defcompositefromapp + return True + +def testApps(): + # Get default app + defapp = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ("'stats", ("'description", '')))),) + assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == defapp + + # Get an app + app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 01, 2012'), ("'content", ("'stats", ("'description", '')))),) + assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('apps', 'app1', 'app.stats') : app1}), mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1 + + # Put and get an app + cache1 = mkcache('cache', {}) + assert apps.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('dashboard', lambda id, app: True), mkref('store', lambda id, app: True), mkref('composites', lambda id, app: True), mkref('pages', lambda id, app: True)) == True + assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1 + return True + + # Reject put from user other than the author + app1otherauthor = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jane@example.com'), ("'updated", 'Jan 03, 2012'), ("'content", ())),) + assert apps.put(('app1',), app1, mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id, app: True), mkref('store', lambda id, app: True), mkref('composites', lambda id, app: True), mkref('pages', lambda id, app: True)) == false + assert apps.get(('app1',), mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1 + + # Reject delete from user other than the author + assert apps.delete(('app1',), mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == False + assert apps.get(('app1',), mkref('user', lambda id: 'jane@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == app1 + + # Delete an app + assert apps.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == True + assert apps.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('dashboard', lambda id: None), mkref('store', lambda id: None), mkref('composites', lambda id: None), mkref('pages', lambda id: None)) == defapp + return True + +def testStore(): + # Get default store + defstore = (("'feed", ("'title", 'App Store'), ("'id", 'top')),) + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defstore + + # Get a store + store1= (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),) + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('store', 'top', 'store.apps') : store1}), mkref('apps', lambda id: None)) == store1 + + store1compact = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ((("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), (("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))))),) + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('store', 'top', 'store.apps') : store1compact}), mkref('apps', lambda id: None)) == store1 + + # Put an app in an empty store + cache1 = mkcache('cache', {}) + app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))),) + store1withapp1 = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1'))))),) + assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp1 + assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp1 + + # Put a second app in the store + app2 = (("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))),) + store1withapp2 = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),) + assert store.put(('top', 'app2'), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp2 + assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp2 + assert store.put(('top', 'app2'), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp2 + + # Put a third app in the store + app3 = (("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3')))),) + store1withapp3 = (("'feed", ("'title", 'App Store'), ("'id", 'top'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))), ("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3'))))),) + assert store.put(('top', 'app3'), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3 + assert store.put(('top', 'app1'), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3 + assert store.put(('top', 'app2'), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3 + assert store.put(('top', 'app3'), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == store1withapp3 + + # Get an app from the store + assert store.get(('top','app1'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app1 + assert store.get(('top','app2'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app2 + assert store.get(('top','app3'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app3 + + # Put a third app in the store, starting from a compacted list + cache2 = mkcache('cache', {('store', 'top', 'store.apps') : store1compact}) + assert store.put(('top', 'app3'), app3, mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == store1withapp3 + + # Delete the apps + assert store.delete(('top', 'app2'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.delete(('top', 'app4'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == False + assert store.delete(('top', 'app1'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.delete(('top', 'app3'), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == defstore + + # Delete a store + assert store.delete(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True + assert store.get(('top',), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == defstore + return True + +def testDashboards(): + # Get default dashboard + defdashboard = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com')),) + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {}), mkref('apps', lambda id: None)) == defdashboard + + # Get the user's dashboard + dash1= (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),) + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('dashboards', 'jdoe@example.com', 'user.apps') : dash1}), mkref('apps', lambda id: None)) == dash1 + + dash1compact = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ((("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), (("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))))),) + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), mkcache('cache', {('dashboards', 'jdoe@example.com', 'user.apps') : dash1compact}), mkref('apps', lambda id: None)) == dash1 + + # Put an app in an empty dashboard + cache1 = mkcache('cache', {}) + app1 = (("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))),) + dash1withapp1 = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1'))))),) + assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp1 + assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp1 + + # Put a second app in the dashboard + app2 = (("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))),) + dash1withapp2 = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2'))))),) + assert dashboards.put(('app2',), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp2 + assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp2 + assert dashboards.put(('app2',), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp2 + + # Put a third app in the dashboard + app3 = (("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3')))),) + dash1withapp3 = (("'feed", ("'title", 'Your Apps'), ("'id", 'jdoe@example.com'), ("'entry", ("'title", 'app1'), ("'id", 'app1'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app1')))), ("'entry", ("'title", 'app2'), ("'id", 'app2'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app2')))), ("'entry", ("'title", 'app3'), ("'id", 'app3'), ("'author", 'jdoe@example.com'), ("'updated", 'Jan 02, 2012'), ("'content", ("'stats", ("'description", 'app3'))))),) + assert dashboards.put(('app3',), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3 + assert dashboards.put(('app1',), app1, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3 + assert dashboards.put(('app2',), app2, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3 + assert dashboards.put(('app3',), app3, mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == dash1withapp3 + + # Get an app from the user's dashboard + assert dashboards.get(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app1 + assert dashboards.get(('app2',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app2 + assert dashboards.get(('app3',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == app3 + + # Put a third app in the dashboard, starting from a compacted list + cache2 = mkcache('cache', {('dashboards', 'jdoe@example.com', 'user.apps') : dash1compact}) + assert dashboards.put(('app3',), app3, mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == dash1withapp3 + + # Delete the apps + assert dashboards.delete(('app2',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.delete(('app4',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == False + assert dashboards.delete(('app1',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.delete(('app3',), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache1, mkref('apps', lambda id: None)) == defdashboard + + # Delete the dashboard + assert dashboards.delete((), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == True + assert dashboards.get((), mkref('user', lambda id: 'jdoe@example.com'), cache2, mkref('apps', lambda id: None)) == defdashboard + return True + +if __name__ == '__main__': + print 'Testing...' + testUser() + testAccounts() + testPages() + testComposites() + testApps() + testStore() + testDashboards() + print 'OK' + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/test/__init__.py b/sca-cpp/branches/lightweight-sca/hosting/server/test/__init__.py new file mode 100644 index 0000000000..de5c2d1b1e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/test/__init__.py @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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/sca-cpp/branches/lightweight-sca/hosting/server/test/cache.py b/sca-cpp/branches/lightweight-sca/hosting/server/test/cache.py new file mode 100644 index 0000000000..98fa174c00 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/test/cache.py @@ -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. + +# Mockup cache for testing + +class cache: + def __init__(self, name, values): + self.name = name + self.values = values + + def get(self, id): + if id in self.values: + return self.values[id] + return None + + def put(self, id, value): + self.values[id] = value + return True + + def post(self, id): + return self.put(id) + + def delete(self, id): + if id in self.values: + del self.values[id] + return True + return False + + def __repr__(self): + return repr((self.name, self.values)) + +def mkcache(name, values = {}): + return cache(name, values) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/test/property.py b/sca-cpp/branches/lightweight-sca/hosting/server/test/property.py new file mode 100644 index 0000000000..1cbb4b2cab --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/test/property.py @@ -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. + +# Mockup component properties for testing + +class property: + def __init__(self, name, l): + self.name = name + self.l = l + + def __call__(self, *args): + return self.l(*args) + + def __getattr__(self, name): + if name == "eval": + return self + raise AttributeError() + + def __repr__(self): + return repr((self.name, self.l())) + +def mkprop(name, l): + return property(name, l) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/test/reference.py b/sca-cpp/branches/lightweight-sca/hosting/server/test/reference.py new file mode 100644 index 0000000000..fe4a66a087 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/test/reference.py @@ -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. + +# Mockup component references for testing + +class reference: + def __init__(self, name, l): + self.name = name + self.l = l + + def __call__(self, *args): + return self.l(*args) + + def __getattr__(self, name): + if name == "get" or name == "put": + return self + raise AttributeError() + + def __repr__(self): + return repr((self.name, self.l)) + +def mkref(name, l): + return reference(name, l) + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/user.py b/sca-cpp/branches/lightweight-sca/hosting/server/user.py new file mode 100644 index 0000000000..8038e43563 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/user.py @@ -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. + +# User info service component + +# Return the current user id +def get(i, user, email, nick, full, first, last, realm, host): + if email.eval() != '?': + return email.eval() + if user.eval() != '?': + return user.eval() + return 'anonymous' + diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/util.py b/sca-cpp/branches/lightweight-sca/hosting/server/util.py new file mode 100644 index 0000000000..24467fd2cb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/util.py @@ -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. + +# 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 cdddr(l): + return cdr(cdr(cdr(l))) + +def cadddr(l): + return car(cdddr(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 isString(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)) + +# Convert a path represented as a list of values to a string +def path(p): + if isNil(p): + return "" + return "/" + car(p) + path(cdr(p)) + +# Split a path into a list of segments +def tokens(path): + return tuple(filter(lambda s: len(s) != 0, path.split("/"))) + +# Return true if s1 contains s2 +def contains(s1, s2): + return s1.find(s2) != -1 + +# 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/sca-cpp/branches/lightweight-sca/kernel/Makefile.am b/sca-cpp/branches/lightweight-sca/kernel/Makefile.am new file mode 100644 index 0000000000..e6a7fdb2b3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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${libsuffix} +libdynlib-test${libsuffix}: + ln -s .libs/libdynlib-test${libsuffix} + +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/sca-cpp/branches/lightweight-sca/kernel/config.hpp b/sca-cpp/branches/lightweight-sca/kernel/config.hpp new file mode 100644 index 0000000000..944b9629e7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/config.hpp @@ -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. + */ + +/* $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 +{ + +/** + * Attribute used to mark unused parameters. + */ +#ifndef unused +#define unused __attribute__ ((unused)) +#endif + +/** + * Compiler feature detection. + */ +#ifdef __clang__ + +#if __has_feature(cxx_lambdas) +#define HAS_CXX0X_LAMBDAS 1 +#endif + +#else + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4) +#define HAS_CXX0X_LAMBDAS 1 +#endif + +#endif + +/** + * Debug utilities. + */ +#ifdef WANT_MAINTAINER_MODE + +/** + * Strict compile warnings. + */ +#define WANT_MAINTAINER_WARNINGS + +/** + * Fast fail assertion. + */ +#define WANT_MAINTAINER_ASSERT + +/** + * Debug log. + */ +#define WANT_MAINTAINER_LOG + +/** + * Add string watch members to important classes to help watch them in a debugger. + */ +//#define WANT_MAINTAINER_WATCH + +/** + * Maintain counters of important objects to help test garbage collection. + */ +//#define WANT_MAINTAINER_COUNTERS + +#ifdef WANT_MAINTAINER_COUNTERS + +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 + +#else + +#define debug_inc(c) +#define debug_dec(c) + +#endif + +} +#endif /* tuscany_config_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/kernel/dynlib-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/dynlib-test.cpp new file mode 100644 index 0000000000..419fa29db5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp b/sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp new file mode 100644 index 0000000000..69359b4dae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/dynlib.hpp @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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) { + } + + const lib& operator=(const lib& l) { + if(this == &l) + return *this; + name = l.name; + h = l.h; + owner = false; + return *this; + } + + ~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); + + 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>>(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/sca-cpp/branches/lightweight-sca/kernel/element.hpp b/sca-cpp/branches/lightweight-sca/kernel/element.hpp new file mode 100644 index 0000000000..27b5af8691 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 bool 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>(isList(cadr<value>(v))? (value)cdr<value>(v) : cadr<value>(v), isList(cadr<value>(car(l)))? (value)cdr<value>(car(l)) : cadr<value>(car(l)))); + return elementToValueGroupValues(g, cdr(l)); + } + const value g = mklist<value>(car<value>(v), cons<value>(isList(cadr<value>(v))? (value)cdr<value>(v) : cadr<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, c_str(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/sca-cpp/branches/lightweight-sca/kernel/fstream.hpp b/sca-cpp/branches/lightweight-sca/kernel/fstream.hpp new file mode 100644 index 0000000000..4f7f5152aa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/fstream.hpp @@ -0,0 +1,404 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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> + +#ifdef WANT_HTTPD_LOG +#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 CLang/LLVM +#undef strtoul +// Hack to workaround compile error with HTTPD 2.3.8 +#define new new_ +#include <http_config.h> +#undef new +#include <http_main.h> +#include <http_log.h> + +#else + +#include <time.h> +#include <sys/time.h> +#include <unistd.h> + +#ifdef WANT_THREADS +#include <pthread.h> +#endif + +#endif + +#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) { + } + + const ofstream& operator=(const ofstream& os) { + if(this == &os) + return *this; + file = os.file; + owner = false; + return *this; + } + + ~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) { + } + + const ifstream& operator=(const ifstream& is) { + if(this == &is) + return *this; + file = is.file; + owner = false; + return *this; + } + + ~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. + */ + +#ifdef WANT_HTTPD_LOG + +/* + * HTTPD-based log stream. + */ +class loghstream : public ostream { +public: + loghstream(const int level) : level(level), len(0) { + } + + ~loghstream() { + } + + ostream& vprintf(const char* fmt, ...) { + va_list args; + va_start (args, fmt); + const int l = vsnprintf(buf + len, (sizeof(buf) - 1) - len, fmt, args); + va_end (args); + len += l; + if (len > (int)(sizeof(buf) - 1)) + len = sizeof(buf) - 1; + return *this; + } + + ostream& write(const string& s) { + if (s != "\n") + return this->vprintf("%s", c_str(s)); + buf[len] = '\0'; + ap_log_error(NULL, 0, -1, level, 0, ap_server_conf, "%s", buf); + len = 0; + return *this; + } + + ostream& flush() { + return *this; + } + +private: + const int level; + int len; + char buf[2049]; +}; + +/** + * Info and failure log streams. + */ +loghstream cinfo(APLOG_INFO); +loghstream cfailure(APLOG_ERR); + +#ifdef WANT_MAINTAINER_LOG + +/** + * Debug log stream. + */ +loghstream cdebug(APLOG_DEBUG); + +/** + * Return true if debug log is enabled. + */ +#define debug_islogging() (bool)(APLOG_MODULE_IS_LEVEL(ap_server_conf, APLOG_NO_MODULE, APLOG_DEBUG)) + +#endif + +#else + +/** + * Format the current time. + */ +const string logTime() { + struct timeval tv; + gettimeofday(&tv, NULL); + const time_t t = tv.tv_sec; + const tm* lt = localtime(&t); + char ft[32]; + strftime(ft, 20, "%a %b %d %H:%M:%S", lt); + sprintf(ft + 19, ".%06lu ", (unsigned long)tv.tv_usec); + strftime(ft + 27, 5, "%Y", lt); + return ft; +} + +/* + * File-based log stream. + */ +class logfstream : public ostream { +public: + logfstream(FILE* file, const string& type) : file(file), type(type), head(false) { + } + + logfstream(const logfstream& os) : file(os.file), type(os.type), head(os.head) { + } + + ~logfstream() { + } + + ostream& vprintf(const char* fmt, ...) { + whead(); + va_list args; + va_start (args, fmt); + vfprintf (file, fmt, args); + va_end (args); + return *this; + } + + ostream& write(const string& s) { + whead(); + fwrite(c_str(s), 1, length(s), file); + if (s == "\n") + head = false; + return *this; + } + + ostream& flush() { + fflush(file); + return *this; + } + +private: + FILE* file; + const string type; + bool head; + + const unsigned long tid() const { +#ifdef WANT_THREADS + return (unsigned long)pthread_self(); +#else + return 0; +#endif + } + + ostream& whead() { + if (head) + return *this; + head = true; + *this << "[" << logTime() << "] [" << type << "] [pid " << (unsigned long)getpid() << ":tid " << tid() << "] "; + return *this; + } +}; + +/** + * Info and failure log streams. + */ +logfstream cinfo(stderr, "info"); +logfstream cfailure(stderr, "error"); + +#ifdef WANT_MAINTAINER_LOG + +/** + * Debug log stream. + */ +logfstream cdebug(stderr, "debug"); + +/** + * Return true if debug log is enabled. + */ +bool debug_isLoggingSet = false; +bool debug_isLoggingEnv = false; + +const bool debug_isLogging() { + if (debug_isLoggingSet) + return debug_isLoggingEnv; + debug_isLoggingEnv = getenv("TUSCANY_DEBUG_LOG") != NULL; + return debug_isLoggingEnv; +} + +#define debug_islogging() debug_isLogging() + +#endif + +#endif + +#ifdef WANT_MAINTAINER_LOG + +/** + * Log a debug message. + */ +const bool debugLog(const string& msg) { + gc_scoped_pool p; + cdebug << msg << endl; + return true; +} + +/** + * Log a debug message and a value. + */ +template<typename V> const bool debugLog(const V& v, const string& msg) { + gc_scoped_pool p; + cdebug << msg << ": " << v << endl; + return true; +} + +/** + * Log a debug message and two values. + */ +template<typename V, typename W> const bool debugLog(const V& v, const W& w, const string& msg) { + gc_scoped_pool p; + cdebug << msg << ": " << v << " : " << w << endl; + return true; +} + +#define debug(...) do { if (debug_islogging()) tuscany::debugLog(__VA_ARGS__); } while(0) + +#else + +#define debug_islogging() false +#define debug(...) + +#endif + +} + +#endif /* tuscany_fstream_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/kernel/function.hpp b/sca-cpp/branches/lightweight-sca/kernel/function.hpp new file mode 100644 index 0000000000..60117dab98 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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_COUNTERS + +/** + * 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/sca-cpp/branches/lightweight-sca/kernel/gc.hpp b/sca-cpp/branches/lightweight-sca/kernel/gc.hpp new file mode 100644 index 0000000000..32ad8160cc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/gc.hpp @@ -0,0 +1,500 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 "config.hpp" +#ifdef WANT_MALLOC_MMAP +#include <sys/mman.h> +#include <malloc.h> +#endif +#include <stdlib.h> +#include <apr_general.h> +#include <apr_pools.h> +#include <apr_strings.h> +#include <assert.h> +#include <new> +#ifdef WANT_THREADS +#include <pthread.h> +#endif + +namespace tuscany +{ + +#ifdef WANT_MAINTAINER_ASSERT + +/** + * Force a core dump on assertion violation. + */ +bool assertOrFail(const bool expr) { + if (!expr) + abort(); + return true; +} + +#else + +#define assertOrFail(expr) + +#endif + +/** + * 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==(T* p) const throw() { + return ptr == p; + } + + const bool operator!=(const gc_ptr& r) const throw() { + return !this->operator==(r); + } + + const bool operator!=(T* p) const throw() { + return !this->operator==(p); + } + + T& operator*() const throw() { + return *ptr; + } + + T* operator->() const throw() { + return ptr; + } + + operator T*() const throw() { + return ptr; + } + + T* ptr; +}; + +/** + * Initialize APR. + */ +class gc_apr_context_t { +public: + gc_apr_context_t() { + apr_initialize(); + } +} gc_apr_context; + +/** + * 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_child_pool; + friend class gc_local_pool; + friend class gc_scoped_pool; + + apr_pool_t* apr_pool; +}; + +/** + * Return the APR pool used by a gc_pool. + */ +apr_pool_t* pool(const gc_pool& pool) { + return pool.apr_pool; +} + +/** + * Maintain a stack of memory pools. + */ +#ifdef WANT_THREADS + +class gc_pool_stack_t { +public: + gc_pool_stack_t() { + int rc = pthread_key_create(&key, NULL); + assertOrFail(rc == 0); + } + + operator apr_pool_t*() const { + return static_cast<apr_pool_t*>(pthread_getspecific(key)); + } + + const gc_pool_stack_t& operator=(apr_pool_t* p) { + pthread_setspecific(key, p); + return *this; + } + +private: + pthread_key_t key; +} gc_pool_stack; + +#else +apr_pool_t* gc_pool_stack = NULL; +#endif + +/** + * 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; +} + +/** + * Return the current memory pool. + */ +apr_pool_t* gc_current_pool() { + apr_pool_t* p = gc_pool_stack; + if (p != NULL) + return p; + + // Create a parent pool for the current thread + apr_pool_create(&p, NULL); + assertOrFail(p != NULL); + gc_push_pool(p); + return p; +} + +/** + * A child memory pool, which will be destroyed when its parent pool is destroyed. + */ +class gc_child_pool : public gc_pool { +public: + + gc_child_pool() : gc_pool(NULL), owner(true) { + apr_pool_create(&apr_pool, gc_current_pool()); + assertOrFail(apr_pool != NULL); + } + + gc_child_pool(const gc_child_pool& p) : gc_pool(p.apr_pool), owner(false) { + } + + const gc_child_pool& operator=(const gc_child_pool& p) { + if(this == &p) + return *this; + apr_pool = p.apr_pool; + owner = false; + return *this; + } + + +private: + bool owner; +}; + +/** + * A local pool scope, which will be destroyed when exiting the current scope. + */ +class gc_local_pool : public gc_pool { +public: + + gc_local_pool() : gc_pool(NULL), owner(true) { + apr_pool_create(&apr_pool, gc_current_pool()); + assertOrFail(apr_pool != NULL); + } + + ~gc_local_pool() { + if (owner) + apr_pool_destroy(apr_pool); + } + + gc_local_pool(const gc_local_pool& p) : gc_pool(p.apr_pool), owner(false) { + } + + const gc_local_pool& operator=(const gc_local_pool& p) { + if(this == &p) + return *this; + apr_pool = p.apr_pool; + owner = false; + return *this; + } + +private: + bool owner; +}; + +/** + * A memory pool scope, used to setup a scope in which a particular pool will be + * used for all allocations. Will be destroyed when existing the current scope. + */ +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, prev); + assertOrFail(apr_pool != NULL); + gc_push_pool(apr_pool); + } + + gc_scoped_pool(apr_pool_t* p) : gc_pool(p), 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); + } + + gc_scoped_pool(const gc_scoped_pool& p) : gc_pool(p.apr_pool), prev(p.prev), owner(false) { + } + + const gc_scoped_pool& operator=(const gc_scoped_pool& p) { + if(this == &p) + return *this; + apr_pool = p.apr_pool; + prev = p.prev; + owner = false; + return *this; + } + +private: + 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 = (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)); + assertOrFail(gc_new_ptr != NULL); + apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup<T>, apr_pool_cleanup_null) ; + return (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)); + assertOrFail(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)); + assertOrFail(gc_cnew_ptr != NULL); + return gc_cnew_ptr; +} + +char* gc_cnew(size_t n) { + return gc_cnew(gc_current_pool(), n); +} + +/** + * Pool based equivalent of the standard malloc function. + */ +void* gc_pool_malloc(size_t n) { + size_t* ptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n)); + assertOrFail(ptr != NULL); + *ptr = n; + return ptr + 1; +} + +/** + * Pool based equivalent of the standard realloc function. + */ +void* gc_pool_realloc(void* ptr, size_t n) { + size_t size = *(static_cast<size_t*>(ptr) - 1); + size_t* rptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n)); + assertOrFail(rptr != NULL); + *rptr = n; + memcpy(rptr + 1, ptr, size < n? size : n); + return rptr + 1; +} + +/** + * Pool based equivalent of the standard free function. + */ +void gc_pool_free(unused void* ptr) { + // Memory allocated from a pool is freed when the pool is freed +} + +/** + * Pool based equivalent of the standard strdup function. + */ +char* gc_pool_strdup(const char* str) { + char* dptr = static_cast<char*>(gc_pool_malloc(strlen(str) + 1)); + assertOrFail(dptr != NULL); + strcpy(dptr, str); + return dptr; +} + +#ifdef WANT_MALLOC_MMAP + +/** + * Mmap based memory allocation functions. + */ + +/** + * Mmap based equivalent of the standard malloc function. + */ +void* gc_mmap_malloc(size_t n, unused const void* caller) { + //printf("gc_mmap_malloc %d", n); + size_t* ptr = static_cast<size_t*>(mmap(NULL, sizeof(size_t) + n, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); + assertOrFail(ptr != NULL); + *ptr = n; + //printf(" %p\n", ptr + 1); + return ptr + 1; +} + +/** + * Mmap based equivalent of the standard realloc function. + */ +void* gc_mmap_realloc(void* ptr, size_t n, const void* caller) { + if (ptr == NULL) + return gc_mmap_malloc(n, caller);; + //printf("gc_mmap_realloc %p %d", ptr, n); + size_t size = *(static_cast<size_t*>(ptr) - 1); + size_t* rptr = static_cast<size_t*>(mremap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size, sizeof(size_t) + n, MREMAP_MAYMOVE, NULL)); + assertOrFail(rptr != NULL); + *rptr = n; + //printf(" %p\n", rptr + 1); + return rptr + 1; +} + +/** + * Mmap based equivalent of the standard free function. + */ +void gc_mmap_free(void* ptr, unused const void* caller) { + //printf("gc_mmap_free %p\n", ptr); + if (ptr == NULL) + return; + size_t size = *(static_cast<size_t*>(ptr) - 1); + munmap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size); +} + +/** + * Mmap based equivalent of the standard memalign function. + */ +void* gc_mmap_memalign(unused size_t alignment, size_t n, unused const void* caller) { + //printf("gc_mmap_memalign %d %d\n", alignment, n); + return gc_mmap_malloc(n, caller); +} + +/** + * Install the mmap based memory allocation functions. + */ +void gc_mmap_init_hook(void) { + __malloc_hook = gc_mmap_malloc; + __realloc_hook = gc_mmap_realloc; + __free_hook = gc_mmap_free; + __memalign_hook = gc_mmap_memalign; +} + +#endif + +} + +#ifdef WANT_MALLOC_MMAP + +void (*__malloc_initialize_hook)(void) = tuscany::gc_mmap_init_hook; + +#endif + +#endif /* tuscany_gc_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp new file mode 100644 index 0000000000..4e6a3654e5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/hash-test.cpp @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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::gc_scoped_pool p; + 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/sca-cpp/branches/lightweight-sca/kernel/hash.hpp b/sca-cpp/branches/lightweight-sca/kernel/hash.hpp new file mode 100644 index 0000000000..993511e3c2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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*)(void*)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/sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp new file mode 100644 index 0000000000..4d2ca2ba81 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/kernel-test.cpp @@ -0,0 +1,614 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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, int>()) == m); + assert(m >> failableF >> failableG == m >> failableH); + + cout << "Failable monad test... " << endl; + const failable<int> ooops = mkfailure<int>("test", 500); + assert(reason(ooops) == "test"); + assert(rcode(ooops) == 500); + assert(ooops >> failableF >> failableG == ooops); + + const failable<value> vooops = mkfailure<value>(ooops); + assert(reason(vooops) == "test"); + assert(rcode(vooops) == 500); + + const value v = value(vooops); + assert(car<value>(v) == value()); + assert(cadr<value>(v) == string("test")); + assert(caddr<value>(v) == value((double)500)); + 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::gc_scoped_pool p; + 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/sca-cpp/branches/lightweight-sca/kernel/lambda-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/lambda-test.cpp new file mode 100644 index 0000000000..05a16c2eb8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/lambda-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 C++0x lambda expressions. + */ + +#include <assert.h> +#include "function.hpp" +#include "sstream.hpp" +#include "fstream.hpp" +#include "perf.hpp" + +namespace tuscany { + +#ifdef HAS_CXX0X_LAMBDAS + +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::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + +#ifdef HAS_CXX0X_LAMBDAS + tuscany::testLambda(); + tuscany::testCppPerf(); +#else + tuscany::cout << "Skipped C++0x lambda tests" << tuscany::endl; +#endif + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/kernel/list.hpp b/sca-cpp/branches/lightweight-sca/kernel/list.hpp new file mode 100644 index 0000000000..d3736de62c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/list.hpp @@ -0,0 +1,617 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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_COUNTERS + +/** + * Debug utilities. Counters used to track instances of lists. + */ +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 + +/** + * Debug utilities. Macro used to write the contents of a list to + * a string, easier to watch in a debugger than the list itself. + */ +#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 + assertOrFail(!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 a list of elements from the 3rd to the end of a list. + */ +template<typename T> const list<T> cddr(const list<T>& p) { + return cdr(cdr(p)); +} + +/** + * Returns a list of elements from the 4th to the end of a list. + */ +template<typename T> const list<T> cdddr(const list<T>& p) { + return cdr(cdr(cdr(p))); +} + +/** + * Returns a list of elements from the 5th to the end of a list. + */ +template<typename T> const list<T> cddddr(const list<T>& p) { + return cdr(cdr(cdr(cdr(p)))); +} + +/** + * Returns a list of elements from the 6th to the end of a list. + */ +template<typename T> const list<T> cdddddr(const list<T>& p) { + return cdr(cdr(cdr(cdr(cdr(p))))); +} + +/** + * Returns a list of elements from the 7th to the end of a list. + */ +template<typename T> const list<T> cddddddr(const list<T>& p) { + return cdr(cdr(cdr(cdr(cdr(cdr(p)))))); +} + +/** + * Returns a list of elements from the 8th to the end of a list. + */ +template<typename T> const list<T> cdddddddr(const list<T>& p) { + return cdr(cdr(cdr(cdr(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/sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp new file mode 100644 index 0000000000..668dabe749 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/mem-test.cpp @@ -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. + */ + +/* $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 = 10000; + 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 = 10000; + 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::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::testPoolAllocPerf(); + tuscany::testStdAllocPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/kernel/monad.hpp b/sca-cpp/branches/lightweight-sca/kernel/monad.hpp new file mode 100644 index 0000000000..b67e92ad79 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/monad.hpp @@ -0,0 +1,627 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 <execinfo.h> +#include <cxxabi.h> +#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, typename C = int> class failable { +public: + failable() : hasv(false), c(-1) { + } + + failable(const V& v) : hasv(true), v(v), c(-1) { + } + + failable(const failable<V, F, C>& m) : hasv(m.hasv), v(m.v), f(m.f), c(m.c) { + } + + const failable<V, F, C>& operator=(const failable<V, F, C>& m) { + if (&m == this) + return *this; + hasv = m.hasv; + v = m.v; + f = m.f; + c = m.c; + return *this; + } + + const bool operator!=(const failable<V, F, C>& m) const { + return !this->operator==(m); + } + + const bool operator==(const failable<V, F, C>& m) const { + if (this == &m) + return true; + if (!hasv) + return !m.hasv && f == m.f && c == m.c; + return m.hasv && v == m.v; + } + +private: + failable(const bool hasv, const F& f, const C& c) : hasv(hasv), f(f), c(c) { + } + + template<typename A, typename B, typename R> friend const bool hasContent(const failable<A, B, R>& m); + template<typename A, typename B, typename R> friend const A content(const failable<A, B, R>& m); + template<typename A, typename B, typename R> friend const B reason(const failable<A, B, R>& m); + template<typename A, typename B, typename R> friend const R rcode(const failable<A, B, R>& m); + template<typename A, typename B, typename R> friend const failable<A, B, R> mkfailure(const B& f, const R& c, const bool log); + template<typename A, typename B> friend const failable<A, B> mkfailure(const B& f, const int c, const bool log); + template<typename A> friend const failable<A> mkfailure(); + + bool hasv; + V v; + F f; + C c; +}; + +/** + * Write a failable monad to a stream. + */ +template<typename V, typename F, typename C> ostream& operator<<(ostream& out, const failable<V, F, C>& m) { + if (!hasContent(m)) { + out << reason(m) << " : " << rcode(m); + return out; + } + out << content(m); + return out; +} + +/** + * Returns a failable monad with a success value in it. + */ +template<typename V, typename F, typename C> const failable<V, F, C> mksuccess(const V& v) { + return failable<V, F, C>(v); +} + +template<typename V, typename F, typename C> const lambda<failable<V, F, C>(const V)> success() { + return mksuccess<V, F, C>; +} + +/** + * Demangle a C++ function name. + */ +const string demangleFrame(const char* fun) { + int status; + char* name = abi::__cxa_demangle(fun, 0, 0, &status); + if (name == NULL) + return fun; + const string s = name; + free(name); + return s; +} + +/** + * Format a backtrace frame. + */ +const char* formatFrameFile(const char* file) { + const char* s = strrchr(file, '/'); + return s == NULL? file : s + 1; +} + +const string formatFrame(const char* symbol) { +#ifdef __clang__ + // Mac OS X CLang/LLVM stack frame format + // 0 kernel-test 0x000000010d440179 _ZN7tuscany9mkfailureINS_5valueENS_6stringEiEEKNS_8failableIT_T0_T1_EERKS5_RKS6_b + 265 + char nb[3]; + char file[256]; + char addr[32]; + char fun[256]; + char offset[16]; + if (sscanf(symbol, "%2s %255s %31s %255s %*[+] %15s", nb, file, addr, fun, offset) == 5) { + char buf[1024]; + if (debug_islogging()) + sprintf(buf, "%.255s %.31s %.511s + %.15s", formatFrameFile(file), addr, c_str(demangleFrame(fun)), offset); + else + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } +#else + // Linux GCC stack frame format + // ./kernel-test(_ZN7tuscany9mkfailureINS_5valueENS_6stringEiEEKNS_8failableIT_T0_T1_EERKS5_RKS6_b+0x23d) [0xb7197afd] + char file[256]; + char fun[256]; + char offset[16]; + char addr[32]; + if (sscanf(symbol, "%[^(]%*[(]%[^+]%*[+]%[^)]%*[)] %*[[]%[^]]%*[]]", file, fun, offset, addr) == 4) { + char buf[1024]; + if (debug_islogging()) + sprintf(buf, "%.255s %.31s %.511s + %.15s", formatFrameFile(file), addr, c_str(demangleFrame(fun)), offset); + else + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } + if (sscanf(symbol, "%[^(]%*[(]%*[^)]%*[)] %*[[]%[^]]%*[]]", file, addr) == 2) { + char buf[512]; + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } + if (sscanf(symbol, "%[^(]%*[(]%*[)] %*[[]%[^]]%*[]]", file, addr) == 2) { + char buf[512]; + sprintf(buf, "%.255s %.31s", formatFrameFile(file), addr); + return buf; + } +#endif + return symbol; +} + +/** + * Log backtrace frames. + */ +const bool logFrames(char** symbols, const int frames, const bool log) { + if (frames == 0) + return true; +#ifdef WANT_MAINTAINER_LOG + if (!log) + debug(formatFrame(*symbols), "failable::backtrace"); +#endif + if (log) + cfailure << "failable::backtrace: " << formatFrame(*symbols) << endl; + return logFrames(symbols + 1, frames - 1, log); +} + +/** + * Log a backtrace. + */ +const bool logBacktrace(void** callstack, const int frames, const bool log) { + char** symbols = backtrace_symbols(callstack, frames); + logFrames(symbols, frames, log); + free(symbols); + return true; +} + +/** + * Returns a failable monad with a failure in it. + */ +template<typename V, typename F, typename C> const failable<V, F, C> mkfailure(const F& f, const C& c, const bool log = true) { +#ifdef WANT_MAINTAINER_LOG + if (!log) { + // Log the failure + debug(f, "failable::mkfailure"); + + // Log the call stack + void* callstack[16]; + const int frames = backtrace(callstack, 16); + logBacktrace(callstack, frames, log); + } +#endif + if (log) { + ostringstream os; + os << f; + if (length(str(os)) != 0) { + // Log the failure + cfailure << "failable::mkfailure: " << f << " : " << c << endl; + + // Print the call stack + void* callstack[16]; + const int frames = backtrace(callstack, 16); + logBacktrace(callstack, frames, log); + } + } + return failable<V, F, C>(false, f, c); +} + +template<typename V, typename F> const failable<V, F> mkfailure(const F& f, const int c = -1, const bool log = true) { + return mkfailure<V, F, int>(f, c, log); +} + +template<typename V> const failable<V> mkfailure(const char* f, const int c = -1, const bool log = true) { + return mkfailure<V, string, int>(string(f), c, log); +} + +template<typename V> const failable<V> mkfailure() { + return failable<V, string>(false, string(), -1); +} + +template<typename V, typename F, typename C> const lambda<failable<V, F, C>(const V)> failure() { + return mkfailure<V, F, C>; +} + +/** + * Convert a failable of a given type to a failable of another type. + */ +template<typename V, typename F, typename C, typename X> const failable<V, F, C> mkfailure(const failable<X, F, C>& f, const bool log = true) { + return mkfailure<V, F, C>(reason(f), rcode(f), log); +} + +/** + * Returns true if the monad contains a content. + */ +template<typename V, typename F, typename C> const bool hasContent(const failable<V, F, C>& m) { + return m.hasv; +} + +/** + * Returns the content of a failable monad. + */ +template<typename V, typename F, typename C> const V content(const failable<V, F, C>& m) { + return m.v; +} + +/** + * Returns the reason for failure of a failable monad. + */ +template<typename V, typename F, typename C> const F reason(const failable<V, F, C>& m) { + return m.f; +} + +/** + * Returns the reason code for failure of a failable monad. + */ +template<typename V, typename F, typename C> const C rcode(const failable<V, F, C>& m) { + return m.c; +} + +/** + * 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 XR, typename V, typename FV, typename XV> +const failable<R, FR, XR> operator>>(const failable<V, FV, XV>& m, const lambda<failable<R, FR, XR>(const V)>& f) { + if (!hasContent(m)) + return m; + return f(content(m)); +} + +template<typename R, typename FR, typename XR, typename V, typename FV, typename XV> +const failable<R, FR, XR> operator>>(const failable<V, FV, XV>& m, const failable<R, FR, XR> (* 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/sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp new file mode 100644 index 0000000000..28e484d42b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/parallel-test.cpp @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 { + +int inci = 0; + +struct incPerf { + incPerf() { + } + const bool operator()() const { + inci = inci + 1; + return true; + } +}; + +const gc_ptr<int> tlsic() { + gc_ptr<int> i = new (gc_new<int>()) int(); + *i = 0; + return i; +} +const perthread_ptr<int> tlsi(tlsic); + +struct tlsPerf { + tlsPerf() { + } + const bool operator()() const { + *tlsi = *tlsi + 1; + return true; + } +}; + +#ifdef WANT_THREADS + +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; + } +}; + +#endif + +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); + } +#ifdef WANT_THREADS + { + 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); + } +#endif + { + const lambda<bool()> l = tlsPerf(); + cout << "Thread local inc test " << time(l, 1000, count) << " ms" << endl; + assert(*tlsi == count + 1000); + } + return true; +} + +#ifdef WANT_THREADS + +const int mtsquare(const int x) { + for(int i = 0; i < 10000000; i++) + ; + return x * x; +} + +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 checkSquareResults(const list<future<int> > r, int i) { + if (isNil(r)) + return true; + assert(car(r) == i * i); + checkSquareResults(cdr(r), i + 1); + return true; +} + +const gc_ptr<unsigned long> tlsvc() { + gc_ptr<unsigned long> i = new (gc_new<unsigned long>()) unsigned long(); + *i = 0l; + return i; +} +const perthread_ptr<unsigned long> tlsv(tlsvc); + +const long int tlsset(gc_ptr<wqueue<bool>> wq, gc_ptr<wqueue<bool>> xq) { + const unsigned long v = *tlsv; + *tlsv = threadId(); + enqueue(*xq, true); + dequeue(*wq); + return v; +} + +const bool tlscheck(gc_ptr<wqueue<bool>> wq, gc_ptr<wqueue<bool>> xq) { + const bool r = *tlsv == threadId(); + enqueue(*xq, true); + dequeue(*wq); + return r; +} + +const bool waitForWorkers(wqueue<bool>& xq, const int n) { + if (n == 0) + return true; + dequeue(xq); + return waitForWorkers(xq, n - 1); +} + +const bool unblockWorkers(wqueue<bool>& wq, const int n) { + if (n == 0) + return true; + enqueue(wq, true); + return unblockWorkers(wq, n - 1); +} + +const list<future<long int> > submitTLSSets(worker& w, wqueue<bool>& wq, wqueue<bool>& xq, const int max, const int i) { + if (i == max) + return list<future<long int> >(); + const lambda<long int()> func = curry(lambda<long int(gc_ptr<wqueue<bool>>, gc_ptr<wqueue<bool>>)>(tlsset), (gc_ptr<wqueue<bool>>)&wq, (gc_ptr<wqueue<bool>>)&xq); + return cons(submit(w, func), submitTLSSets(w, wq, xq, max, i + 1)); +} + +bool checkTLSSets(const list<future<long int> > s) { + if (isNil(s)) + return true; + assert(car(s) == 0); + return checkTLSSets(cdr(s)); +} + +const list<future<bool> > submitTLSChecks(worker& w, wqueue<bool>& wq, wqueue<bool>& xq, const int max, const int i) { + if (i == max) + return list<future<bool> >(); + const lambda<bool()> func = curry(lambda<bool(gc_ptr<wqueue<bool>>, gc_ptr<wqueue<bool>>)>(tlscheck), (gc_ptr<wqueue<bool>>)&wq, (gc_ptr<wqueue<bool>>)&xq); + return cons(submit(w, func), submitTLSChecks(w, wq, xq, max, i + 1)); +} + +bool checkTLSResults(const list<future<bool> > r) { + if (isNil(r)) + return true; + assert(car(r) == true); + return checkTLSResults(cdr(r)); +} + +bool testWorker() { + const int max = 100; + worker w(max); + { + const lambda<int()> func = curry(lambda<int(const int)> (mtsquare), 2); + assert(submit(w, func) == 4); + } + { + const list<future<int> > r(submitSquares(w, max, 0)); + checkSquareResults(r, 0); + } + { + wqueue<bool> wq(max); + unblockWorkers(wq, max); + waitForWorkers(wq, max); + unblockWorkers(wq, max); + waitForWorkers(wq, max); + } + { + wqueue<bool> wq(max); + wqueue<bool> xq(max); + const list<future<long int> > s(submitTLSSets(w, wq, xq, max, 0)); + waitForWorkers(xq, max); + unblockWorkers(wq, max); + checkTLSSets(s); + const list<future<bool> > r(submitTLSChecks(w, wq, xq, max, 0)); + waitForWorkers(xq, max); + unblockWorkers(wq, max); + checkTLSResults(r); + } + shutdown(w); + return true; +} + +#endif + +} + +int main() { + tuscany::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::testAtomicPerf(); +#ifdef WANT_THREADS + tuscany::testWorker(); +#else + tuscany::cout << "Skipped multi-thread tests" << tuscany::endl; +#endif + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/kernel/parallel.hpp b/sca-cpp/branches/lightweight-sca/kernel/parallel.hpp new file mode 100644 index 0000000000..3be4d3bc8e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/parallel.hpp @@ -0,0 +1,466 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#include <unistd.h> +#ifdef WANT_THREADS +#include <pthread.h> +#endif + +#include "function.hpp" +#include "list.hpp" + +namespace tuscany { + +/** + * Returns the current process id. + */ +unsigned long processId() { + return (unsigned long)getpid(); +} + +#ifdef WANT_THREADS + +/** + * Returns the current thread id. + */ +unsigned long threadId() { + return (unsigned long)pthread_self(); +} + +/** + * 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; +} + +#else + +/** + * Returns the current thread id. + */ +unsigned long threadId() { + return 0; +} + +#endif + +/** + * Represents a per-thread value. + */ +template<typename T> class perthread_ptr { +public: + perthread_ptr() : key(createkey()), owner(true), cl(lambda<gc_ptr<T>()>()), managed(false) { + } + + perthread_ptr(const lambda<gc_ptr<T>()>& cl) : key(createkey()), owner(true), cl(cl), managed(true) { + } + + ~perthread_ptr() { + if (owner) + deletekey(key); + } + + perthread_ptr(const perthread_ptr& c) : key(c.key), owner(false), cl(c.cl), managed(c.managed) { + } + + perthread_ptr& operator=(const perthread_ptr& r) throw() { + if(this == &r) + return *this; + key = r.key; + owner = false; + cl = r.cl; + managed = r.managed; + return *this; + } + + const perthread_ptr& operator=(const gc_ptr<T>& v) { + set(v); + return *this; + } + + const perthread_ptr& operator=(T* v) { + set(v); + return *this; + } + + const bool operator==(const gc_ptr<T>& r) const throw() { + return get() == r; + } + + const bool operator==(T* p) const throw() { + return get() == p; + } + + const bool operator!=(const gc_ptr<T>& r) const throw() { + return !this->operator==(r); + } + + const bool operator!=(T* p) const throw() { + return !this->operator==(p); + } + + T& operator*() const throw() { + return *get(); + } + + T* operator->() const throw() { + return get(); + } + + operator gc_ptr<T>() const { + return get(); + } + + operator T*() const { + return get(); + } + +private: +#ifdef WANT_THREADS + pthread_key_t createkey() { + pthread_key_t k; + pthread_key_create(&k, NULL); + return k; + } + + bool deletekey(pthread_key_t k) { + pthread_key_delete(k); + return true; + } + + bool set(const gc_ptr<T>& v) { + pthread_setspecific(key, (T*)v); + return true; + } + + gc_ptr<T> get() const { + const gc_ptr<T> v = static_cast<T*>(pthread_getspecific(key)); + if (v != NULL || !managed) + return v; + const gc_ptr<T> nv = cl(); + pthread_setspecific(key, nv); + return nv; + } + +#else + gc_ptr<gc_ptr<T> > createkey() { + return new (gc_new<gc_ptr<T> >()) gc_ptr<T>(); + } + + bool deletekey(unused gc_ptr<gc_ptr<T> > k) { + return true; + } + + bool set(const gc_ptr<T>& v) { + *key = v; + return true; + } + + gc_ptr<T> get() const { + if (*key != NULL || !managed) + return *key; + *key = cl(); + return *key; + } + +#endif + +#ifdef WANT_THREADS + pthread_key_t key; +#else + gc_ptr<gc_ptr<T> >key; +#endif + + bool owner; + lambda<const gc_ptr<T>()> cl; + bool managed; +}; + +} +#endif /* tuscany_parallel_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/kernel/perf.hpp b/sca-cpp/branches/lightweight-sca/kernel/perf.hpp new file mode 100644 index 0000000000..04aad06664 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/perf.hpp @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 { + for (long i = 0; i < count; i++) + f(); + 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; +} + +const unsigned long timems() { + struct timeval t; + gettimeofday(&t, NULL); + return (unsigned long)(t.tv_sec * 1000 + t.tv_usec / 1000); +} + +const unsigned long timens() { + struct timeval t; + gettimeofday(&t, NULL); + return (unsigned long)(t.tv_sec * 1000000000 + t.tv_usec * 1000); +} + +} +#endif /* tuscany_perf_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/kernel/sstream.hpp b/sca-cpp/branches/lightweight-sca/kernel/sstream.hpp new file mode 100644 index 0000000000..17fd28b48b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/sstream.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_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); +} + +/** + * Write a list of strings into a buffer. + */ +const bool writeList(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 writeList(cdr(l), b); +} + +/** + * 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: + const string str() { + if (isNil(buf)) + return string(); + string s; + s.len = len; + s.buf = gc_cnew(s.len + 1); + writeList(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 size_t slen, const string& str, const size_t start) { + 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, slen, str, i + slen)); + } + }; + return nested::tokenize(sep, strlen(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/sca-cpp/branches/lightweight-sca/kernel/stream.hpp b/sca-cpp/branches/lightweight-sca/kernel/stream.hpp new file mode 100644 index 0000000000..8ccfed948f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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_LOG + +/** + * 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/sca-cpp/branches/lightweight-sca/kernel/string-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/string-test.cpp new file mode 100644 index 0000000000..b6f016b294 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/string-test.cpp @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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(); + unused 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(find_first_of("abcd", "cd") == 2); + assert(find_first_of("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[16385]; + +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 = 10000; + { + 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::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::testCopies(); + tuscany::testString(); + tuscany::testStream(); + tuscany::testStringPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/kernel/string.hpp b/sca-cpp/branches/lightweight-sca/kernel/string.hpp new file mode 100644 index 0000000000..e726a61b84 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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_COUNTERS + +/** + * 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_COUNTERS + 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_LOG + 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/sca-cpp/branches/lightweight-sca/kernel/tree.hpp b/sca-cpp/branches/lightweight-sca/kernel/tree.hpp new file mode 100644 index 0000000000..89a131c324 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/kernel/value.hpp b/sca-cpp/branches/lightweight-sca/kernel/value.hpp new file mode 100644 index 0000000000..206fe8b32b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/value.hpp @@ -0,0 +1,656 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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_COUNTERS + +/** + * Debug utilities. Counters used to track instances of values + */ +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 + +/** + * Debug utilities. Macro used to write the contents of a value to + * a string, easier to watch in a debugger than the value itself. + */ + +#define debug_watchValue() do { \ + this->watch = watchValue(*this); \ + } while (0) + +#else + +#define debug_watchValue() + +#endif + +class value; + +class value { +public: + + enum ValueType { + Nil, Symbol, String, List, Number, Bool, Lambda, Ptr + }; + + value() : type(value::Nil) { + 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)) : rcode(m) == 1? mklist<value>(value(), reason(m)) : mklist<value>(value(), reason(m), rcode(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::Nil: + return v.type == value::Nil; + 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 an escape string to a buffer. + */ +const char* escapestr(const char* s, char* buf) { + if (*s == '\0') { + *buf = '\0'; + return buf; + } + if (*s == '\\' || *s == '"') { + *buf = '\\'; + *(buf + 1) = *s; + return escapestr(s + 1, buf + 2); + } + *buf = *s; + return escapestr(s + 1, buf + 1); +} + +/** + * Write an escaped string value to a stream. + */ +ostream& escvwrite(const string& str, ostream& out) { + char* buf = gc_cnew(length(str) * 2 + 1); + escapestr(c_str(str), buf); + out << buf; + return out; +} + +/** + * 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: + out << '\"'; + escvwrite(v.str()(), out); + return out << '\"'; + 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 << "nil"; + } +} + +/** + * 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::Nil; +} + +/** + * 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/sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp new file mode 100644 index 0000000000..0523cc74a6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/xml-test.cpp @@ -0,0 +1,235 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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\" targetNamespace=\"http://services\" name=\"currency\">\n" +" <component name=\"CurrencyConverterWebService\">\n" +" <implementation.java class=\"services.CurrencyConverterImpl\"/>\n" +" <service name=\"CurrencyConverter\">\n" +" <binding.ws/>\n" +" </service>\n" +" </component>\n" +" <component name=\"CurrencyConverterWebService2\">\n" +" <implementation.java class=\"services.CurrencyConverterImpl2\"/>\n" +" <service name=\"CurrencyConverter2\">\n" +" <binding.atom/>\n" +" </service>\n" +" <property name=\"currency\">US</property>\n" +" </component>\n" +"</composite>\n"; + +const string customerXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<customer>\n" +" <name>jdoe</name>\n" +" <address>\n" +" <city>san francisco</city>\n" +" <state>ca</state>\n" +" </address>\n" +" <account>\n" +" <id>1234</id>\n" +" <balance>1000</balance>\n" +" </account>\n" +" <account>\n" +" <id>6789</id>\n" +" <balance>2000</balance>\n" +" </account>\n" +" <account>\n" +" <id>4567</id>\n" +" <balance>3000</balance>\n" +" </account>\n" +"</customer>\n"; + +const string abcXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<a>\n" +" <m>abc</m>\n" +" <m>def</m>\n" +" <m>xyz</m>\n" +" <m>tuv</m>\n" +"</a>\n"; + +const string xyzXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<a>\n" +" <m>\n" +" <id>123</id>\n" +" <name>abc</name>\n" +" </m>\n" +" <m>\n" +" <id>234</id>\n" +" <name>def</name>\n" +" </m>\n" +" <m>\n" +" <id>345</id>\n" +" <name>xyz</name>\n" +" </m>\n" +" <m>\n" +" <id>456</id>\n" +" <name>tuv</name>\n" +" </m>\n" +"</a>\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(abcXML); + 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) == abcXML); + } + { + istringstream is(xyzXML); + 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) == xyzXML); + } + { + 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::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::testReadXML(); + tuscany::testWriteXML(); + tuscany::testElements(); + tuscany::testValues(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/kernel/xml.hpp b/sca-cpp/branches/lightweight-sca/kernel/xml.hpp new file mode 100644 index 0000000000..d00a2905fb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/kernel/xml.hpp @@ -0,0 +1,412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 { + +/** + * APR-based memory management functions. + */ + + +/** + * Initializes the libxml2 library. + */ +class XMLParser { +public: + XMLParser() { + debug("xml::XMLParser"); + xmlMemSetup(gc_pool_free, gc_pool_malloc, gc_pool_realloc, gc_pool_strdup); + xmlInitParser(); + } + + ~XMLParser() { + } +} 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), owner(true), tokenType(None), isEmptyElement(false), hasValue(false), hasAttributes(false) { + debug("xml::XMLReader::xml"); + xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1); + xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1); + } + + XMLReader(const XMLReader& r) : xml(r.xml), owner(false), tokenType(r.tokenType), isEmptyElement(r.isEmptyElement), hasValue(r.hasValue), hasAttributes(r.hasAttributes) { + debug("xml::XMLReader::copy"); + } + + const XMLReader& operator=(const XMLReader& r) { + debug("xml::XMLReader::operator="); + if(this == &r) + return *this; + xml = r.xml; + owner = false; + tokenType = r.tokenType; + isEmptyElement = r.isEmptyElement; + hasValue = r.hasValue; + hasAttributes = r.hasAttributes; + return *this; + } + + ~XMLReader() { + if (!owner) + return; + 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: + xmlTextReaderPtr xml; + bool owner; + 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) { + debug(ilist, "xml::readXML"); + XMLReadContext cx(ilist); + xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET | XML_PARSE_NODICT); + 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, isList(car(l))? (list<value>)car(l) : mklist(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>("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"); + xmlTextWriterSetIndent(xml, 1); + + const failable<bool> w = write(l, xml, xmlTag); + xmlFreeTextWriter(xml); + if (!hasContent(w)) { + return mkfailure<R>(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) { + debug(l, "xml::writeXML"); + 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/sca-cpp/branches/lightweight-sca/kernel/xsd-test.cpp b/sca-cpp/branches/lightweight-sca/kernel/xsd-test.cpp new file mode 100644 index 0000000000..fbd2ee6dca --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/Makefile.am new file mode 100644 index 0000000000..16fe2791f7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 opencl java openid oauth wsgi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/http/Makefile.am new file mode 100644 index 0000000000..a504adcda5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/Makefile.am @@ -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. + +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 cache-conf cache-ssl-conf cache-manifest proxy-conf proxy-base-conf proxy-ssl-conf proxy-balancer-conf proxy-member-conf proxy-ssl-member-conf proxy-ssl-nossl-member-conf alt-host-conf mass-host-conf mass-host-ssl-conf httpd-tunnel-ssl-conf tunnel-ssl-conf httpd-worker-conf httpd-event-conf httpd-loglevel-conf minify-html minify-js minify-css +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${libsuffix} libmod_tuscany_openauth${libsuffix} + +libmod_tuscany_ssltunnel_la_SOURCES = mod-ssltunnel.cpp +libmod_tuscany_ssltunnel_la_LDFLAGS = -lxml2 -lcurl -lmozjs +libmod_tuscany_ssltunnel${libsuffix}: + ln -s .libs/libmod_tuscany_ssltunnel${libsuffix} + +libmod_tuscany_openauth_la_SOURCES = mod-openauth.cpp +libmod_tuscany_openauth_la_LDFLAGS = -lxml2 -lcurl -lmozjs +libmod_tuscany_openauth${libsuffix}: + ln -s .libs/libmod_tuscany_openauth${libsuffix} + +mod_DATA = httpd.prefix httpd-apachectl.prefix httpd-modules.prefix curl.prefix pagespeed.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 + +if WANT_PAGESPEED + +pagespeed.prefix: $(top_builddir)/config.status + echo ${PAGESPEED_PREFIX} >pagespeed.prefix + +else + +pagespeed.prefix: $(top_builddir)/config.status + echo "" >pagespeed.prefix + +endif + +if WANT_MODSECURITY + +modsecurity.prefix: $(top_builddir)/config.status + echo ${MODSECURITY_PREFIX} >modsecurity.prefix + +dist_modsecurity_SCRIPTS = mod-security-conf mod-security-audit-conf +modsecurity_DATA = modsecurity.prefix +modsecuritydir = $(prefix)/modules/http + +endif + +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/sca-cpp/branches/lightweight-sca/modules/http/alt-host-conf b/sca-cpp/branches/lightweight-sca/modules/http/alt-host-conf new file mode 100755 index 0000000000..f6148173b4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/alt-host-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. + +# Generate an alternate host name configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 + +cat >>$root/conf/hostcond.conf <<EOF +# Generated by: alt-host-conf $* +RewriteCond %{HTTP_HOST} !^$host [NC] + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/basic-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/basic-auth-conf new file mode 100755 index 0000000000..8710d1fdf7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/basic-auth-conf @@ -0,0 +1,69 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then + loc="/" +else + loc="$3" +fi + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: basic-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate basic authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: basic-auth-conf $* +# Require clients to present a userid + password for HTTP +# basic authentication +<Location $loc> +AuthType Basic +AuthName "$host" +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +Require valid-user +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cache-conf b/sca-cpp/branches/lightweight-sca/modules/http/cache-conf new file mode 100755 index 0000000000..09ad5dc444 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cache-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 cache configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/cache + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: cache-conf $* + +# Enable caching +CacheEnable disk / +CacheQuickHandler Off +CacheRoot $root/cache +CacheHeader On +#CacheDetailHeader On +CacheIgnoreQueryString On +CacheIgnoreCacheControl On +CacheIgnoreHeaders Set-Cookie + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cache-manifest b/sca-cpp/branches/lightweight-sca/modules/http/cache-manifest new file mode 100755 index 0000000000..3752a61dde --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cache-manifest @@ -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. + +# Generate a cache-manifest.cmf file from a template and the list +# of files in the cached application +root=$1 +shift +sha=`cat $* | shasum | awk '{ print $1 }'` +cat $root/cache-template.cmf | sed -e "s/SHA1/$sha/" >$root/cache-manifest.cmf + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cache-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/cache-ssl-conf new file mode 100755 index 0000000000..7a902c37eb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cache-ssl-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 cache configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/cache + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: cache-conf $* + +# Enable caching +CacheEnable disk / +CacheQuickHandler Off +CacheRoot $root/cache +CacheHeader On +#CacheDetailHeader On +CacheIgnoreQueryString On +CacheIgnoreCacheControl On +CacheIgnoreHeaders Set-Cookie + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/cert-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/cert-auth-conf new file mode 100755 index 0000000000..a30fdfff8c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/cert-auth-conf @@ -0,0 +1,74 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: cert-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate authentication configuration +cat >>$root/conf/locauth$sslsuffix.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 socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +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:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=$host/OU=proxy/CN=$host:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=$host/OU=tunnel/CN=$host:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=localhost/OU=server/CN=localhost:xxj31ZMTZzkVA +/C=US/ST=CA/L=San Francisco/O=localhost/OU=tunnel/CN=localhost:xxj31ZMTZzkVA +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/conf/mime.types b/sca-cpp/branches/lightweight-sca/modules/http/conf/mime.types new file mode 100644 index 0000000000..3f083f9a32 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/conf/mime.types @@ -0,0 +1,608 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 b64 +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/cache-manifest cmf +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/sca-cpp/branches/lightweight-sca/modules/http/curl-connect.cpp b/sca-cpp/branches/lightweight-sca/modules/http/curl-connect.cpp new file mode 100644 index 0000000000..9f5ee17368 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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, "", 0); + 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/sca-cpp/branches/lightweight-sca/modules/http/curl-get.cpp b/sca-cpp/branches/lightweight-sca/modules/http/curl-get.cpp new file mode 100644 index 0000000000..a16daeeae3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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, "", 0); + 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/sca-cpp/branches/lightweight-sca/modules/http/curl-test.cpp b/sca-cpp/branches/lightweight-sca/modules/http/curl-test.cpp new file mode 100644 index 0000000000..f0806ea577 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/curl-test.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$ */ + +/** + * 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("", "", "", "", 0); + { + 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("", "", "", "", 0); + lambda<bool()> gl = getLoop(ch); + cout << "Static GET test " << time(gl, 5, 200) << " ms" << endl; + return true; +} + +} +} + +int main() { + tuscany::gc_scoped_pool p; + 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/sca-cpp/branches/lightweight-sca/modules/http/form-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/form-auth-conf new file mode 100755 index 0000000000..fbe943f3d9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/form-auth-conf @@ -0,0 +1,82 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then + pw=`cat $root/cert/ca.key | head -2 | tail -1` +else + pw="$3" +fi + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: form-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate form authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: form-auth-conf $* +# Require clients to present a userid + password through form-based +# authentication +<Location /> +AuthType Form +AuthName "$host" +AuthFormProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +AuthFormLoginRequiredLocation /login/ +AuthFormLogoutLocation / +Session On +SessionCookieName TuscanyFormAuth domain=.$host; path=/ +SessionCryptoPassphrase $pw +Require valid-user +</Location> + +<Location /login/dologin> +SetHandler form-login-handler +</Location> + +<Location /logout/dologout> +SetHandler form-logout-handler +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/group-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/group-auth-conf new file mode 100755 index 0000000000..e9617f696a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/group-auth-conf @@ -0,0 +1,57 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +user=$2 +group="members" + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: group-auth-conf $* +# Disallow public access to server resources + +EOF + +# 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/locauth$sslsuffix.conf | grep "Generated by: group-auth-conf"` +if [ "$conf" = "" ]; then + cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: group-auth-conf $1 +# Allow group member access to root location +<Location /> +Require group members +</Location> + +EOF +fi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/htdocs/index.html b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/index.html new file mode 100644 index 0000000000..236864edfb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>It works</title> +</head> +<body> +<h1>It works!</h1> +</body> +</html> + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/login/index.html new file mode 100644 index 0000000000..fd3bc21889 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/login/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign in</title> +</head> +<body> +<h1>Sign in</h1> +<br/> + +<script type="text/javascript"> +function submitFormSignin() { + clearauthcookie(); + 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/sca-cpp/branches/lightweight-sca/modules/http/htdocs/logout/index.html b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/logout/index.html new file mode 100644 index 0000000000..218dd5d52c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/htdocs/logout/index.html @@ -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. +--> + +<html> +<body> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign out</title> +</head> +<h1>Sign out</h1> +<br/> + +<form name="signout" action="/login" method="GET"> +<script type="text/javascript"> +function submitSignout() { + clearauthcookie(); + document.signout.submit(); + return true; +} +</script> +<input type="button" onclick="submitSignout()" value="Sign out"/> +</form> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/modules/http/http-test b/sca-cpp/branches/lightweight-sca/modules/http/http-test new file mode 100755 index 0000000000..956b13a516 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/http-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 +rm -rf tmp +./httpd-conf tmp localhost 8090 htdocs +./httpd-event-conf tmp +./httpd-start tmp +sleep 2 + +# Test +./curl-test 2>/dev/null +rc=$? + +# Cleanup +./httpd-stop tmp +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/http/http.hpp b/sca-cpp/branches/lightweight-sca/modules/http/http.hpp new file mode 100644 index 0000000000..408b9fdee5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/http.hpp @@ -0,0 +1,1042 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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/easy.h> +#include <apr.h> +#include <apr_lib.h> +#include <apr_network_io.h> +#include <apr_portable.h> +#include <apr_poll.h> +#include <apr_uri.h> + +#include "string.hpp" +#include "gc.hpp" +#include "list.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" +#include "parallel.hpp" +#include "../scheme/io.hpp" +#include "../atom/atom.hpp" +#include "../rss/rss.hpp" +#include "../json/json.hpp" + +namespace tuscany { +namespace http { + +/** + * Enable CURL verbose debug log. + */ +//#define WANT_MAINTAINER_CURL_VERBOSE + +/** + * 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(), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL), owner(false), ca(""), cert(""), key(""), cookie(""), timeout(0) { + } + + CURLSession(const string& ca, const string& cert, const string& key, const string& cookie, const int timeout) : h(NULL), p(), sock(NULL), wpollset(NULL), wpollfd(NULL), rpollset(NULL), rpollfd(NULL), owner(true), ca(ca), cert(cert), key(key), cookie(cookie), timeout(timeout) { + } + + 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), cookie(c.cookie), timeout(c.timeout) { + } + + const CURLSession& operator=(const CURLSession& c) { + if(this == &c) + return *this; + 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; + cookie = c.cookie; + timeout = c.timeout; + return *this; + } + + ~CURLSession() { + if (!owner) + return; + if (h == NULL) + return; + curl_easy_cleanup(h); + } + +private: + CURL* h; + gc_child_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<CURL*> setup(const string& url, CURLSession& cs); + friend const failable<bool> cleanup(CURLSession& cs); + friend const failable<bool> connect(const string& url, CURLSession& cs); + friend const failable<bool> send(const char* c, const size_t l, CURLSession& cs); + friend const failable<size_t> recv(char* c, const size_t l, CURLSession& cs); + +public: + string ca; + string cert; + string key; + string cookie; + int timeout; +}; + +/** + * 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)); +} + +/** + * Escape a URI or a query argument. + */ +const char escape_c2x[] = "0123456789ABCDEF"; + +const string escape(const string& unesc, const char* reserv) { + char* copy = (char*)apr_palloc(gc_current_pool(), 3 * length(unesc) + 3); + const unsigned char* s = (const unsigned char *)c_str(unesc); + unsigned char* d = (unsigned char*)copy; + unsigned c; + while ((c = *s)) { + if (!apr_isalnum(c) && !strchr(reserv, c)) { + *d++ = '%'; + *d++ = escape_c2x[c >> 4]; + *d++ = escape_c2x[c & 0xf]; + } + else { + *d++ = (unsigned char)c; + } + ++s; + } + *d = '\0'; + return copy; +} + +const string escapeURI(const string& uri) { + debug(uri, "http::escapeURI::uri"); + const string e = escape(uri, "?$-_.+!*'(),:@&=/~%"); + debug(e, "http::escapeURI::result"); + return e; +} + +const string escapeArg(const string& arg) { + debug(arg, "http::escapeArg::arg"); + const string e = escape(arg, "-_.~"); + debug(e, "http::escapeArg::result"); + return e; +} + +/** + * Return true if a URI is absolute. + */ +const bool isAbsolute(const string& uri) { + return contains(uri, "://"); +} + +/** + * Parse a URI and return its host name. + */ +const string hostName(const string& uri, const gc_pool& p) { + apr_uri_t u; + const apr_status_t rc = apr_uri_parse(pool(p), c_str(uri), &u); + if (rc != APR_SUCCESS) + return ""; + if (u.hostname == NULL) + return ""; + return u.hostname; +} + +/** + * Parse a URI and return its scheme. + */ +const string scheme(const string& uri, const gc_pool& p) { + apr_uri_t u; + const apr_status_t rc = apr_uri_parse(pool(p), c_str(uri), &u); + if (rc != APR_SUCCESS) + return ""; + if (u.scheme == NULL) + return ""; + return u.scheme; +} + +/** + * Return the first subdomain name in a host name. + */ +const string subDomain(const string& host) { + return substr(host, 0, find(host, '.')); +} + +/** + * Return the top domain name in a host name. + */ +const string topDomain(const string& host) { + const size_t d = find(host, '.'); + return d == length(host) ? host : substr(host, d + 1); +} + +/** + * Setup a CURL session + */ +const failable<CURL*> setup(const string& url, CURLSession& cs) { + + // Init CURL session + if (cs.h != NULL) + cleanup(cs); + cs.h = curl_easy_init(); + CURL* ch = cs.h; + curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0"); +#ifdef WANT_MAINTAINER_CURL_VERBOSE + curl_easy_setopt(ch, CURLOPT_VERBOSE, true); +#endif + + // 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); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(ch, CURLOPT_TIMEOUT, cs.timeout); + + // 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"); + } + if (cs.cookie != "") { + debug(cs.cookie, "http::setup::cookie"); + curl_easy_setopt(ch, CURLOPT_COOKIE, c_str(cs.cookie)); + } + + // Set up HTTP basic auth if requested + apr_uri_t u; + apr_pool_t* p = gc_current_pool(); + const apr_status_t prc = apr_uri_parse(p, c_str(url), &u); + if (prc == APR_SUCCESS) { + if (u.user != NULL) { + debug(u.user, "http::setup::user"); + curl_easy_setopt(ch, CURLOPT_USERNAME, u.user); + } + if (u.password != NULL) { + debug(u.password, "http::setup::pass"); + curl_easy_setopt(ch, CURLOPT_PASSWORD, u.password); + } + if (u.user != NULL || u.password != NULL) { + curl_easy_setopt(ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + + // Set target URL, omitting the user:password part + curl_easy_setopt(ch, CURLOPT_URL, c_str(escapeURI(apr_uri_unparse(p, &u, APR_URI_UNP_OMITUSERINFO)))); + + return ch; + } + } + + // Set target URL + curl_easy_setopt(ch, CURLOPT_URL, c_str(escapeURI(url))); + + return ch; +} + +/** + * Cleanup a CURL session + */ +const failable<bool> cleanup(CURLSession& cs) { + if (cs.h == NULL) + return true; + curl_easy_cleanup(cs.h); + cs.h = NULL; + return true; +} + +/** + * 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, 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)) { + cleanup(cs); + return mkfailure<list<R>>(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 == "PATCH") { + curl_easy_setopt(ch, CURLOPT_UPLOAD, true); + curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, "PATCH"); + 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) { + cleanup(cs); + return mkfailure<list<R> >(string(curl_easy_strerror(rc))); + } + long httprc; + curl_easy_getinfo (ch, CURLINFO_RESPONSE_CODE, &httprc); + if (httprc != 200 && httprc != 201) { + cleanup(cs); + ostringstream es; + es << "HTTP code " << httprc; + return mkfailure<list<R> >(str(es)); + } + + cleanup(cs); + 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, 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>(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>(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>(rval); + return content(rval); +} + +/** + * Find and return a header. + */ +const maybe<string> header(const char* prefix, const list<string>& h) { + if (isNil(h)) + return maybe<string>(); + 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 string location(const list<string>& h) { + const maybe<string> l = header("Location: ", h); + return hasContent(l)? content(l) : ""; +} + +/** + * Convert a location to an entry id. + */ +const value entryId(const failable<string> l) { + if (!hasContent(l)) + return list<value>(); + const string ls(content(l)); + return value(mklist<value>(string(substr(ls, find_last(ls, '/') + 1)))); +} + +/** + * Find and return a content-type header. + */ +const string contentType(const list<string>& h) { + const maybe<string> ct = header("Content-Type: ", h); + return hasContent(ct)? content(ct) : ""; +} + +/** + * 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, 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, 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>(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; +} + +/** + * Convert an HTTP content response to a value. + */ +const failable<value> responseValue(const list<list<string> > res) { + + // Parse the returned content + const string ct = contentType(car(res)); + debug(ct, "http::responseValue::contentType"); + + const list<string> ls(reverse(cadr(res))); + debug(ls, "http::responseValue::content"); + + if (atom::isATOMEntry(ls)) { + // Read an ATOM entry + const value val(elementsToValues(content(atom::readATOMEntry(ls)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "application/atom+xml") || atom::isATOMFeed(ls)) { + // Read an ATOM feed + const value val(elementsToValues(content(atom::readATOMFeed(ls)))); + debug(val, "http::responseValue::result"); + return val; + } + if (contains(ct, "application/rss+xml") || rss::isRSSFeed(ls)) { + // Read an RSS feed + const value val(elementsToValues(content(rss::readRSSFeed(ls)))); + debug(val, "http::responseValue::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::responseValue::result"); + return val; + } + if (contains(ct, "application/x-javascript")) { + // Read a JSON document enclosed in a javascript function call + // Extract the JSON out of the enclosing parenthesis + ostringstream os; + write(ls, os); + const string s = str(os); + const size_t fp = find(s, '('); + const size_t lp = find_last(s, ')'); + const list<string> jls = mklist<string>(substr(s, fp + 1, lp - (fp + 1))); + debug(jls, "http::responseValue::javascript::content"); + + js::JSContext cx; + const value val(json::jsonValues(content(json::readJSON(jls, cx)))); + debug(val, "http::responseValue::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::responseValue::result"); + return val; + } + + // Return the content type and a content list + const value val(mklist<value>(ct, mkvalues(ls))); + debug(val, "http::responseValue::result"); + return val; +} + +/** + * HTTP GET, return a list of values representing the resource at the given URL. + */ +const failable<value> get(const string& url, 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>(res); + + // Parse the returned content + return responseValue(content(res)); +} + +/** + * Form an HTTP content request. + */ +const failable<list<list<string> > > writeRequest(const failable<list<string> >& ls, const string& ct) { + if (!hasContent(ls)) + return mkfailure<list<list<string> > >(ls); + const list<list<string> > req = mklist<list<string> >(mklist<string>(string("Content-Type: ") + ct), content(ls)); + debug(req, "http::writeRequest::req"); + return req; +} + +/** + * Convert a value to an HTTP content request. + */ +const failable<list<list<string> > > contentRequest(const value& c, unused const string& url) { + + // Check if the client requested a specific format + //TODO derive that from given URL + const list<value> fmt = assoc<value>("format", list<value>()); + + // Write as a scheme value if requested by the client + if (!isNil(fmt) && cadr(fmt) == "scheme") + return writeRequest(mklist<string>(scheme::writeValue(c)), "text/plain; charset=utf-8"); + + // Write a simple value as a JSON value + if (!isList(c)) { + js::JSContext cx; + if (isSymbol(c)) { + const list<value> lc = mklist<value>(mklist<value>("name", value(string(c)))); + debug(lc, "http::contentRequest::symbol"); + return writeRequest(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8"); + } + const list<value> lc = mklist<value>(mklist<value>("value", c)); + debug(lc, "http::contentRequest::value"); + return writeRequest(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8"); + } + + // Write an empty list as a JSON empty value + if (isNil((list<value>)c)) { + js::JSContext cx; + debug(list<value>(), "http::contentRequest::empty"); + return writeRequest(json::writeJSON(list<value>(), cx), "application/json; charset=utf-8"); + } + + // Write content-type / content-list pair + if (isString(car<value>(c)) && !isNil(cdr<value>(c)) && isList(cadr<value>(c))) + return writeRequest(convertValues<string>(cadr<value>(c)), car<value>(c)); + + // Write an assoc value as JSON + if (isSymbol(car<value>(c)) && !isNil(cdr<value>(c))) { + js::JSContext cx; + const list<value> lc = mklist<value>(c); + debug(lc, "http::contentRequest::assoc"); + debug(valuesToElements(lc), "http::contentRequest::assoc::element"); + return writeRequest(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8"); + } + + // Write value as JSON if requested by the client + if (!isNil(fmt) && cadr(fmt) == "json") { + js::JSContext cx; + return writeRequest(json::writeJSON(valuesToElements(c), cx), "application/json; charset=utf-8"); + } + + // Convert list of values to element values + const list<value> e = valuesToElements(c); + debug(e, "http::contentRequest::elements"); + + // Write an ATOM feed or entry + if (isList(car<value>(e)) && !isNil(car<value>(e))) { + const list<value> el = car<value>(e); + if (isSymbol(car<value>(el)) && car<value>(el) == element && !isNil(cdr<value>(el)) && isSymbol(cadr<value>(el)) && elementHasChildren(el) && !elementHasValue(el)) { + if (cadr<value>(el) == atom::feed) + return writeRequest(atom::writeATOMFeed(e), "application/atom+xml; charset=utf-8"); + if (cadr<value>(el) == atom::entry) + return writeRequest(atom::writeATOMEntry(e), "application/atom+xml; charset=utf-8"); + } + } + + // Write any other compound value as a JSON value + js::JSContext cx; + return writeRequest(json::writeJSON(e, cx), "application/json; charset=utf-8"); +} + +/** + * HTTP POST. + */ +const failable<value> post(const value& val, const string& url, CURLSession& cs) { + debug(url, "http::post::url"); + + // Convert value to a content request + const failable<list<list<string> > > req = contentRequest(val, url); + if (!hasContent(req)) + return mkfailure<value>(req); + debug(content(req), "http::post::input"); + + // POST it to the URL + const failable<list<list<string> > > res = apply<list<string>>(content(req), rcons<string>, list<string>(), url, "POST", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + // Return the new entry id from the HTTP location header, if any + const string loc = location(car(content(res))); + if (length(loc) != 0) { + const value eid(entryId(location(car(content(res))))); + debug(eid, "http::post::result"); + return eid; + } + + // Return the returned content + return responseValue(content(res)); +} + +/** + * HTTP PUT. + */ +const failable<value> put(const value& val, const string& url, CURLSession& cs) { + debug(url, "http::put::url"); + + // Convert value to a content request + const failable<list<list<string> > > req = contentRequest(val, url); + if (!hasContent(req)) + return mkfailure<value>(req); + debug(content(req), "http::put::input"); + + // PUT it to the URL + const failable<list<list<string> > > res = apply<list<string> >(content(req), rcons<string>, list<string>(), url, "PUT", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + debug(true, "http::put::result"); + return value(true); +} + +/** + * HTTP PATCH. + */ +const failable<value> patch(const value& val, const string& url, CURLSession& cs) { + debug(url, "http::put::patch"); + + // Convert value to a content request + const failable<list<list<string> > > req = contentRequest(val, url); + if (!hasContent(req)) + return mkfailure<value>(req); + debug(content(req), "http::patch::input"); + + // PATCH it to the URL + const failable<list<list<string> > > res = apply<list<string> >(content(req), rcons<string>, list<string>(), url, "PATCH", cs); + if (!hasContent(res)) + return mkfailure<value>(res); + + debug(true, "http::patch::result"); + return value(true); +} + +/** + * HTTP DELETE. + */ +const failable<value, string> del(const string& url, 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>(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)) { + cleanup(cs); + return mkfailure<bool>(fch); + } + CURL* ch = content(fch); + + // Connect + curl_easy_setopt(ch, CURLOPT_CONNECT_ONLY, true); + const CURLcode rc = curl_easy_perform(ch); + if (rc) { + cleanup(cs); + 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) { + cleanup(cs); + 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) { + cleanup(cs); + 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) { + cleanup(cs); + 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, 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) { + cleanup(cs); + 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, 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) { + cleanup(cs); + 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) { + cleanup(cs); + return mkfailure<size_t>(apreason(pollrc)); + } + + // Receive again + return recv(c, l, cs); +} + +/** + * 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; + const list<value> arg = car(args); + debug(arg, "http::queryString::arg"); + if (isNil(arg) || isNil(cdr(arg))) + return queryString(cdr(args), os); + os << car(arg) << "=" << c_str(cadr(arg)); + 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)); +} + +/** + * Filter path segment in a list of arguments. + */ +const bool filterPath(const value& arg) { + return isString(arg) || isSymbol(arg); +} + +/** + * Filter query string arguments in a list of arguments. + */ +const bool filterQuery(const value& arg) { + return isList(arg); +} + +/** + * Escape a query string argument. + */ +const value escapeQuery(const value& arg) { + return arg; + //return mklist<value>(car<value>(arg), escapeArg(cadr<value>(arg))); +} + +/** + * HTTP client proxy function. + */ +struct proxy { + proxy(const string& uri, const string& ca, const string& cert, const string& key, const string& cookie, const int timeout, const gc_pool& p) : p(p), uri(uri), ca(ca), cert(cert), key(key), cookie(cookie), cs(*(new (gc_new<CURLSession>(p)) CURLSession(ca, cert, key, cookie, timeout))) { + } + + const value operator()(const list<value>& args) const { + debug(args, "http::proxy::args"); + const value fun = car(args); + if (fun == "get") { + const list<value> lp = filter<value>(filterPath, cadr(args)); + debug(lp, "http::proxy::path"); + const list<value> lq = map<value, value>(escapeQuery, filter<value>(filterQuery, cadr(args))); + debug(lp, "http::proxy::query"); + const value p = path(lp); + const value q = queryString(lq); + const failable<value> val = get(uri + p + (q != ""? string("?") + q : string("")), 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 == "patch") { + const failable<value> val = patch(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 string cookie; + CURLSession& cs; +}; + +} +} + +#endif /* tuscany_http_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-addr b/sca-cpp/branches/lightweight-sca/modules/http/httpd-addr new file mode 100755 index 0000000000..735c152f43 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-addr @@ -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. + +# 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 diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-conf new file mode 100755 index 0000000000..730775fa89 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-conf @@ -0,0 +1,375 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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` +if [ "$pport" = "80" ]; then + pportsuffix="" +else + pportsuffix=":$pport" +fi + +mkdir -p $4 +htdocs=`echo "import os; print os.path.realpath('$4')" | python` + +user=`id -un` +group=`id -gn` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" + sendfile=Off +else + libsuffix=".so" + sendfile=On +fi + +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$pportsuffix +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 +RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500 +LimitRequestBody 1048576 +HostNameLookups Off +#MaxKeepAliveRequests 25 +#MaxConnectionsPerChild 100 + +# 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 +LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [access] %h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" combined +Include conf/log.conf + +# Configure Mime types and default charsets +TypesConfig $here/conf/mime.types +AddDefaultCharset utf-8 +AddCharset utf-8 .html .js .css + +# Configure cache control +<Directory /> +ExpiresActive On +ExpiresDefault A604800 +Header onsuccess merge Cache-Control public env=!private-cache +</Directory> + +# Enable Linux Kernel sendfile +EnableSendFile $sendfile + +# Configure auth modules +Include conf/auth.conf + +# Set default document root +DocumentRoot $htdocs +DirectoryIndex index-min.html index.html + +# Protect server files +<Directory /> +Options None +AllowOverride None +Require all denied +</Directory> + +# Configure output filters to enable compression and rate limiting +<Location /> +#SetOutputFilter RATE_LIMIT;DEFLATE +SetOutputFilter DEFLATE + +BrowserMatch ^Mozilla/4 gzip-only-text/html +BrowserMatch ^Mozilla/4\.0[678] no-gzip +BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html +BrowserMatch ^check_http/ check_http +SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary +Header append Vary User-Agent env=!dont-vary + +#SetEnv rate-limit 400 +</Location> + +# Listen on HTTP port +Listen $listen + +# Setup HTTP virtual host +<VirtualHost $vhost> +ServerName http://$host$pportsuffix + +<Location /> +RewriteEngine on +Include conf/hostcond.conf +RewriteCond %{HTTP:X-Forwarded-Server} ^$ [NC] +RewriteCond %{REQUEST_URI} !^/server-status [NC] +RewriteCond %{REQUEST_URI} !^/balancer-manager [NC] +RewriteCond %{REQUEST_URI} !^/proxy/ [NC] +RewriteRule .* http://$host$pportsuffix%{REQUEST_URI} [R] +</Location> + +Include conf/svhost.conf + +# Configure authentication +Include conf/noauth.conf +Include conf/locauth.conf +Include conf/pubauth.conf +Include conf/adminauth.conf + +</VirtualHost> + +EOF + +# Configure logging +cat >$root/conf/log.conf <<EOF +# Generated by: httpd-conf $* +ErrorLog $root/logs/error_log +CustomLog $root/logs/access_log combined + +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 + +if [ $uname = "Darwin" ]; then + cat >>$root/conf/mpm.conf <<EOF +# Generated by: httpd-conf $* +# Set thread stack size +ThreadStackSize 2097152 + +EOF +fi + +# 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 headers_module ${modules_prefix}/modules/mod_headers.so +LoadModule alias_module ${modules_prefix}/modules/mod_alias.so +LoadModule authn_file_module ${modules_prefix}/modules/mod_authn_file.so +LoadModule authn_socache_module ${modules_prefix}/modules/mod_authn_socache.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 socache_shmcb_module ${modules_prefix}/modules/mod_socache_shmcb.so +LoadModule cache_module ${modules_prefix}/modules/mod_cache.so +LoadModule cache_disk_module ${modules_prefix}/modules/mod_cache_disk.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 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 +LoadModule env_module ${modules_prefix}/modules/mod_env.so +LoadModule expires_module ${modules_prefix}/modules/mod_expires.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 actions_module ${modules_prefix}/modules/mod_actions.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 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 ssl_module ${modules_prefix}/modules/mod_ssl.so + +EOF + +# Generate auth configuration +cat >$root/conf/auth.conf <<EOF +# Generated by: httpd-conf $* + +EOF + +cat >$root/conf/locauth.conf <<EOF +# Generated by: httpd-conf $* +# Authentication and authorization 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" +AuthGroupFile "$root/conf/httpd.groups" +Require all granted +</Location> + +EOF + +cat >$root/conf/pubauth.conf <<EOF +# Generated by: httpd-conf $* +# Allow everyone to access public locations +<Location /login> +AuthType None +Require all granted +# Mark login page with a header +Header set X-Login open-auth +</Location> +<Location /logout> +AuthType None +Require all granted +</Location> +<Location /public> +AuthType None +Require all granted +</Location> +<Location /proxy/public> +AuthType None +Require all granted +</Location> +<Location /favicon.ico> +AuthType None +Require all granted +</Location> +<Location /robots.txt> +AuthType None +Require all granted +</Location> + +EOF + +cat >$root/conf/adminauth.conf <<EOF + +# Allow the server admin to view the server status +<Location /server-status> +Require user admin +</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 + +# Allow public access to server resources +cat >$root/conf/noauth.conf <<EOF +# Generated by: httpd-conf $* +# Allow public access to server resources + +# Allow access to document root +<Directory "$htdocs"> +AuthType None +Require all granted +</Directory> + +# Allow everyone to access root location +<Location /> +AuthType None +Require all granted +</Location> + +EOF + +# Generate vhost configuration +cat >$root/conf/vhost.conf <<EOF +# Generated by: httpd-conf $* +# Virtual host configuration +UseCanonicalName Off + +# Enable HTTP reverse proxy +ProxyRequests Off +ProxyPreserveHost On +ProxyStatus On + +# Enable server status +<Location /server-status> +SetHandler server-status +HostnameLookups on +</Location> + +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 + +# Generate host name check condition +cat >$root/conf/hostcond.conf <<EOF +# Generated by: httpd-conf $* +RewriteCond %{HTTP_HOST} !^$host [NC] + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-debug b/sca-cpp/branches/lightweight-sca/modules/http/httpd-debug new file mode 100755 index 0000000000..df0d21fbe5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-debug @@ -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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +httpd=`cat $here/httpd.prefix` +$httpd/bin/httpd -X -E $root/logs/error_log -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-event-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-event-conf new file mode 100755 index 0000000000..093bbe78d9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-event-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. + +# Configure HTTPD to run with the event MPM +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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 + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + cat >>$root/conf/mpm.conf <<EOF +# Generated by: httpd-conf $* +# Set thread stack size +ThreadStackSize 2097152 + +EOF +fi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-loglevel-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-loglevel-conf new file mode 100755 index 0000000000..c9d2ad81d5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-loglevel-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. + +# Configure HTTPD log level +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +level=$2 + +# Configure log level +cat >>$root/conf/log.conf <<EOF +# Generated by: httpd-loglevel-conf $* +LogLevel $level + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-memgrind b/sca-cpp/branches/lightweight-sca/modules/http/httpd-memgrind new file mode 100755 index 0000000000..55e113bbd3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-memgrind @@ -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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +httpd=`cat $here/httpd.prefix` +$here/../../etc/memgrind $httpd/bin/httpd -X -E $root/logs/error_log -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-restart b/sca-cpp/branches/lightweight-sca/modules/http/httpd-restart new file mode 100755 index 0000000000..81b098d85d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +apachectl=`cat $here/httpd-apachectl.prefix` +$apachectl -k graceful -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-ssl-conf new file mode 100755 index 0000000000..f99a10071c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-ssl-conf @@ -0,0 +1,259 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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` +if [ "$sslpport" = "443" ]; then + sslpportsuffix="" +else + sslpportsuffix=":$sslpport" +fi + +dothost=`echo $host | grep "\."` + +htdocs=`echo $conf | awk '{ print $8 }'` +mkdir -p $htdocs +htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +modules_prefix=`cat $here/httpd-modules.prefix` + +# 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$sslpportsuffix + +<Location /> +RewriteEngine on +Include conf/hostcond.conf +RewriteCond %{HTTP:X-Forwarded-Server} ^$ [NC] +RewriteCond %{REQUEST_URI} !^/server-status [NC] +RewriteCond %{REQUEST_URI} !^/balancer-manager [NC] +RewriteCond %{REQUEST_URI} !^/proxy/ [NC] +RewriteRule .* https://$host$sslpportsuffix%{REQUEST_URI} [R] +</Location> + +Include conf/svhost-ssl.conf + +# Configure authentication +Include conf/noauth-ssl.conf +Include conf/locauth-ssl.conf +Include conf/pubauth-ssl.conf +Include conf/adminauth-ssl.conf + +# Configure tracking +Include conf/tracking-ssl.conf + +</VirtualHost> + +EOF + +# Generate auth configuration +cat >$root/conf/locauth-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Authentication and authorization configuration +Include conf/locauth.conf + +EOF + +cat >$root/conf/pubauth-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Allow everyone to access public locations +Include conf/pubauth.conf + +EOF + +cat >$root/conf/adminauth-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Allow admin access +Include conf/adminauth.conf + +EOF + +# Allow public access to server resources +cat >$root/conf/noauth-ssl.conf <<EOF +# Generated by: httpd-conf $* +# Allow public access to server resources +Include conf/noauth.conf + +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$sslpportsuffix%{REQUEST_URI} [R] +</Location> + +EOF + +# Redirect HTTP traffic to HTTPS in HTTP vhost +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}$sslpportsuffix%{REQUEST_URI} [R] +</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 %{mod_security-message}i" sslcombined +Include conf/log-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 +SSLProxyCheckPeerCN Off + +# Enable server status +<Location /server-status> +SetHandler server-status +HostnameLookups on +</Location> + +EOF + +# Generate tracking configuration +cat >$root/conf/tracking-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +# Configure tracking +CookieTracking on +CookieName TuscanyVisitorId +CookieStyle Cookie +CookieExpires 31556926 + +EOF + +if [ "$dothost" != "" ]; then + cat >>$root/conf/tracking-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +CookieDomain .$dothost + +EOF + +fi + +# Configure logging +cat >$root/conf/log-ssl.conf <<EOF +# Generated by: httpd-ssl-conf $* +CustomLog $root/logs/ssl_access_log sslcombined + +EOF + +# Configure virtual hosts +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" + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-start b/sca-cpp/branches/lightweight-sca/modules/http/httpd-start new file mode 100755 index 0000000000..e38c2f9a94 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +apachectl=`cat $here/httpd-apachectl.prefix` +$apachectl -E $root/logs/error_log -k start -d $root -f $root/conf/httpd.conf diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-stop b/sca-cpp/branches/lightweight-sca/modules/http/httpd-stop new file mode 100755 index 0000000000..9010e4dd17 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +apachectl=`cat $here/httpd-apachectl.prefix` +$apachectl -k graceful-stop -d $root -f $root/conf/httpd.conf 2>/dev/null diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-test b/sca-cpp/branches/lightweight-sca/modules/http/httpd-test new file mode 100755 index 0000000000..ab6ab5ad41 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-test @@ -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. + +echo "Testing..." +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../http/curl.prefix` + +# Setup +rm -rf tmp +./httpd-conf tmp localhost 8090 htdocs +./httpd-event-conf tmp +./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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-tunnel-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-tunnel-ssl-conf new file mode 100755 index 0000000000..0028576364 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-tunnel-ssl-conf @@ -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. + +# Generate a minimal HTTPD SSL Tunnel configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +# Generate required modules list +cat >>$root/conf/modules.conf <<EOF +# Generated by: httpd-tunnel-ssl-conf $* +LoadModule mod_tuscany_ssltunnel $here/libmod_tuscany_ssltunnel$libsuffix + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd-worker-conf b/sca-cpp/branches/lightweight-sca/modules/http/httpd-worker-conf new file mode 100755 index 0000000000..0a061dbffa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd-worker-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. + +# Configure HTTPD to run with the worker MPM +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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 + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + cat >>$root/conf/mpm.conf <<EOF +# Generated by: httpd-conf $* +# Set thread stack size +ThreadStackSize 2097152 + +EOF +fi + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/httpd.hpp b/sca-cpp/branches/lightweight-sca/modules/http/httpd.hpp new file mode 100644 index 0000000000..6470d6c587 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/httpd.hpp @@ -0,0 +1,753 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +extern "C" { +#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 CLang/LLVM +#undef strtoul +// 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> +// Ignore conversion warnings in HTTPD 2.3.15 header +#ifdef WANT_MAINTAINER_WARNINGS +#ifndef IS_DARWIN +#pragma GCC diagnostic ignored "-Wconversion" +#endif +#endif +#include <http_protocol.h> +// Re-enable conversion warnings +#ifdef WANT_MAINTAINER_WARNINGS +#ifndef IS_DARWIN +#pragma GCC diagnostic warning "-Wconversion" +#endif +#endif +// 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 <mod_session.h> +} + +#include "string.hpp" +#include "stream.hpp" +#include "sstream.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "http.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; +} + +/** + * Returns a request-scoped module configuration. + */ +template<typename C> C& makeRequestConf(const request_rec* r, const module* mod) { + C* c = new (gc_new<C>(r->pool)) C(r->pool, r); + ap_set_module_config(r->request_config, mod, c); + return *c; +} + +template<typename C> C& requestConf(const request_rec* r, const module* mod) { + C* c = (C*)ap_get_module_config(r->request_config, mod); + if (c == NULL) + return makeRequestConf<C>(r, mod); + return *c; +} + +/** + * 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* fh = apr_table_get(r->headers_in, "X-Forwarded-Server"); + if (fh != NULL) + return fh; + const char* h = ap_get_server_name(r); + return h != NULL? h : (r->server->server_hostname != NULL? r->server->server_hostname : def); +} + +/** + * Convert a host name to a realm. + */ +const string realm(const string& host) { + const string pre = substr(host, 0, 4); + return pre == "www." || pre == "ww1." || pre == "ww2." || pre == "ww3."? substr(host, 4) : host; +} + +/** + * 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") { + const char* fs = apr_table_get(r->headers_in, "X-Forwarded-HTTPS"); + if (fs != NULL) + return !strcmp(fs, "on")? "https" : "http"; + return r->server->server_scheme != NULL? r->server->server_scheme : def; +} + +/** + * Return the port number for a server. + */ +const int port(const server_rec* s, const int def = 80) { + return s->port != 0? s->port : def; +} + +/** + * Return the port number from an HTTP request. + */ +const int port(request_rec* r, const int def = 80) { + const char* fp = apr_table_get(r->headers_in, "X-Forwarded-Port"); + if (fp != NULL) + return atoi(fp); + const int p = ap_get_server_port(r); + return p != 0? p : def; +} + +/** + * Return the name of a server. + */ +const string serverName(const server_rec* s, const string& def = "localhost") { + ostringstream n; + const string sc = scheme(s); + const string h = hostName(s, def); + const int p = port(s, sc == "https"? 443 : 80); + n << sc << "://" << h; + if (!((sc == "http" && p == 80) || (sc == "https" && p == 443))) + n << ":" << p; + n << (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 string s = scheme(r); + const string h = hostName(r, def); + const int p = port(r, s == "https"? 443 : 80); + n << s << "://" << h; + if (!((s == "http" && p == 80) || (s == "https" && p == 443))) + n << ":" << p; + n << (r->server->path != NULL? string(r->server->path, r->server->pathlen) : ""); + return str(n); +} + +/** + * Return true if a request is targeting a virtual host. + */ +const bool isVhostRequest(const server_rec* s, const string& d, request_rec* r) { + const string rh = hostName(r); + return rh != hostName(s) && http::topDomain(rh) == d; +} + +/** + * 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 cookie header of a request. + */ +const string cookie(const request_rec* r) { + const char* c = apr_table_get(r->headers_in, "Cookie"); + if (c == NULL) + return ""; + return c; +} + +/** + * 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 to an absolute URL. + */ +const string url(const string& uri, request_rec* r) { + if (contains(uri, "://")) + return uri; + ostringstream n; + const string s = scheme(r); + const string h = hostName(r, "localhost"); + const int p = port(r, s == "https"? 443 : 80); + n << s << "://" << h; + if (!((s == "http" && p == 80) || (s == "https" && p == 443))) + n << ":" << p; + n << uri; + return str(n); +} + +/** + * Convert a URI and a path to an absolute URL. + */ +const string url(const string& uri, const list<value>& p, request_rec* r) { + return url(uri + path(p), 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; +} + +/** + * Unescape a list of key of value pairs representing query args. + */ +const list<value> unescapeArg(const list<value> a) { + return mklist<value>(car(a), unescape(cadr(a))); +} + +const list<list<value> > unescapeArgs(const list<list<value> > args) { + debug(args, "httpd::unescape::args"); + const list<list<value> > uargs = map<list<value>, list<value>>(unescapeArg, args); + debug(uargs, "httpd::unescape::result"); + return uargs; +} + +/** + * 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 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>(ls); + ostringstream os; + write(content(ls), os); + const string ob(str(os)); + + // Make sure browsers come back and check for updated dynamic content + apr_table_set(r->headers_out, "Cache-Control", "must-revalidate, max-age=0"); + apr_table_set(r->headers_out, "Expires", "Tue, 01 Jan 1980 00:00:00 GMT"); + apr_table_set(r->subprocess_env, "private-cache", "1"); + + // Compute and return an Etag for the returned content + const string etag(ap_md5_binary(r->pool, (const unsigned char*)c_str(ob), (int)length(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; + debug(r->status, "httpd::writeResult::status"); + return OK; + } + + debug(r->status, "httpd::writeResult::status"); + debug(ct, "httpd::writeResult::contentType"); + debug(ob, "httpd::writeResult::content"); + ap_set_content_type(r, apr_pstrdup(r->pool, c_str(ct))); + ap_rwrite(c_str(ob), (int)length(ob), r); + return OK; +} + +/** + * Report a request execution status. + */ +const int reportStatus(const failable<int>& rc) { + debug(rc, "httpd::reportStatus::rc"); + if (!hasContent(rc)) { + const int r = rcode(rc); + return r == -1 ? HTTP_INTERNAL_SERVER_ERROR : r; + } + return content(rc); +} + +/** + * 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. + */ +const failable<request_rec*> internalRedirectRequest(const string& nr_uri, request_rec* r) { + if (ap_is_recursion_limit_exceeded(r)) + return mkfailure<request_rec*>("Redirect recursion limit exceeded", 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*>("Error handling internal redirect", rrc); + + return nr; +} + +/** + * Process an HTTPD internal redirect request. + * Similar to httpd/modules/http/http_request.c::ap_internal_redirect. + */ +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*> nr = httpd::internalRedirectRequest(uri, r); + if (!hasContent(nr)) + return rcode(nr); + return httpd::internalRedirect(content(nr)); +} + +/** + * Create an HTTPD sub request. + * Similar to httpd/server/request.c::make_sub_request + */ +const failable<request_rec*> internalSubRequest(const string& nr_uri, request_rec* r) { + if (ap_is_recursion_limit_exceeded(r)) + return mkfailure<request_rec*>("Redirect recursion limit exceeded", 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))); + apr_table_setn(r->headers_out, "Cache-Control", "no-store"); + apr_table_addn(r->err_headers_out, "Cache-Control", "no-store"); + 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_LOG + +/** + * 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) { + gc_scoped_pool pool; + 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 debug_httpdRequest(r, msg) do { if (debug_islogging()) httpd::debugRequest(r, msg); } while(0) + +#else + +#define debug_httpdRequest(r, msg) + +#endif + +} +} + +#endif /* tuscany_httpd_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mass-host-conf b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-conf new file mode 100755 index 0000000000..2da8f4f836 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-conf @@ -0,0 +1,62 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +vroot=`echo "import os; print os.path.realpath('$2')" | python` +vhtdocs=$3 + +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=`echo "import os; print os.path.realpath('$htdocs')" | python` + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: mass-host-conf $* +# Enable mass dynamic virtual hosting +NameVirtualHost $vhost + +<VirtualHost $vhost> +ServerName http://vhost.$host:$pport +ServerAlias *.$host + +# Map /v/<app-name>/<path> to vroot/<app-name>/vhtdocs/<path> +AliasMatch /v/([^/]+)(.*)$ $vroot/\$1/$vhtdocs/\$2 + +Include conf/dvhost.conf + +# Configure authentication +Include conf/noauth.conf +Include conf/locauth.conf +Include conf/pubauth.conf +Include conf/adminauth.conf + +</VirtualHost> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mass-host-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-ssl-conf new file mode 100755 index 0000000000..68bd5b4606 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mass-host-ssl-conf @@ -0,0 +1,68 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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` + +vhostconf=`cat $root/conf/httpd.conf | grep "# Generated by: mass-host-conf"` +vroot=`echo $vhostconf | awk '{ print $6 }'`; vroot=`echo "import os; print os.path.realpath('$vroot')" | python` +vhtdocs=`echo $vhostconf | awk '{ print $7 }'` + +htdocs=`echo $conf | awk '{ print $8 }'` +mkdir -p $htdocs +htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python` + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: mass-host-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 + +# Map /v/<app-name>/<path> to vroot/<app-name>/vhtdocs/<path> +AliasMatch /v/([^/]+)(.*)$ $vroot/\$1/$vhtdocs/\$2 + +Include conf/dvhost-ssl.conf + +# Configure authentication +Include conf/noauth-ssl.conf +Include conf/locauth-ssl.conf +Include conf/pubauth-ssl.conf +Include conf/adminauth-ssl.conf + +# Configure tracking +Include conf/tracking-ssl.conf + +</VirtualHost> + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/minify-css b/sca-cpp/branches/lightweight-sca/modules/http/minify-css new file mode 100755 index 0000000000..734d041aba --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/minify-css @@ -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. + +# Minify a CSS file +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pagespeed_prefix=`cat $here/pagespeed.prefix` + +if [ "${pagespeed_prefix}" = "" ]; then + minify_css="cat" +else + minify_css="${pagespeed_prefix}/jsmin_bin" +fi + +css="$1" +mincss="$2" + +${minify_css} <${css} >${mincss} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/minify-html b/sca-cpp/branches/lightweight-sca/modules/http/minify-html new file mode 100755 index 0000000000..31bb329d94 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/minify-html @@ -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. + +# Minify an HTML file +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pagespeed_prefix=`cat $here/pagespeed.prefix` + +if [ "${pagespeed_prefix}" = "" ]; then + minify_html="cp" +else + minify_html="${pagespeed_prefix}/minify_html_bin" +fi + +html="$1" +minhtml="$2" + +${minify_html} ${html} ${minhtml} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/minify-js b/sca-cpp/branches/lightweight-sca/modules/http/minify-js new file mode 100755 index 0000000000..5e7cbb1bc0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/minify-js @@ -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. + +# Minify a JS file +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +pagespeed_prefix=`cat $here/pagespeed.prefix` + +if [ "${pagespeed_prefix}" = "" ]; then + minify_js="cat" +else + minify_js="${pagespeed_prefix}/jsmin_bin" +fi + +js="$1" +minjs="$2" + +${minify_js} <${js} >${minjs} + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-openauth.cpp b/sca-cpp/branches/lightweight-sca/modules/http/mod-openauth.cpp new file mode 100644 index 0000000000..2e308ecedb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-openauth.cpp @@ -0,0 +1,478 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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> + +#define WANT_HTTPD_LOG 1 +#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; +}; + +/** + * Authentication provider configuration. + */ +class AuthnProviderConf { +public: + AuthnProviderConf() : name(), provider(NULL) { + } + AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) { + } + + string name; + const authn_provider* provider; +}; + +/** + * 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; + list<AuthnProviderConf> apcs; +}; + +#ifdef WANT_MAINTAINER_LOG + +/** + * Log session entries. + */ +int debugSessionEntry(unused void* r, const char* key, const char* value) { + cdebug << " session key: " << key << ", value: " << value << endl; + return 1; +} + +const bool debugSession(request_rec* r, session_rec* z) { + apr_table_do(debugSessionEntry, r, z->entries, NULL); + return true; +} + +#define debug_authSession(r, z) if (debug_islogging()) openauth::debugSession(r, z) + +#else + +#define debug_authSession(r, z) + +#endif + +/** + * Run the authnz hooks to authenticate a request. + */ +const failable<int> checkAuthnzProviders(const string& user, const string& pw, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (isNil(apcs)) + return mkfailure<int>("Authentication failure for: " + user); + const AuthnProviderConf apc = car<AuthnProviderConf>(apcs); + if (apc.provider == NULL || !apc.provider->check_password) + return checkAuthnzProviders(user, pw, r, cdr(apcs)); + + apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name)); + const authn_status auth_result = apc.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 checkAuthnzProviders(user, pw, r, cdr(apcs)); + return OK; +} + +const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r, const DirConf& dc) { + if (substr(user, 0, 1) == "/" && pw == "password") + return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + + if (isNil(dc.apcs)) { + const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); + return checkAuthnzProviders(user, pw, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, pw, r, dc.apcs); +} + +/** + * Return the user info from a form auth encrypted session cookie. + */ +static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL; +static int (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL; + +const failable<value> userInfoFromSession(const string& realm, request_rec* r) { + debug("modopenauth::userInfoFromSession"); + if (ap_session_load_fn == NULL) + ap_session_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load); + session_rec *z = NULL; + ap_session_load_fn(r, &z); + if (z == NULL) + return mkfailure<value>("Couldn't retrieve user session"); + debug_authSession(r, z); + + if (ap_session_get_fn == NULL) + ap_session_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get); + const char* user = NULL; + ap_session_get_fn(r, z, c_str(realm + "-user"), &user); + if (user == NULL) + return mkfailure<value>("Couldn't retrieve user id"); + const char* pw = NULL; + ap_session_get_fn(r, z, c_str(realm + "-pw"), &pw); + if (pw == NULL) + return mkfailure<value>("Couldn't retrieve password"); + return value(mklist<value>(mklist<value>("realm", realm), mklist<value>("id", string(user)), mklist<value>("password", string(pw)))); +} + +/** + * Return the user info from a form auth session cookie. + */ +const failable<value> userInfoFromCookie(const value& sid, const string& realm, request_rec* r) { + const list<list<value>> info = httpd::queryArgs(sid); + debug(info, "modopenauth::userInfoFromCookie::info"); + const list<value> user = assoc<value>(realm + "-user", info); + if (isNil(user)) + return userInfoFromSession(realm, r); + 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> userInfoFromHeader(const char* header, const string& realm, request_rec* r) { + debug(header, "modopenauth::userInfoFromHeader::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; +} + +/** + * Check user authentication. + */ +static int checkAuthn(request_rec *r) { + gc_scoped_pool pool(r->pool); + + // 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; + debug_httpdRequest(r, "modopenauth::checkAuthn::input"); + debug(atype, "modopenauth::checkAuthn::auth_type"); + + // Get the request args + const list<list<value> > args = httpd::queryArgs(r); + + // Get session id from the request + const maybe<string> sid = sessionID(r, "TuscanyOpenAuth"); + 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> userinfo = userInfoFromCookie(content(sid), aname, r); + if (hasContent(userinfo)) { + + // Try to authenticate the request + const value uinfo = content(userinfo); + const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc); + if (!hasContent(authz)) { + + // Authentication failed, redirect to login page + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(login(dc.login, value(), 1, r)); + } + + // Successfully authenticated, store the user info in the request + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(authenticated(uinfo, 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 = userInfoFromHeader(header, aname, r); + if (hasContent(info)) { + + // Try to authenticate the request + const value uinfo = content(info); + const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc); + if (!hasContent(authz)) { + + // Authentication failed, redirect to login page + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(login(dc.login, value(), 1, r)); + } + + // Successfully authenticated, store the user info in the request + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(authenticated(uinfo, r)); + } + } + + // Decline if the request is for another authentication provider + if (!isNil(assoc<value>("openid_identifier", args))) + return DECLINED; + + // Redirect to the login page, unless we have a session id from another module + if (hasContent(sessionID(r, "TuscanyOpenIDAuth")) || + hasContent(sessionID(r, "TuscanyOAuth1")) || + hasContent(sessionID(r, "TuscanyOAuth2"))) + return DECLINED; + + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(login(dc.login, value(), value(), r)); +} + +/** + * Save the auth session cookie in the response. + */ +static int sessionCookieSave(request_rec* r, session_rec* z) { + gc_scoped_pool pool(r->pool); + + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; + + debug(c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))), "modopenauth::setcookie"); + apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r)))); + return OK; +} + +/** + * Load the auth session cookie from the request. Similar + */ +static int sessionCookieLoad(request_rec* r, session_rec** z) { + gc_scoped_pool pool(r->pool); + + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; + + // First look in the notes + const char* note = apr_pstrcat(r->pool, "mod_openauth", "TuscanyOpenAuth", NULL); + session_rec* zz = (session_rec*)(void*)apr_table_get(r->notes, note); + if (zz != NULL) { + *z = zz; + return OK; + } + + // Parse the cookie + const maybe<string> sid = openauth::sessionID(r, "TuscanyOpenAuth"); + + // Create a new session + zz = (session_rec*)apr_pcalloc(r->pool, sizeof(session_rec)); + zz->pool = r->pool; + zz->entries = apr_table_make(r->pool, 10); + zz->encoded = hasContent(sid)? c_str(content(sid)) : NULL; + zz->uuid = (apr_uuid_t *) apr_pcalloc(r->pool, sizeof(apr_uuid_t)); + *z = zz; + + // Store it in the notes + apr_table_setn(r->notes, note, (char*)zz); + + return OK; +} + +/** + * 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; +} +const char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + + // Lookup and cache the Authn provider + const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION); + if (provider == NULL) + return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg); + if (!provider->check_password) + return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg); + dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider))); + return NULL; +} + +/** + * HTTP server module declaration. + */ +const command_rec commands[] = { + AP_INIT_ITERATE("AuthOpenAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"), + 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); + ap_hook_session_load(sessionCookieLoad, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_session_save(sessionCookieSave, NULL, NULL, APR_HOOK_MIDDLE); +} + +} +} + +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/sca-cpp/branches/lightweight-sca/modules/http/mod-security-audit-conf b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-audit-conf new file mode 100755 index 0000000000..5914bd1df4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-audit-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. + +# Generate a minimal mod-security audit configuration. +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +mkdir -p $root/tmp + +cat >>$root/conf/mod-security.conf <<EOF +# Generated by: mod-security-audit-conf $* +# Enable mod-security audit log +SecAuditEngine RelevantOnly +SecAuditLogRelevantStatus "^(?:5|4(?!04))" +SecAuditLogParts ABIJDEFHKZ +SecAuditLogType Serial +Include conf/mod-security-audit-log.conf + +EOF + +# Configure audit logging +cat >$root/conf/mod-security-audit-log.conf <<EOF +# Generated by: mod-security-audit-conf $* +SecAuditLog $root/logs/secaudit_log + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-security-conf b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-conf new file mode 100755 index 0000000000..5d03fc5cfb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-security-conf @@ -0,0 +1,184 @@ +#!/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 mod-security configuration. +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +modules_prefix=`cat $here/httpd-modules.prefix` +modsecurity_prefix=`cat $here/modsecurity.prefix` + +mkdir -p $root/tmp + +cat >>$root/conf/modules.conf <<EOF +# Generated by: mod-security-conf $* +# Load support for mod-security +LoadModule unique_id_module ${modules_prefix}/modules/mod_unique_id.so +LoadModule security2_module $modsecurity_prefix/lib/mod_security2.so + +EOF + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: mod-security-conf $* +# Enable mod-security +Include conf/mod-security.conf + +EOF + +cat >$root/conf/mod-security.conf <<EOF +# Generated by: mod-security-conf $* +# Enable mod-security rules +SecRuleEngine On +SecDefaultAction "phase:2,pass,nolog,auditlog" + +#SecDebugLog $root/logs//modsec_debug_log +#SecDebugLogLevel 3 + +# Process request bodies +SecRequestBodyAccess Off +SecRule REQUEST_HEADERS:Content-Type "text/xml" "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" +SecRule REQUEST_HEADERS:Content-Type "application/xml" "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" +SecRequestBodyLimit 13107200 +SecRequestBodyNoFilesLimit 131072 +SecRequestBodyInMemoryLimit 131072 +SecRequestBodyLimitAction Reject + +# Verify that we've correctly processed the request body +SecRule REQBODY_ERROR "!@eq 0" "phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + +# By default be strict with what we accept in multipart/form-data request body +SecRule MULTIPART_STRICT_ERROR "!@eq 0" "phase:2,t:none,log,deny,status:44,msg:'Multipart request body failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_SEMICOLON_MISSING}, \ +IQ %{MULTIPART_INVALID_QUOTING}, \ +IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ +IH %{MULTIPART_FILE_LIMIT_EXCEEDED}'" + +# Did we see anything that might be a boundary? +SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" "phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'" + +# Avoid a potential RegEx DoS condition +SecPcreMatchLimit 50000 +SecPcreMatchLimitRecursion 50000 +SecRule TX:/^MSC_/ "!@streq 0" "phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + +# Detect slow DoS attacks +SecRule RESPONSE_STATUS "@streq 408" "phase:5,t:none,nolog,pass, setvar:ip.slow_dos_counter=+1,expirevar:ip.slow_dos_counter=60" +SecRule IP:SLOW_DOS_COUNTER "@gt 5" "phase:1,t:none,log,drop, msg:'Client Connection Dropped due to high # of slow DoS alerts'" +SecWriteStateLimit 50 + +# Process response bodies +SecResponseBodyAccess Off +SecResponseBodyMimeType text/plain text/html text/xml application/xml +SecResponseBodyLimit 524288 +SecResponseBodyLimitAction ProcessPartial + +# The location where mod-security stores temporary files +SecTmpDir $root/tmp/ +SecDataDir $root/tmp/ + +# Use & as application/x-www-form-urlencoded parameter separator +SecArgumentSeparator & + +# Settle on version 0 (zero) cookies. +SecCookieFormat 0 + +# Enable anomaly scoring +SecAction "phase:1,id:'981206',t:none,nolog,pass,setvar:tx.anomaly_score_blocking=on" +SecAction "phase:1,id:'981207',t:none,nolog,pass, \ +setvar:tx.critical_anomaly_score=5, \ +setvar:tx.error_anomaly_score=4, \ +setvar:tx.warning_anomaly_score=3, \ +setvar:tx.notice_anomaly_score=2" +SecAction "phase:1,id:'981208',t:none,nolog,pass,setvar:tx.inbound_anomaly_score_level=10" +SecAction "phase:1,id:'981209',t:none,nolog,pass,setvar:tx.outbound_anomaly_score_level=8" + +# Paranoid mode +SecAction "phase:1,id:'981210',t:none,nolog,pass,setvar:tx.paranoid_mode=0" + +# HTTP policy settings +SecAction "phase:1,id:'981211',t:none,nolog,pass,setvar:tx.max_num_args=255" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.arg_name_length=100" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.arg_length=400" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.total_arg_length=64000" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.max_file_size=1048576" +SecAction "phase:1,t:none,nolog,pass,setvar:tx.combined_file_sizes=1048576" +SecAction "phase:1,id:'981212',t:none,nolog,pass, \ +setvar:'tx.allowed_methods=GET HEAD POST PUT OPTIONS DELETE CONNECT', \ +setvar:'tx.allowed_request_content_type=application/x-www-form-urlencoded multipart/form-data text/xml application/xml application/json application/json-rpc application/atom+xml', \ +setvar:'tx.allowed_http_versions=HTTP/0.9 HTTP/1.0 HTTP/1.1', \ +setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/', \ +setvar:'tx.restricted_headers=/Proxy-Connection/ /Lock-Token/ /Content-Range/ /Translate/ /via/ /if/'" + +# Brute force protection +SecAction "phase:1,id:'981214',t:none,nolog,pass, \ +setvar:'tx.brute_force_protected_urls=/login', \ +setvar:'tx.brute_force_burst_time_slice=60', \ +setvar:'tx.brute_force_counter_threshold=10', \ +setvar:'tx.brute_force_block_timeout=300'" + +# DoS protection +SecAction "phase:1,id:'981215',t:none,nolog,pass, \ +setvar:'tx.dos_burst_time_slice=60', \ +setvar:'tx.dos_counter_threshold=100', \ +setvar:'tx.dos_block_timeout=600'" + +# Check UTF-8 encoding +SecAction "phase:1,id:'981216',t:none,nolog,pass,setvar:tx.crs_validate_utf8_encoding=1" + +# Global and IP collections +SecRule REQUEST_HEADERS:User-Agent "^(.*)$" "phase:1,id:'981217',t:none,pass,nolog,t:sha1,t:hexEncode,setvar:tx.ua_hash=%{matched_var}" +SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" "phase:1,id:'981225',t:none,pass,nolog,capture,setvar:tx.real_ip=%{tx.1}" +SecRule &TX:REAL_IP "!@eq 0" "phase:1,id:'981226',t:none,pass,nolog,initcol:global=global,initcol:ip=%{tx.real_ip}_%{tx.ua_hash}" +SecRule &TX:REAL_IP "@eq 0" "phase:1,id:'981218',t:none,pass,nolog,initcol:global=global,initcol:ip=%{remote_addr}_%{tx.ua_hash}" + +# Include all base mod-security CRS rules +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_20_protocol_violations.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_xss_attacks.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_50_outbound.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_35_bad_robots.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_47_common_exceptions.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_60_correlation.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_40_generic_attacks.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_21_protocol_anomalies.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_30_http_policy.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_49_inbound_blocking.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_sql_injection_attacks.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_45_trojans.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_59_outbound_blocking.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_23_request_limits.conf +Include ${modsecurity_prefix}/base_rules/modsecurity_crs_42_tight_security.conf + +# Include some optional mod-security CRS rules +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_10_ignore_static.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_13_xml_enabler.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_25_cc_known.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_42_comment_spam.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_47_skip_outbound_checks.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_55_application_defects.conf + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/mod-ssltunnel.cpp b/sca-cpp/branches/lightweight-sca/modules/http/mod-ssltunnel.cpp new file mode 100644 index 0000000000..b66cd29959 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/mod-ssltunnel.cpp @@ -0,0 +1,379 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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> + +#define WANT_HTTPD_LOG 1 +#include "string.hpp" +#include "stream.hpp" +#include "list.hpp" +#include "tree.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "httpd.hpp" +#include "http.hpp" + +// Ignore cast align warnings in APR macros +#ifdef WANT_MAINTAINER_WARNINGS +#pragma GCC diagnostic ignored "-Wcast-align" +#endif + +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), "modssltunnel::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), "modssltunnel::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, "", 0); + 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 pool(conn->pool); + + // Get the server configuration + 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; + + gc_scoped_pool pool(r->pool); + + // 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 +}; + +} + +// Reenable cast align warnings +#ifdef WANT_MAINTAINER_WARNINGS +#pragma GCC diagnostic warning "-Wcast-align" +#endif + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/open-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/open-auth-conf new file mode 100755 index 0000000000..f4715b3a1c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/open-auth-conf @@ -0,0 +1,100 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +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"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then + pw=`cat $root/cert/ca.key | head -2 | tail -1` +else + pw="$3" +fi + +# Configure HTTPD mod_tuscany_openauth module +cat >>$root/conf/modules.conf <<EOF +# Generated by: open-auth-conf $* +# Load support for Open authentication +LoadModule mod_tuscany_openauth $here/libmod_tuscany_openauth$libsuffix + +EOF + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: open-auth-conf $* +# Disallow public access to server resources + +EOF + +# Generate form authentication configuration +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: open-auth-conf $* +# Enable Tuscany open authentication +<Location /> +AuthType Open +AuthName "$host" +AuthOpenAuthProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +Session On +SessionCryptoPassphrase $pw +AuthOpenAuth On +AuthOpenAuthLoginPage /login/ +Require valid-user +</Location> + +# Use HTTPD form-based authentication +<Location /login/dologin> +AuthType Form +AuthName "$host" +AuthFormProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +AuthFormLoginRequiredLocation /login/?openauth_attempt=1 +AuthFormLogoutLocation / +Require valid-user +SetHandler form-login-handler +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/openauth.hpp b/sca-cpp/branches/lightweight-sca/modules/http/openauth.hpp new file mode 100644 index 0000000000..3ffa88d362 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/openauth.hpp @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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, const string& key) { + 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) == key) + return cadr(kv); + } + } + return sessionID(cdr(c), key); +} + +const maybe<string> sessionID(const request_rec* r, const string& key) { + const string c = httpd::cookie(r); + debug(c, "openauth::sessionid::cookies"); + if (length(c) == 0) + return maybe<string>(); + return sessionID(tokenize(";", c), key); +} + +/** + * Convert a session id to a cookie string. + */ +const string cookie(const string& key, const string& sid, const string& domain) { + 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 = key + string("=") + sid + "; expires=" + string(exp) + "; domain=." + httpd::realm(domain) + "; path=/"; + debug(c, "openauth::cookie"); + return c; +} + +/** + * Redirect to the configured login page. + */ +const failable<int> login(const string& page, const value& ref, const value& attempt, request_rec* r) { + const list<list<value> > rarg = ref == string("/")? list<list<value> >() : mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(isNil(ref)? r->uri : ref, r)))); + const list<list<value> > aarg = isNil(attempt)? list<list<value> >() : mklist<list<value> >(mklist<value>("openauth_attempt", attempt)); + const list<list<value> > largs = append<list<value> >(rarg, aarg); + const string loc = isNil(largs)? httpd::url(page, r) : httpd::url(page, r) + string("?") + http::queryString(largs); + debug(loc, "openauth::login::uri"); + return httpd::externalRedirect(loc, r); +} + +} +} + +#endif /* tuscany_openauth_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/http/passwd-auth-conf b/sca-cpp/branches/lightweight-sca/modules/http/passwd-auth-conf new file mode 100755 index 0000000000..718b96de0a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +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/sca-cpp/branches/lightweight-sca/modules/http/proxy-balancer-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-balancer-conf new file mode 100755 index 0000000000..0b63c9e481 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-balancer-conf @@ -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. + +# Generate a minimal HTTPD proxy balancer configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +bal=$2 +if [ "$bal" = "" ]; then + bal="cluster" +fi +loc=$3 +if [ "$loc" = "" ]; then + loc="/" +fi + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-pass-conf $* +# Enable load balancing +ProxyPass $loc balancer://$bal/ + +<Proxy balancer://$bal> +Require all granted +ProxySet lbmethod=byrequests +</Proxy> + +<Location $loc> +RequestHeader set X-Forwarded-HTTPS %{HTTPS}s +RequestHeader set X-Forwarded-Port %{SERVER_PORT}s +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-base-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-base-conf new file mode 100755 index 0000000000..377175328d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-base-conf @@ -0,0 +1,48 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-base-conf $* +# Do not proxy admin pages +ProxyPass /balancer-manager ! +ProxyPass /server-status ! +ProxyPass /proxy ! + +# Enable balancer manager +<Location /balancer-manager> +SetHandler balancer-manager +HostnameLookups on +</Location> + +EOF + +cat >>$root/conf/adminauth.conf <<EOF +# Generated by: proxy-base-conf $* +# Allow the server admin to manage the load balancer +<Location /balancer-manager> +Require user admin +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-conf new file mode 100755 index 0000000000..ce990bbfd3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-conf @@ -0,0 +1,60 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-conf $* +# Do not proxy admin pages +ProxyPass /balancer-manager ! +ProxyPass /server-status ! +ProxyPass /proxy ! + +# Enable load balancing +ProxyPass / balancer://cluster/ +<Proxy balancer://cluster> +Require all granted +ProxySet lbmethod=byrequests +</Proxy> + +<Location /> +RequestHeader set X-Forwarded-HTTPS %{HTTPS}s +RequestHeader set X-Forwarded-Port %{SERVER_PORT}s +</Location> + +# Enable balancer manager +<Location /balancer-manager> +SetHandler balancer-manager +HostnameLookups on +</Location> + +EOF + +cat >>$root/conf/adminauth.conf <<EOF +# Generated by: proxy-conf $* +# Allow the server admin to manage the load balancer +<Location /balancer-manager> +Require user admin +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-member-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-member-conf new file mode 100755 index 0000000000..a046a4fd08 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-member-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. + +# Add a proxy balancer member +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=`$here/httpd-addr port $3` +if [ "$port" = "80" ]; then + portsuffix="" +else + portsuffix=":$port" +fi + +bal=$4 +if [ "$bal" = "" ]; then + bal="cluster" +fi + +cat >>$root/conf/vhost.conf <<EOF +# Generated by: proxy-member-conf $* +# Add proxy balancer member +BalancerMember balancer://$bal http://$host$portsuffix +ProxyPassReverse / http://$host$portsuffix/ + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-conf new file mode 100755 index 0000000000..ad7f26d83a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-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 minimal HTTPD proxy balancer configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: proxy-ssl-conf $* +# Do not proxy admin pages +ProxyPass /balancer-manager ! +ProxyPass /server-status ! +ProxyPass /proxy ! + +# Enable load balancing +ProxyPass / balancer://sslcluster/ +<Proxy balancer://sslcluster> +Require all granted +ProxySet lbmethod=byrequests +</Proxy> + +<Location /> +RequestHeader set X-Forwarded-HTTPS %{HTTPS}s +RequestHeader set X-Forwarded-Port %{SERVER_PORT}s +</Location> + +# Enable balancer manager +<Location /balancer-manager> +SetHandler balancer-manager +HostnameLookups on +</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/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-member-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-member-conf new file mode 100755 index 0000000000..cb42a1e9db --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-member-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. + +# Add a proxy balancer member +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +sslport=`$here/httpd-addr port $3` +if [ "$sslport" = "443" ]; then + sslportsuffix="" +else + sslportsuffix=":$sslport" +fi + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: proxy-ssl-member-conf $* +# Add proxy balancer member +BalancerMember balancer://sslcluster https://$host$sslportsuffix +ProxyPassReverse / https://$host$sslportsuffix/ + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-nossl-member-conf b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-nossl-member-conf new file mode 100755 index 0000000000..17b766d986 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-ssl-nossl-member-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. + +# Add a proxy balancer member +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=`$here/httpd-addr port $3` +if [ "$port" = "80" ]; then + portsuffix="" +else + portsuffix=":$port" +fi + +cat >>$root/conf/vhost-ssl.conf <<EOF +# Generated by: proxy-ssl-nossl-member-conf $* +# Add proxy balancer member +BalancerMember balancer://sslcluster http://$host$portsuffix +ProxyPassReverse / http://$host$portsuffix/ + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/proxy-test b/sca-cpp/branches/lightweight-sca/modules/http/proxy-test new file mode 100755 index 0000000000..0333dd280b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/proxy-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 +rm -rf tmp +./httpd-conf tmp localhost 8091/8090 htdocs +./httpd-event-conf tmp +./httpd-start tmp +./httpd-conf tmp/proxy localhost 8090 tmp/proxy/htdocs +./httpd-event-conf tmp/proxy +./proxy-conf tmp/proxy +./proxy-member-conf tmp/proxy localhost 8091 +./httpd-start tmp/proxy +sleep 2 + +# Test +./curl-test 2>/dev/null +rc=$? + +# Cleanup +./httpd-stop tmp/proxy +./httpd-stop tmp +sleep 2 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/http/ssl-ca-conf b/sca-cpp/branches/lightweight-sca/modules/http/ssl-ca-conf new file mode 100755 index 0000000000..bceca8f300 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 + +# Don't override existing certificate +if [ -f $root/cert/ca.crt ]; then + exit 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 +perl /usr/bin/c_rehash $root/cert/hash + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-conf b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-conf new file mode 100755 index 0000000000..9e785ec86e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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 + exit 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 +perl /usr/bin/c_rehash $root/cert/hash + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-find b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-find new file mode 100755 index 0000000000..7a4b4f0220 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/http/ssl-cert-find @@ -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. + +# List certificate files, useful to distribute them to another host +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +cd $root +find . -name "*.crt" +find . -name "*.pem" +find . -name "*.p12" +find . -name "*.key" +find . -name "*.0" + diff --git a/sca-cpp/branches/lightweight-sca/modules/http/tunnel-ssl-conf b/sca-cpp/branches/lightweight-sca/modules/http/tunnel-ssl-conf new file mode 100755 index 0000000000..021d205ed9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +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/sca-cpp/branches/lightweight-sca/modules/java/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/java/Makefile.am new file mode 100644 index 0000000000..8b80276d15 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/Makefile.am @@ -0,0 +1,70 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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${libsuffix} +libmod_tuscany_java${libsuffix}: + ln -s .libs/libmod_tuscany_java${libsuffix} + +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 client-test +mod_PROGRAMS = java-shell +TESTS = jni-test java-test server-test + +endif diff --git a/sca-cpp/branches/lightweight-sca/modules/java/client-test.cpp b/sca-cpp/branches/lightweight-sca/modules/java/client-test.cpp new file mode 100644 index 0000000000..d06c57721e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/domain-test.composite b/sca-cpp/branches/lightweight-sca/modules/java/domain-test.composite new file mode 100644 index 0000000000..a4c696c38d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/domain-test.composite @@ -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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://domain/test" + name="domain-test"> + + <component name="java-test"> + <implementation.java class="test.ServerImpl"/> + <service name="test"> + <binding.http uri="java"/> + </service> + </component> + + <component name="client-test"> + <implementation.java class="test.ClientImpl"/> + <service name="client"> + <binding.http uri="client"/> + </service> + <reference name="ref" target="java-test"> + <binding.http/> + </reference> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/modules/java/driver.hpp b/sca-cpp/branches/lightweight-sca/modules/java/driver.hpp new file mode 100644 index 0000000000..ddfc057940 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/eval.hpp b/sca-cpp/branches/lightweight-sca/modules/java/eval.hpp new file mode 100644 index 0000000000..31fb09f741 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/eval.hpp @@ -0,0 +1,566 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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() { + debug("java::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_ASSERT + // 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); + } + + ~JavaRuntime() { + } + + 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/sca-cpp/branches/lightweight-sca/modules/java/java-conf b/sca-cpp/branches/lightweight-sca/modules/java/java-conf new file mode 100755 index 0000000000..baa5c059c2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/java-conf @@ -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. + +# Generate a Java server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +cat >>$root/conf/modules.conf <<EOF +# Generated by: java-conf $* +# Support for Java SCA components +LoadModule mod_tuscany_eval $here/libmod_tuscany_java${libsuffix} + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/java/java-shell.cpp b/sca-cpp/branches/lightweight-sca/modules/java/java-shell.cpp new file mode 100644 index 0000000000..51df513990 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/java-test.cpp b/sca-cpp/branches/lightweight-sca/modules/java/java-test.cpp new file mode 100644 index 0000000000..f811a4f58d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/jni-test.cpp b/sca-cpp/branches/lightweight-sca/modules/java/jni-test.cpp new file mode 100644 index 0000000000..727af13dc6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/mod-java.cpp b/sca-cpp/branches/lightweight-sca/modules/java/mod-java.cpp new file mode 100644 index 0000000000..d96861cc6d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/mod-java.cpp @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +#define WANT_HTTPD_LOG 1 +#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); + if (contains(itype, ".widget")) + return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype, -1, false); + return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype); +} + +} +} +} diff --git a/sca-cpp/branches/lightweight-sca/modules/java/mod-java.hpp b/sca-cpp/branches/lightweight-sca/modules/java/mod-java.hpp new file mode 100644 index 0000000000..b68f17aa3f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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), rcode(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>&)> >(jc); + return lambda<value(const list<value>&)>(applyImplementation(content(jc), px, jr)); +} + +} +} +} + +#endif /* tuscany_modjava_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/ClassLoader.java b/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/ClassLoader.java new file mode 100644 index 0000000000..ef7b2316fb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/InvocationHandler.java b/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/InvocationHandler.java new file mode 100644 index 0000000000..06466fe9fc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/IterableUtil.java b/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/IterableUtil.java new file mode 100644 index 0000000000..2366d79af6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/IterableUtil.java @@ -0,0 +1,398 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 cdr of the cdr of the cdr of a list. + */ + public static <T> Iterable<T> cdddr(final Object l) { + return cdr(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 car of the cdr of the cdr of the cdr of a list. + */ + @SuppressWarnings("unchecked") + public static <T> T cadddr(final Object l) { + return (T)car(cdddr(l)); + } + + /** + * Appends a list and another list. + */ + @SuppressWarnings("unchecked") + public static <T> Iterable<T> append(final Object a, final Object b) { + if (isNil(a)) + return (Iterable<T>)b; + return cons(car(a), append(cdr(a), b)); + } + + /** + * 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); + + final Iterable<Object> a = list(0, 1, 2); + final Iterable<Object> b = list(3, 4); + final Iterable<Object> ab = append(a, b); + assert ab.toString().equals("[0, 1, 2, 3, 4]"); + 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/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/Service.java b/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/Service.java new file mode 100644 index 0000000000..a00d5b1b53 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/UUIDUtil.java b/sca-cpp/branches/lightweight-sca/modules/java/org/apache/tuscany/UUIDUtil.java new file mode 100644 index 0000000000..60076c62ca --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/server-test b/sca-cpp/branches/lightweight-sca/modules/java/server-test new file mode 100755 index 0000000000..0b45649ace --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/server-test @@ -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. + +# Setup +rm -rf tmp +../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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/java/test/Adder.java b/sca-cpp/branches/lightweight-sca/modules/java/test/Adder.java new file mode 100644 index 0000000000..7236548c41 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/test/AdderImpl.java b/sca-cpp/branches/lightweight-sca/modules/java/test/AdderImpl.java new file mode 100644 index 0000000000..e607012b78 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/test/CalcImpl.java b/sca-cpp/branches/lightweight-sca/modules/java/test/CalcImpl.java new file mode 100644 index 0000000000..5bea01a43f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/test/Client.java b/sca-cpp/branches/lightweight-sca/modules/java/test/Client.java new file mode 100644 index 0000000000..c3bd875fcc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/test/ClientImpl.java b/sca-cpp/branches/lightweight-sca/modules/java/test/ClientImpl.java new file mode 100644 index 0000000000..ade2ba302e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/test/Server.java b/sca-cpp/branches/lightweight-sca/modules/java/test/Server.java new file mode 100644 index 0000000000..3dfe3c84ef --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/java/test/ServerImpl.java b/sca-cpp/branches/lightweight-sca/modules/java/test/ServerImpl.java new file mode 100644 index 0000000000..ee25cf7bf8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/test/ServerImpl.java @@ -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. + */ + +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(list("'feed", list("'title", "Sample Feed"), list("'id", "123456789"), list("'entry", list( + list(list("'title", "Item"), list("'id", "111"), + list("'content", list("'item", list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99)))), + list(list("'title", "Item"), list("'id", "222"), + list("'content", list("'item", list("'name", "Orange"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 3.55)))), + list(list("'title", "Item"), list("'id", "333"), + list("'content", list("'item", list("'name", "Pear"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 1.55)))))))); + + final Iterable<?> content = list("'content", list("'item", list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99))); + return list(list("'entry", list("'title", "Item"), list("'id", car(id)), content)); + } + + 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/sca-cpp/branches/lightweight-sca/modules/java/wiring-test b/sca-cpp/branches/lightweight-sca/modules/java/wiring-test new file mode 100755 index 0000000000..dd865c4c66 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/java/wiring-test @@ -0,0 +1,81 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../http/curl.prefix` + +# Setup +rm -rf tmp +../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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/js/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/js/Makefile.am new file mode 100644 index 0000000000..38627678a1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/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. + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/modules/js + +jsfiles = htdocs/util.js htdocs/elemutil.js htdocs/xmlutil.js htdocs/atomutil.js htdocs/jsonutil.js htdocs/scdl.js htdocs/ui.js htdocs/component.js + +BUILT_SOURCES = htdocs/all.js +htdocs/all.js: ${jsfiles} + cat $^ >htdocs/all.js + +minified = htdocs/all-min.js htdocs/ui-min.css + +SUFFIXES = -min.html -min.js -min.css +.html-min.html: + ../../modules/http/minify-html $< $@ + +.js-min.js: + ../../modules/http/minify-js $< $@ + +.css-min.css: + ../../modules/http/minify-css $< $@ + +CLEANFILES = htdocs/all.js ${minified} + +dist_mod_SCRIPTS = js-conf +moddir = $(prefix)/modules/js +nobase_dist_mod_DATA = ${minified} +EXTRA_DIST = ${jsfiles} htdocs/ui.css + +js_test_SOURCES = js-test.cpp +js_test_LDFLAGS = -lmozjs + +js_shell_SOURCES = js-shell.cpp +js_shell_LDFLAGS = -lmozjs + +noinst_PROGRAMS = js-test +mod_PROGRAMS = js-shell +dist_noinst_SCRIPTS = util-test +TESTS = js-test util-test + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/eval.hpp b/sca-cpp/branches/lightweight-sca/modules/js/eval.hpp new file mode 100644 index 0000000000..f8f4cbe598 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/eval.hpp @@ -0,0 +1,365 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 +#ifdef WANT_MAINTAINER_WARNINGS +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif +#include <jsapi.h> +#ifdef WANT_MAINTAINER_WARNINGS +#pragma GCC diagnostic warning "-Wunused-parameter" +#pragma GCC diagnostic warning "-Wsign-compare" +#pragma GCC diagnostic warning "-Wredundant-decls" +#endif +#include "string.hpp" +#include "list.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" +#include "parallel.hpp" + +namespace tuscany { +namespace js { + +/** + * Report Javascript errors. + */ +void reportError(unused ::JSContext *cx, const char *message, JSErrorReport *report) { + cfailure << (const char*)(report->filename? report->filename : "<no filename>") << ":" + << (int)report->lineno << ":" << message << endl; +} + +/** + * Encapsulates a JavaScript runtime. Shared by multiple threads in + * a process. + */ +class JSRuntime { +public: + JSRuntime() { + // Create JS runtime + debug("js::jsruntime"); + rt = JS_NewRuntime(1L * 512L * 1024L); + if(rt == NULL) + cleanup(); + } + + operator ::JSRuntime*() const { + return rt; + } + + ~JSRuntime() { + debug("js::~jsruntime"); + } + +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_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS }; + +/** + * Represents a JavaScript context. Maintains one context per thread. + */ +#ifdef WANT_THREADS +perthread_ptr<JSContext> jsContext; +#else +::JSContext* jsContext = NULL; +#endif + +class JSContext { +public: + JSContext() { + // Create JS context if necessary + debug("js::jscontext"); + if (jsContext != NULL) { + cx = jsContext; + JS_BeginRequest(cx); + return; + } + debug("js::jsnewcontext"); + cx = JS_NewContext(jsRuntime, 8192); + if(cx == NULL) + return; + JS_BeginRequest(cx); + + JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT); + JS_SetVersion(cx, JSVERSION_LATEST); + JS_SetErrorReporter(cx, reportError); + //JS_SetGCZeal(cx, 2); + + // Create global JS object + global = JS_NewCompartmentAndGlobalObject(cx, &jsGlobalClass, 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 = cx; + } + + ~JSContext() { + debug("js::~jscontext"); + cleanup(); + } + + operator ::JSContext*() const { + return cx; + } + + JSObject* getGlobal() const { + return global; + } + +private: + bool cleanup() { + if(cx != NULL) { + JS_MaybeGC(cx); + JS_EndRequest(cx); + if (cx != jsContext) { + debug("js::jsdestroycontext"); + 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)) + return propertiesSoFar; + jsval idv; + JS_IdToValue(cx, id, &idv); + if (idv == JSVAL_VOID) + return propertiesSoFar; + + jsval jsv; + if(!JS_GetPropertyById(cx, o, id, &jsv)) + return propertiesSoFar; + const value val = jsValToValue(jsv, cx); + + if(JSVAL_IS_STRING(idv)) { + char* cname = JS_EncodeString(cx, JSVAL_TO_STRING(idv)); + const string name = cname; + JS_free(cx, cname); + if (isNil(val) && !isList(val)) + return jsPropertiesToValues(cons<value> (mklist<value> (element, c_str(name), val), propertiesSoFar), o, i, cx); + //return jsPropertiesToValues(propertiesSoFar, o, i, cx); + 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: { + char* cvalue = JS_EncodeString(cx, JSVAL_TO_STRING(jsv)); + const string svalue = string(cvalue); + JS_free(cx, cvalue); + return value(svalue); + } + 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: { + jsval jsv; + if (!JS_NewNumberValue(cx, (jsdouble)val, &jsv)) + return DOUBLE_TO_JSVAL(0); + return jsv; + } + 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)); + } + case value::Nil: { + return JSVAL_NULL; + } + 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/sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js new file mode 100644 index 0000000000..068b5de2fd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 = {}; + +/** + * Convert a list of elements to a list of values representing an ATOM entry. + */ +atom.entryElementValues = function(e) { + var lt = filter(selector(mklist(element, "'title")), e); + var t = mklist(element, "'title", isNil(lt)? '' : elementValue(car(lt))); + + var li = filter(selector(mklist(element, "'id")), e); + var i = mklist(element, "'id", isNil(li)? '' : elementValue(car(li))); + + var la = filter(selector(mklist(element, "'author")), e); + var lan = isNil(la)? mklist() : filter(selector(mklist(element, "'name")), car(la)); + var lae = isNil(la)? mklist() : filter(selector(mklist(element, "'email")), car(la)); + var laa = isNil(lan)? lae : lan; + var a = isNil(laa)? mklist() : mklist(mklist(element, "'author", elementValue(car(laa)))); + + var lu = filter(selector(mklist(element, "'updated")), e); + var u = isNil(lu)? mklist() : mklist(mklist(element, "'updated", elementValue(car(lu)))); + + var lc = filter(selector(mklist(element, "'content")), e); + var c = isNil(lc)? mklist() : mklist(mklist(element, "'content", elementValue(car(lc)))); + + return append(append(append(mklist(element, "'entry", t, i), a), u), c); +}; + +/** + * Convert a list of elements to a list of values representing ATOM entries. + */ +atom.entriesElementValues = function(e) { + if (isNil(e)) + return e; + return cons(atom.entryElementValues(car(e)), atom.entriesElementValues(cdr(e))); +}; + +/** + * Return true if a list of strings represents an ATOM entry. + */ +atom.isATOMEntry = function(l) { + if (!isXML(l)) + return false; + return car(l).match('<entry') != null && 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 entry. + */ +atom.readATOMEntryDocument = function(doc) { + var e = readXMLDocument(doc); + if (isNil(e)) + return mklist(); + return mklist(atom.entryElementValues(car(e))); +}; + +/** + * Convert a list of strings to a list of values representing an ATOM entry. + */ +atom.readATOMEntry = function(l) { + return atom.readATOMEntryDocument(parseXML(l)); +}; + +/** + * 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)); + return mklist(append( + mklist(element, "'feed", mklist(element, "'title", elementValue(car(t))), mklist(element, "'id", elementValue(car(i)))), + atom.entriesElementValues(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 a list of values representy an ATOM entry to a list of elements. + */ +atom.entryElement = function(l) { + var title = elementValue(namedElementChild("'title", l)); + var id = elementValue(namedElementChild("'id", l)); + var author = namedElementChild("'author", l); + var email = isNil(author)? false : (elementValue(author).indexOf('@') != -1); + var updated = namedElementChild("'updated", l); + var content = namedElementChild("'content", l); + var text = isNil(content)? false : elementHasValue(content); + return append(append(append(append( + mklist(element, "'entry", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"), + mklist(element, "'title", mklist(attribute, "'type", "text"), title), mklist(element, "'id", id)), + isNil(author)? mklist() : mklist(element, "'author", + (email? mklist(element, "'email", elementValue(author)) : mklist(element, "'name", elementValue(author))))), + isNil(updated)? mklist() : mklist(element, "'updated", elementValue(updated))), + isNil(content)? mklist() : + mklist(append(mklist(element, "'content", mklist(attribute, "'type", text? "text" : "application/xml")), + text? mklist(elementValue(content)) : elementChildren(content)))), + mklist(mklist(element, "'link", mklist(attribute, "'href", id)))); +}; + +/** + * 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(ll) { + var l = isNil(ll)? ll : car(ll); + return writeXML(mklist(atom.entryElement(l)), true); +}; + +/** + * Convert a list of values representing an ATOM feed to an ATOM feed. + */ +atom.writeATOMFeed = function(ll) { + var l = isNil(ll)? ll : car(ll); + var lt = filter(selector(mklist(element, "'title")), l); + var t = isNil(lt)? '' : elementValue(car(lt)); + var li = filter(selector(mklist(element, "'id")), l); + var i = isNil(li)? '' : elementValue(car(li)); + 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))); + + // Write ATOM entries + var le = filter(selector(mklist(element, "'entry")), l); + if (isNil(le)) + return writeXML(mklist(f), true); + + // Write a single ATOM entry element with a list of values + if (!isNil(le) && !isNil(car(le)) && isList(car(caddr(car(le))))) { + var fe = append(f, atom.entriesElements(caddr(car(le)))); + return writeXML(mklist(fe), true); + } + + // Write separate ATOM entry elements + var fe = append(f, atom.entriesElements(le)); + return writeXML(mklist(fe), true); +}; + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js new file mode 100644 index 0000000000..c3799ef708 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js @@ -0,0 +1,637 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ + +var JSONClient = {}; + +/** + * Escape a character. + */ +JSONClient.escapeJSONChar = function(c) { + if(c == "\"" || c == "\\") return "\\" + c; + if (c == "\b") return "\\b"; + if (c == "\f") return "\\f"; + if (c == "\n") return "\\n"; + if (c == "\r") return "\\r"; + if (c == "\t") return "\\t"; + var hex = c.charCodeAt(0).toString(16); + if(hex.length == 1) return "\\u000" + hex; + if(hex.length == 2) return "\\u00" + hex; + if(hex.length == 3) return "\\u0" + hex; + 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"; + if(o.constructor == String) + return JSONClient.escapeJSONString(o); + if(o.constructor == Number) + return o.toString(); + if(o.constructor == Boolean) + return o.toString(); + if(o.constructor == Date) + return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; + if(o.constructor == Array) { + var v = []; + for(var i = 0; i < o.length; i++) + v.push(JSONClient.toJSON(o[i])); + return "[" + v.join(", ") + "]"; + } + 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(name, uri, domain) { + this.name = name; + this.domain = domain; + this.uri = uri; + this.apply = this.createApplyMethod(); +} + +/** + * JSON-RPC request counter. + */ +HTTPBindingClient.jsonrpcID = 1; + +/** + * HTTPBindingClient implementation + */ + +/** + * Generate client proxy apply method. + */ +HTTPBindingClient.prototype.createApplyMethod = function() { + var fn = function() { + var methodName = arguments[0]; + var args = []; + for(var i = 1; i < arguments.length; i++) + args.push(arguments[i]); + + var cb = null; + if (typeof args[args.length - 1] == "function") + cb = args.pop(); + + var req = HTTPBindingClient.makeJSONRequest(methodName, args, cb); + return fn.client.jsonApply(req); + }; + fn.client = this; + return fn; +}; + +/** + * Make a JSON-RPC request. + */ +HTTPBindingClient.makeJSONRequest = function(methodName, args, cb) { + var req = {}; + req.id = HTTPBindingClient.jsonrpcID++; + if (cb) + req.cb = cb; + var obj = {}; + obj.id = req.id; + obj.method = methodName; + obj.params = args; + req.data = JSONClient.toJSON(obj); + return req; +}; + +/** + * Return the JSON result from an XMLHttpRequest. + */ +HTTPBindingClient.jsonResult = function(http) { + // Get the charset + function httpCharset(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"; + } + if(!HTTPBindingClient.charset) + HTTPBindingClient.charset = httpCharset(http); + + // Unmarshall the JSON response + var obj; + eval("obj = " + http.responseText); + if(obj.error) + throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg); + var res = obj.result; + return res; +}; + +/** + * Apply a function remotely using JSON-RPC. + */ +HTTPBindingClient.prototype.jsonApply = function(req) { + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + var hascb = req.cb? true : false; + http.open("POST", this.uri, hascb); + http.setRequestHeader("Accept", "*/*"); + http.setRequestHeader("Content-Type", "application/json-rpc"); + + // Construct call back if we have one + if(hascb) { + http.onreadystatechange = function() { + if(http.readyState == 4) { + // Pass the result or exception + if(http.status == 200) { + var res = null; + try { + res = HTTPBindingClient.jsonResult(http); + try { + req.cb(res); + } catch(cbe) {} + } catch(e) { + try { + req.cb(null, e); + } catch(cbe) {} + } + } else + try { + req.cb(null, HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + }; + + // Send the request + http.send(req.data); + return req.id; + } + + // Send the request and return the result or exception + http.send(req.data); + if (http.status == 200) + return HTTPBindingClient.jsonResult(http); + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + + +/** + * REST GET method. + */ +HTTPBindingClient.prototype.get = function(id, cb) { + var u = id? (this.uri? this.uri + '/' + id : id) : this.uri; + var hascb = cb? true : false; + + // Get from local storage first + var ls = window.lstorage || localStorage; + var item = null; + try { item = ls.getItem(u); } catch(e) {} + //log('localStorage.getItem', u, item); + if (item != null && item != '') { + if (!hascb) + return item; + + // Pass local result to callback + try { + cb(item); + } catch (cbe) {} + } + + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + http.open("GET", u, hascb); + http.setRequestHeader("Accept", "*/*"); + + // Construct call back if we have one + if (hascb) { + http.onreadystatechange = function() { + //log('readystate', http.readyState, 'status', http.status, 'headers', http.getAllResponseHeaders()); + if (http.readyState == 4) { + // Pass result if different from local result + if (http.status == 200) { + + if (http.getResponseHeader("X-Login") != null) { + // Detect redirect to a login page + try { + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + return cb(null, le); + } catch(cbe) {} + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + // Report empty response + try { + return cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); + } catch(cbe) {} + + } else { + if (item == null || http.responseText != item) { + // Store retrieved entry in local storage + if (http.responseText != null) { + //log('localStorage.setItem', u, http.responseText); + try { ls.setItem(u, http.responseText); } catch(e) {} + } + try { + return cb(http.responseText); + } catch(cbe) {} + } + } + } + else { + // Pass exception if we didn't have a local result + if (item == null) { + try { + return cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + } + } + }; + + // Send the request + http.send(null); + return true; + } + + // Send the request and return the result or exception + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + + // Detect redirect to a login page + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + throw le; + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + + // Report empty response + throw new HTTPBindingClient.Exception(403, 'No-Content'); + } + return http.responseText; + } + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + +/** + * REST GET method, does not use the local cache. + */ +HTTPBindingClient.prototype.getnocache = function(id, cb) { + var u = id? (this.uri? this.uri + '/' + id : id) : this.uri; + var hascb = cb? true : false; + + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + http.open("GET", u, hascb); + http.setRequestHeader("Accept", "*/*"); + + // Construct call back if we have one + if (hascb) { + http.onreadystatechange = function() { + if (http.readyState == 4) { + if (http.status == 200) { + + if (http.getResponseHeader("X-Login") != null) { + // Detect redirect to a login page + try { + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + return cb(null, le); + } catch(cbe) {} + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + // Report empty response + try { + return cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); + } catch(cbe) {} + + } else { + try { + return cb(http.responseText); + } catch(cbe) {} + } + } else { + try { + return cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + } + }; + + // Send the request + http.send(null); + return true; + } + + // Send the request and return the result or exception + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + + // Detect redirect to a login page + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + throw le; + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + + // Report empty response + throw new HTTPBindingClient.Exception(403, 'No-Content'); + } + return http.responseText; + } + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + +/** + * REST POST method. + */ +HTTPBindingClient.prototype.post = function (entry, cb) { + + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + var hascb = cb? true : false; + http.open("POST", this.uri, hascb); + http.setRequestHeader("Accept", "*/*"); + http.setRequestHeader("Content-Type", "application/atom+xml"); + + // Construct call back if we have one + if (hascb) { + http.onreadystatechange = function() { + // Pass the result or exception + if (http.readyState == 4) { + if (http.status == 201) { + try { + cb(http.responseText); + } catch(cbe) {} + } + else { + try { + cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + } + }; + // Send the request + http.send(entry); + return true; + } + + // Send the request and return the result or exception + http.send(entry); + if (http.status == 201) + return http.responseText; + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + +/** + * REST PUT method. + */ +HTTPBindingClient.prototype.put = function (id, entry, cb) { + var u = this.uri + '/' + id; + + // Update local storage + var ls = window.lstorage || localStorage; + try { ls.setItem(u, entry); } catch(e) {} + //log('localStorage.setItem', u, entry); + + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + var hascb = cb? true : false; + http.open("PUT", u, hascb); + http.setRequestHeader("Accept", "*/*"); + http.setRequestHeader("Content-Type", "application/atom+xml"); + + // Construct call back if we have one + if (hascb) { + http.onreadystatechange = function() { + if (http.readyState == 4) { + // Pass any exception + if (http.status == 200) { + try { + cb(); + } catch(cbe) {} + } else { + try { + cb(new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + } + }; + // Send the request + http.send(entry); + return true; + } + + // Send the request and return any exception + http.send(entry); + if (http.status == 200) + return true; + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + +/** + * REST DELETE method. + */ +HTTPBindingClient.prototype.del = function (id, cb) { + var u = this.uri + '/' + id; + + // Update local storage + var ls = window.lstorage || localStorage; + try { ls.removeItem(u); } catch(e) {} + //log('localStorage.removeItem', u); + + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + var hascb = cb? true : false; + http.open("DELETE", u, hascb); + http.setRequestHeader("Accept", "*/*"); + + // Construct call back if we have one + if (cb) { + http.onreadystatechange = function() { + if (http.readyState == 4) { + // Pass any exception + if (http.status == 200) { + try { + cb(); + } catch(cbe) {} + } + else { + try { + cb(new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + } + }; + // Send the request + http.send(null); + return true; + } + + // Send the request and return any exception + http.send(null); + if (http.status == 200) + return true; + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + +/** + * HTTPBindingClient exceptions. + */ +HTTPBindingClient.Exception = function(code, message) { + this.name = "HTTPBindingClientException"; + this.code = code; + this.message = message; +}; + +HTTPBindingClient.Exception.prototype = new Error(); + +HTTPBindingClient.Exception.prototype.toString = function() { + return this.name + ": " + this.message; +}; + +/** + * XMLHttpRequest wrapper. + */ +HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" ]; + +HTTPBindingClient.getHTTPRequest = function() { + if (HTTPBindingClient.httpFactory) + return HTTPBindingClient.httpFactory(); + + // Mozilla XMLHttpRequest + try { + HTTPBindingClient.httpFactory = function() { + return new XMLHttpRequest(); + }; + return HTTPBindingClient.httpFactory(); + } catch(e) {} + + // Microsoft MSXML ActiveX + for (var i = 0; i < HTTPBindingClient.msxmlNames.length; i++) { + try { + HTTPBindingClient.httpFactory = function() { + return new ActiveXObject(HTTPBindingClient.msxmlNames[i]); + }; + return HTTPBindingClient.httpFactory(); + } catch (e) {} + } + + // Can't create XMLHttpRequest + HTTPBindingClient.httpFactory = null; + throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object"); +}; + +/** + * Public API. + */ + +var sca = {}; + +/** + * Return an HTTP client proxy. + */ +sca.httpclient = function(name, uri, domain) { + return new HTTPBindingClient(name, uri, domain); +}; + +/** + * Return a component proxy. + */ +sca.component = function(name, domain) { + if (!domain) + return new HTTPBindingClient(name, '/c/' + name, domain); + return new HTTPBindingClient(name, '/' + domain + '/c/' + name, domain); +}; + +/** + * Return a reference proxy. + */ +sca.reference = function(comp, rname) { + if (!comp.domain) + return new HTTPBindingClient(comp.name + '/' + rname, '/r/' + comp.name + '/' + rname, comp.domain); + return new HTTPBindingClient(comp.name + '/' + rname, '/' + comp.domain + '/r/' + comp.name + '/' + rname, comp.domain); +}; + +/** + * 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/sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js new file mode 100644 index 0000000000..37d641f7b3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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) { + return (!(!isList(v) || isNil(v) || car(v) != element)); +} + +/** + * Return true if a value is an attribute. + */ +function isAttribute(v) { + return (!(!isList(v) || isNil(v) || car(v) != attribute)); +} + +/** + * Return the name of an attribute. + */ +attributeName = cadr; + +/** + * Return the value of an attribute. + */ +attributeValue = caddr; + +/** + * Return the name of an element. + */ +elementName = cadr; + +/** + * Return true if an element has children. + */ +function elementHasChildren(l) { + return !isNil(cddr(l)); +} + +/** + * Return the children of an element. + */ +elementChildren = cddr; + +/** + * Return true if an element has a value. + */ +function elementHasValue(l) { + var r = reverse(l); + if (isSymbol(car(r))) + return false; + return (!(isList(car(r)) && !isNil(car(r)) && isSymbol(car(car(r))))) +} + +/** + * 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) { + return (!(!isList(v)) || isNil(v) || !isSymbol(car(v))); +} + +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(2), 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 attribute with the given name. + */ +function namedAttribute(name, l) { + return memo(l, name, function() { + var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l); + if (isNil(f)) + return null; + return car(f); + }); +} + +/** + * Return the value of the attribute with the given name. + */ +function namedAttributeValue(name, l) { + var a = namedAttribute(name, l); + if (a == null) + return null + return attributeValue(a); +} + +/** + * Return child elements with the given name. + */ +function namedElementChildren(name, l) { + return memo(l, name, function() { + 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); +} + +/** + * Side effect functions. Use with moderation. + */ + +/** + * Set the contents of an element. + */ +function setElement(l, e) { + setlist(l, e); + l.memo = {}; +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js new file mode 100644 index 0000000000..8aa291bc89 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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. + */ +var json = {}; + +/** + * JSON exceptions. + */ +json.Exception = function(code, message) { + this.name = "JSONException"; + this.code = code; + this.message = message; +}; + +json.Exception.prototype = new Error(); + +json.Exception.prototype.toString = function() { + return this.name + ": " + this.message; +}; + +/** + * Return true if a list represents a JS array. + */ +json.isJSArray = function(l) { + if (isNil(l)) + return true; + var v = car(l); + if (isSymbol(v)) + return false; + if (isList(v)) + if (!isNil(v) && isSymbol(car(v))) + return false; + return true; +}; + +/** + * Converts JSON properties to values. + */ +json.jsPropertiesToValues = function(propertiesSoFar, o, i) { + if (isNil(i)) + return propertiesSoFar; + var p = car(i); + var jsv = o[p]; + var v = json.jsValToValue(jsv); + + if (typeof p == 'string') { + var n = '' + p; + if (n.slice(0, 1) == '@') + return json.jsPropertiesToValues(cons(mklist(attribute, "'" + n.slice(1), v), propertiesSoFar), o, cdr(i)); + if (isList(v) && !json.isJSArray(v)) + return json.jsPropertiesToValues(cons(cons(element, cons("'" + n, v)), propertiesSoFar), o, cdr(i)); + return json.jsPropertiesToValues(cons(mklist(element, "'" + n, v), propertiesSoFar), o, cdr(i)); + } + return json.jsPropertiesToValues(cons(v, propertiesSoFar), o, cdr(i)); +}; + +/** + * Converts a JSON val to a value. + */ +json.jsValToValue = function(jsv) { + if (jsv == null) + return null; + if (isList(jsv)) + return json.jsPropertiesToValues(mklist(), jsv, reverse(range(0, jsv.length))); + if (typeof jsv == 'object') + return json.jsPropertiesToValues(mklist(), jsv, reverse(properties(jsv))); + if (typeof jsv == 'string') + return '' + jsv; + return jsv; +} + +/** + * Return true if a list of strings contains a JSON document. + */ +json.isJSON = function(l) { + if (isNil(l)) + return false; + var s = car(l).slice(0, 1); + return s == "[" || s == "{"; +}; + +/** + * Convert a list of strings representing a JSON document to a list of values. + */ +json.readJSON = function(l) { + var s = writeStrings(l); + var obj; + eval('obj = { \"val\": ' + s + " }"); + return json.jsValToValue(obj.val); +}; + +/** + * Convert a list of values to JSON array elements. + */ +json.valuesToJSElements = function(a, l, i) { + if (isNil(l)) + return a; + var pv = json.valueToJSVal(car(l)); + a[i] = pv + return json.valuesToJSElements(a, cdr(l), i + 1); +}; + +/** + * Convert a value to a JSON value. + */ +json.valueToJSVal = function(v) { + if (!isList(v)) + return v; + if (json.isJSArray(v)) + return json.valuesToJSElements(range(0, v.length), v, 0); + return json.valuesToJSProperties({}, v); +}; + +/** + * Convert a list of values to JSON properties. + */ +json.valuesToJSProperties = function(o, l) { + if (isNil(l)) + return o; + var token = car(l); + if (isTaggedList(token, attribute)) { + var pv = json.valueToJSVal(attributeValue(token)); + o['@' + attributeName(token).slice(1)] = pv; + } else if (isTaggedList(token, element)) { + if (elementHasValue(token)) { + var pv = json.valueToJSVal(elementValue(token)); + o[elementName(token).slice(1)] = pv; + } else { + var child = {}; + o[elementName(token).slice(1)] = child; + json.valuesToJSProperties(child, elementChildren(token)); + } + } + return json.valuesToJSProperties(o, cdr(l)); +}; + +/** + * Convert a list of values to a list of strings representing a JSON document. + */ +json.writeJSON = function(l) { + var jsv; + if (json.isJSArray(l)) + jsv = json.valuesToJSElements(range(0, l.length), l, 0); + else + jsv = json.valuesToJSProperties({}, l); + var s = json.toJSON(jsv); + return mklist(s); +} + +/** + * Convert a list + params to a JSON-RPC request. + */ +json.jsonRequest = function(id, func, params) { + var r = mklist(mklist("'id", id), mklist("'method", func), mklist("'params", params)); + return json.writeJSON(valuesToElements(r)); +}; + +/** + * Convert a value to a JSON-RPC result. + */ +json.jsonResult = function(id, val) { + return json.writeJSON(valuesToElements(mklist(mklist("'id", id), mklist("'result", val)))); +}; + +/** + * Convert a JSON-RPC result to a value. + */ +json.jsonResultValue = function(s) { + var jsres = json.readJSON(s); + var res = elementsToValues(jsres); + var val = cadr(assoc("'result", res)); + if (isList(val) && !json.isJSArray(val)) + return mklist(val); + return val; +}; + +/** + * Escape a character. + */ +json.escapeJSONChar = function(c) { + if(c == "\"" || c == "\\") return "\\" + c; + if (c == "\b") return "\\b"; + if (c == "\f") return "\\f"; + if (c == "\n") return "\\n"; + if (c == "\r") return "\\r"; + if (c == "\t") return "\\t"; + var hex = c.charCodeAt(0).toString(16); + if(hex.length == 1) return "\\u000" + hex; + if(hex.length == 2) return "\\u00" + hex; + if(hex.length == 3) return "\\u0" + hex; + return "\\u" + hex; +}; + +/** + * Encode a string into JSON format. + */ +json.escapeJSONString = function(s) { + // The following should suffice but Safari's regex is broken (doesn't support callback substitutions) + // return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, json.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] = json.escapeJSONChar(parts[i]); + } + return "\"" + parts.join("") + "\""; +}; + +/** + * Marshall objects to JSON format. + */ +json.toJSON = function(o) { + if(o == null) + return "null"; + if(o.constructor == String) + return json.escapeJSONString(o); + if(o.constructor == Number) + return o.toString(); + if(o.constructor == Boolean) + return o.toString(); + if(o.constructor == Date) + return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; + if(o.constructor == Array) { + var v = []; + for(var i = 0; i < o.length; i++) + v.push(json.toJSON(o[i])); + return "[" + v.join(", ") + "]"; + } + var v = []; + for(attr in o) { + if(o[attr] == null) + v.push("\"" + attr + "\": null"); + else if(typeof o[attr] == "function") + ; // Skip + else + v.push(json.escapeJSONString(attr) + ": " + json.toJSON(o[attr])); + } + return "{" + v.join(", ") + "}"; +}; + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js new file mode 100644 index 0000000000..50dab53e7c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 = {}; + +/** + * Returns a composite element. + */ +scdl.composite = function(l) { + var cs = namedElementChildren("'composite", l); + if (isNil(cs)) + return cs; + return car(cs); +}; + +/** + * 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 a list of service promotions in a composite. + */ +scdl.promotions = function(l) { + var cs = namedElementChildren("'composite", l); + if (isNil(cs)) + return cs; + return namedElementChildren("'service", car(cs)); +}; + +/** + * Returns the target of a service promotion. + */ +scdl.promote = function(l) { + var puri = namedAttributeValue("'promote", l); + if (isNil(puri)) + return puri; + return car(tokens(puri)); +}; + +/** + * Returns the name of a component, componentType, service or reference. + */ +scdl.name = function(l) { + return namedAttributeValue("'name", l); +}; + +/** + * Returns the description of a component, componentType, service or reference. + */ +scdl.documentation = function(l) { + var d = namedElementChildren("'documentation", l); + if (isNil(d)) + return null; + if (!elementHasValue(car(d))) + return null; + var v = elementValue(car(d)); + return v; +}; + +/** + * Returns the title of a component or componentType. + */ +scdl.title = function(l) { + return namedAttributeValue("'title", l); +}; + +/** + * Returns the display style of a component, componentType, reference or property. + */ +scdl.style = function(l) { + return namedAttributeValue("'style", l); +}; + +/** + * Returns the color of a component or componentType. + */ +scdl.color = function(l) { + return namedAttributeValue("'color", l); +}; + +/** + * Returns the x position of a component. + */ +scdl.x = function(l) { + return namedAttributeValue("'x", l); +}; + +/** + * Returns the y position of a component. + */ +scdl.y = function(l) { + return namedAttributeValue("'y", 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 a component or componentType 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 the visible attribute of a service or reference. + */ +scdl.visible = function(l) { + return namedAttributeValue("'visible", l); +}; + +/** + * Returns the clonable attribute of a reference. + */ +scdl.clonable = function(l) { + return namedAttributeValue("'clonable", l); +}; + +/** + * Returns a list of services in a component or componentType. + */ +scdl.services = function(l) { + return namedElementChildren("'service", l); +}; + +/** + * Returns a list of references in a component or componentType. + */ +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 = scdl.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 or componentType. + */ +scdl.properties = function(l) { + return namedElementChildren("'property", l); +}; + +/** + * Returns the value of a property. + */ +scdl.propertyValue = function(l) { + if (!elementHasValue(l)) + return ''; + 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/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css new file mode 100644 index 0000000000..ddc21b2095 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css @@ -0,0 +1,709 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 { +margin-top: 0px; margin-bottom: 2px; margin-left: 2px; margin-right: 2px; +font-family: Arial; font-style: normal; font-variant: normal; font-size: 14px; +background-color: #ffffff; opacity: 1; +-webkit-text-size-adjust: none; +-webkit-touch-callout: none; +-webkit-tap-highlight-color: rgba(0,0,0,0); +-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; +cursor: default; +-webkit-backface-visibility: hidden; +} + +.delayed { +visibility: hidden; +} + +.fixed { +position: fixed; +} + +.devicewidth { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +} + +.mainbody { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible; +-webkit-backface-visibility: hidden; +} + +.viewcontainer3dm { +position: absolute; left: 0px; top: 35px; width: 100%; +-webkit-backface-visibility: hidden; +} + +.viewcontainer3d { +position: absolute; left: 0px; top: 35px; width: 100%; +-webkit-backface-visibility: hidden; +} + +.leftviewloading3dm { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +z-index: -10; background-color: #ffffff; +-webkit-transform: translate(100%, 0px); +-moz-transform: translate(100%, 0px); +-ms-transform: translate(100%, 0px); +-o-transform: translate(100%, 0px); +transform: translate(100%, 0px); +-webkit-backface-visibility: hidden; +} + +.rightviewloading3dm { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +z-index: -10; background-color: #ffffff; +-webkit-transform: translate(-100%, 0px); +-moz-transform: translate(-100%, 0px); +-ms-transform: translate(-100%, 0px); +-o-transform: translate(-100%, 0px); +transform: translate(-100%, 0px); +-webkit-backface-visibility: hidden; +} + +.viewloading3d { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +visibility: hidden; z-index: -10; background-color: #ffffff; +-webkit-transform: translate(100%, 0px); +-moz-transform: translate(100%, 0px); +-ms-transform: translate(100%, 0px); +-o-transform: translate(100%, 0px); +transform: translate(100%, 0px); +-webkit-backface-visibility: hidden; +} + +.viewloaded3dm { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible; +z-index: 0; background-color: #ffffff; +-webkit-transition: -webkit-transform 0.4s ease-in-out; +-moz-transition: -moz-transform 0.4s ease-in-out; +-ms-transition: -ms-transform 0.4s ease-in-out; +-o-transition: -o-transform 0.4s ease-in-out; +transition: transform 0.4s ease-in-out; +-webkit-transform: translate(0px, 0px); +-moz-transform: translate(0px, 0px); +-ms-transform: translate(0px, 0px); +-o-transform: translate(0px, 0px); +transform: translate(0px, 0px); +-webkit-backface-visibility: hidden; +} + +.viewloaded3d { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible; +z-index: 0; background-color: #ffffff; +-webkit-transform: translate(0px, 0px); +-moz-transform: translate(0px, 0px); +-ms-transform: translate(0px, 0px); +-o-transform: translate(0px, 0px); +transform: translate(0px, 0px); +-webkit-backface-visibility: hidden; +} + +.viewunloading3dm { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +z-index: 0; background-color: #ffffff; +-webkit-transform: translate(0px, 0px); +-moz-transform: translate(0px, 0px); +-ms-transform: translate(0px, 0px); +-o-transform: translate(0px, 0px); +transform: translate(0px, 0px); +-webkit-backface-visibility: hidden; +} + +.leftviewunloaded3dm { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +z-index: -10; background-color: #ffffff; +-webkit-transition: -webkit-transform 0.4s ease-in-out; +-moz-transition: -moz-transform 0.4s ease-in-out; +-ms-transition: -ms-transform 0.4s ease-in-out; +-o-transition: -o-transform 0.4s ease-in-out; +transition: transform 0.4s ease-in-out; +-webkit-transform: translate(-100%, 0px); +-moz-transform: translate(-100%, 0px); +-ms-transform: translate(-100%, 0px); +-o-transform: translate(-100%, 0px); +transform: translate(-100%, 0px); +-webkit-backface-visibility: hidden; +} + +.rightviewunloaded3dm { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +z-index: -10; background-color: #ffffff; +-webkit-transition: -webkit-transform 0.4s ease-in-out; +-moz-transition: -moz-transform 0.4s ease-in-out; +-ms-transition: -ms-transform 0.4s ease-in-out; +-o-transition: -o-transform 0.4s ease-in-out; +transition: transform 0.4s ease-in-out; +-webkit-transform: translate(100%, 0px); +-moz-transform: translate(100%, 0px); +-ms-transform: translate(100%, 0px); +-o-transform: translate(100%, 0px); +transform: translate(100%, 0px); +-webkit-backface-visibility: hidden; +} + +.body { +width: 100%; height: 5000px; overflow: visible; +-webkit-backface-visibility: hidden; +} + +.viewhead { +position: absolute; left: 0px; top: 35px; height: 35px; line-height: 35px; width: 100%; z-index: 8; +font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; +overflow: hidden; +-webkit-backface-visibility: hidden; +} + +.viewheadbackground { +position: absolute; left: 0px; top: 35px; height: 35px; line-height: 35px; width: 2500px; z-index: 7; +background-color: #f1f1f1; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; +overflow: hidden; +-webkit-backface-visibility: hidden; +} + +.viewfoot { +position: absolute; left: 0px; bottom: 0px; height: 25px; line-height: 25px; width: 100%; z-index: 8; +font-size: 12px; background-color: #ffffff; color: #404040; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff; +overflow: hidden; +-webkit-backface-visibility: hidden; +} + +.status { +position: absolute; left: 0px; bottom: 0px; height: 35px; line-height: 35px; width: 100%; z-index: 9; +font-size: 12px; background-color: #ffffff; color: #404040; +border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff; +overflow: hidden; +-webkit-transform: translate(0px, 0px); +-moz-transform: translate(0px, 0px); +-ms-transform: translate(0px, 0px); +-o-transform: translate(0px, 0px); +transform: translate(0px, 0px); +-webkit-backface-visibility: hidden; +} + +.statusout3 { +position: absolute; left: 0px; bottom: 0px; height: 35px; line-height: 35px; width: 100%; z-index: 9; +font-size: 12px; background-color: #ffffff; color: #404040; +border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff; +overflow: hidden; +-webkit-transition: -webkit-transform 0.4s ease-in-out 3s; +-moz-transition: -moz-transform 0.4s ease-in-out 3s; +-ms-transition: -ms-transform 0.4s ease-in-out 3s; +-o-transition: -o-transform 0.4s ease-in-out 3s; +transition: transform 0.4s ease-in-out 3s; +-webkit-transform: translate(0px, 35px); +-moz-transform: translate(0px, 35px); +-ms-transform: translate(0px, 35px); +-o-transform: translate(0px, 35px); +transform: translate(0px, 35px); +-webkit-backface-visibility: hidden; +} + +.statusout1 { +position: absolute; left: 0px; bottom: 0px; height: 35px; line-height: 35px; width: 100%; z-index: 9; +font-size: 12px; background-color: #ffffff; color: #404040; +border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff; +overflow: hidden; +-webkit-transition: -webkit-transform 0.4s ease-in-out 1s; +-moz-transition: -moz-transform 0.4s ease-in-out 1s; +-ms-transition: -ms-transform 0.4s ease-in-out 1s; +-o-transition: -o-transform 0.4s ease-in-out 1s; +transition: transform 0.4s ease-in-out 1s; +-webkit-transform: translate(0px, 35px); +-moz-transform: translate(0px, 35px); +-ms-transform: translate(0px, 35px); +-o-transform: translate(0px, 35px); +transform: translate(0px, 35px); +-webkit-backface-visibility: hidden; +} + +.okstatus { +font-size: 110%; font-weight: bold; padding-left: 6px; padding-right: 6px; white-space: nowrap; text-decoration: none; +background-color: #f1f1f1; color: #000000; +width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right; +} + +.errorstatus { +font-size: 110%; font-weight: bold; padding-left: 6px; padding-right: 6px; white-space: nowrap; text-decoration: none; +background-color: #d14836; color: #ffffff; +width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right; +} + +.viewfootbackground { +position: absolute; left: 0px; bottom: 0px; height: 25px; line-height: 25px; width: 2500px; z-index: 7; +background-color: #ffffff; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; +border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff; +overflow: hidden; +-webkit-backface-visibility: hidden; +} + +.viewcontent { +position: absolute; left: 0px; top: 38px; width: 100%; +-webkit-backface-visibility: hidden; +} + +.viewform { +position: absolute; left: 0px; top: 40px; width: 100%; +} + +table { +border: 0px; border-collapse: collapse; border-color: #a2bae7; border-style: solid; +font-family: Arial; font-style: normal; font-variant: normal; font-size: 14px; +overflow: visible; +} + +.trb { +border-bottom: 1px; border-bottom-style: solid; border-color: #dcdcdc; +} + +th { +font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000; +text-align: left; padding-left: 2px; padding-right: 8px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; white-space: nowrap; +border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px; border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; border-left-color: #e5e5e5; border-right-color: #e5e5e5; +overflow: hidden; +} + +.section { +font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000; height: 30px; line-height: 30px; +text-align: left; padding-top: 0px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; white-space: nowrap; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; border-left-color: #e5e5e5; border-right-color: #e5e5e5; +overflow: hidden; +} + +.hsection { +width: 100%; height: 0px; visibility: hidden; +border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border-style: solid; border-bottom-color: #000000; background-color: #ffffff; +padding-left: 2px; padding-right: 2px; padding-top: 0px; padding-bottom: 0px; margin-bottom: 0px; margin-left: auto; margin-right: auto; text-align: center; +} + +.fsection{ +width: 100%; height: 0px; visibility: hidden; +border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #a2bae7; +padding: 0px; margin-top: 0px; margin-left: auto; margin-right: auto; text-align: center; +} + +.bluetext { +color: #4787ed; +} + +.redtext { +color: #d14836; +} + +.mirror { +display: inline-block; +-webkit-transform: scaleX(-1); +-moz-transform: scaleX(-1); +-ms-transform: scaleX(-1); +-o-transform: scaleX(-1); +transform: scaleX(-1); +} + +.greentext { +color: #009900; +} + +.text { +padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap; +} + +.link { +padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap; +} + +.checkbox { +padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap; +} + +.thl { +border-left: 0px; +} + +.thr { +border-right: 0px; +} + +.ths { +padding: 0px; +} + +td { +padding-left: 2px; padding-top: 2px; padding-right: 8px; white-space: nowrap; vertical-align: middle; border: 0px; +} + +.tdl { +border-right: 1px; border-style: solid; border-color: #a2bae7; width: 10px; +} + +.tdr { +border-left: 1px; border-style: solid; border-color: #a2bae7; +} + +.tdw { +padding-left: 2px; padding-top: 2px; padding-right: 8px; white-space: normal; vertical-align: middle; +} + +.datatd { +border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; width: 10px; vertical-align: middle; +} + +.datatdl { +border-right: 1px; border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; width: 10px; vertical-align: middle; +} + +.datatdltop { +border-right: 1px; border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; width: 10px; vertical-align: top; +} + +.datatdr { +border-left: 1px; border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; vertical-align: middle; +} + +.datatable { +border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; +overflow: visible; +} + +.databg { +opacity: .6; +-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; +filter: alpha(opacity=60); +} + +.guide { +border: 1px; border-style: solid; border-color: #c0c0c0; +} + +iframe { +border: 0px; margin: 0px; padding: 0px; +} + +.fakeframe { +padding: 3px; background-color: #dcdcdc; color: #000000; +} + +input { +vertical-align: middle; +font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px; +outline: none; +-webkit-text-size-adjust: 100%; +} + +button { +vertical-align: middle; +font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px; +outline: none; +-webkit-text-size-adjust: 100%; +} + +textarea { +font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px; +outline: none; +overflow: auto; resize: none; +} + +.flatentry { +font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px; +-webkit-appearance: none; appearance: none; +border: 1px solid #d9d9d9!important; border-top: 1px solid silver!important; +box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; +border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px; +margin: 1px!important; padding: 3px 1px 3px 3px; +} + +.graphentry { +font-family: Arial; font-style: normal; font-variant: normal; font-size: 13px; +-webkit-appearance: none; appearance: none; +border: 1px solid #d9d9d9!important; border-top: 1px solid silver!important; +box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; +border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px; +margin: 0px; padding: 0px; +} + +.flatcheckbox { +} + +.editablewidget { +-webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; +outline: none; -moz-outline-style: none; +} + +.noneditablewidget { +outline: none; -moz-outline-style: none; +} + +.editablesvg { +background-color: transparent; +font-family: inherit; font-style: inherit; font-variant: inherit; font-size: inherit; font-weight: inherit; +padding: 0px; margin: 0px; +overflow: auto; resize: none; +outline: none; -moz-outline-style: none; +-webkit-appearance: none; -webkit-text-size-adjust: 100%; +border: 0px; +} + +a:link { +color: #357ae8; text-decoration: none; white-space: nowrap; cursor: pointer; +} + +a:visited { +color: #357ae8; text-decoration: none; white-space: nowrap; cursor: pointer; +} + +.tbarmenu { +position: absolute; top: 0px; left: 0px; z-index: 10; width: 100%; margin: 0px; padding: 0px; border-collapse: separate; +height: 35px; line-height: 35px; background-color: #2c2c2c; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #2c2c2c; border-bottom-color: #2c2c2c; +-webkit-backface-visibility: hidden; +} + +.tbarbackground { +position: absolute; top: 0px; left: 0px; z-index: 9; width: 2500px; margin: 0px; padding: 0px; border-collapse: separate; +height: 35px; line-height: 35px; background-color: #2c2c2c; +border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #2c2c2c; border-bottom-color: #2c2c2c; +overflow: hidden; +-webkit-backface-visibility: hidden; +} + +.tbarleft { +padding-left: 2px; padding-right: 6px; white-space: nowrap; float: left; +} + +.tbarright { +padding-left: 6px; padding-right: 2px; white-space: nowrap; float: right; +} + +.tbaramenu { +font-size: 110%; color: #cccccc; text-decoration: none; white-space: nowrap; +} + +.tbarsmenu { +font-size: 110%; font-weight: bold; color: #ffffff; text-decoration: none; white-space: nowrap; +} + +.amenu { +padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #808080; text-decoration: none; float: left; +} + +.smenu { +padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none; float: left; +} + +.cmenu { +font-size: 18px; padding-left: 6px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none; +width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right; +} + +.bcmenu { +font-size: 22px; padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none; +} + +.rmenu { +padding-left: 2px; padding-right: 2px; white-space: nowrap; white-space: nowrap; float: right; +} + +h1 { +font-size: 150%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; white-space: nowrap; +} + +h2 { +font-size: 120%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; white-space: nowrap; +} + +.hd1 { +font-size: 150%; font-weight: bold; white-space: nowrap; +} + +.hd2 { +font-size: 120%; font-weight: bold; white-space: nowrap; +} + +img { +border: 0px; +} + +.plusminus { +font-size: 18px; font-family: "Courier New"; +} + +.imgbutton { +width: 142px; height: 64px; margin-left: 20px; margin-right: 20px; padding: 0px; border: 1px; cursor: pointer; +} + +.graybutton { +display: inline-block; text-align: center; color: #444; font-weight: bold; +padding-top: 0px; padding-bottom: 0px; padding-left: 4px; padding-right: 4px; +height: 28px; line-height: 28px; min-width: 30px; +-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; +border: 1px solid gainsboro; background-color: whiteSmoke; +background-image: -webkit-gradient(linear,left top,left bottom,from(whiteSmoke),to(#f1f1f1)); +background-image: -webkit-linear-gradient(top,whiteSmoke,#f1f1f1); +background-image: -moz-linear-gradient(top,whiteSmoke,#f1f1f1); +background-image: -ms-linear-gradient(top,whiteSmoke,#f1f1f1); +background-image: -o-linear-gradient(top,whiteSmoke,#f1f1f1); +background-image: linear-gradient(top,whiteSmoke,#f1f1f1); +cursor: default; +} + +.graybutton:hover { +border: 1px solid #c6c6c6; color: #333; text-shadow: 0 1px rgba(0, 0, 0, 0.3); background-color: #f8f8f8; +background-image: -webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f1f1f1)); +background-image: -webkit-linear-gradient(top,#f8f8f8,#f1f1f1); +background-image: -moz-linear-gradient(top,#f8f8f8,#f1f1f1); +background-image: -ms-linear-gradient(top,#f8f8f8,#f1f1f1); +background-image: -o-linear-gradient(top,#f8f8f8,#f1f1f1); +background-image: linear-gradient(top,#f8f8f8,#f1f1f1); +} + +.graybutton:active { +background-color: #f6f6f6; +background-image: -webkit-gradient(linear,left top,left bottom,from(#f6f6f6),to(#f1f1f1)); +background-image: -webkit-linear-gradient(top,#f6f6f6,#f1f1f1); +background-image: -moz-linear-gradient(top,#f6f6f6,#f1f1f1); +background-image: -ms-linear-gradient(top,#f6f6f6,#f1f1f1); +background-image: -o-linear-gradient(top,#f6f6f6,#f1f1f1); +background-image: linear-gradient(top,#f6f6f6,#f1f1f1); +-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.graybutton:disabled { +color: #c0c0c0; +} + +.bluebutton { +border: 1px solid #3079ed; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.1); background-color: #4d90fe; +background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed)); +background-image: -webkit-linear-gradient(top,#4d90fe,#4787ed); +background-image: -moz-linear-gradient(top,#4d90fe,#4787ed); +background-image: -ms-linear-gradient(top,#4d90fe,#4787ed); +background-image: -o-linear-gradient(top,#4d90fe,#4787ed); +background-image: linear-gradient(top,#4d90fe,#4787ed); +} + +.bluebutton:disabled { +color: #c0c0c0; +} + +.bluebutton:hover { +border: 1px solid #2f5bb7; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.3); background-color: #357ae8; +background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8)); +background-image: -webkit-linear-gradient(top,#4d90fe,#357ae8); +background-image: -moz-linear-gradient(top,#4d90fe,#357ae8); +background-image: -ms-linear-gradient(top,#4d90fe,#357ae8); +background-image: -o-linear-gradient(top,#4d90fe,#357ae8); +background-image: linear-gradient(top,#4d90fe,#357ae8); +} + +.bluebutton:hover:disabled { +color: #c0c0c0; +} + +.redbutton { +border: 1px solid transparent; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.1); background-color: #d14836; +background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836)); +background-image: -webkit-linear-gradient(top,#dd4b39,#d14836); +background-image: -moz-linear-gradient(top,#dd4b39,#d14836); +background-image: -ms-linear-gradient(top,#dd4b39,#d14836); +background-image: -o-linear-gradient(top,#dd4b39,#d14836); +background-image: linear-gradient(top,#dd4b39,#d14836); +-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -ms-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); +-o-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); +} + +.redbutton:disabled { +color: #c0c0c0; +} + +.redbutton:hover { +border: 1px solid #b0281a; border-bottom-color: #af301f; color: white; background-color: #c53727; +background-image: -webkit-linear-gradient(top,#dd4b39,#c53727); +background-image: -moz-linear-gradient(top,#dd4b39,#c53727); +background-image: -ms-linear-gradient(top,#dd4b39,#c53727); +background-image: -o-linear-gradient(top,#dd4b39,#c53727); +background-image: linear-gradient(top,#dd4b39,#c53727); +-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -ms-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +-o-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} + +.redbutton:hover:disabled { +color: #c0c0c0; +} + +.box { +width: 150px; display: inline-block; +border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse; +white-space: nowrap; margin: 2px; padding: 2px; vertical-align: top; +} + +.appicon { +float: left; +height: 50px; width: 50px; vertical-align: top; margin: 0px; padding: 0px; +} + +.apptitle { +font-weight: bold; +} + +.note { +font-size: 12px; color: #808080; +} + +.pagediv { +position: absolute; display: block; overflow: visible; +-webkit-backface-visibility: hidden; +} + +.graphdiv { +position: absolute; display: block; overflow: visible; +-webkit-backface-visibility: hidden; +} + +.g { +position: absolute; display: block; overflow: visible; +-webkit-backface-visibility: hidden; +} + +.path { +position: absolute; background: transparent; display: block; overflow: visible; +visibility: visible; +-webkit-backface-visibility: hidden; +} + +.gtitle { +position: absolute; +margin: 4px; padding: 0px; line-height: 15px; vertical-align: middle; white-space: nowrap; +font-family: Arial; font-style: normal; font-variant: normal; font-size: 13px; cursor: default; +background: transparent; display: block; overflow: visible; +-webkit-text-size-adjust: none; +-webkit-touch-callout: none; +-webkit-tap-highlight-color: rgba(0,0,0,0); +-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js new file mode 100644 index 0000000000..fb53598390 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js @@ -0,0 +1,409 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 = {}; + +/** + * Return a child element of a node with the given id. + */ +ui.elementByID = function(node, id) { + if (node.skipNode == true) + return null; + 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) + return document; + return ui.elementByID($(document), id); +}; + +/** + * Return a list of elements with the given class name. + */ +ui.elementsByClassName = function(node, c) { + return nodeList(node.getElementsByClassName(c)); +}; + +/** + * Return the query string of a URL. + */ +ui.query = function(url) { + var u = '' + url; + var q = u.indexOf('?'); + return q >= 0? u.substring(q + 1) : ''; +}; + +/** + * Return the fragment part of a URL. + */ +ui.fragment = function(url) { + var u = '' + url; + var h = u.indexOf('#'); + return h >= 0? u.substring(h + 1) : ''; +}; + +/** + * Return the path and parameters of a URL. + */ +ui.pathandparams = function(url) { + var u = '' + url; + var ds = u.indexOf('//'); + var u2 = ds > 0? u.substring(ds + 2) : u; + var s = u2.indexOf('/'); + return s > 0? u2.substring(s) : ''; +}; + +/** + * Return a dictionary of query parameters in a URL. + */ +ui.queryParams = function(url) { + var qp = new Array(); + var qs = ui.query(url).split('&'); + for (var i = 0; i < qs.length; i++) { + var e = qs[i].indexOf('='); + if (e > 0) + qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1)); + } + return qp; +}; + +/** + * Return a dictionary of fragment parameters in a URL. + */ +ui.fragmentParams = function(url) { + var qp = new Array(); + var qs = ui.fragment(url).split('&'); + for (var i = 0; i < qs.length; i++) { + var e = qs[i].indexOf('='); + if (e > 0) + qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1)); + } + return qp; +}; + +/** + * Convert a base64-encoded image to a data URL. + */ +ui.b64img = function(b64) { + return 'data:image/png;base64,' + b64; +}; + +/** + * Declare a CSS stylesheet. + */ +ui.declareCSS = function(s) { + var e = document.createElement('style'); + e.type = 'text/css'; + e.textContent = s; + return e; +}; + +/** + * Declare a script. + */ +ui.declareScript = function(s) { + var e = document.createElement('script'); + e.type = 'text/javascript'; + e.text = s; + return e; +}; + +/** + * Return the scripts elements under a given element. + */ +ui.innerScripts = function(e) { + return map(function(s) { return s.text; }, nodeList(e.getElementsByTagName('script'))); +}; + +/** + * Evaluate a script. + */ +ui.evalScript = function(s) { + return eval('(function() {\n' + s + '\n})();'); +}; + +/** + * Include a script. + */ +ui.includeScript = function(s) { + //log('include', s); + return eval(s); +}; + +/** + * Return true if the client is a mobile device. + */ +ui.mobiledetected = false; +ui.mobile = false; +ui.isMobile = function() { + if (ui.mobiledetected) + return ui.mobile; + var ua = navigator.userAgent; + if (ua.match(/iPhone/i) || ua.match(/iPad/i) || ua.match(/Android/i) || ua.match(/Blackberry/i) || ua.match(/WebOs/i)) + ui.mobile = true; + ui.mobiledetected = true; + return ui.mobile; +}; + +/** + * Convert a CSS position to a numeric position. + */ +ui.numpos = function(p) { + return p == ''? 0 : Number(p.substr(0, p.length - 2)); +}; + +/** + * Convert a numeric position to a CSS pixel position. + */ +ui.pixpos = function(p) { + return p + 'px'; +}; + +/** + * Default orientation change behavior. + */ +ui.onorientationchange = function(e) { + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + + // Change fixed position elements to absolute then back to fixed + // to make sure they're correctly layed out after the orientation + // change + map(function(e) { + e.style.position = 'absolute'; + return e; + }, ui.elementsByClassName(document, 'fixed')); + + setTimeout(function() { + map(function(e) { + e.style.position = 'fixed'; + return e; + }, ui.elementsByClassName(document, 'fixed')); + }, 0); + return true; +}; + +/** + * Default page load behavior. + */ +ui.onload = function() { + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + + // Initialize fixed position elements only after the page is loaded, + // to workaround layout issues with fixed position on mobile devices + setTimeout(function() { + map(function(e) { + e.style.position = 'fixed'; + return e; + }, ui.elementsByClassName(document, 'fixed')); + }, 0); + return true; +}; + +/** + * Navigate to a new document. + */ +ui.navigate = function(url, win) { + //log('navigate', url, win); + + // Open a new window + if (win == '_blank') { + window.top.open(url, win); + return false; + } + + // Open a new document in the current window + if (win == '_self') { + window.top.open(url, win); + return false; + } + + // Reload the current window + if (win == '_reload') { + window.top.location = url; + window.top.location.reload(); + return false; + } + + // Let the current top window handle the navigation + if (win == '_view') { + if (!window.top.onnavigate) + return window.top.open(url, '_self'); + window.top.onnavigate(url); + return false; + } + + window.top.open(url, win); + return false; +} + +/** + * Build a portable <a href> tag. + */ +ui.href = function(id, loc, target, html) { + if (target == '_blank') + return '<a id="' + id + '" href="' + loc + '" target="_blank">' + html + '</a>'; + return '<a id="' + id + '" href="' + loc + '" onclick="return ui.navigate(\'' + loc + '\', \'' + target + '\');">' + html + '</a>'; +}; + +/** + * Build a menu bar. + */ +ui.menu = function(id, name, href, target, hilight) { + function Menu() { + this.content = function() { + if (hilight == true) + return ui.href(id, href, target, '<span class="tbarsmenu">' + name + '</span>'); + else if (hilight == false) + return ui.href(id, href, target, '<span class="tbaramenu">' + name + '</span>'); + else + return ui.href(id, href, target, '<span class="' + hilight + '">' + name + '</span>'); + }; + } + return new Menu(); +}; + +ui.menufunc = function(id, name, fun, hilight) { + function Menu() { + this.content = function() { + function href(id, fun, html) { + return '<a id="' + id + '" href="/" onclick="' + fun + '">' + html + '</a>'; + } + + if (hilight == true) + return href(id, fun, '<span class="tbarsmenu">' + name + '</span>'); + else if (hilight == false) + return href(id, fun, '<span class="tbaramenu">' + name + '</span>'); + else + return href(id, fun, '<span class="' + hilight + '">' + name + '</span>'); + }; + } + return new Menu(); +}; + +ui.menubar = function(left, right) { + var bar = ''; + for (i in left) + bar = bar + '<span class="tbarleft">' + left[i].content() + '</span>'; + for (i in right) + bar = bar + '<span class="tbarright">' + right[i].content() + '</span>'; + return bar; +}; + +/** + * Convert a list of elements to an HTML table. + */ +ui.datatable = function(l) { + + function indent(i) { + if (i == 0) + return ''; + return ' ' + indent(i - 1); + } + + function rows(l, i) { + if (isNil(l)) + return ''; + var e = car(l); + + // Convert a list of simple values into a list of name value pairs + if (!isList(e)) + return rows(expandElementValues("'value", l), i); + + // Convert a list of complex values into a list of name value pairs + if (isList(car(e))) + return rows(expandElementValues("'value", l), i); + + // Generate table row for a simple element value + if (elementHasValue(e)) { + var v = elementValue(e); + if (!isList(v)) { + return '<tr><td class="datatdl">' + indent(i) + elementName(e).slice(1) + '</td>' + + '<td class="datatdr tdw">' + (v != null? v : '') + '</td></tr>' + + rows(cdr(l), i); + } + + return rows(expandElementValues(elementName(e), v), i) + rows(cdr(l), i); + } + + // Generate table row for an element with children + return '<tr><td class="datatdl">' + indent(i) + elementName(e).slice(1) + '</td>' + + '<td class="datatdr tdw">' + '</td></tr>' + + rows(elementChildren(e), i + 1) + + rows(cdr(l), i); + } + + return '<table class="datatable ' + (window.name == 'dataFrame'? ' databg' : '') + '" style="width: 100%;">' + rows(l, 0) + '</table>'; +} + +/** + * Convert a list of elements to an HTML single column table. + */ +ui.datalist = function(l) { + + function rows(l, i) { + if (isNil(l)) + return ''; + var e = car(l); + + // Convert a list of simple values into a list of name value pairs + if (!isList(e)) + return rows(expandElementValues("'value", l), i); + + // Convert a list of complex values into a list of name value pairs + if (isList(car(e))) + return rows(expandElementValues("'value", l), i); + + // Generate table row for a simple element value + if (elementHasValue(e)) { + var v = elementValue(e); + if (!isList(v)) { + return '<tr><td class="datatd tdw">' + (v != null? v : '') + '</td></tr>' + + rows(cdr(l), i); + } + + return rows(expandElementValues(elementName(e), v), i) + rows(cdr(l), i); + } + + // Generate rows for an element's children + return rows(elementChildren(e), i + 1) + rows(cdr(l), i); + } + + return '<table class="datatable ' + (window.name == 'dataFrame'? ' databg' : '') + '" style="width: 100%;">' + rows(l, 0) + '</table>'; +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js new file mode 100644 index 0000000000..0f7de94289 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js @@ -0,0 +1,471 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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) { + var a = new Array(); + a.push(car); + return a.concat(cdr); +} + +function car(l) { + return l[0]; +} + +function first(l) { + return l[0]; +} + +function cdr(l) { + return l.slice(1); +} + +function rest(l) { + return l.slice(1); +} + +function cadr(l) { + return l[1]; +} + +function cddr(l) { + return l.slice(2); +} + +function caddr(l) { + return l[2]; +} + +function cdddr(l) { + return l.slice(3); +} + +function cadddr(l) { + return l[3]; +} + +function append(a, b) { + return a.concat(b); +} + +function reverse(l) { + return l.slice(0).reverse(); +} + +function range(a, b) { + var l = new Array(); + for (var x = a; x < b; x++) + l.push(x); + return l; +} + +function isNil(v) { + return (v == null || typeof v == 'undefined' || (v.constructor == Array && v.length == 0)); +} + +function isSymbol(v) { + return (typeof v == 'string' && v.slice(0, 1) == "'"); +} + +function isString(v) { + return (typeof v == 'string' && v.slice(0, 1) != "'"); +} + +function isList(v) { + return (v != null && typeof v != 'undefined' && v.constructor == Array); +} + +function isTaggedList(v, t) { + return (isList(v) && !isNil(v) && car(v) == t); +} + +var emptylist = new Array(); + +function mklist() { + if (arguments.length == 0) + return emptylist; + 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 emptylist; + var n = l.length; + for(var i = 0; i < n; i++) { + if (k == car(l[i])) + return l[i]; + } + return emptylist; +} + +/** + * Map, filter and reduce functions. + */ +function map(f, l) { + if (isNil(l)) + return l; + var n = l.length; + var a = new Array(); + for(var i = 0; i < n; i++) { + a.push(f(l[i])); + } + return a; +} + +function filter(f, l) { + if (isNil(l)) + return l; + var n = l.length; + var a = new Array(); + for(var i = 0; i < n; i++) { + if (f(l[i])) + a.push(l[i]); + } + return a; +} + +function reduce(f, i, l) { + if (isNil(l)) + return i; + return reduce(f, f(i, car(l)), cdr(l)); +} + +/** + * Split a path into a list of segments. + */ +function tokens(path) { + return filter(function(s) { return length(s) != 0; }, path.split("/")); +} + +/** + * Debug log a value. + */ +var rconsole; + +function debug(v) { + try { + var s = ''; + for (i = 0; i < arguments.length; i++) { + s = s + writeValue(arguments[i]); + if (i < arguments.length) + s = s + ' '; + } + + if (rconsole) { + try { + rconsole.log(s); + } catch (e) {} + } + try { + console.log(s); + } catch (e) {} + } catch (e) {} + return true; +} + +/** + * Dump an object to the console. + */ +function dump(o) { + try { + for (f in o) { + try { + debug('dump ' + f + '=' + o[f]); + } catch (e) {} + } + } catch (e) {} + return true; +} + +/** + * Return true if the current browser is Internet Explorer. + */ +function isIE() { + if (typeof isIE.detected != 'undefined') + return isIE.detected; + isIE.detected = navigator.appName == 'Microsoft Internet Explorer'; + return isIE.detected; +}; + +/** + * External build configuration. + */ +var config; +if (isNil(config)) + config = {}; + +/** + * Simple assert function. + */ +function AssertException() { +} + +AssertException.prototype.toString = function () { + return 'AssertException'; +}; + +function assert(exp) { + if (!exp) + throw new AssertException(); +} + +/** + * Write a list of strings. + */ +function writeStrings(l) { + if (isNil(l)) + return ''; + var s = ''; + var n = l.length; + for(var i = 0; i < n; i++) { + s = s + l[i]; + } + return s; +} + +/** + * 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)) + ')'; +} + +/** + * Apply a function and memoize its result. + */ +function memo(obj, key, f) { + if (!('memo' in obj)) { + obj.memo = {}; + return obj.memo[key] = f(); + } + if (key in obj.memo) + return obj.memo[key]; + return obj.memo[key] = f(); +} + +/** + * Un-memoize stored results. + */ +function unmemo(obj) { + obj.memo = {}; + return true; +} + +/** + * Local storage. + */ +var lstorage = {}; +lstorage.enabled = true; + +/** + * Get an item. + */ +lstorage.getItem = function(k) { + if (!lstorage.enabled) + return null; + try { + return localStorage.getItem(k); + } catch(e) { + return null; + } +} + +/** + * Set an item. + */ +lstorage.setItem = function(k, v) { + if (!lstorage.enabled) + return null; + try { + return localStorage.setItem(k, v); + } catch(e) { + return null; + } +} + +/** + * Remove an item. + */ +lstorage.removeItem = function(k) { + if (!lstorage.enabled) + return null; + try { + return localStorage.removeItem(k); + } catch(e) { + return null; + } +} + +/** + * Returns a list of the properties of an object. + */ +function properties(o) { + var a = new Array(); + for (p in o) + a.push(p); + return a; +} + +/** + * Convert a host name to a domain name. + */ +function domainname(host) { + var ds = host.indexOf('//'); + if (ds != -1) + return domainname(host.substring(ds + 2)); + var s = host.indexOf('/'); + if (s != -1) + return domainname(host.substring(0, s)); + var h = reverse(host.split('.')); + var d = (!isNil(cddr(h)) && caddr(h) == 'www')? mklist(car(h), cadr(h), caddr(h)) : mklist(car(h), cadr(h)); + return reverse(d).join('.'); +} + +/** + * Return true if a host name is a subdomain. + */ +function issubdomain(host) { + return host.split('.').length > 2; +} + +/** + * Return true if the document cookie contains auth information. + */ +function hasauthcookie() { + return !isNil(document.cookie) && + (document.cookie.indexOf('TuscanyOpenAuth=') != -1 || + document.cookie.indexOf('TuscanyOAuth1=') != -1 || + document.cookie.indexOf('TuscanyOAuth2=') != -1 || + document.cookie.indexOf('TuscanyOpenIDAuth=') != -1); +} + +/** + * Clear auth information from the document cookie. + */ +function clearauthcookie() { + document.cookie = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = 'TuscanyOAuth1=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = 'TuscanyOAuth2=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = 'TuscanyOpenIDAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + return true; +} + +/** + * Format a string like Python format. + */ +function format() { + var i = 0; + var s = ''; + for (a in arguments) { + s = i == 0? arguments[a] : s.replace('{' + a + '}', arguments[a]); + i++; + } + return s; +} + +/** + * Functions with side effects. Use with moderation. + */ + +/** + * Set the car of a list. + */ +function setcar(l, v) { + l[0] = v; + return l; +} + +/** + * Set the cadr of a list. + */ +function setcadr(l, v) { + l[1] = v; + return l; +} + +/** + * Set the caddr of a list. + */ +function setcaddr(l, v) { + l[2] = v; + return l; +} + +/** + * Append the elements of a list to a list. + */ +function setappend(a, b) { + if (isNil(b)) + return a; + a.push(car(b)); + return setappend(a, cdr(b)); +} + +/** + * Set the cdr of a list. + */ +function setcdr(a, b) { + a.length = 1; + return setappend(a, b); +} + +/** + * Set the contents of a list. + */ +function setlist(a, b) { + if (b == a) + return b; + a.length = 0; + return setappend(a, b); +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js new file mode 100644 index 0000000000..4d943cce75 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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; +} + +/** + * Append a list of nodes to a parent node. + */ +function appendNodes(nodes, p) { + if (isNil(nodes)) + return p; + p.appendChild(car(nodes)); + return appendNodes(cdr(nodes), p); +}; + +/** + * 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) { + function trim(s) { + return s.replace(/^\s*/, '').replace(/\s*$/, ''); + } + return filter(function(n) { return n.nodeType == 3 && trim(n.nodeValue) != ''; }, nodeList(e.childNodes)); +} + +/** + * Read a list of XML attributes. + */ +function readAttributes(p, a) { + if (isNil(a)) + return a; + var x = car(a); + return cons(mklist(attribute, "'" + x.nodeName, x.nodeValue), readAttributes(p, cdr(a))); +} + +/** + * Read an XML element. + */ +function readElement(e, childf) { + var l = append(append(mklist(element, "'" + e.nodeName), readAttributes(e, childf(e))), readElements(childElements(e), childf)); + 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, childf) { + if (isNil(l)) + return l; + return cons(readElement(car(l), childf), readElements(cdr(l), childf)); +} + +/** + * 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); + var p = new DOMParser(); + return p.parseFromString(s, "text/xml"); +} + +/** + * 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), childAttributes)); +} + +/** + * Read a list of values from an XHTML element. + */ +function readXHTMLElement(xhtml) { + // Special XHTML attribute filtering on IE + function ieChildAttributes(e) { + var a = filter(function(n) { + // Filter out empty and internal DOM attributes + if (n.nodeType != 2 || isNil(n.nodeValue) || n.nodeValue == '') + return false; + if (n.nodeName == 'contentEditable' || n.nodeName == 'maxLength' || n.nodeName == 'loop' || n.nodeName == 'start') + return false; + return true; + }, nodeList(e.attributes)); + + if (e.style.cssText == '') + return a; + + // Add style attribute + var sa = new Object(); + sa.nodeName = 'style'; + sa.nodeValue = e.style.cssText; + return cons(sa, a); + } + + var childf = (typeof(XMLSerializer) != 'undefined')? childAttributes : ieChildAttributes; + return mklist(readElement(xhtml, childf)); +} + +/** + * Read a list of values from a list of strings representing an XML document. + */ +function readXML(l) { + return readXMLDocument(parseXML(l)); +} + +/** + * 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)) { + if (isIE()) { + var aname = attributeName(token).substring(1); + if (aname != 'xmlns') + node.setAttribute(aname, '' + attributeValue(token)); + } else + node.setAttribute(attributeName(token).substring(1), '' + attributeValue(token)); + + } else if (isTaggedList(token, element)) { + + function mkelem(tok, doc) { + function xmlns(l) { + if (isNil(l)) + return null; + var t = car(l); + if (isTaggedList(t, attribute)) { + if (attributeName(t).substring(1) == 'xmlns') + return attributeValue(t); + } + return xmlns(cdr(l)); + } + + var ns = xmlns(elementChildren(tok)); + if (isIE()) + return doc.createElementNS(ns != null? ns : node.namespaceURI, elementName(tok).substring(1)); + if (ns == null) + return doc.createElement(elementName(tok).substring(1)); + return doc.createElementNS(ns, elementName(tok).substring(1)); + } + + if (elementHasValue(token)) { + var v = elementValue(token); + if (isList(v)) { + var e = expandElementValues(elementName(token), v); + writeList(e, node, doc); + } else { + var child = mkelem(token, doc); + writeList(elementChildren(token), child, doc); + node.appendChild(child); + } + } else { + var child = mkelem(token, doc); + writeList(elementChildren(token), child, doc); + node.appendChild(child); + } + } else + node.appendChild(doc.createTextNode('' + token)); + + writeList(cdr(l), node, doc); + return node; +} + +/** + * Make a new XML document. + */ +function mkXMLDocument() { + return document.implementation.createDocument('', '', null); +} + +/** + * Convert a list of values to a list of strings representing an XML document. + */ +function writeXML(l, xmlTag) { + var doc = mkXMLDocument(); + 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/sca-cpp/branches/lightweight-sca/modules/js/js-conf b/sca-cpp/branches/lightweight-sca/modules/js/js-conf new file mode 100755 index 0000000000..aa29920619 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/js-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. + +# Add Javascript scripts and CSS to a server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +cat >>$root/conf/httpd.conf <<EOF +# Generated by: js-conf $* +# Serve JavaScript scripts and CSS +Alias /ui-min.css $here/htdocs/ui-min.css +Alias /all-min.js $here/htdocs/all-min.js +Alias /proxy/ui-min.css $here/htdocs/ui-min.css +Alias /proxy/all-min.js $here/htdocs/all-min.js + +EOF + +cat >>$root/conf/pubauth.conf <<EOF +# Generated by: js-conf $* +<Location /ui-min.css> +AuthType None +Require all granted +</Location> +<Location /all-min.js> +AuthType None +Require all granted +</Location> +<Location /proxy/ui-min.css> +AuthType None +Require all granted +</Location> +<Location /proxy/all-min.js> +AuthType None +Require all granted +</Location> + +EOF + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/js-shell.cpp b/sca-cpp/branches/lightweight-sca/modules/js/js-shell.cpp new file mode 100644 index 0000000000..ee0fa89b31 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/js-shell.cpp @@ -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. + */ + +/* $Rev$ $Date$ */ + +/** + * Evaluate a JavaScript script. + */ + +#include <assert.h> +#include "stream.hpp" +#include "fstream.hpp" +#include "string.hpp" +#include "eval.hpp" + +namespace tuscany { +namespace js { + +bool eval() { + ostringstream os; + for(;;) { + int c = cin.get(); + if (c == -1) + break; + os << (char)c; + } + failable<value> v = evalScript(str(os)); + assert(hasContent(v)); + cout << v; + return true; +} + +} +} + +int main() { + tuscany::js::eval(); + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/js/js-test.cpp b/sca-cpp/branches/lightweight-sca/modules/js/js-test.cpp new file mode 100644 index 0000000000..a7e5597610 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/js-test.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$ */ + +/** + * 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::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::js::testJSEval(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/js/json-test.js b/sca-cpp/branches/lightweight-sca/modules/js/json-test.js new file mode 100644 index 0000000000..fb53fa6347 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/json-test.js @@ -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. + */ + +/** + * Test JSON data encoding functions. + */ +function testJSON() { + var ad = mklist(mklist(attribute, "'city", "san francisco"), mklist(attribute, "'state", "ca")); + var ac = mklist(mklist(element, "'id", "1234"), mklist(attribute, "'balance", 1000)); + var cr = mklist(mklist(attribute, "'name", "jdoe"), cons(element, cons("'address", ad)), cons(element, cons("'account", ac))); + var c = mklist(cons(element, cons("'customer", cr))); + var s = json.writeJSON(c); + assert(car(s) == "{\"customer\": {\"@name\": \"jdoe\", \"address\": {\"@city\": \"san francisco\", \"@state\": \"ca\"}, \"account\": {\"id\": \"1234\", \"@balance\": 1000}}}"); + + var phones = mklist("408-1234", "650-1234"); + var l = mklist(mklist(element, "'phones", phones), mklist(element, "'lastName", "test\ttab"), mklist(attribute, "'firstName", "test1")); + var s2 = json.writeJSON(l); + assert(car(s2) == "{\"phones\": [\"408-1234\", \"650-1234\"], \"lastName\": \"test\\ttab\", \"@firstName\": \"test1\"}"); + + var r = json.readJSON(s2); + var w = json.writeJSON(r); + assert(car(w) == "{\"phones\": [\"408-1234\", \"650-1234\"], \"lastName\": \"test\\ttab\", \"@firstName\": \"test1\"}"); + + var l4 = mklist(mklist("'ns1:echoString", mklist("'@xmlns:ns1", "http://ws.apache.org/axis2/services/echo"), mklist("'text", "Hello World!"))); + var s4 = json.writeJSON(valuesToElements(l4)); + assert(car(s4) == "{\"ns1:echoString\": {\"@xmlns:ns1\": \"http://ws.apache.org/axis2/services/echo\", \"text\": \"Hello World!\"}}"); + + var r5 = elementsToValues(json.readJSON(s4)); + var s5 = json.writeJSON(valuesToElements(r5)); + assert(car(s5) == "{\"ns1:echoString\": {\"@xmlns:ns1\": \"http://ws.apache.org/axis2/services/echo\", \"text\": \"Hello World!\"}}"); + return true; +} + +testJSON(); + diff --git a/sca-cpp/branches/lightweight-sca/modules/js/util-test b/sca-cpp/branches/lightweight-sca/modules/js/util-test new file mode 100755 index 0000000000..c69f46c67c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/js/util-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. + +# Run Javascript util test cases +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` + +echo "Testing..." +cat htdocs/util.js htdocs/elemutil.js htdocs/jsonutil.js json-test.js | ./js-shell 2>/dev/null 1>&2 +rc=$? +if [ "$rc" = "0" ]; then + echo "OK" +fi + +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/opencl/Makefile.am new file mode 100644 index 0000000000..3e76a435c8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/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_OPENCL + +INCLUDES = -I${OPENCL_INCLUDE} + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/modules/opencl + +dist_mod_SCRIPTS = opencl-conf +moddir = $(prefix)/modules/opencl + +EXTRA_DIST = domain-test.composite server-test.cl + +if DARWIN +OPENCL_FLAGS = -framework OpenCL +else +OPENCL_FLAGS = -L${OPENCL_LIB} -R${OPENCL_LIB} -lOpenCL +endif + +#mod_LTLIBRARIES = libmod_tuscany_opencl.la +#libmod_tuscany_opencl_la_SOURCES = mod-opencl.cpp +#libmod_tuscany_opencl_la_LDFLAGS = -lxml2 -lcurl -lmozjs -framework OpenCL +#noinst_DATA = libmod_tuscany_opencl${libsuffix} +#libmod_tuscany_opencl${libsuffix}: +# ln -s .libs/libmod_tuscany_opencl${libsuffix} + +opencl_test_SOURCES = opencl-test.cpp +opencl_test_LDFLAGS = ${OPENCL_FLAGS} + +opencl_shell_SOURCES = opencl-shell.cpp +opencl_shell_LDFLAGS = ${OPENCL_FLAGS} + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +dist_noinst_SCRIPTS = server-test +noinst_PROGRAMS = opencl-test client-test +mod_PROGRAMS = opencl-shell +TESTS = opencl-test + +endif diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/client-test.cpp b/sca-cpp/branches/lightweight-sca/modules/opencl/client-test.cpp new file mode 100644 index 0000000000..7af3cc73d2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/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/opencl"; + + tuscany::server::testServer(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/domain-test.composite b/sca-cpp/branches/lightweight-sca/modules/opencl/domain-test.composite new file mode 100644 index 0000000000..e69399d581 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/domain-test.composite @@ -0,0 +1,31 @@ +<?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" + targetNamespace="http://domain/test" + name="domain-test"> + + <component name="opencl-test"> + <implementation.opencl kernel="server-test.cl"/> + <service name="test"> + <binding.http uri="opencl"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/driver.hpp b/sca-cpp/branches/lightweight-sca/modules/opencl/driver.hpp new file mode 100644 index 0000000000..b4b6c2845b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/driver.hpp @@ -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$ */ + +#ifndef tuscany_opencl_driver_hpp +#define tuscany_opencl_driver_hpp + +/** + * OpenCL evaluator main driver loop. + */ + +#include "string.hpp" +#include "stream.hpp" +#include "monad.hpp" +#include "../scheme/driver.hpp" +#include "eval.hpp" + +namespace tuscany { +namespace opencl { + +const value evalDriverLoop(const OpenCLProgram& clprog, istream& in, ostream& out, const OpenCLContext& cl) { + scheme::promptForInput(scheme::evalInputPrompt, out); + value input = scheme::readValue(in); + if (isNil(input)) + return input; + const failable<value> output = evalKernel(createKernel(input, clprog), input, 1, value::String, 512, cl); + scheme::announceOutput(scheme::evalOutputPrompt, out); + scheme::userPrint(content(output), out); + return evalDriverLoop(clprog, in, out, cl); +} + +const bool evalDriverRun(const char* path, istream& in, ostream& out) { + OpenCLContext cl(OpenCLContext::DEFAULT); + scheme::setupDisplay(out); + ifstream is(path); + failable<OpenCLProgram> clprog = readProgram(path, is, cl); + if (!hasContent(clprog)) + return true; + evalDriverLoop(content(clprog), in, out, cl); + return true; +} + +} +} +#endif /* tuscany_opencl_driver_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/eval.hpp b/sca-cpp/branches/lightweight-sca/modules/opencl/eval.hpp new file mode 100644 index 0000000000..5606b2f57a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/eval.hpp @@ -0,0 +1,724 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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_opencl_eval_hpp +#define tuscany_opencl_eval_hpp + +/** + * OpenCL kernel evaluation logic. + */ +#ifdef IS_DARWIN +#include <OpenCL/opencl.h> +#else +#include <CL/cl.h> +#endif + +#include "list.hpp" +#include "value.hpp" +#include "perf.hpp" + +namespace tuscany { +namespace opencl { + +/** + * Convert an OpenCL error code to a string. + */ +const string clError(const cl_int e) { + ostringstream s; + s << "error " << e; + return str(s); +} + +/** + * OpenCL profiling counters. + */ +#ifdef WANT_MAINTAINER_OPENCL_PROF + +cl_ulong memtime = 0; +cl_ulong kernelqtime = 0; +cl_ulong kerneltime = 0; +cl_ulong preptime = 0; +cl_ulong evaltime = 0; + +/** + * Reset the OpenCL profiling counters. + */ +bool resetOpenCLCounters() { + memtime = kernelqtime = kerneltime = preptime = evaltime = 0; + return true; +} + +/** + * Print the OpenCL profiling counters. + */ +bool printOpenCLCounters(const long n) { + cout << " kernelq " << ((double)kernelqtime / 1000000.0) / (double)n << " ms kernel " << ((double)kerneltime / 1000000.0) / (double)n << " ms memory " << ((double)memtime / 1000000.0) / (double)n << " ms prep " << ((double)preptime / 1000000.0) / (double)n << " ms eval " << ((double)evaltime / 1000000.0) / (double)n << " ms"; + return true; +} + +/** + * Profile a memory event. + */ +failable<cl_ulong> profileMemEvent(const cl_event evt) { + cl_ulong start = 0; + const cl_int serr = clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL); + if (serr != CL_SUCCESS) + return mkfailure<cl_ulong>("Couldn't profile memory event start: " + clError(serr)); + cl_ulong end = 0; + const cl_int eerr = clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL); + if (eerr != CL_SUCCESS) + return mkfailure<cl_ulong>("Couldn't profile memory event end: " + clError(eerr)); + const cl_ulong t = end - start; + memtime += t; + return t; +} + +/** + * Profile a kernel event. + */ +failable<cl_ulong> profileKernelEvent(const cl_event evt) { + cl_ulong queued = 0; + const cl_int qerr = clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_QUEUED, sizeof(cl_ulong), &queued, NULL); + if (qerr != CL_SUCCESS) + return mkfailure<cl_ulong>("Couldn't profile kernel event queue: " + clError(qerr)); + cl_ulong start = 0; + const cl_int serr = clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL); + if (serr != CL_SUCCESS) + return mkfailure<cl_ulong>("Couldn't profile kernel event start: " + clError(serr)); + cl_ulong end = 0; + const cl_int eerr = clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL); + if (eerr != CL_SUCCESS) + return mkfailure<cl_ulong>("Couldn't profile kernel event end: " + clError(eerr)); + const cl_ulong q = start - queued; + kernelqtime += q; + const cl_ulong t = end - start; + kerneltime += t; + return t; +} + +/** + * Profile an array of memory events. + */ +failable<cl_ulong> profileMemEvents(const cl_uint n, const cl_event* evt) { + if (n == 0) + return 0; + const failable<cl_ulong> t = profileMemEvent(*evt); + if (!hasContent(t)) + return t; + const failable<cl_ulong> r = profileMemEvents(n - 1, evt + 1); + if (!hasContent(r)) + return r; + return content(t) + content(r); +} + +#else + +#define resetOpenCLCounters() +#define printOpenCLCounters(n) + +#endif + +class OpenCLContext; +class OpenCLProgram; +class OpenCLKernel; +class OpenCLBuffer; + +/** + * Represent an OpenCL context. + */ +class OpenCLContext { +public: +#define OPENCL_MAX_DEVICES 64 + + enum DeviceType { + DEFAULT = 0, CPU = 1, GPU = 2 + }; + + OpenCLContext(const OpenCLContext::DeviceType devtype) : dev(OpenCLContext::DEFAULT), ndevs(0), ctx(0) { + debug("opencl::OpenCLContext"); + for (int i = 0; i < OPENCL_MAX_DEVICES; i++) + cq[i] = 0; + + // Get the available platforms + cl_uint nplatforms; + cl_platform_id platforms[16]; + const cl_int gperr = clGetPlatformIDs(16, platforms, &nplatforms); + if(nplatforms == 0 || gperr != CL_SUCCESS) { + mkfailure<bool>("Couldn't get OpenCL platforms: " + clError(gperr)); + return; + } + for(cl_uint i = 0; i < nplatforms; ++i) { + char vendor[256]; + const cl_int gverr = clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, sizeof(vendor), vendor, NULL); + if(gverr != CL_SUCCESS) { + mkfailure<bool>("Couldn't get OpenCL platform: " + clError(gverr)); + return; + } + debug(vendor, "opencl::OpenCLContext::vendor"); + } + + // Get the available devices of the requested type + if (devtype == OpenCLContext::DEFAULT || devtype == OpenCLContext::GPU) { + for(cl_uint i = 0; i < nplatforms; ++i) { + const cl_int err = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, OPENCL_MAX_DEVICES, devid, &ndevs); + if (err == CL_SUCCESS) { + debug(ndevs, "opencl::OpenCLContext::gcpus"); + dev = OpenCLContext::GPU; + break; + } + } + } + if ((devtype == OpenCLContext::DEFAULT && ndevs == 0) || devtype == OpenCLContext::CPU) { + for(cl_uint i = 0; i < nplatforms; ++i) { + const cl_int err = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU, OPENCL_MAX_DEVICES, devid, &ndevs); + if (err == CL_SUCCESS) { + debug(ndevs, "opencl::OpenCLContext::ncpus"); + dev = OpenCLContext::CPU; + break; + } + } + } + if (ndevs == 0) + return; + + // Initialize OpenCL context and command queues + cl_int ccerr; + ctx = clCreateContext(0, ndevs, devid, NULL, NULL, &ccerr); + if(!ctx || ccerr != CL_SUCCESS) { + mkfailure<bool>("Couldn't create OpenCL context: " + clError(ccerr)); + return; + } + + for (cl_uint i = 0; i < ndevs; i++) { + cl_int cqerr; +#ifdef WANT_MAINTAINER_OPENCL_PROF + cq[i] = clCreateCommandQueue(ctx, devid[i], CL_QUEUE_PROFILING_ENABLE, &cqerr); +#else + cq[i] = clCreateCommandQueue(ctx, devid[i], 0, &cqerr); +#endif + if (!cq[i] || cqerr != CL_SUCCESS) { + mkfailure<bool>("Couldn't create OpenCL command queue: " + clError(cqerr)); + return; + } + } + } + + ~OpenCLContext() { + for (cl_uint i = 0; i < ndevs; i++) { + if (cq[i] != 0) + clReleaseCommandQueue(cq[i]); + } + if (ctx != 0) + clReleaseContext(ctx); + } + +private: + OpenCLContext::DeviceType dev; + cl_uint ndevs; + cl_device_id devid[OPENCL_MAX_DEVICES]; + cl_context ctx; + cl_command_queue cq[OPENCL_MAX_DEVICES]; + + friend const cl_uint devices(const OpenCLContext& cl); + friend const cl_command_queue commandq(const OpenCLContext& cl); + friend const failable<OpenCLBuffer> readOnlyBuffer(const size_t size, const void* p, const OpenCLContext& cl, cl_command_queue cq); + friend const failable<OpenCLBuffer> writeOnlyBuffer(const size_t size, const OpenCLContext& cl); + friend const failable<value> evalKernel(const failable<OpenCLKernel>& kernel, const value& expr, const size_t gwsize, const value::ValueType type, const size_t n, const OpenCLContext& cl); + friend const failable<OpenCLProgram> readProgram(const string& path, istream& is, const OpenCLContext& cl); +}; + +/** + * Return the number of computing devices available in a context. + */ +const cl_uint devices(const OpenCLContext& cl) { + return cl.ndevs; +} + +/** + * Return a command queue from a context. + */ +const cl_command_queue commandq(const OpenCLContext& cl) { + return cl.cq[0]; +} + +/** + * Represents an OpenCL program. + */ +class OpenCLProgram { +public: + OpenCLProgram() : prog(0) { + } + + OpenCLProgram(const cl_program prog) : prog(prog) { + } + + OpenCLProgram(const OpenCLProgram& c) : prog(c.prog) { + const cl_int rperr = clRetainProgram(prog); + if (rperr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't retain OpenCL program: ") + clError(rperr)); + } + + ~OpenCLProgram() { + if (!prog) + return; + const cl_int rperr = clReleaseProgram(prog); + if (rperr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't release OpenCL program: ") + clError(rperr)); + } + +private: + const cl_program prog; + + friend const failable<OpenCLKernel> createKernel(const value& expr, const OpenCLProgram& clprog); + friend const failable<value> evalKernel(const failable<OpenCLKernel>& kernel, const value& expr, const size_t gwsize, const value::ValueType type, const size_t n, const OpenCLContext& cl); +}; + +/** + * Represents an OpenCL kernel. + */ +class OpenCLKernel { +public: + OpenCLKernel() : k(0) { + } + + OpenCLKernel(const cl_kernel k) : k(k) { + } + + OpenCLKernel(const OpenCLKernel& c) : k(c.k) { + const cl_int rkerr = clRetainKernel(k); + if (rkerr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't retain OpenCL kernel: ") + clError(rkerr)); + } + + ~OpenCLKernel() { + if (!k) + return; + const cl_int rkerr = clReleaseKernel(k); + if (rkerr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't release OpenCL kernel: ") + clError(rkerr)); + } + +private: + const cl_kernel k; + + friend const failable<OpenCLBuffer> valueToKernelArg(const cl_uint i, const size_t size, const void* p, const failable<OpenCLBuffer>& buf, const OpenCLKernel& kernel); + friend const failable<value> evalKernel(const failable<OpenCLKernel>& kernel, const value& expr, const size_t gwsize, const value::ValueType type, const size_t n, const OpenCLContext& cl); +}; + +/** + * Represents an OpenCL buffer. + */ +class OpenCLBuffer { +public: + OpenCLBuffer() : mem(0), evt(0) { + } + + OpenCLBuffer(const cl_mem mem, const cl_event evt) : mem(mem), evt(evt) { + } + + OpenCLBuffer(const OpenCLBuffer& c) : mem(c.mem), evt(c.evt) { + if (mem != 0) { + const cl_int rmerr = clRetainMemObject(mem); + if (rmerr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't retain OpenCL buffer: ") + clError(rmerr)); + } + if (evt != 0) { + const cl_int reerr = clRetainEvent(evt); + if (reerr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't retain OpenCL event: ") + clError(reerr)); + } + } + + ~OpenCLBuffer() { + if (mem != 0) { + const cl_int rmerr = clReleaseMemObject(mem); + if (rmerr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't release OpenCL buffer: ") + clError(rmerr)); + } + if (evt != 0) { + const cl_int reerr = clReleaseEvent(evt); + if (reerr != CL_SUCCESS) + mkfailure<bool>(string("Couldn't release OpenCL event: ") + clError(reerr)); + } + } + +private: + const cl_mem mem; + const cl_event evt; + + friend const cl_uint writeBufferEvents(const list<OpenCLBuffer>& buf, cl_event* evt); + friend const failable<OpenCLBuffer> valueToKernelArg(const cl_uint i, const size_t size, const void* p, const failable<OpenCLBuffer>& buf, const OpenCLKernel& kernel); + friend const failable<value> evalKernel(const failable<OpenCLKernel>& kernel, const value& expr, const size_t gwsize, const value::ValueType type, const size_t n, const OpenCLContext& cl); +}; + +/** + * Return a read-only memory buffer. + */ +const failable<OpenCLBuffer> readOnlyBuffer(const size_t size, const void* p, const OpenCLContext& cl, const cl_command_queue cq) { + if (cl.dev == OpenCLContext::CPU) { + cl_int err; + const cl_mem buf = clCreateBuffer(cl.ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, size, const_cast<void*>(p), &err); + if (!buf || err != CL_SUCCESS) + return mkfailure<OpenCLBuffer>(string("Couldn't map OpenCL host memory: ") + clError(err)); + return OpenCLBuffer(buf, 0); + } + cl_int berr; + const cl_mem buf = clCreateBuffer(cl.ctx, CL_MEM_READ_ONLY, size, NULL, &berr); + if (!buf || berr != CL_SUCCESS) + return mkfailure<OpenCLBuffer>(string("Couldn't allocate OpenCL device memory: ") + clError(berr)); + cl_event wevt; + const cl_int werr = clEnqueueWriteBuffer(cq, buf, CL_FALSE, 0, size, p, 0, NULL, &wevt); + if (werr != CL_SUCCESS) { + clReleaseMemObject(buf); + return mkfailure<OpenCLBuffer>(string("Couldn't enqueue write to device memory: ") + clError(werr)); + } + return OpenCLBuffer(buf, wevt); +} + +/** + * Fill an array of write events for a given list of buffers. + */ +const cl_uint writeBufferEvents(const list<OpenCLBuffer>& buf, cl_event* evt) { + if (isNil(buf)) + return 0; + const cl_event e = car(buf).evt; + if (e == 0) + return writeBufferEvents(cdr(buf), evt); + *evt = e; + return 1 + writeBufferEvents(cdr(buf), evt + 1); +} + +/** + * Return a write-only memory buffer. + */ +const failable<OpenCLBuffer> writeOnlyBuffer(const size_t size, const OpenCLContext& cl) { + if (cl.dev == OpenCLContext::CPU) { + cl_int err; + const cl_mem buf = clCreateBuffer(cl.ctx, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, size, NULL, &err); + if (!buf || err != CL_SUCCESS) + return mkfailure<OpenCLBuffer>(string("Couldn't map OpenCL host memory: ") + clError(err)); + return OpenCLBuffer(buf, 0); + } + cl_int err; + const cl_mem buf = clCreateBuffer(cl.ctx, CL_MEM_WRITE_ONLY, size, NULL, &err); + if (!buf || err != CL_SUCCESS) + return mkfailure<OpenCLBuffer>(string("Couldn't allocate OpenCL device memory: ") + clError(err)); + return OpenCLBuffer(buf, 0); +} + +/** + * Convert a value to a kernel arg. + */ +const failable<OpenCLBuffer> valueToKernelArg(const cl_uint i, const size_t size, const void* p, const failable<OpenCLBuffer>& buf, const OpenCLKernel& kernel) { + if (!hasContent(buf)) + return buf; + if (p != NULL) { + const cl_int err = clSetKernelArg(kernel.k, (cl_uint)i, size, p); + if (err != CL_SUCCESS) + return mkfailure<OpenCLBuffer>(string("Couldn't set OpenCL simple kernel arg: ") + clError(err)); + return buf; + } + const OpenCLBuffer b = content(buf); + const cl_int err = clSetKernelArg(kernel.k, i, sizeof(cl_mem), &b.mem); + if (err != CL_SUCCESS) + return mkfailure<OpenCLBuffer>(string("Couldn't set OpenCL buffer kernel arg: ") + clError(err)); + return buf; +} + +const failable<OpenCLBuffer> valueToKernelArg(const value& v, const cl_uint i, const OpenCLKernel& kernel, const OpenCLContext& cl, const cl_command_queue cq) { + switch (type(v)) { + case value::Symbol: { + const string s = string("'") + v; + return valueToKernelArg(i, 0, NULL, readOnlyBuffer(length(s) + 1, c_str(s), cl, cq), kernel); + } + case value::String: { + const string s = (string)v; + return valueToKernelArg(i, 0, NULL, readOnlyBuffer(length(s) + 1, c_str(s), cl, cq), kernel); + } + case value::Number: { + const cl_float d = (cl_float)((double)v); + return valueToKernelArg(i, sizeof(cl_float), &d, OpenCLBuffer(), kernel); + } + case value::Bool: { + const cl_int b = (cl_int)((bool)v); + return valueToKernelArg(i, sizeof(cl_int), &b, OpenCLBuffer(), kernel); + } + default: { + return valueToKernelArg(i, sizeof(cl_mem), NULL, readOnlyBuffer(sizeof(value), &v, cl, cq), kernel); + } + } +} + +/** + * Convert a list of values to kernel args. + */ +const failable<list<OpenCLBuffer>> valuesToKernelArgsListHelper(const list<value>& v, const cl_uint i, const OpenCLKernel& kernel, const OpenCLContext& cl, const cl_command_queue cq) { + if (isNil(v)) + return list<OpenCLBuffer>(); + const failable<OpenCLBuffer> a = valueToKernelArg(car(v), i, kernel, cl, cq); + if (!hasContent(a)) + return mkfailure<list<OpenCLBuffer>>(a); + const failable<list<OpenCLBuffer>> al = valuesToKernelArgsListHelper(cdr(v), i + 1, kernel, cl, cq); + if (!hasContent(al)) + return al; + return cons<OpenCLBuffer>(content(a), content(al)); +} + +const failable<list<OpenCLBuffer>> valuesToKernelArgs(const list<value>& v, const OpenCLKernel& kernel, const OpenCLContext& cl, const cl_command_queue cq) { + return valuesToKernelArgsListHelper(v, 0, kernel, cl, cq); +} + +/** + * Convert a kernel result to a value. + */ +const value kernelResultToValue(const void* p, const value::ValueType type) { + switch(type) { + case value::Symbol: { + const char* s = static_cast<const char*>(p); + const size_t l = strlen(s); + if (l != 0 && *s == '\'') + return value(s + 1); + return value(s); + } + case value::String: { + const char* s = static_cast<const char*>(p); + const size_t l = strlen(s); + if (l != 0 && *s == '\'') + return value(s + 1); + return value(string(s, l)); + } + case value::Number: + return (double)(*(static_cast<const cl_float*>(p))); + case value::Bool: + return (bool)(*(static_cast<const cl_int*>(p))); + default: + return *(static_cast<const value*>(p)); + } +} + +/** + * Return the value type corresponding to a C99 type name. + */ +const value::ValueType valueType(const string& t) { + if (t == "float") + return value::Number; + if (t == "int") + return value::Bool; + if (t == "char") + return value::String; + return value::Nil; +} + +/** + * Return the size of a C99 type corresponding to a value type. + */ +const size_t valueSize(const value::ValueType type) { + switch(type) { + case value::Number: + return sizeof(cl_float); + case value::Bool: + return sizeof(cl_int); + case value::Symbol: + return sizeof(cl_char); + case value::String: + return sizeof(cl_char); + default: + return sizeof(value); + } +} + +/** + * Return the result type of a kernel. + */ +class OpenCLResultType { +public: + OpenCLResultType(const value::ValueType type, const size_t n, const size_t size) : type(type), n(n), size(size) {} + const value::ValueType type; + const size_t n; + const size_t size; +}; + +const OpenCLResultType kernelResultType(const string& fn, value::ValueType type, const size_t n) { + if (type != value::Nil) + return OpenCLResultType(type, n, valueSize(type)); + const string s = car(tokenize("_", fn)); + const size_t d = find_first_of(s, "0123456789"); + if (d == length(s)) { + const value::ValueType vt = valueType(s); + return OpenCLResultType(vt, 1, valueSize(vt)); + } + const value::ValueType vt = valueType(substr(s, 0, d)); + return OpenCLResultType(vt, atoi(c_str(substr(s, d))), valueSize(vt)); +} + +/** + * Create the kernel implementing an expression. + */ +const failable<OpenCLKernel> createKernel(const value& expr, const OpenCLProgram& clprog) { + + // Create an OpenCL kernel for the requested function + const value fn = car<value>(expr); + cl_int ckerr; + const cl_kernel k = clCreateKernel(clprog.prog, c_str(fn), &ckerr); + if (k == NULL || ckerr != CL_SUCCESS) { + + // The start, stop, and restart functions are optional + //if (fn == "start" || fn == "stop") + //return value(lambda<value(const list<value>&)>()); + + return mkfailure<OpenCLKernel>(string("Couldn't find function: ") + car<value>(expr) + " : " + clError(ckerr)); + } + return OpenCLKernel(k); +} + +/** + * Evaluate an expression implemented by a kernel. + */ +const failable<value> evalKernel(const failable<OpenCLKernel>& fkernel, const value& expr, const size_t gwsize, const value::ValueType type, const size_t n, const OpenCLContext& cl) { + +#ifdef WANT_MAINTAINER_OPENCL_PROF + const cl_uint estart = (cl_uint)timens(); + const cl_uint pstart = estart; +#endif + + if (!hasContent(fkernel)) + return mkfailure<value>(fkernel); + const OpenCLKernel kernel = content(fkernel); + + // Get a command queue for the specified device type + const cl_command_queue cq = commandq(cl); + + // Set the kernel input args + const failable<list<OpenCLBuffer>> args = valuesToKernelArgs(cdr<value>(expr), kernel, cl, cq); + if (!hasContent(args)) { + return mkfailure<value>(args); + } + + // Allocate result buffer in device memory + const value fn = car<value>(expr); + const OpenCLResultType rtype = kernelResultType(fn, type, n); + const size_t rsize = rtype.n * rtype.size; + const failable<OpenCLBuffer> rbuf = writeOnlyBuffer(rsize, cl); + if (!hasContent(rbuf)) + return mkfailure<value>(rbuf); + + // Set it as a kernel output arg + const cl_mem rmem = content(rbuf).mem; + const failable<OpenCLBuffer> rarg = valueToKernelArg((cl_uint)length(cdr<value>(expr)), sizeof(cl_mem), &rmem, rbuf, kernel); + if (!hasContent(rarg)) + return mkfailure<value>(rarg); + + // Enqueue the kernel, to be executed after all the writes complete + cl_event wevt[32]; + const cl_uint nwevt = writeBufferEvents(content(args), wevt); + cl_event kevt; + const cl_int qerr = clEnqueueNDRangeKernel(cq, kernel.k, 1, NULL, &gwsize, NULL, nwevt, nwevt != 0? wevt : NULL, &kevt); + if (qerr != CL_SUCCESS) + return mkfailure<value>(string("Couldn't enqueue kernel task: ") + clError(qerr)); + + // Enqueue result buffer read, to be executed after the kernel completes + char res[rsize]; + cl_event revt; + const cl_int rerr = clEnqueueReadBuffer(cq, rmem, CL_FALSE, 0, rsize, res, 1, &kevt, &revt); + if (rerr != CL_SUCCESS) { + clReleaseEvent(kevt); + return mkfailure<value>(string("Couldn't read from OpenCL device memory: ") + clError(rerr)); + } + +#ifdef WANT_MAINTAINER_OPENCL_PROF + const cl_uint pend = (cl_uint)timens(); + preptime += (pend - pstart); +#endif + + // Wait for completion + const cl_int werr = clWaitForEvents(1, &revt); + if (werr != CL_SUCCESS) { + clReleaseEvent(revt); + clReleaseEvent(kevt); + return mkfailure<value>(string("Couldn't wait for kernel completion: ") + clError(werr)); + } + +#ifdef WANT_MAINTAINER_OPENCL_PROF + profileMemEvents(nwevt, wevt); + profileKernelEvent(kevt); + profileMemEvent(revt); +#endif + + // Convert the result to a value + const value v = kernelResultToValue(res, rtype.type); + + // Release OpenCL resources + clReleaseEvent(revt); + clReleaseEvent(kevt); + +#ifdef WANT_MAINTAINER_OPENCL_PROF + const cl_uint eend = (cl_uint)timens(); + evaltime += (eend - estart); +#endif + + return v; +} + +const failable<value> evalKernel(const failable<OpenCLKernel>& kernel, const value& expr, const OpenCLContext& cl) { + return evalKernel(kernel, expr, 1, value::Nil, 0, cl); +} + +/** + * Read an opencl program from an input stream. + */ +const failable<OpenCLProgram> readProgram(const string& path, istream& is, const OpenCLContext& cl) { + + // Read the program source + const list<string> ls = streamList(is); + ostringstream os; + write(ls, os); + const char* cs = c_str(str(os)); + + // Create the OpenCL program + cl_int cperr; + const cl_program prog = clCreateProgramWithSource(cl.ctx, 1, (const char **)&cs, NULL, &cperr); + if (!prog || cperr != CL_SUCCESS) + return mkfailure<OpenCLProgram>(string("Couldn't create OpenCL program from source: ") + path + " : " + clError(cperr)); + + // Built it + const cl_int bperr = clBuildProgram(prog, 0, NULL, NULL, NULL, NULL); + if(bperr != CL_SUCCESS) { + size_t l; + char b[2048]; + clGetProgramBuildInfo(prog, cl.devid[0], CL_PROGRAM_BUILD_LOG, sizeof(b), b, &l); + return mkfailure<OpenCLProgram>(string("Couldn't build OpenCL program: ") + path + " : " + clError(bperr) + "\n" + string(b)); + } + return OpenCLProgram(prog); +} + +/** + * Evaluate an expression against an OpenCL program provided as an input stream. + */ +const failable<value> evalKernel(const value& expr, istream& is, const OpenCLContext& cl) { + failable<OpenCLProgram> clprog = readProgram("program.cl", is, cl); + if (!hasContent(clprog)) + return mkfailure<value>(clprog); + return evalKernel(createKernel(expr, content(clprog)), expr, 1, value::Nil, 0, cl); +} + +} +} +#endif /* tuscany_opencl_eval_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-conf b/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-conf new file mode 100755 index 0000000000..1ba2c336a3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-conf @@ -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. + +# Generate an OpenCL server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +cat >>$root/conf/modules.conf <<EOF +# Generated by: opencl-conf $* +# Support for OpenCL SCA components +LoadModule mod_tuscany_eval $here/libmod_tuscany_opencl$libsuffix + +EOF diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-shell.cpp b/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-shell.cpp new file mode 100644 index 0000000000..1dfeaeea1d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-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$ */ + +/** + * OpenCL 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: opencl-shell <kernel.cl>" << tuscany::endl; + return 1; + } + tuscany::opencl::evalDriverRun(argv[1], tuscany::cin, tuscany::cout); + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-test.cpp b/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-test.cpp new file mode 100644 index 0000000000..17bc5ccfa6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/opencl-test.cpp @@ -0,0 +1,332 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 OpenCL kernel evaluator. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "driver.hpp" +#include "parallel.hpp" +#include "perf.hpp" + +namespace tuscany { +namespace opencl { + +const string testFloatsCPU = + "kernel void add(const float x, const float y, global float* r) {\n" + " float l_x;\n" + " float l_y;\n" + " l_x = x;\n" + " l_y = y;\n" + " *r = l_x + l_y;\n" + "}\n" + "kernel void float_add(const float x, const float y, global float* r) {\n" + " add(x, y, r);\n" + "}\n"; + +const string testFloatsGPU = + "kernel void add(const float x, const float y, global float* r) {\n" + " local float l_x;\n" + " local float l_y;\n" + " l_x = x;\n" + " l_y = y;\n" + " barrier(CLK_LOCAL_MEM_FENCE);\n" + " *r = l_x + l_y;\n" + "}\n" + "kernel void float_add(const float x, const float y, global float* r) {\n" + " add(x, y, r);\n" + "}\n"; + +const string testBoolsCPU = + "kernel void int_or(const int x, const int y, global int* r) {\n" + " int l_x;\n" + " int l_y;\n" + " l_x = x;\n" + " l_y = y;\n" + " *r = l_x || l_y;\n" + "}\n"; + +const string testBoolsGPU = + "kernel void int_or(const int x, const int y, global int* r) {\n" + " local int l_x;\n" + " local int l_y;\n" + " l_x = x;\n" + " l_y = y;\n" + " barrier(CLK_LOCAL_MEM_FENCE);\n" + " *r = l_x || l_y;\n" + "}\n"; + +const string testCharsCPU = + "kernel void add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " const int ixl = (int)xl;\n" + " const int iyl = (int)yl;\n" + " for (int i = 0; i < ixl; i++)\n" + " r[i] = x[i];\n" + " for (int i = 0; i < iyl; i++)\n" + " r[ixl + i] = y[i];\n" + " r[ixl + iyl] = '\\0';\n" + "}\n" + "kernel void char128_add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " add(xl, x, yl, y, r);\n" + "}\n"; + +const string testCharsCopyGPU = + "kernel void add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " const int ixl = (int)xl;\n" + " const int iyl = (int)yl;\n" + " local char l_x[128];\n" + " local char l_y[128];\n" + " event_t re = async_work_group_copy(l_x, x, ixl, 0);\n" + " async_work_group_copy(l_y, y, iyl, re);\n" + " wait_group_events(1, &re);\n" + " local char l_r[128];\n" + " for (int i = 0; i < ixl; i++)\n" + " l_r[i] = l_x[i];\n" + " for (int i = 0; i < iyl; i++)\n" + " l_r[ixl + i] = l_y[i];\n" + " l_r[ixl + iyl] = '\\0';\n" + " event_t we = async_work_group_copy(r, l_r, ixl + iyl + 1, 0);\n" + " wait_group_events(1, &we);\n" + "}\n" + "kernel void char128(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " add(xl, x, yl, y, r);\n" + "}\n"; + +const string testCharsGPU = + "kernel void add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " const int ixl = (int)xl;\n" + " const int iyl = (int)yl;\n" + " for (int i = 0; i < ixl; i++)\n" + " r[i] = x[i];\n" + " for (int i = 0; i < iyl; i++)\n" + " r[ixl + i] = y[i];\n" + " r[ixl + iyl] = '\\0';\n" + "}\n" + "kernel void char128(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " add(xl, x, yl, y, r);\n" + "}\n"; + +const string testCharsParallelCPU = + "kernel void add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " const int i = get_global_id(0);\n" + " const int ixl = (int)xl;\n" + " const int iyl = (int)yl;\n" + " r[i] = i < ixl? x[i] : i < ixl + iyl? y[i - ixl] : '\\0';\n" + "}\n"; + +const string testCharsParallelCopyGPU = + "kernel void add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " const int i = get_global_id(0);\n" + " const int ixl = (int)xl;\n" + " const int iyl = (int)yl;\n" + " local char l_x[128];\n" + " local char l_y[128];\n" + " event_t re = async_work_group_copy(l_x, x, ixl, 0);\n" + " async_work_group_copy(l_y, y, iyl, re);\n" + " wait_group_events(1, &re);\n" + " local char l_r[128];\n" + " l_r[i] = i < ixl? l_x[i] : i < ixl + iyl? l_y[i - ixl] : '\\0';\n" + " event_t we = async_work_group_copy(r, l_r, ixl + iyl + 1, 0);\n" + " wait_group_events(1, &we);\n" + "}\n"; + +const string testCharsParallelGPU = + "kernel void add(const float xl, global const char* x, const float yl, global const char* y, global char* r) {\n" + " const int i = get_global_id(0);\n" + " const int ixl = (int)xl;\n" + " const int iyl = (int)yl;\n" + " r[i] = i < ixl? x[i] : i < ixl + iyl? y[i - ixl] : '\\0';\n" + "}\n"; + +bool testTaskParallel(const OpenCLContext::DeviceType dev) { + gc_scoped_pool pool; + OpenCLContext cl(dev); + if (!devices(cl) != 0) + return true; + + { + istringstream is(dev == OpenCLContext::CPU? testFloatsCPU : testFloatsGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + const value exp = mklist<value>("float_add", 2, 3); + const failable<value> r = evalKernel(createKernel(exp, content(clprog)), exp, cl); + assert(hasContent(r)); + assert(content(r) == value(5)); + } + if (true) return true; + { + istringstream is(dev == OpenCLContext::CPU? testFloatsCPU : testFloatsGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + const value exp = mklist<value>("add", 2, 3); + const failable<value> r = evalKernel(createKernel(exp, content(clprog)), exp, 1, value::Number, 1, cl); + assert(hasContent(r)); + assert(content(r) == value(5)); + } + { + istringstream is(dev == OpenCLContext::CPU? testBoolsCPU : testBoolsGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + + const value exp = mklist<value>("int_or", true, false); + const failable<value> r = evalKernel(createKernel(exp, content(clprog)), exp, cl); + assert(hasContent(r)); + assert(content(r) == value(true)); + + const value exp2 = mklist<value>("int_or", false, false); + const failable<value> r2 = evalKernel(createKernel(exp2, content(clprog)), exp2, cl); + assert(hasContent(r2)); + assert(content(r2) == value(false)); + } + { + istringstream is(dev == OpenCLContext::CPU? testCharsCPU : testCharsGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + + const value exp = mklist<value>("char128", 60, string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello "), 60, string("World World World World World World World World World World ")); + const failable<value> r = evalKernel(createKernel(exp, content(clprog)), exp, cl); + assert(hasContent(r)); + assert(content(r) == value(string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello World World World World World World World World World World "))); + } + { + istringstream is(dev == OpenCLContext::CPU? testCharsCPU : testCharsGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + + const value exp = mklist<value>("add", 60, string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello "), 60, string("World World World World World World World World World World ")); + const failable<value> r = evalKernel(createKernel(exp, content(clprog)), exp, 1, value::String, 128, cl); + assert(hasContent(r)); + assert(content(r) == value(string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello World World World World World World World World World World "))); + } + + return true; +} + +struct evalTaskParallelLoop { + evalTaskParallelLoop(const OpenCLContext& cl, const OpenCLProgram& clprog) : cl(cl), clprog(clprog), exp(mklist<value>("add", 60, string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello "), 60, string("World World World World World World World World World World "))) { + } + const bool operator()() const { + const failable<value> r = evalKernel(createKernel(exp, clprog), exp, 1, value::String, 128, cl); + assert(hasContent(r)); + assert(content(r) == value(string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello World World World World World World World World World World "))); + return true; + } + + const OpenCLContext& cl; + const OpenCLProgram& clprog; + const value exp; +}; + +const bool testTaskParallelPerf(const OpenCLContext::DeviceType dev, const bool copy) { + gc_scoped_pool pool; + OpenCLContext cl(dev); + if (!devices(cl) != 0) + return true; + + istringstream is(dev == OpenCLContext::CPU? testCharsCPU : copy? testCharsCopyGPU : testCharsGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + + resetOpenCLCounters(); + const lambda<bool()> el = evalTaskParallelLoop(cl, content(clprog)); + cout << "OpenCL task-parallel eval " << (dev == OpenCLContext::CPU? "CPU" : "GPU") << (copy? " copy" : "") << " test " << time(el, 5, 500) << " ms"; + printOpenCLCounters(500); + cout << endl; + return true; +} + +bool testDataParallel(const OpenCLContext::DeviceType dev) { + gc_scoped_pool pool; + OpenCLContext cl(dev); + if (!devices(cl) != 0) + return true; + + { + istringstream is(dev == OpenCLContext::CPU? testCharsParallelCPU : testCharsParallelGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + + const value exp = mklist<value>("add", 6, string("Hello "), 5, string("World")); + const failable<value> r = evalKernel(createKernel(exp, content(clprog)), exp, 121, value::String, 128, cl); + assert(hasContent(r)); + assert(content(r) == value(string("Hello World"))); + } + + return true; +} + +struct evalDataParallelLoop { + evalDataParallelLoop(const OpenCLContext& cl, const OpenCLProgram& clprog) : cl(cl), clprog(clprog), exp(mklist<value>("add", 60, string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello "), 60, string("World World World World World World World World World World "))) { + } + const bool operator()() const { + const failable<value> r = evalKernel(createKernel(exp, clprog), exp, 121, value::String, 128, cl); + assert(hasContent(r)); + assert(content(r) == value(string("Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello World World World World World World World World World World "))); + return true; + } + + const OpenCLContext& cl; + const OpenCLProgram& clprog; + const value exp; +}; + +const bool testDataParallelPerf(const OpenCLContext::DeviceType dev, const bool copy) { + gc_scoped_pool pool; + OpenCLContext cl(dev); + if (!devices(cl) != 0) + return true; + + istringstream is(dev == OpenCLContext::CPU? testCharsParallelCPU : copy? testCharsParallelCopyGPU : testCharsParallelGPU); + failable<OpenCLProgram> clprog = readProgram("kernel.cl", is, cl); + assert(hasContent(clprog)); + + resetOpenCLCounters(); + const lambda<bool()> el = evalDataParallelLoop(cl, content(clprog)); + cout << "OpenCL data-parallel eval " << (dev == OpenCLContext::CPU? "CPU" : "GPU") << (copy? " copy" : "") << " test " << time(el, 5, 500) << " ms"; + printOpenCLCounters(500); + cout << endl; + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::opencl::testTaskParallel(tuscany::opencl::OpenCLContext::CPU); + tuscany::opencl::testTaskParallelPerf(tuscany::opencl::OpenCLContext::CPU, false); + tuscany::opencl::testDataParallel(tuscany::opencl::OpenCLContext::CPU); + tuscany::opencl::testDataParallelPerf(tuscany::opencl::OpenCLContext::CPU, false); + + tuscany::opencl::testTaskParallel(tuscany::opencl::OpenCLContext::GPU); + tuscany::opencl::testTaskParallelPerf(tuscany::opencl::OpenCLContext::GPU, false); + tuscany::opencl::testTaskParallelPerf(tuscany::opencl::OpenCLContext::GPU, true); + tuscany::opencl::testDataParallel(tuscany::opencl::OpenCLContext::GPU); + tuscany::opencl::testDataParallelPerf(tuscany::opencl::OpenCLContext::GPU, false); + tuscany::opencl::testDataParallelPerf(tuscany::opencl::OpenCLContext::GPU, true); + + tuscany::cout << "OK" << tuscany::endl; + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/server-test b/sca-cpp/branches/lightweight-sca/modules/opencl/server-test new file mode 100755 index 0000000000..c103c45487 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/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 +rm -rf tmp +../http/httpd-conf tmp localhost 8090 ../server/htdocs +../server/server-conf tmp +./opencl-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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/opencl/server-test.cl b/sca-cpp/branches/lightweight-sca/modules/opencl/server-test.cl new file mode 100644 index 0000000000..de5c2d1b1e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/opencl/server-test.cl @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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/sca-cpp/branches/lightweight-sca/modules/scdl/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/scdl/Makefile.am new file mode 100644 index 0000000000..54a9b46e4f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 diff --git a/sca-cpp/branches/lightweight-sca/modules/scdl/scdl-test.cpp b/sca-cpp/branches/lightweight-sca/modules/scdl/scdl-test.cpp new file mode 100644 index 0000000000..4c10f515df --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scdl/scdl-test.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$ */ + +/** + * 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(implementationType(impl) == "implementation.scheme"); + assert(attributeValue("script", impl) == string("store.scm")); + + 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) == "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) == "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::gc_scoped_pool p; + 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/sca-cpp/branches/lightweight-sca/modules/scdl/scdl.hpp b/sca-cpp/branches/lightweight-sca/modules/scdl/scdl.hpp new file mode 100644 index 0000000000..7cf43e3b14 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scdl/scdl.hpp @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 a list of service promotions in a composite. + */ +const list<value> promotions(const value& l) { + const list<value> cs = elementChildren("composite", l); + if (isNil(cs)) + return cs; + return elementChildren("service", car(cs)); +} + +/** + * Returns the target or a service promotion. + */ +const value promote(const value& l) { + return attributeValue("promote", l); +} + +/** + * 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 true if a reference is declared as wired by impl. + */ +const bool wiredByImpl(const value& l) { + return attributeValue("wiredByImpl", l) == string("true"); +} + +/** + * 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); +} + +/** + * Returns the absolute path of a resource in a contribution. + */ +const string resourcePath(const string& contrib, const string& path) { + return c_str(path)[0] == '/'? path : contrib + path; +} + +} +} + +#endif /* tuscany_scdl_hpp */ diff --git a/sca-cpp/branches/lightweight-sca/modules/scdl/test.composite b/sca-cpp/branches/lightweight-sca/modules/scdl/test.composite new file mode 100644 index 0000000000..5d8c5d3b88 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scdl/test.composite @@ -0,0 +1,63 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.scheme script="store.scm"/> + <service name="Widget"> + <binding.http uri="/store"/> + </service> + <reference name="catalog" target="Catalog"> + <binding.jsonrpc/> + </reference> + <reference name="shoppingCart" target="ShoppingCart/Cart"> + <binding.atom/> + </reference> + <reference name="shoppingTotal" target="ShoppingCart/Total"> + <binding.jsonrpc/> + </reference> + </component> + + <component name="Catalog"> + <implementation.scheme script="fruits-catalog.scm"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.scheme script="shopping-cart.scm"/> + <service name="Cart"> + <binding.atom uri="/ShoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc/> + </service> + </component> + + <component name="CurrencyConverter"> + <implementation.scheme script="currency-converter.scm"/> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/modules/scdl/validate-test b/sca-cpp/branches/lightweight-sca/modules/scdl/validate-test new file mode 100755 index 0000000000..9f277cf15a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=$? +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/scheme/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/scheme/Makefile.am new file mode 100644 index 0000000000..130fe14303 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/Makefile.am @@ -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. + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/modules/scheme + +moddir = $(prefix)/modules/scheme + +scheme_test_SOURCES = scheme-test.cpp + +scheme_shell_SOURCES = scheme-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 = scheme-test +mod_PROGRAMS = scheme-shell element-value value-element xml-value value-xml json-value value-json +TESTS = scheme-test diff --git a/sca-cpp/branches/lightweight-sca/modules/scheme/driver.hpp b/sca-cpp/branches/lightweight-sca/modules/scheme/driver.hpp new file mode 100644 index 0000000000..112c226ed1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/scheme/element-value.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/element-value.cpp new file mode 100644 index 0000000000..8a443dbdb2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/scheme/environment.hpp b/sca-cpp/branches/lightweight-sca/modules/scheme/environment.hpp new file mode 100644 index 0000000000..303a37cb3c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/environment.hpp @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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)))) { + if (isNil(cdr(cdr(exps)))) + return value(); + 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/sca-cpp/branches/lightweight-sca/modules/scheme/eval.hpp b/sca-cpp/branches/lightweight-sca/modules/scheme/eval.hpp new file mode 100644 index 0000000000..34d1a7bc17 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/scheme/io.hpp b/sca-cpp/branches/lightweight-sca/modules/scheme/io.hpp new file mode 100644 index 0000000000..8f9d70e7fe --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/io.hpp @@ -0,0 +1,239 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 failable<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 failable<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 mkfailure<value>(); + logStream() << "Illegal lexical syntax '" << firstChar << "'" << endl; + return readToken(in); +} + +const failable<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 failable<value> ftoken = readToken(in); + if (!hasContent(ftoken)) + return reverse(listSoFar); + const value token = content(ftoken); + if(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); + if (val == "nil") + return value(); + return val; +} + +const list<char> readStringHelper(const list<char>& listSoFar, istream& in) { + const char nextChar = readChar(in); + if(nextChar == -1 || nextChar == '"') + return reverse(listSoFar); + if (nextChar == '\\') { + const char escapedChar = readChar(in); + if (escapedChar == -1) + return reverse(listSoFar); + return readStringHelper(cons(escapedChar, listSoFar), in); + } + return readStringHelper(cons(nextChar, listSoFar), in); +} + +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 failable<value> fnextToken = readToken(in); + if (!hasContent(fnextToken)) + return value(); + const value nextToken = content(fnextToken); + if(isLeftParenthesis(nextToken)) + return readList(list<value>(), in); + return nextToken; +} + +const value readValue(const string s) { + istringstream in(s); + const failable<value> fnextToken = readToken(in); + if (!hasContent(fnextToken)) + return value(); + const value nextToken = content(fnextToken); + 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/sca-cpp/branches/lightweight-sca/modules/scheme/json-value.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/json-value.cpp new file mode 100644 index 0000000000..4bdf8bd37f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/json-value.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 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) << " : " << rcode(lv); + return 1; + } + cout << writeValue(content(lv)); + return 0; +} + +} +} + +int main() { + return tuscany::scheme::jsonValue(); +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/scheme/primitive.hpp b/sca-cpp/branches/lightweight-sca/modules/scheme/primitive.hpp new file mode 100644 index 0000000000..59aee12073 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/primitive.hpp @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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" +#include "parallel.hpp" + +namespace tuscany { +namespace scheme { + +const value primitiveSymbol("primitive"); +const value quoteSymbol("'"); +const value lambdaSymbol("lambda"); + +#ifdef WANT_THREADS +perthread_ptr<ostream> displayOutStream; +#else +ostream* displayOutStream = NULL; +#endif + +#ifdef WANT_THREADS +perthread_ptr<ostream> logOutStream; +#else +ostream* logOutStream = NULL; +#endif + +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(const list<value>& args) { + return cadr((list<value> )car(args)); +} + +const value caddrProc(const list<value>& args) { + return caddr((list<value> )car(args)); +} + +const value cadddrProc(const list<value>& args) { + return cadddr((list<value> )car(args)); +} + +const value cddrProc(const list<value>& args) { + return cddr((list<value> )car(args)); +} + +const value cdddrProc(const list<value>& args) { + return cdddr((list<value> )car(args)); +} + +const value appendProc(const list<value>& args) { + return append((list<value> )car(args), (list<value>)cadr(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" + + "append" + + "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(appendProc) + + 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/sca-cpp/branches/lightweight-sca/modules/scheme/scheme-shell.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/scheme-shell.cpp new file mode 100644 index 0000000000..4aa67c2375 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/scheme-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/sca-cpp/branches/lightweight-sca/modules/scheme/scheme-test.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/scheme-test.cpp new file mode 100644 index 0000000000..5b69b8e588 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/scheme/scheme-test.cpp @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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); + } + { + const list<value> i = mklist<value>("x", value()); + const list<value> a = mklist<value>(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::gc_scoped_pool p; + 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/sca-cpp/branches/lightweight-sca/modules/scheme/value-element.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/value-element.cpp new file mode 100644 index 0000000000..a4acdaf2d7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/scheme/value-json.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/value-json.cpp new file mode 100644 index 0000000000..a8c875fcc8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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(readValue(cin), cx); + if (!hasContent(s)) { + cerr << reason(s) << " : " << rcode(s); + return 1; + } + write(content(s), cout); + return 0; +} + +} +} + +int main() { + return tuscany::scheme::valueJSON(); +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/scheme/value-xml.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/value-xml.cpp new file mode 100644 index 0000000000..ff785899c6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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(readValue(cin)); + if (!hasContent(s)) { + cerr << reason(s) << " : " << rcode(s); + return 1; + } + write(content(s), cout); + return 0; +} + +} +} + +int main() { + return tuscany::scheme::valueXML(); +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/scheme/xml-value.cpp b/sca-cpp/branches/lightweight-sca/modules/scheme/xml-value.cpp new file mode 100644 index 0000000000..d88f754aa5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = readXML(streamList(cin)); + cout << writeValue(v); + return 0; +} + +} +} + +int main() { + return tuscany::scheme::xmlValue(); +} + diff --git a/sca-cpp/branches/lightweight-sca/modules/server/Makefile.am b/sca-cpp/branches/lightweight-sca/modules/server/Makefile.am new file mode 100644 index 0000000000..e2fd67d9b8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/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. + +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/*.html htdocs/test/*.xml htdocs/test/*.txt + +mod_LTLIBRARIES = libmod_tuscany_eval.la +noinst_DATA = libmod_tuscany_eval${libsuffix} + +libmod_tuscany_eval_la_SOURCES = mod-eval.cpp +libmod_tuscany_eval_la_LDFLAGS = -lxml2 -lcurl -lmozjs +libmod_tuscany_eval${libsuffix}: + ln -s .libs/libmod_tuscany_eval${libsuffix} + +noinst_test_LTLIBRARIES = libimpl-test.la +noinst_testdir = `pwd`/tmp +noinst_DATA += libimpl-test${libsuffix} + +libimpl_test_la_SOURCES = impl-test.cpp +libimpl-test${libsuffix}: + ln -s .libs/libimpl-test${libsuffix} + +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/sca-cpp/branches/lightweight-sca/modules/server/client-test.cpp b/sca-cpp/branches/lightweight-sca/modules/server/client-test.cpp new file mode 100644 index 0000000000..3f5ff20c56 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/scheme"; + + tuscany::server::testServer(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/lightweight-sca/modules/server/client-test.hpp b/sca-cpp/branches/lightweight-sca/modules/server/client-test.hpp new file mode 100644 index 0000000000..1c7b26da39 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/client-test.hpp @@ -0,0 +1,372 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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/scheme"; +bool testBlobs = true; + +ostream* curlWriter(const string& s, ostream* os) { + (*os) << s; + return os; +} + +const bool testGet() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + { + 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("", "", "", "", 0); + 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("", "", "", "", 0); + const failable<value> r = http::evalExpr(mklist<value>(string("echo"), string("Hello")), testURI, ch); + assert(hasContent(r)); + assert(content(r) == 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 failable<value> r = http::evalExpr(mklist<value>(string("echo"), string("Hello")), uri, ch); + assert(hasContent(r)); + assert(content(r) == 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 failable<value> r = content(http::evalExpr(mklist<value>(string("echo"), blobs), uri, ch)); + assert(hasContent(r)); + assert(content(r) == blobs); + return true; + } +}; + +const bool testEvalPerf() { + gc_scoped_pool pool; + http::CURLSession ch("", "", "", "", 0); + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + http::CURLSession ch("", "", "", "", 0); + 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("", "", "", "", 0); + { + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "blob1" + blob) + + (list<value>() + "blob2" + blob) + + (list<value>() + "price" + string("$2.99"))); + const list<value> val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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("", "", "", "", 0); + 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; + worker& w; + const int threads; + postThreadLoop(const lambda<bool()>& l, worker& w, const int threads) : l(l), w(w), threads(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; + worker w(threads); + + const list<value> i = list<value>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const value val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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, w, 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("", "", "", "", 0); + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const value val = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + 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>() + "content" + (list<value>() + "item" + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99"))); + const list<value> a = list<value>() + (list<value>() + "entry" + + (list<value>() + "title" + string("item")) + + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + i); + http::CURLSession ch("", "", "", "", 0); + 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("", "", "", "", 0); + 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/sca-cpp/branches/lightweight-sca/modules/server/client-test.scm b/sca-cpp/branches/lightweight-sca/modules/server/client-test.scm new file mode 100644 index 0000000000..47b799d390 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/server/cpp-conf b/sca-cpp/branches/lightweight-sca/modules/server/cpp-conf new file mode 100755 index 0000000000..6b74f60ec5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/cpp-conf @@ -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. + +# Generate a C++ server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +cat >>$root/conf/modules.conf <<EOF +# Generated by: cpp-conf $* +# Support for C++ SCA components +LoadModule mod_tuscany_eval $here/libmod_tuscany_eval$libsuffix + +EOF diff --git a/sca-cpp/branches/lightweight-sca/modules/server/domain-test.composite b/sca-cpp/branches/lightweight-sca/modules/server/domain-test.composite new file mode 100644 index 0000000000..1819b3bf4c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/domain-test.composite @@ -0,0 +1,58 @@ +<?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" + targetNamespace="http://domain/test" + name="domain-test"> + + <component name="scheme-test"> + <implementation.scheme script="server-test.scm"/> + <service name="scheme"> + <binding.http uri="scheme"/> + </service> + </component> + + <component name="property-test"> + <implementation.scheme script="property-test.scm"/> + <service name="properties"> + <binding.http uri="properties"/> + </service> + <property name="host"></property> + <property name="path"></property> + <property name="query"></property> + </component> + + <component name="cpp-test"> + <implementation.cpp path="." library="libimpl-test"/> + <service name="cpp"> + <binding.http uri="cpp"/> + </service> + </component> + + <component name="client-test"> + <implementation.scheme script="client-test.scm"/> + <service name="client"> + <binding.http uri="client"/> + </service> + <reference name="ref" target="scheme-test"> + <binding.http/> + </reference> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/modules/server/htdocs/index.html b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/index.html new file mode 100644 index 0000000000..236864edfb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>It works</title> +</head> +<body> +<h1>It works!</h1> +</body> +</html> + diff --git a/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/entry.xml b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/entry.xml new file mode 100644 index 0000000000..46053c3138 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/entry.xml @@ -0,0 +1,14 @@ +<?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/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/feed.xml b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/feed.xml new file mode 100644 index 0000000000..337320e4c5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/feed.xml @@ -0,0 +1,44 @@ +<?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/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-properties.txt b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-properties.txt new file mode 100644 index 0000000000..2cff8b7339 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-properties.txt @@ -0,0 +1,14 @@ +{ + "id": "1", + "result": { + "host": "localhost", + "path": [ + "c", + "property-test" + ], + "query": { + "id": "1", + "method": "print" + } + } +}
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-request.txt b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-request.txt new file mode 100644 index 0000000000..b5c2457309 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-request.txt @@ -0,0 +1,7 @@ +{ + "id": 1, + "method": "echo", + "params": [ + "Hello" + ] +} diff --git a/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-result.txt b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-result.txt new file mode 100644 index 0000000000..72b27b67db --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/htdocs/test/json-result.txt @@ -0,0 +1,4 @@ +{ + "id": 1, + "result": "Hello" +}
\ No newline at end of file diff --git a/sca-cpp/branches/lightweight-sca/modules/server/httpd-test b/sca-cpp/branches/lightweight-sca/modules/server/httpd-test new file mode 100755 index 0000000000..195caa4562 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/httpd-test @@ -0,0 +1,87 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../http/curl.prefix` + +# Setup +rm -rf tmp +../http/httpd-conf tmp localhost 8090 htdocs +../http/httpd-event-conf tmp +./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/scheme/ >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/scheme/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/scheme/ -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/scheme/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/scheme/111 -X DELETE 2>/dev/null + rc=$? +fi + +# Test JSON-RPC +if [ "$rc" = "0" ]; then + $curl_prefix/bin/curl http://localhost:8090/scheme/ -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 + +# Test built-in properties +if [ "$rc" = "0" ]; then + $curl_prefix/bin/curl 'http://localhost:8090/properties?id=1&method=print' >tmp/json-properties.txt 2>/dev/null + diff tmp/json-properties.txt htdocs/test/json-properties.txt + rc=$? +fi + +# Cleanup +../http/httpd-stop tmp +sleep 2 +if [ "$rc" = "0" ]; then + echo "OK" +fi +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/server/impl-test.cpp b/sca-cpp/branches/lightweight-sca/modules/server/impl-test.cpp new file mode 100644 index 0000000000..1bd0843745 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/server/mod-cpp.hpp b/sca-cpp/branches/lightweight-sca/modules/server/mod-cpp.hpp new file mode 100644 index 0000000000..8cae35e493 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/server/mod-eval.cpp b/sca-cpp/branches/lightweight-sca/modules/server/mod-eval.cpp new file mode 100644 index 0000000000..3fd69c1fea --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/mod-eval.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$ */ + +/** + * HTTPD module used to eval C++ and Scheme component implementations. + */ + +#define WANT_HTTPD_LOG 1 +#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); + if (contains(itype, ".widget")) + return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype, -1, false); + return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype); +} + +} +} +} diff --git a/sca-cpp/branches/lightweight-sca/modules/server/mod-eval.hpp b/sca-cpp/branches/lightweight-sca/modules/server/mod-eval.hpp new file mode 100644 index 0000000000..ee99baa039 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/mod-eval.hpp @@ -0,0 +1,1600 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more provider license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 <sys/stat.h> + +#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 "../scheme/io.hpp" +#include "../atom/atom.hpp" +#include "../json/json.hpp" +#include "../scdl/scdl.hpp" +#include "../http/http.hpp" +#include "../http/httpd.hpp" + +#include "apr_md5.h" +#include "ap_provider.h" +#include "mod_auth.h" + +extern "C" { +extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval; +} + +namespace tuscany { +namespace server { +namespace modeval { + +/** + * SSL certificate configuration. + */ +class SSLConf { +public: + SSLConf() { + } + + string ca; + string cert; + string key; +}; + +/** + * Virtual host configuration. + */ +class VhostConf { +public: + VhostConf() { + } + + string domain; + string contribPath; + string composName; + string contributorName; + value contributor; + string authenticatorName; + value authenticator; +}; + +/** + * Contribution configuration. + */ +class ContribConf { +public: + ContribConf() { + } + + string contribPath; + string composName; +}; + +/** + * Composite assocs. + */ +class Composite { +public: + Composite() { + } + + Composite(const list<value>& refs, const list<value>& svcs, const list<value>& impls) : refs(refs), svcs(svcs), impls(impls) { + } + + list<value> refs; + list<value> svcs; + list<value> impls; +}; + +/** + * Server configuration. + */ +class ServerConf { +public: + ServerConf() { + } + + ServerConf(apr_pool_t* p, const server_rec* s) : p(p), server(s), timeout(0) { + } + + const gc_pool p; + const server_rec* server; + lambda<value(const list<value>&)> lifecycle; + ContribConf contribc; + SSLConf sslc; + int timeout; + VhostConf vhostc; + Composite compos; +}; + +/** + * Request configuration. + */ +class RequestConf { +public: + RequestConf(apr_pool_t* p, const request_rec* r) : p(p), request(r), vhost(false), valias(false) { + } + + const gc_pool p; + const request_rec* request; + bool vhost; + bool valias; + list<value> rpath; + list<value> vpath; + list<value> impls; +}; + +/** + * Authentication cache store function. + */ +static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authnCacheStore = NULL; + +/** + * Convert a result represented as a (content reason? code?) tuple 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)), isNil(cddr(v))? -1 : (int)caddr(v), false); +} + +/** + * Store current HTTP request for access from property and proxy lambda functions. + */ +#ifdef WANT_THREADS +perthread_ptr<request_rec> currentRequest; +#else +request_rec* currentRequest = NULL; +#endif + +class ScopedRequest { +public: + ScopedRequest(request_rec* r) { + currentRequest = r; + } + + ~ScopedRequest() { + currentRequest = NULL; + } +}; + +/** + * Make an HTTP proxy lambda to an absolute URI + */ +const value mkhttpProxy(const string& uri, const int timeout, const gc_pool& p) { + debug(uri, "modeval::mkhttpProxy::uri"); + return lambda<value(const list<value>&)>(http::proxy(uri, "", "", "", "", timeout, p)); +} + +/** + * Return a component implementation proxy lambda. + */ +class implProxy { +public: + implProxy(const value& name, const list<value>& impls, const SSLConf& sslc, const int timeout) : name(name), impls(impls), sslc(sslc), timeout(timeout) { + } + + const value callImpl(const value& cname, const list<value>& aparams) const { + //debug(impls, "modeval::implProxy::callImpl::impls"); + + // Lookup the component implementation + const list<value> impl(assoctree<value>(cname, impls)); + if (isNil(impl)) + return mkfailure<value>(string("Couldn't find component implementation: ") + cname); + + // Call its lambda function + const lambda<value(const list<value>&)> l(cadr<value>(impl)); + const value func = c_str(car(aparams)); + const failable<value> val = failableResult(l(cons(func, cdr(aparams)))); + debug(val, "modeval::implProxy::result"); + if (!hasContent(val)) + return value(); + return content(val); + } + + const value operator()(const list<value>& params) const { + debug(name, "modeval::implProxy::name"); + debug(params, "modeval::implProxy::input"); + + // If the reference was 'wiredByImpl' use the first param as target + if (isNil(name)) { + const value uri = cadr(params); + const list<value> aparams = cons<value>(car(params), cddr(params)); + debug(uri, "modeval::implProxy::wiredByImpl::uri"); + debug(aparams, "modeval::implProxy::wiredByImpl::input"); + + // Use an HTTP proxy if the target is an absolute :// target + if (http::isAbsolute(uri)) { + gc_pool p(currentRequest->pool); + + // Interpret a uri in the form app://appname, convert it using the scheme, + // top level domain and port number from the current request + if (http::scheme(uri, p) == "app") { + ostringstream appuri; + appuri << httpd::scheme(currentRequest) << "://" << substr(uri, 6) << "." << http::topDomain(httpd::hostName(currentRequest)) << ":" << httpd::port(currentRequest) << "/"; + debug(str(appuri), "modeval::implProxy::httpproxy::appuri"); + const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(str(appuri), sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), timeout, p)); + return px(aparams); + } + + // Pass our SSL certificate and the cookie from the current request + // only if the target is in the same top level domain + if (http::topDomain(http::hostName(uri, p)) == http::topDomain(httpd::hostName(currentRequest))) { + debug(uri, "modeval::implProxy::httpproxy::samedomain"); + const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(uri, sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), timeout, p)); + return px(aparams); + } + + // No SSL certificate or cookie on a cross domain call + debug(uri, "modeval::implProxy::httpproxy::crossdomain"); + const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(uri, "", "", "", "", timeout, p)); + return px(aparams); + } + + // Call the component implementation + return callImpl(uri, aparams); + } + + // Call the component implementation + return callImpl(name, params); + } + +private: + const value name; + const list<value>& impls; + const SSLConf& sslc; + const int timeout; +}; + +const value mkimplProxy(const value& name, const list<value>& impls, const SSLConf& sslc, const int timeout) { + debug(name, "modeval::implProxy::impl"); + return lambda<value(const list<value>&)>(implProxy(name, impls, sslc, timeout)); +} + +/** + * Return a proxy lambda for an unwired reference. + */ +class unwiredProxy { +public: + unwiredProxy(const value& name) : name(name) { + } + + const value operator()(const list<value>& params) const { + debug(name, "modeval::unwiredProxy::name"); + debug(params, "modeval::unwiredProxy::input"); + + // Get function returns a default empty value + if (car(params) == "get") { + debug(value(), "modeval::unwiredProxy::result"); + return value(); + } + + // All other functions return a failure + return mkfailure<value>(string("Reference is not wired: ") + name); + } + +private: + const value name; +}; + +/** + * Make a proxy lambda for an unwired reference. + */ +const value mkunwiredProxy(const string& ref) { + debug(ref, "modeval::mkunwiredProxy::ref"); + return lambda<value(const list<value>&)>(unwiredProxy(ref)); +} + +/** + * Convert a list of component references to a list of proxy lambdas. + */ +const value mkrefProxy(const value& ref, const list<value>& impls, const SSLConf& sslc, const int timeout, const gc_pool& p) { + const value target = scdl::target(ref); + const bool wbyimpl = scdl::wiredByImpl(ref); + debug(ref, "modeval::mkrefProxy::ref"); + debug(target, "modeval::mkrefProxy::target"); + debug(wbyimpl, "modeval::mkrefProxy::wiredByImpl"); + + // Use an HTTP proxy or an internal proxy to the component implementation + if (wbyimpl) + return mkimplProxy(value(), impls, sslc, timeout); + if (isNil(target)) + return mkunwiredProxy(scdl::name(ref)); + if (http::isAbsolute(target)) + return mkhttpProxy(target, timeout, p); + return mkimplProxy(car(pathValues(target)), impls, sslc, timeout); +} + +const list<value> refProxies(const list<value>& refs, const list<value>& impls, const SSLConf& sslc, const int timeout, const gc_pool& p) { + if (isNil(refs)) + return refs; + return cons(mkrefProxy(car(refs), impls, sslc, timeout, p), refProxies(cdr(refs), impls, sslc, timeout, p)); +} + +/** + * 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 { + if (currentRequest == NULL) + return http::hostName(); + const value h = httpd::hostName(currentRequest, v); + debug(h, "modeval::hostPropProxy::value"); + return h; + } +}; + +struct appPropProxy { + const value v; + appPropProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + const RequestConf& reqc = httpd::requestConf<RequestConf>(currentRequest, &mod_tuscany_eval); + const value a = isNil(reqc.vpath)? v : car(reqc.vpath); + debug(a, "modeval::appPropProxy::value"); + return a; + } +}; + +struct pathPropProxy { + const value v; + pathPropProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + const RequestConf& reqc = httpd::requestConf<RequestConf>(currentRequest, &mod_tuscany_eval); + const value p = reqc.rpath; + debug(p, "modeval::pathPropProxy::value"); + return p; + } +}; + +struct queryPropProxy { + const value v; + queryPropProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + const value q = httpd::unescapeArgs(httpd::queryArgs(currentRequest)); + debug(q, "modeval::queryPropProxy::value"); + return q; + } +}; + +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 { + if (currentRequest == NULL) + return v; + const char* env = apr_table_get(currentRequest->subprocess_env, c_str(name)); + if (env == NULL || *env == '\0') + return v; + debug(name, "modeval::envPropProxy::name"); + const value e = string(env); + debug(e, "modeval::envPropProxy::value"); + return e; + } +}; + +struct realmPropProxy { + const value v; + realmPropProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + const char* env = apr_table_get(currentRequest->subprocess_env, "REALM"); + if (env == NULL) + return v; + const string realm = httpd::realm(string(env)); + if (length(realm) == 0) + return v; + const value r = realm; + debug(r, "modeval::realmPropProxy::value"); + return r; + } +}; + +struct timeoutPropProxy { + const value v; + timeoutPropProxy(const value& v) : v(atoi(c_str((string)v))) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + const ServerConf& sc = httpd::serverConf<ServerConf>(currentRequest, &mod_tuscany_eval); + const value r = sc.timeout; + debug(r, "modeval::timeoutPropProxy::value"); + return r; + } +}; + +struct userPropProxy { + const value v; + userPropProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + if (currentRequest->user == NULL) + return v; + const value u = string(currentRequest->user); + debug(u, "modeval::userPropProxy::value"); + return u; + } +}; + +const value mkpropProxy(const value& prop) { + const value n = scdl::name(prop); + const value v = elementHasValue(prop)? elementValue(prop):value(string("")); + if (n == "app") + return lambda<value(const list<value>&)>(appPropProxy(v)); + if (n == "host") + return lambda<value(const list<value>&)>(hostPropProxy(v)); + if (n == "path") + return lambda<value(const list<value>&)>(pathPropProxy(v)); + if (n == "query") + return lambda<value(const list<value>&)>(queryPropProxy(v)); + if (n == "user") + return lambda<value(const list<value>&)>(userPropProxy(v)); + if (n == "realm") + return lambda<value(const list<value>&)>(realmPropProxy(v)); + if (n == "timeout") + return lambda<value(const list<value>&)>(timeoutPropProxy(v)); + if (n == "email") + return lambda<value(const list<value>&)>(envPropProxy("EMAIL", v)); + if (n == "nickname") + return lambda<value(const list<value>&)>(envPropProxy("NICKNAME", v)); + if (n == "fullname") + return lambda<value(const list<value>&)>(envPropProxy("FULLNAME", v)); + if (n == "firstname") + return lambda<value(const list<value>&)>(envPropProxy("FIRSTNAME", v)); + if (n == "lastname") + return lambda<value(const list<value>&)>(envPropProxy("LASTNAME", v)); + return lambda<value(const list<value>&)>(propProxy(v)); +} + +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(const string& contribPath, const value& comp, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { + 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 + const list<value> rpx(refProxies(scdl::references(comp), impls, sslc, timeout, p)); + + // Convert component properties 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(contribPath, impl, append(rpx, ppx), 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(const list<value>& c, const string& contribPath, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { + if (isNil(c)) + return c; + return cons<value>(mklist<value>(scdl::name(car(c)), + evalComponent(contribPath, car(c), impls, lifecycle, sslc, timeout, p)), + componentToImplementationAssoc(cdr(c), contribPath, impls, lifecycle, sslc, timeout, p)); +} + +/** + * 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))); +} + +/** + * Get the components returned by a contributor. + */ +const failable<list<value> > getComponents(const lambda<value(const list<value>&)>& contributor, const string& name) { + const failable<value> val = failableResult(contributor(cons<value>("get", mklist<value>(mklist<value>(name))))); + if (!hasContent(val)) + return mkfailure<list<value> >(val); + const list<value> c = assoc<value>(value("composite"), assoc<value>(value("content"), (list<list<value> >)cdr<value>(car<value>(content(val))))); + debug(c, "modeval::getComponents::comp"); + if (isNil(c)) + return mkfailure<list<value> >(string("Could not get composite: ") + name); + const failable<list<string> > x = writeXML(car<value>(valuesToElements(mklist<value>(mklist<value>(c))))); + if (!hasContent(x)) + return mkfailure<list<value> >(x); + return scdl::components(readXML(content(x))); +} + +/** + * 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> >(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)); +} + +/** + * 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 deployed composite. + */ +const failable<Composite> confComponents(const string& contribPath, const string& composName, const value& contributor, const string& vhost, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { + debug(contribPath, "modeval::confComponents::contribPath"); + debug(composName, "modeval::confComponents::composName"); + debug(contributor, "modeval::confComponents::contributor"); + debug(vhost, "modeval::confComponents::vhost"); + debug(impls, "modeval::confComponents::impls"); + + const failable<list<value> > fcomps = isNil(contributor)? + readComponents(scdl::resourcePath(length(vhost) != 0? contribPath + vhost + "/" : contribPath, composName)) : + getComponents(contributor, vhost); + if (!hasContent(fcomps)) + return mkfailure<Composite>(fcomps); + + const list<value> comps = content(fcomps); + debug(comps, "modeval::confComponents::comps"); + + const list<value> refs = mkbtree(sort(componentReferenceToTargetAssoc(comps))); + debug(flatten(refs), "modeval::confComponents::refs"); + + const list<value> svcs = mkbtree(sort(uriToComponentAssoc(comps))); + debug(flatten(svcs), "modeval::confComponents::svcs"); + + const list<value> cimpls = mkbtree(sort(componentToImplementationAssoc(comps, + isNil(contributor)? length(vhost) != 0? contribPath + vhost + "/" : contribPath : contribPath, + impls, lifecycle, sslc, timeout, p))); + debug(flatten(cimpls), "modeval::confComponents::impls"); + + return Composite(refs, svcs, cimpls); +} + +/** + * Start the components declared in a composite. + */ +const failable<list<value> > startComponents(const list<value>& impls) { + debug(flatten(impls), "modeval::startComponents::impls"); + const failable<list<value> > fsimpls = applyLifecycleExpr(flatten(impls), mklist<value>("start")); + if (!hasContent(fsimpls)) + return mkfailure<list<value> >(fsimpls); + + const list<value> simpls = content(fsimpls); + debug(impls, "modeval::startComponents::simpls"); + return mkbtree(sort(simpls)); +} + +/** + * Stop the components declared in a composite. + */ +const failable<bool> stopComponents(const list<value>& simpls) { + debug(flatten(simpls), "modeval::stopComponents::simpls"); + applyLifecycleExpr(flatten(simpls), mklist<value>("stop")); + return true; +} + +/** + * Handle an HTTP GET. + */ +const failable<int> get(const list<value>& rpath, 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>(val); + + // Return JSON result + js::JSContext cx; + return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc; charset=utf-8", r); + } + + // Evaluate the GET expression + const list<value> params(cddr(rpath)); + const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(params)))); + if (!hasContent(val)) + return mkfailure<int>(val); + const value c = content(val); + debug(c, "modeval::get::content"); + + // Return a nil value as a not found status + if (!isList(c) && isNil(c)) + return HTTP_NOT_FOUND; + + // Check if the client requested a specific format + const list<value> fmt = assoc<value>("format", args); + + // Write as a scheme value if requested by the client + if (!isNil(fmt) && cadr(fmt) == "scheme") + return httpd::writeResult(mklist<string>(scheme::writeValue(c)), "text/plain; charset=utf-8", r); + + // Write a simple value as a JSON value + if (!isList(c)) { + js::JSContext cx; + if (isSymbol(c)) { + const list<value> lc = mklist<value>(mklist<value>("name", value(string(c)))); + debug(lc, "modeval::get::symbol"); + return httpd::writeResult(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8", r); + } + + const list<value> lc = mklist<value>(mklist<value>("value", c)); + debug(lc, "modeval::get::value"); + return httpd::writeResult(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8", r); + } + + // Write an empty list as a JSON empty value + if (isNil((list<value>)c)) { + js::JSContext cx; + debug(list<value>(), "modeval::get::empty"); + return httpd::writeResult(json::writeJSON(list<value>(), cx), "application/json; charset=utf-8", r); + } + + // Write content-type / content-list pair + if (isString(car<value>(c)) && !isNil(cdr<value>(c)) && isList(cadr<value>(c))) + return httpd::writeResult(convertValues<string>(cadr<value>(c)), car<value>(c), r); + + // Write an assoc value as a JSON result + if (isSymbol(car<value>(c)) && !isNil(cdr<value>(c))) { + js::JSContext cx; + const list<value> lc = mklist<value>(c); + debug(lc, "modeval::get::assoc"); + debug(valuesToElements(lc), "modeval::get::assoc::element"); + return httpd::writeResult(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8", r); + } + + // Write value as JSON if requested by the client + if (!isNil(fmt) && cadr(fmt) == "json") { + js::JSContext cx; + return httpd::writeResult(json::writeJSON(valuesToElements(c), cx), "application/json; charset=utf-8", r); + } + + // Convert list of values to element values + const list<value> e = valuesToElements(c); + debug(e, "modeval::get::elements"); + + // Write an ATOM feed or entry + if (isList(car<value>(e)) && !isNil(car<value>(e))) { + const list<value> el = car<value>(e); + if (isSymbol(car<value>(el)) && car<value>(el) == element && !isNil(cdr<value>(el)) && isSymbol(cadr<value>(el)) && elementHasChildren(el) && !elementHasValue(el)) { + if (cadr<value>(el) == atom::feed) + return httpd::writeResult(atom::writeATOMFeed(e), "application/atom+xml; charset=utf-8", r); + if (cadr<value>(el) == atom::entry) + return httpd::writeResult(atom::writeATOMEntry(e), "application/atom+xml; charset=utf-8", r); + } + } + + // Write any other compound value as a JSON value + js::JSContext cx; + return httpd::writeResult(json::writeJSON(e, cx), "application/json; charset=utf-8", r); +} + +/** + * Handle an HTTP POST. + */ +const failable<int> post(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::post::uri"); + + // 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>(val); + + // Return JSON result + return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc; charset=utf-8", 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 int rc = httpd::setupReadPolicy(r); + if(rc != OK) + return rc; + const list<string> ls = httpd::read(r); + debug(ls, "modeval::post::input"); + const value aval = elementsToValues(content(atom::isATOMEntry(ls)? atom::readATOMEntry(ls) : atom::readATOMFeed(ls))); + + // Evaluate the POST expression + const failable<value> val = failableResult(impl(cons<value>("post", mklist<value>(cddr(rpath), aval)))); + if (!hasContent(val)) + return mkfailure<int>(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>(val); + return (int)content(val); +} + +/** + * Handle an HTTP PUT. + */ +const failable<int> put(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::put::uri"); + + // Read the ATOM entry + 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 aval = elementsToValues(content(atom::isATOMEntry(ls)? atom::readATOMEntry(ls) : atom::readATOMFeed(ls))); + + // Evaluate the PUT expression and update the corresponding resource + const failable<value> val = failableResult(impl(cons<value>("put", mklist<value>(cddr(rpath), aval)))); + if (!hasContent(val)) + return mkfailure<int>(val); + if (val == value(false)) + return HTTP_NOT_FOUND; + return OK; +} + +/** + * Handle an HTTP DELETE. + */ +const failable<int> del(const list<value>& rpath, request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::delete::uri"); + + // Evaluate an ATOM delete request + const failable<value> val = failableResult(impl(cons<value>("delete", mklist<value>(cddr(rpath))))); + if (!hasContent(val)) + return mkfailure<int>(val); + if (val == value(false)) + return HTTP_NOT_FOUND; + return OK; +} + +/** + * Proceed to handle a service component request. + */ +int proceedToHandler(request_rec* r, const int rc) { + r->handler = "mod_tuscany_eval"; + return rc; +} + +int proceedToHandler(request_rec* r, const int rc, const bool valias, const list<value>& rpath, const list<value>& vpath, const list<value>& impls) { + r->handler = "mod_tuscany_eval"; + r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:") + r->uri)); + + // Store the selected vhost, path and composite in the request + RequestConf& reqc = httpd::requestConf<RequestConf>(r, &mod_tuscany_eval); + reqc.valias = valias; + reqc.rpath = rpath; + reqc.vpath = vpath; + reqc.impls = impls; + return rc; +} + +/** + * Route a component request to the specified component. + */ +int translateComponent(request_rec *r, const list<value>& rpath, const list<value>& vpath, const list<value>& impls) { + debug(rpath, "modeval::translateComponent::rpath"); + debug(flatten(impls), "modeval::translateComponent::impls"); + + // Find the requested component + if (isNil(cdr(rpath))) + return HTTP_NOT_FOUND; + const list<value> impl(assoctree(cadr(rpath), impls)); + if (isNil(impl)) + return HTTP_NOT_FOUND; + debug(impl, "modeval::translateComponent::impl"); + + return proceedToHandler(r, OK, false, rpath, vpath, impls);; +} + +/** + * Route a /references/component-name/reference-name request, + * to the target of the component reference. + */ +int translateReference(request_rec *r, const list<value>& rpath, const list<value>& vpath, const list<value>& refs, const list<value>& impls) { + debug(rpath, "modeval::translateReference::rpath"); + debug(flatten(refs), "modeval::translateReference::refs"); + + // Find the requested component + if (isNil(cdr(rpath))) + return HTTP_NOT_FOUND; + const list<value> comp(assoctree(cadr(rpath), refs)); + if (isNil(comp)) + return HTTP_NOT_FOUND; + debug(comp, "modeval::translateReference::comp"); + + // Find the requested reference and target configuration + const list<value> ref(assoctree<value>(caddr(rpath), cadr(comp))); + if (isNil(ref)) + return HTTP_NOT_FOUND; + debug(ref, "modeval::translateReference::ref"); + + const string target(cadr(ref)); + debug(target, "modeval::translateReference::target"); + + // Route to an absolute target URI using mod_proxy or an HTTP client redirect + const list<value> pathInfo = cdddr(rpath); + if (http::isAbsolute(target)) { + string turi = target + path(pathInfo) + (r->args != NULL? string("?") + string(r->args) : string("")); + const string proxy(string("proxy:") + turi); + debug(proxy, "modeval::translateReference::proxy"); + r->filename = apr_pstrdup(r->pool, c_str(proxy)); + r->proxyreq = PROXYREQ_REVERSE; + r->handler = "proxy-server"; + apr_table_setn(r->notes, "proxy-nocanon", "1"); + return OK; + } + + // Route to a relative target URI using a local internal redirect + // / c / target component name / request path info + const value tname = substr(target, 0, find(target, '/')); + const list<value> redir = cons<value>(string("c"), cons(tname, pathInfo)); + debug(redir, "modeval::translateReference::redirect"); + return proceedToHandler(r, OK, false, redir, vpath, impls);; +} + +/** + * 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(request_rec *r, const list<value>& rpath, const list<value>& vpath, const list<value>& svcs, const list<value>& impls) { + debug(rpath, "modeval::translateService::rpath"); + debug(flatten(svcs), "modeval::translateService::svcs"); + + // Find the requested component + if (isNil(rpath)) + return HTTP_NOT_FOUND; + const list<value> svc(assocPath(rpath, svcs)); + if (isNil(svc)) + return DECLINED; + debug(svc, "modeval::translateService::svc"); + + // Dispatch to the target component using a local internal redirect + // / c / target component name / request path info + const list<value> redir = cons<value>(string("c"), cons<value>(cadr(svc), httpd::pathInfo(rpath, car(svc)))); + debug(redir, "modeval::translateService::redirect"); + return proceedToHandler(r, OK, false, redir, vpath, impls); +} + +/** + * Translate a request to the target app and component. + */ +const int translateRequest(request_rec* r, const list<value>& rpath, const list<value>& vpath, const list<value>& refs, const list<value>& svcs, const list<value>& impls) { + debug(vpath, "modeval::translateRequest::vpath"); + debug(rpath, "modeval::translateRequest::rpath"); + const string prefix = isNil(rpath)? "" : car(rpath); + + // Translate a component request + if ((prefix == string("components") || prefix == string("c")) && translateComponent(r, rpath, vpath, impls) == OK) + return proceedToHandler(r, OK); + + // Translate a component reference request + if ((prefix == string("references") || prefix == string("r")) && translateReference(r, rpath, vpath, refs, impls) == OK) + return proceedToHandler(r, OK); + + // Attempt to translate the request to a service request + if (translateService(r, rpath, vpath, svcs, impls) == OK) + return proceedToHandler(r, OK); + + // Attempt to map a request targeting the main host to an actual file + if (isNil(vpath)) { + const failable<request_rec*> fnr = httpd::internalSubRequest(r->uri, r); + if (!hasContent(fnr)) + return rcode(fnr); + request_rec* nr = content(fnr); + nr->uri = r->filename; + const int tr = ap_core_translate(nr); + if (tr != OK) + return tr; + if (ap_directory_walk(nr) == OK && ap_file_walk(nr) == OK && nr->finfo.filetype != APR_NOFILE) { + + // Found the target file, let the default handler serve it + debug(nr->filename, "modeval::translateRequest::file"); + return DECLINED; + } + } else { + + // Make sure a document root request ends with a '/' using + // an external redirect + if (isNil(rpath) && r->uri[strlen(r->uri) - 1] != '/') { + const string target = string(r->uri) + string("/") + (r->args != NULL? string("?") + string(r->args) : string("")); + debug(target, "modeval::translateRequest::location"); + return proceedToHandler(r, httpd::externalRedirect(target, r)); + } + + // If the request didn't match a service, reference or component, + // redirect it to / v / app / path. This will allow mapping to + // the actual app resource using HTTPD aliases. + debug(true, "modeval::translateRequest::valias"); + return proceedToHandler(r, OK, true, rpath, vpath, impls); + } + + return HTTP_NOT_FOUND; +} + +/** + * Translate a 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; + + gc_scoped_pool pool(r->pool); + + debug_httpdRequest(r, "modeval::translate::input"); + + // Get the server configuration + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval); + + // Parse the request path + const list<value> rpath = pathValues(r->uri); + + // Let default handler handle a resource request + const string prefix = isNil(rpath)? "" : car(rpath); + if (prefix == string("vhosts") || prefix == string("v")) + return DECLINED; + + // Get the request configuration + RequestConf& reqc = httpd::requestConf<RequestConf>(r, &mod_tuscany_eval); + + // If the request is targeting a virtual host, configure the components + // in that virtual host + if (length(sc.vhostc.domain) != 0 && (length(sc.vhostc.contribPath) != 0 || !isNil(sc.vhostc.contributor)) && httpd::isVhostRequest(sc.server, sc.vhostc.domain, r)) { + const string vname = http::subDomain(httpd::hostName(r)); + const failable<Composite> fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.contributor, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.timeout, sc.p); + if (!hasContent(fvcompos)) + return DECLINED; + const Composite vcompos = content(fvcompos); + + // Flag the request as virtual host based + reqc.vhost = true; + + // Translate the request + reqc.impls = vcompos.impls; + return translateRequest(r, rpath, mklist<value>(vname), vcompos.refs, vcompos.svcs, reqc.impls); + } + + // Translate a request targeting the main host + const int rc = translateRequest(r, rpath, list<value>(), sc.compos.refs, sc.compos.svcs, sc.compos.impls); + if (rc != HTTP_NOT_FOUND) + return rc; + + // Attempt to map the first segment of the request path to a virtual host + if (length(prefix) != 0 && (length(sc.vhostc.contribPath) != 0 || !isNil(sc.vhostc.contributor))) { + const string vname = prefix; + const failable<Composite> fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.contributor, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.timeout, sc.p); + if (!hasContent(fvcompos)) + return DECLINED; + const Composite vcompos = content(fvcompos); + + // Translate the request + reqc.impls = vcompos.impls; + return translateRequest(r, cdr(rpath), mklist<value>(vname), vcompos.refs, vcompos.svcs, reqc.impls); + } + return DECLINED; +} + +/** + * Handle a component request. + */ +const int handleRequest(const list<value>& rpath, request_rec *r, const list<value>& impls) { + debug(rpath, "modeval::handleRequest::path"); + + // Get the component implementation lambda + const list<value> impl(assoctree<value>(cadr(rpath), impls)); + if (isNil(impl)) { + mkfailure<int>(string("Couldn't find component implementation: ") + cadr(rpath)); + return HTTP_NOT_FOUND; + } + const lambda<value(const list<value>&)> l(cadr<value>(impl)); + + // Handle HTTP method + if (r->header_only) + return OK; + if(r->method_number == M_GET) + return httpd::reportStatus(get(rpath, r, l)); + if(r->method_number == M_POST) + return httpd::reportStatus(post(rpath, r, l)); + if(r->method_number == M_PUT) + return httpd::reportStatus(put(rpath, r, l)); + if(r->method_number == M_DELETE) + return httpd::reportStatus(del(rpath, r, l)); + return HTTP_NOT_IMPLEMENTED; +} + +/** + * HTTP request handler. + */ +int handler(request_rec *r) { + if (r->handler != NULL && r->handler[0] != '\0') + return DECLINED; + + // Attempt to translate the request + const int trc = translate(r); + + // Pass if we couldn't translate the request + if(trc != OK) + return trc; + if(strcmp(r->handler, "mod_tuscany_eval")) + return DECLINED; + + // Create a scope for the current request + gc_scoped_pool pool(r->pool); + ScopedRequest sr(r); + + debug_httpdRequest(r, "modeval::handler::input"); + + // Get the request configuration + RequestConf& reqc = httpd::requestConf<RequestConf>(r, &mod_tuscany_eval); + + // Handle an internal redirect as directed by the translate hook + if (reqc.valias) { + const string redir = path(cons<value>(string("v"), reqc.vhost? reqc.vpath : list<value>())) + string(r->uri) + (r->args != NULL? string("?") + string(r->args) : string("")); + debug(redir, "modeval::handler::internalredirect"); + return httpd::internalRedirect(redir, r); + } + if (isNil(reqc.rpath)) + return HTTP_NOT_FOUND; + + // Get the server configuration + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval); + + // Handle a request targeting a component in a virtual host + if (!isNil(reqc.vpath)) { + + // Start the components in the virtual host + const failable<list<value> > fsimpls = startComponents(reqc.impls); + if (!hasContent(fsimpls)) + return HTTP_INTERNAL_SERVER_ERROR; + const list<value> simpls = content(fsimpls); + + // Merge the components in the virtual host with the components in the main host + reqc.impls = mkbtree(sort(append(flatten(sc.compos.impls), flatten(simpls)))); + + // Handle the request against the running components + const int rc = handleRequest(reqc.rpath, r, reqc.impls); + + // Stop the components in the virtual host + stopComponents(simpls); + return rc; + } + + // Handle a request targeting a component in the main host + return handleRequest(reqc.rpath, r, sc.compos.impls); +} + +/** + * Call an authenticator component to check a user's password. + */ +authn_status checkPassword(request_rec* r, const char* u, const char* p) { + gc_scoped_pool pool(r->pool); + + // Prevent FakeBasicAuth spoofing + const string user = u; + const string password = p; + debug(user, "modeval::checkPassword::user"); + if (substr(user, 0, 1) != "/" && find(user, "/") != length(user) && password == "password") { + mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + return AUTH_DENIED; + } + + // Get the server configuration + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval); + if (isNil(sc.vhostc.authenticator)) { + mkfailure<int>("SCA authenticator not configured"); + return AUTH_GENERAL_ERROR; + } + + // Retrieve the user's password hash + const list<value> uid = pathValues(user); + const failable<value> val = failableResult(sc.vhostc.authenticator(cons<value>("get", mklist<value>(uid)))); + if (!hasContent(val)) { + mkfailure<int>(string("SCA authentication check user failed, user not found: ") + user); + return AUTH_USER_NOT_FOUND; + } + const value hval = content(val); + const list<value> hcontent = isList(hval) && !isNil(hval) && isList(car<value>(hval)) && !isNil(car<value>(hval))? assoc<value>(value("content"), cdr<value>(car<value>(hval))) : list<value>(); + const list<value> hassoc = isNil(hcontent)? list<value>() : assoc<value>(value("hash"), cdr<value>(hcontent)); + if (isNil(hassoc)) { + mkfailure<int>(string("SCA authentication check user failed, hash not found: ") + user); + return AUTH_USER_NOT_FOUND; + } + const string hash = cadr<value>(hassoc); + if (length(hash) == 0) { + mkfailure<int>(string("SCA authentication check user failed: ") + user); + return AUTH_USER_NOT_FOUND; + } + + // Cache the hash in the auth cache provider, if available + if (authnCacheStore != NULL) + authnCacheStore(r, "component", u, NULL, c_str(hash)); + + // Validate the presented password against the hash + const apr_status_t rv = apr_password_validate(p, c_str(hash)); + if (rv != APR_SUCCESS) { + mkfailure<int>(string("SCA authentication user password check failed: ") + user); + return AUTH_DENIED; + } + return AUTH_GRANTED; +} + +/** + * 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 + stopComponents(sc.compos.impls); + + // 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"); + sc.lifecycle = mainsc.lifecycle; + sc.contribc = mainsc.contribc; + sc.vhostc = mainsc.vhostc; + if (sc.sslc.ca == "") sc.sslc.ca = mainsc.sslc.ca; + if (sc.sslc.cert == "") sc.sslc.cert = mainsc.sslc.cert; + if (sc.sslc.key == "") sc.sslc.key = mainsc.sslc.key; + sc.timeout = mainsc.timeout; + sc.compos = mainsc.compos; + 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 server name + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval); + debug(httpd::serverName(s), "modeval::postConfig::serverName"); + debug(sc.contribc.contribPath, "modeval::postConfig::contribPath"); + debug(sc.contribc.composName, "modeval::postConfig::composName"); + + // 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.contribc.contribPath)) != 0) { + mkfailure<bool>(string("Couldn't chdir to the deployed contribution: ") + sc.contribc.contribPath); + return -1; + } + + debug("modeval::postConfig::start"); + const failable<value> r = failableResult(applyLifecycle(mklist<value>("start"))); + if (!hasContent(r)) + return -1; + debug("modeval::postConfig::setlifecycle"); + 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; + debug("modeval::postConfig::setlifecycle"); + sc.lifecycle = content(r); + } + + // Configure the deployed components + const failable<Composite> compos = confComponents(sc.contribc.contribPath, sc.contribc.composName, value(), "", sc.compos.impls, sc.lifecycle, sc.sslc, sc.timeout, sc.p); + if (!hasContent(compos)) { + cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; + return -1; + } + sc.compos = content(compos); + + // 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); +} + +/** + * Exit after a failure. + */ +void failureExitChild() { + cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; + exit(APEXIT_CHILDFATAL); +} + +/** + * 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) + failureExitChild(); + ServerConf& sc = *psc; + + // Start the components in the child process + const failable<list<value> > fsimpls = startComponents(sc.compos.impls); + if (!hasContent(fsimpls)) + failureExitChild(); + sc.compos.impls = content(fsimpls); + + // Get the vhost contributor component implementation lambda + if (length(sc.vhostc.contributorName) != 0) { + const list<value> impl(assoctree<value>(sc.vhostc.contributorName, sc.compos.impls)); + if (isNil(impl)) { + mkfailure<int>(string("Couldn't find contributor component implementation: ") + sc.vhostc.contributorName); + failureExitChild(); + } + sc.vhostc.contributor = cadr<value>(impl); + } + + // Get the vhost authenticator component implementation lambda + if (length(sc.vhostc.authenticatorName) != 0) { + const list<value> impl(assoctree<value>(sc.vhostc.authenticatorName, sc.compos.impls)); + if (isNil(impl)) { + mkfailure<int>(string("Couldn't find authenticator component implementation: ") + sc.vhostc.authenticatorName); + failureExitChild(); + } + sc.vhostc.authenticator = cadr<value>(impl); + } + + // 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* 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.contribc.contribPath = 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.contribc.composName = arg; + return NULL; +} +const char* confVirtualDomain(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.vhostc.domain = 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.vhostc.contribPath = arg; + return NULL; +} +const char* confVirtualContributor(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.vhostc.contributorName = 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.vhostc.composName = arg; + return NULL; +} +const char* confAuthenticator(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.vhostc.authenticatorName = 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.sslc.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.sslc.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.sslc.key = arg; + return NULL; +} +const char* confTimeout(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.timeout = atoi(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("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("SCAVirtualDomain", (const char*(*)())confVirtualDomain, NULL, RSRC_CONF, "SCA virtual host domain"), + AP_INIT_TAKE1("SCAVirtualContribution", (const char*(*)())confVirtualContribution, NULL, RSRC_CONF, "SCA virtual host contribution path"), + AP_INIT_TAKE1("SCAVirtualContributor", (const char*(*)())confVirtualContributor, NULL, RSRC_CONF, "SCA virtual host contributor component"), + AP_INIT_TAKE1("SCAVirtualComposite", (const char*(*)())confVirtualComposite, NULL, RSRC_CONF, "SCA virtual composite location"), + AP_INIT_TAKE1("SCAAuthenticator", (const char*(*)())confAuthenticator, NULL, RSRC_CONF, "SCA authenticator component"), + 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"), + AP_INIT_TAKE1("SCAWiringTimeout", (const char*(*)())confTimeout, NULL, RSRC_CONF, "SCA wiring timeout"), + {NULL, NULL, NULL, 0, NO_ARGS, NULL} +}; + + +const authn_provider AuthnProvider = { + &checkPassword, + NULL +}; + +void retrieveAuthnCacheStore() { + authnCacheStore = APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store); +} + +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_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "component", AUTHN_PROVIDER_VERSION, &AuthnProvider, AP_AUTH_INTERNAL_PER_CONF); + ap_hook_optional_fn_retrieve(retrieveAuthnCacheStore, NULL, NULL, APR_HOOK_MIDDLE); +} + +} +} +} + +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/sca-cpp/branches/lightweight-sca/modules/server/mod-scheme.hpp b/sca-cpp/branches/lightweight-sca/modules/server/mod-scheme.hpp new file mode 100644 index 0000000000..43d7bf4041 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/modules/server/property-test.scm b/sca-cpp/branches/lightweight-sca/modules/server/property-test.scm new file mode 100644 index 0000000000..f5ba76f1f3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/property-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. + +; Built-in property test case + +(define (print host path query) (list (list 'host (host)) (list 'path (path)) (list 'query (query)))) + diff --git a/sca-cpp/branches/lightweight-sca/modules/server/scheme-conf b/sca-cpp/branches/lightweight-sca/modules/server/scheme-conf new file mode 100755 index 0000000000..bc4074c8be --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/scheme-conf @@ -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. + +# Generate a Scheme server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +cat >>$root/conf/modules.conf <<EOF +# Generated by: scheme-conf $* +# Support for Scheme SCA components +LoadModule mod_tuscany_eval $here/libmod_tuscany_eval$libsuffix + +EOF diff --git a/sca-cpp/branches/lightweight-sca/modules/server/server-conf b/sca-cpp/branches/lightweight-sca/modules/server/server-conf new file mode 100755 index 0000000000..bfa5ac8473 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/server-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. + +# Generate a server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +# Serve Javascript scripts and CSS +$here/../js/js-conf $1 + +# Configure SSL cert used for wiring +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/sca-cpp/branches/lightweight-sca/modules/server/server-test b/sca-cpp/branches/lightweight-sca/modules/server/server-test new file mode 100755 index 0000000000..6b48d13e83 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/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 +rm -rf tmp +../http/httpd-conf tmp localhost 8090 htdocs +../http/httpd-event-conf tmp +./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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/modules/server/server-test.scm b/sca-cpp/branches/lightweight-sca/modules/server/server-test.scm new file mode 100644 index 0000000000..4bbff6e5c2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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) + '((feed (title "Sample Feed") (id "123456789") (entry + (((title "Item") (id "111") (content (item (name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99)))) + ((title "Item") (id "222") (content (item (name "Orange") (currencyCode "USD") (currencySymbol "$") (price 3.55)))) + ((title "Item") (id "333") (content (item (name "Pear") (currencyCode "USD") (currencySymbol "$") (price 1.55)))))))) + + (list (list 'entry '(title "Item") (list 'id (car id)) '(content (item (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/sca-cpp/branches/lightweight-sca/modules/server/wiring-test b/sca-cpp/branches/lightweight-sca/modules/server/wiring-test new file mode 100755 index 0000000000..7e1aea22b1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/modules/server/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../http/curl.prefix` + +# Setup +rm -rf tmp +../http/httpd-conf tmp localhost 8090 htdocs +../http/httpd-event-conf tmp +./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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/patches/apr-util-1.4.1.patch b/sca-cpp/branches/lightweight-sca/patches/apr-util-1.4.1.patch new file mode 100644 index 0000000000..2b88d3575f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/patches/apr-util-1.4.1.patch @@ -0,0 +1,12 @@ +--- memcache/apr_memcache.c ++++ memcache/apr_memcache.c +@@ -301,9 +301,6 @@ + } + + rv = apr_socket_connect(conn->sock, sa); +- if (rv != APR_SUCCESS) { +- return rv; +- } + + rv = apr_socket_timeout_set(conn->sock, -1); + if (rv != APR_SUCCESS) { diff --git a/sca-cpp/branches/lightweight-sca/patches/modsecurity-crs_2.2.2.patch b/sca-cpp/branches/lightweight-sca/patches/modsecurity-crs_2.2.2.patch new file mode 100644 index 0000000000..a0935b5bc2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/patches/modsecurity-crs_2.2.2.patch @@ -0,0 +1,14 @@ +--- base_rules/modsecurity_crs_40_generic_attacks.conf ++++ base_rules/modsecurity_crs_40_generic_attacks.conf +164,165c164,165 +< SecRule ARGS "(?:ft|htt)ps?.*\?+$" \ +< "phase:2,rev:'2.2.2',t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,status:501,msg:'Remote File Inclusion Attack',id:'950119',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.rfi_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{tx.0}" +--- +> #SecRule ARGS "(?:ft|htt)ps?.*\?+$" \ +> # "phase:2,rev:'2.2.2',t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,status:501,msg:'Remote File Inclusion Attack',id:'950119',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.rfi_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{tx.0}" +--- base_rules/modsecurity_crs_50_outbound.conf ++++ base_rules/modsecurity_crs_50_outbound.conf +39c39 +< SecRule RESPONSE_BODY "\<\%" "phase:4,rev:'2.2.2',chain,t:none,capture,ctl:auditLogParts=+E,block,msg:'ASP/JSP source code leakage',id:'970903',tag:'LEAKAGE/SOURCE_CODE_ASP_JSP',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',tag:'PCI/6.5.6',severity:'3'" +--- +> #SecRule RESPONSE_BODY "\<\%" "phase:4,rev:'2.2.2',chain,t:none,capture,ctl:auditLogParts=+E,block,msg:'ASP/JSP source code leakage',id:'970903',tag:'LEAKAGE/SOURCE_CODE_ASP_JSP',tag:'WASCTC/WASC-13',tag:'OWASP_TOP_10/A6',tag:'PCI/6.5.6',severity:'3'" diff --git a/sca-cpp/branches/lightweight-sca/patches/scribe-2.2.patch b/sca-cpp/branches/lightweight-sca/patches/scribe-2.2.patch new file mode 100644 index 0000000000..16c2e3871e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/patches/scribe-2.2.patch @@ -0,0 +1,78 @@ +--- src/common.h ++++ src/common.h +@@ -42,6 +42,8 @@ + #include <sys/types.h> + #include <sys/stat.h> + #include <unistd.h> ++#include <signal.h> ++#include <fcntl.h> + #include <boost/shared_ptr.hpp> + #include <boost/filesystem/operations.hpp> + #include <boost/filesystem/convenience.hpp> + +--- src/file.cpp ++++ src/file.cpp +@@ -74,9 +74,21 @@ + } + + bool StdFile::openWrite() { ++ // if file is a fifo, temporarily open it for read ++ int fd = -1; ++ struct stat st; ++ int s = stat(filename.c_str(), &st); ++ if (s != -1 && S_ISFIFO(st.st_mode)) ++ fd = ::open(filename.c_str(), O_RDONLY | O_NONBLOCK); ++ + // open file for write in append mode + ios_base::openmode mode = fstream::out | fstream::app; +- return open(mode); ++ bool r = open(mode); ++ ++ // close fifo ++ if (fd != -1) ++ ::close(fd); ++ return r; + } + + bool StdFile::openTruncate() { + +--- src/scribe_server.cpp ++++ src/scribe_server.cpp +@@ -55,6 +55,8 @@ + if (-1 == setrlimit(RLIMIT_NOFILE, &r_fd)) { + LOG_OPER("setrlimit error (setting max fd size)"); + } ++ ++ signal(SIGPIPE, SIG_IGN); + + int next_option; + const char* const short_options = "hp:c:"; +@@ -110,7 +112,7 @@ + } + + TNonblockingServer server(processor, binaryProtocolFactory, +- g_Handler->port, thread_manager); ++ g_Handler->host, g_Handler->port, thread_manager); + + LOG_OPER("Starting scribe server on port %lu", g_Handler->port); + fflush(stderr); +@@ -583,6 +585,8 @@ + throw runtime_error("No port number configured"); + } + ++ config.getString("host", host); ++ + // check if config sets the size to use for the ThreadManager + unsigned long int num_threads; + if (config.getUnsigned("num_thrift_server_threads", num_threads)) { + +--- src/scribe_server.h ++++ src/scribe_server.h +@@ -51,6 +51,7 @@ + void setStatusDetails(const std::string& new_status_details); + + unsigned long int port; // it's long because that's all I implemented in the conf class ++ std::string host; + + // number of threads processing new Thrift connections + size_t numThriftServerThreads; diff --git a/sca-cpp/branches/lightweight-sca/patches/thrift-0.2.0.patch b/sca-cpp/branches/lightweight-sca/patches/thrift-0.2.0.patch new file mode 100644 index 0000000000..a834faca02 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/patches/thrift-0.2.0.patch @@ -0,0 +1,39 @@ +--- lib/cpp/src/server/TNonblockingServer.cpp ++++ lib/cpp/src/server/TNonblockingServer.cpp +@@ -622,8 +622,8 @@ + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + sprintf(port, "%d", port_); + +- // Wildcard address +- error = getaddrinfo(NULL, port, &hints, &res0); ++ // Wildcard or specified address ++ error = getaddrinfo(host_ == "" || host_ =="*"? NULL : host_.c_str(), port, &hints, &res0); + if (error) { + string errStr = "TNonblockingServer::serve() getaddrinfo " + string(gai_strerror(error)); + GlobalOutput(errStr.c_str()); + +--- lib/cpp/src/server/TNonblockingServer.h ++++ lib/cpp/src/server/TNonblockingServer.h +@@ -65,6 +65,9 @@ + // Server socket file descriptor + int serverSocket_; + ++ // Host server runs on ++ std::string host_; ++ + // Port server runs on + int port_; + +@@ -117,10 +120,12 @@ + + TNonblockingServer(boost::shared_ptr<TProcessor> processor, + boost::shared_ptr<TProtocolFactory> protocolFactory, ++ std::string host, + int port, + boost::shared_ptr<ThreadManager> threadManager = boost::shared_ptr<ThreadManager>()) : + TServer(processor), + serverSocket_(-1), ++ host_(host), + port_(port), + threadManager_(threadManager), + eventBase_(NULL), diff --git a/sca-cpp/branches/lightweight-sca/samples/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/Makefile.am new file mode 100644 index 0000000000..604a963d5d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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-constdb store-vhost store-cluster relay-python relay-gae + +sample_DATA = README +sampledir=$(prefix)/samples + diff --git a/sca-cpp/branches/lightweight-sca/samples/README b/sca-cpp/branches/lightweight-sca/samples/README new file mode 100644 index 0000000000..818a2faaf8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/README @@ -0,0 +1,3 @@ +Apache Tuscany SCA Samples +========================== + diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-gae/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/relay-gae/Makefile.am new file mode 100644 index 0000000000..7b24ddde27 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/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. + +if WANT_PYTHON +if WANT_GAE + +dist_sample_SCRIPTS = start stop +sampledir = $(prefix)/samples/relay-gae + +BUILT_SOURCES = target.stamp +target.stamp: app.yaml *.py *.composite $(top_builddir)/modules/wsgi/*.py htdocs/*.html + 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 + touch target.stamp + +clean-local: + rm -rf target.stamp target + +nobase_sample_DATA = target/app.yaml target/*.py target/*.composite target/htdocs/*.html + +EXTRA_DIST = app.yaml *.composite *.py htdocs/*.html + +endif +endif diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-gae/app.yaml b/sca-cpp/branches/lightweight-sca/samples/relay-gae/app.yaml new file mode 100644 index 0000000000..d4e78701bc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/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-relay
+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))
+
+- url: /.*
+ script: composite.py
+
diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-gae/domain.composite b/sca-cpp/branches/lightweight-sca/samples/relay-gae/domain.composite new file mode 100644 index 0000000000..470ac88da1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/domain.composite @@ -0,0 +1,74 @@ +<?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" + targetNamespace="http://relay" + name="relay"> + + <component name="JSONTwit"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="jsontwit"/> + </service> + <reference name="target"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.json?screen_name=jsdelfino"/> + </reference> + </component> + + <component name="XMLTwit"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="xmltwit"/> + </service> + <reference name="target"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=jsdelfino"/> + </reference> + </component> + + <component name="RSSTwit"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="rsstwit"/> + </service> + <reference name="target"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=jsdelfino"/> + </reference> + </component> + + <component name="HTML"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="html"/> + </service> + <reference name="target"> + <binding.http uri="http://people.apache.org/~jsdelfino/"/> + </reference> + </component> + + <component name="JSONFB"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="jsonfb"/> + </service> + <reference name="target"> + <binding.http uri="https://graph.facebook.com/100001053301307"/> + </reference> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-gae/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/relay-gae/htdocs/index.html new file mode 100644 index 0000000000..b8b606d3d9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/htdocs/index.html @@ -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. +--> +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Relay</title> +</head> +<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/sca-cpp/branches/lightweight-sca/samples/relay-gae/relay.py b/sca-cpp/branches/lightweight-sca/samples/relay-gae/relay.py new file mode 100644 index 0000000000..5fe99803c1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/relay.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. + +# Relay implementation +def get(id, target): + return target.get(id) + diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-gae/start b/sca-cpp/branches/lightweight-sca/samples/relay-gae/start new file mode 100755 index 0000000000..2e219758a8 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/start @@ -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/wsgi/gae-start target 8090 diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-gae/stop b/sca-cpp/branches/lightweight-sca/samples/relay-gae/stop new file mode 100755 index 0000000000..3aff1d5a77 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-gae/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/wsgi/gae-stop target 8090 diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-python/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/relay-python/Makefile.am new file mode 100644 index 0000000000..57938aff69 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = relay.py relay.composite htdocs/*.html + +endif diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-python/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/relay-python/htdocs/index.html new file mode 100644 index 0000000000..ad5f86aa02 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-python/htdocs/index.html @@ -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. +--> +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<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/sca-cpp/branches/lightweight-sca/samples/relay-python/relay.composite b/sca-cpp/branches/lightweight-sca/samples/relay-python/relay.composite new file mode 100644 index 0000000000..470ac88da1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-python/relay.composite @@ -0,0 +1,74 @@ +<?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" + targetNamespace="http://relay" + name="relay"> + + <component name="JSONTwit"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="jsontwit"/> + </service> + <reference name="target"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.json?screen_name=jsdelfino"/> + </reference> + </component> + + <component name="XMLTwit"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="xmltwit"/> + </service> + <reference name="target"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=jsdelfino"/> + </reference> + </component> + + <component name="RSSTwit"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="rsstwit"/> + </service> + <reference name="target"> + <binding.http uri="http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=jsdelfino"/> + </reference> + </component> + + <component name="HTML"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="html"/> + </service> + <reference name="target"> + <binding.http uri="http://people.apache.org/~jsdelfino/"/> + </reference> + </component> + + <component name="JSONFB"> + <implementation.python script="relay.py"/> + <service name="Relay"> + <binding.http uri="jsonfb"/> + </service> + <reference name="target"> + <binding.http uri="https://graph.facebook.com/100001053301307"/> + </reference> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-python/relay.py b/sca-cpp/branches/lightweight-sca/samples/relay-python/relay.py new file mode 100644 index 0000000000..5fe99803c1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-python/relay.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. + +# Relay implementation +def get(id, target): + return target.get(id) + diff --git a/sca-cpp/branches/lightweight-sca/samples/relay-python/start b/sca-cpp/branches/lightweight-sca/samples/relay-python/start new file mode 100755 index 0000000000..e9d9d2d51f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/relay-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/http/httpd-event-conf tmp +../../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/sca-cpp/branches/lightweight-sca/samples/relay-python/stop b/sca-cpp/branches/lightweight-sca/samples/relay-python/stop new file mode 100755 index 0000000000..3b4f46694d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-cluster/Makefile.am new file mode 100644 index 0000000000..f856e63c59 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 domains/*/htdocs/*.html domains/*/htdocs/*/*.html domains/*/*.py domains/*/*.composite shared/*.composite + +dist_noinst_SCRIPTS = server-test +#TESTS = server-test + +endif +endif +endif +endif +endif diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/currency-converter.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/currency-converter.py new file mode 100644 index 0000000000..2fded8f616 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/fruits-catalog.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/fruits-catalog.py new file mode 100644 index 0000000000..fb20b4ff27 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/index.html new file mode 100644 index 0000000000..832c0a1472 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Jane's Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/login/index.html new file mode 100644 index 0000000000..2a7be01ff1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/login/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign in</title> +</head> +<body> +<h1>Sign in with an OpenID or OAuth provider</h1> +<br/> + +<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 '/'; + q = r.indexOf('?'); + if (q > 0) + return r.substring(0, q); + return r; +} + +if (typeof(openauthReferrer()) == 'undefined') { + document.location = '/'; +} + +function submitOpenIDSignin(w) { + clearauthcookie(); + 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(); + clearauthcookie(); + document.oauth2Signin.oauth2_authorize.value = parms[0]; + document.oauth2Signin.oauth2_access_token.value = parms[1]; + document.oauth2Signin.oauth2_client_id.value = parms[2]; + document.oauth2Signin.oauth2_info.value = parms[3]; + document.oauth2Signin.oauth2_scope.value = parms[4]; + document.oauth2Signin.oauth2_display.value = parms[5]; + document.oauth2Signin.openauth_referrer.value = openauthReferrer(); + document.oauth2Signin.action = '/oauth2/authorize/'; + 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', 'email', 'page']; + 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', 'email', '']; + return parms; +} + +function submitOAuth1Signin(w) { + parms = w(); + clearauthcookie(); + document.oauth1Signin.oauth1_request_token.value = parms[0]; + document.oauth1Signin.oauth1_authorize.value = parms[1]; + document.oauth1Signin.oauth1_access_token.value = parms[2]; + document.oauth1Signin.oauth1_client_id.value = parms[3]; + document.oauth1Signin.oauth1_info.value = parms[4]; + document.oauth1Signin.openauth_referrer.value = openauthReferrer(); + document.oauth1Signin.action = '/oauth1/authorize/'; + 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="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="oauth2_authorize" value=""/> +<input type="hidden" name="oauth2_access_token" value=""/> +<input type="hidden" name="oauth2_client_id" value=""/> +<input type="hidden" name="oauth2_info" value=""/> +<input type="hidden" name="oauth2_scope" value=""/> +<input type="hidden" name="oauth2_display" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +<form name="oauth1Signin" action="/" method="GET"> +<input type="hidden" name="oauth1_request_token" value=""/> +<input type="hidden" name="oauth1_authorize" value=""/> +<input type="hidden" name="oauth1_access_token" value=""/> +<input type="hidden" name="oauth1_client_id" value=""/> +<input type="hidden" name="oauth1_info" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/logout/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/logout/index.html new file mode 100644 index 0000000000..50a10bdd8b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/htdocs/logout/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign out</title> +</head> +<body> +<h1>Sign out</h1> +<br/> + +<form name="signout" action="/login" method="GET"> +<script type="text/javascript"> +function submitSignout() { + clearauthcookie(); + document.signout.submit(); + return true; +} +</script> +<input type="button" onclick="submitSignout()" value="Sign out"/> +</form> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/shopping-cart.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/shopping-cart.py new file mode 100644 index 0000000000..b3818a6727 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = (("'entry", item[0][1], ("'id", id), item[0][3]),) + 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 (("'entry", ("'title", "Item"), ("'id", 0)),) + elif id == cart[0][2][1]: + return (cart[0],) + else: + return find(id, cart[1:]) + +# Get items from the cart +def get(id, cache, host, email): + if id == (): + return ((("'feed", ("'title", "Your Cart"), ("'id", 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[3][1][1:])[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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/store.composite new file mode 100644 index 0000000000..c8955af24e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/store.composite @@ -0,0 +1,63 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <property name="host">localhost</property> + <property name="email">anonymous@localhost</property> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/store.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/jane/store.py new file mode 100644 index 0000000000..ff82f1d327 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/currency-converter.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/currency-converter.py new file mode 100644 index 0000000000..2fded8f616 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/fruits-catalog.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/fruits-catalog.py new file mode 100644 index 0000000000..6644421683 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/index.html new file mode 100644 index 0000000000..0caf8b3df1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Joe's Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/login/index.html new file mode 100644 index 0000000000..2a7be01ff1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/login/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign in</title> +</head> +<body> +<h1>Sign in with an OpenID or OAuth provider</h1> +<br/> + +<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 '/'; + q = r.indexOf('?'); + if (q > 0) + return r.substring(0, q); + return r; +} + +if (typeof(openauthReferrer()) == 'undefined') { + document.location = '/'; +} + +function submitOpenIDSignin(w) { + clearauthcookie(); + 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(); + clearauthcookie(); + document.oauth2Signin.oauth2_authorize.value = parms[0]; + document.oauth2Signin.oauth2_access_token.value = parms[1]; + document.oauth2Signin.oauth2_client_id.value = parms[2]; + document.oauth2Signin.oauth2_info.value = parms[3]; + document.oauth2Signin.oauth2_scope.value = parms[4]; + document.oauth2Signin.oauth2_display.value = parms[5]; + document.oauth2Signin.openauth_referrer.value = openauthReferrer(); + document.oauth2Signin.action = '/oauth2/authorize/'; + 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', 'email', 'page']; + 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', 'email', '']; + return parms; +} + +function submitOAuth1Signin(w) { + parms = w(); + clearauthcookie(); + document.oauth1Signin.oauth1_request_token.value = parms[0]; + document.oauth1Signin.oauth1_authorize.value = parms[1]; + document.oauth1Signin.oauth1_access_token.value = parms[2]; + document.oauth1Signin.oauth1_client_id.value = parms[3]; + document.oauth1Signin.oauth1_info.value = parms[4]; + document.oauth1Signin.openauth_referrer.value = openauthReferrer(); + document.oauth1Signin.action = '/oauth1/authorize/'; + 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="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="oauth2_authorize" value=""/> +<input type="hidden" name="oauth2_access_token" value=""/> +<input type="hidden" name="oauth2_client_id" value=""/> +<input type="hidden" name="oauth2_info" value=""/> +<input type="hidden" name="oauth2_scope" value=""/> +<input type="hidden" name="oauth2_display" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +<form name="oauth1Signin" action="/" method="GET"> +<input type="hidden" name="oauth1_request_token" value=""/> +<input type="hidden" name="oauth1_authorize" value=""/> +<input type="hidden" name="oauth1_access_token" value=""/> +<input type="hidden" name="oauth1_client_id" value=""/> +<input type="hidden" name="oauth1_info" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/logout/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/logout/index.html new file mode 100644 index 0000000000..50a10bdd8b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/htdocs/logout/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign out</title> +</head> +<body> +<h1>Sign out</h1> +<br/> + +<form name="signout" action="/login" method="GET"> +<script type="text/javascript"> +function submitSignout() { + clearauthcookie(); + document.signout.submit(); + return true; +} +</script> +<input type="button" onclick="submitSignout()" value="Sign out"/> +</form> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/shopping-cart.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/shopping-cart.py new file mode 100644 index 0000000000..b3818a6727 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = (("'entry", item[0][1], ("'id", id), item[0][3]),) + 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 (("'entry", ("'title", "Item"), ("'id", 0)),) + elif id == cart[0][2][1]: + return (cart[0],) + else: + return find(id, cart[1:]) + +# Get items from the cart +def get(id, cache, host, email): + if id == (): + return ((("'feed", ("'title", "Your Cart"), ("'id", 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[3][1][1:])[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/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/store.composite new file mode 100644 index 0000000000..c8955af24e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/store.composite @@ -0,0 +1,63 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <property name="host">localhost</property> + <property name="email">anonymous@localhost</property> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/store.py b/sca-cpp/branches/lightweight-sca/samples/store-cluster/domains/joe/store.py new file mode 100644 index 0000000000..811b05c580 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/index.html new file mode 100644 index 0000000000..50c7e25ee6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/index.html @@ -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. +--> +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> +</head> + +<body> +<h1>Store</h1> +<br/> +<p>For this sample to work, add the sample domain to your /etc/hosts as follows:<br/> +127.0.0.1 example.com jane.example.com joe.example.com</p> + +<p/> +<p>Jane's store at <a href="http://jane.example.com/">jane.example.com</a> +<br/>Joe's store at <a href="http://joe.example.com/">joe.example.com</a></p> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/login/index.html new file mode 100644 index 0000000000..2a7be01ff1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/login/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign in</title> +</head> +<body> +<h1>Sign in with an OpenID or OAuth provider</h1> +<br/> + +<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 '/'; + q = r.indexOf('?'); + if (q > 0) + return r.substring(0, q); + return r; +} + +if (typeof(openauthReferrer()) == 'undefined') { + document.location = '/'; +} + +function submitOpenIDSignin(w) { + clearauthcookie(); + 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(); + clearauthcookie(); + document.oauth2Signin.oauth2_authorize.value = parms[0]; + document.oauth2Signin.oauth2_access_token.value = parms[1]; + document.oauth2Signin.oauth2_client_id.value = parms[2]; + document.oauth2Signin.oauth2_info.value = parms[3]; + document.oauth2Signin.oauth2_scope.value = parms[4]; + document.oauth2Signin.oauth2_display.value = parms[5]; + document.oauth2Signin.openauth_referrer.value = openauthReferrer(); + document.oauth2Signin.action = '/oauth2/authorize/'; + 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', 'email', 'page']; + 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', 'email', '']; + return parms; +} + +function submitOAuth1Signin(w) { + parms = w(); + clearauthcookie(); + document.oauth1Signin.oauth1_request_token.value = parms[0]; + document.oauth1Signin.oauth1_authorize.value = parms[1]; + document.oauth1Signin.oauth1_access_token.value = parms[2]; + document.oauth1Signin.oauth1_client_id.value = parms[3]; + document.oauth1Signin.oauth1_info.value = parms[4]; + document.oauth1Signin.openauth_referrer.value = openauthReferrer(); + document.oauth1Signin.action = '/oauth1/authorize/'; + 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="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="oauth2_authorize" value=""/> +<input type="hidden" name="oauth2_access_token" value=""/> +<input type="hidden" name="oauth2_client_id" value=""/> +<input type="hidden" name="oauth2_info" value=""/> +<input type="hidden" name="oauth2_scope" value=""/> +<input type="hidden" name="oauth2_display" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +<form name="oauth1Signin" action="/" method="GET"> +<input type="hidden" name="oauth1_request_token" value=""/> +<input type="hidden" name="oauth1_authorize" value=""/> +<input type="hidden" name="oauth1_access_token" value=""/> +<input type="hidden" name="oauth1_client_id" value=""/> +<input type="hidden" name="oauth1_info" value=""/> +<input type="hidden" name="openauth_referrer" value=""/> +</form> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/logout/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/logout/index.html new file mode 100644 index 0000000000..50a10bdd8b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/htdocs/logout/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign out</title> +</head> +<body> +<h1>Sign out</h1> +<br/> + +<form name="signout" action="/login" method="GET"> +<script type="text/javascript"> +function submitSignout() { + clearauthcookie(); + document.signout.submit(); + return true; +} +</script> +<input type="button" onclick="submitSignout()" value="Sign out"/> +</form> +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/proxy-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/proxy-conf new file mode 100755 index 0000000000..c43feff551 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/mass-host-conf $root $root/domains htdocs +../../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/sca-cpp/branches/lightweight-sca/samples/store-cluster/proxy-ssl-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/proxy-ssl-conf new file mode 100755 index 0000000000..e4ddbb0c4b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/proxy-ssl-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. + +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/mass-host-conf $root $root/domains htdocs +../../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/httpd-tunnel-ssl-conf $root +../../modules/http/mass-host-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/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-conf new file mode 100755 index 0000000000..089e1842db --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-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 + +set -x + +# Configure an app server +../../modules/http/httpd-conf $root sca-store.com $port/80 htdocs +../../modules/http/httpd-event-conf $root +../../modules/http/mass-host-conf $root domains htdocs +../../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 +SCAVirtualDomain sca-store.com +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/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-ssl-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-ssl-conf new file mode 100755 index 0000000000..4180a44056 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-ssl-conf @@ -0,0 +1,66 @@ +#!/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/httpd-event-conf $root +../../modules/http/mass-host-conf $root domains htdocs + +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/httpd-tunnel-ssl-conf $root +../../modules/http/mass-host-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 +SCAVirtualDomain sca-store.com +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/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-test b/sca-cpp/branches/lightweight-sca/samples/store-cluster/server-test new file mode 100755 index 0000000000..836097dcae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 example.com joe.example.com joe.example.com + +echo "Testing..." +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../../modules/http/curl.prefix` + +# Setup +./start +sleep 2 + +# Test HTTP GET +$curl_prefix/bin/curl http://joe.example.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.example.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.example.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.example.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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/shared/shared.composite b/sca-cpp/branches/lightweight-sca/samples/store-cluster/shared/shared.composite new file mode 100644 index 0000000000..d11d31b9ea --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/shared/shared.composite @@ -0,0 +1,63 @@ +<?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" + targetNamespace="http://shared" + name="shared"> + + <component name="Cache"> + <implementation.cpp path="../../../components/cache" library="libdatacache"/> + <service name="Cache"> + <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"> + <binding.atom uri="memcache"/> + </service> + <property name="server">localhost:11211</property> + <property name="server">localhost:11212</property> + <property name="server">localhost:11213</property> + </component> + + <component name="Masterdb"> + <implementation.cpp path="../../../components/sqldb" library="libsqldb"/> + <property name="conninfo">host=localhost port=6432 dbname=db</property> + <property name="table">store</property> + <service name="Masterdb"> + <binding.atom uri="masterdb"/> + </service> + </component> + + <component name="Standbydb"> + <implementation.cpp path="../../../components/sqldb" library="libsqldb"/> + <property name="conninfo">host=localhost port=6433 dbname=db</property> + <property name="table">store</property> + <service name="Standbydb"> + <binding.atom uri="standbydb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cluster/sqldb-master-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/sqldb-master-conf new file mode 100755 index 0000000000..83f78be999 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/sqldb-standby-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/sqldb-standby-conf new file mode 100755 index 0000000000..4998ead4b4 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cluster/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-cluster/ssl-start new file mode 100755 index 0000000000..04aa267d5e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 example.com +../../modules/http/ssl-cert-conf tmp/ssl localhost server +../../modules/http/ssl-cert-conf tmp/ssl *.example.com vhost +../../modules/http/ssl-cert-conf tmp/ssl example.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 tmp 127.0.0.1:11411 +../../modules/http/tunnel-ssl-conf tmp/tunnel 11212 localhost 563 11412 +../../components/cache/memcached-start tmp 127.0.0.1:11412 +../../modules/http/tunnel-ssl-conf tmp/tunnel 11213 localhost 563 11413 +../../components/cache/memcached-start tmp 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/sca-cpp/branches/lightweight-sca/samples/store-cluster/ssl-stop b/sca-cpp/branches/lightweight-sca/samples/store-cluster/ssl-stop new file mode 100755 index 0000000000..37addf8094 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp 127.0.0.1:11411 +../../components/cache/memcached-stop tmp 127.0.0.1:11412 +../../components/cache/memcached-stop tmp 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/sca-cpp/branches/lightweight-sca/samples/store-cluster/start b/sca-cpp/branches/lightweight-sca/samples/store-cluster/start new file mode 100755 index 0000000000..dcc7e1e7a7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/start @@ -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. + +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 +rm -rf tmp +../../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 tmp 11211 +../../components/cache/memcached-start tmp 11212 +../../components/cache/memcached-start tmp 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/sca-cpp/branches/lightweight-sca/samples/store-cluster/stop b/sca-cpp/branches/lightweight-sca/samples/store-cluster/stop new file mode 100755 index 0000000000..fb6c6489fc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp 11211 +../../components/cache/memcached-stop tmp 11212 +../../components/cache/memcached-stop tmp 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/sca-cpp/branches/lightweight-sca/samples/store-cluster/tunnel-ssl-conf b/sca-cpp/branches/lightweight-sca/samples/store-cluster/tunnel-ssl-conf new file mode 100755 index 0000000000..f798fdab0b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cluster/tunnel-ssl-conf @@ -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. + +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/httpd-tunnel-ssl-conf $root +../../modules/http/cert-auth-conf $root + diff --git a/sca-cpp/branches/lightweight-sca/samples/store-constdb/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-constdb/Makefile.am new file mode 100644 index 0000000000..d2783f3f3b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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-constdb + +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/sca-cpp/branches/lightweight-sca/samples/store-constdb/currency-converter.scm b/sca-cpp/branches/lightweight-sca/samples/store-constdb/currency-converter.scm new file mode 100644 index 0000000000..fc506c3d73 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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/sca-cpp/branches/lightweight-sca/samples/store-constdb/fruits-catalog.scm b/sca-cpp/branches/lightweight-sca/samples/store-constdb/fruits-catalog.scm new file mode 100644 index 0000000000..d55394b96a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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/sca-cpp/branches/lightweight-sca/samples/store-constdb/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-constdb/htdocs/index.html new file mode 100644 index 0000000000..0698a32cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-constdb/server-test b/sca-cpp/branches/lightweight-sca/samples/store-constdb/server-test new file mode 100755 index 0000000000..fb629a6814 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-constdb/shopping-cart.scm b/sca-cpp/branches/lightweight-sca/samples/store-constdb/shopping-cart.scm new file mode 100644 index 0000000000..e653f1e33c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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 'entry (cadr (car item)) (list 'id id) (cadddr (car 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) + (list (list 'entry (list 'title "Item") (list 'id "0"))) + (if (= id (cadr (caddr (car cart)))) + (list (car cart)) + (find id (cdr cart)))) +) + +; Get items from the cart +(define (get id cache) + (if (nul id) + (list (append (list 'feed (list 'title "Your Cart") (list 'id 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 (cadr (cadddr 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/sca-cpp/branches/lightweight-sca/samples/store-constdb/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-constdb/ssl-start new file mode 100755 index 0000000000..047ec974cb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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/constdb/tinycdb -c -m tmp/store.cdb </dev/null +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-constdb/start b/sca-cpp/branches/lightweight-sca/samples/store-constdb/start new file mode 100755 index 0000000000..58b15c0ec3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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. + +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../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/constdb/tinycdb -c -m tmp/store.cdb </dev/null +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-constdb/stop b/sca-cpp/branches/lightweight-sca/samples/store-constdb/stop new file mode 100755 index 0000000000..3b4f46694d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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/sca-cpp/branches/lightweight-sca/samples/store-constdb/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-constdb/store.composite new file mode 100644 index 0000000000..168be26ab6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/store.composite @@ -0,0 +1,69 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.scheme script="store.scm"/> + <service name="Widget"> + <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.scheme script="fruits-catalog.scm"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.scheme script="shopping-cart.scm"/> + <service name="Cart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="ConstDb"/> + </component> + + <component name="CurrencyConverter"> + <implementation.scheme script="currency-converter.scm"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="ConstDb"> + <implementation.cpp path="../../components/constdb" library="libconstdb"/> + <property name="dbname">tmp/store.cdb</property> + <service name="ConstDb"> + <binding.atom uri="constdb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-constdb/store.scm b/sca-cpp/branches/lightweight-sca/samples/store-constdb/store.scm new file mode 100644 index 0000000000..f54257343e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-constdb/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/sca-cpp/branches/lightweight-sca/samples/store-cpp/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-cpp/Makefile.am new file mode 100644 index 0000000000..3f9d8e87eb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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${libsuffix} libfruits-catalog${libsuffix} libshopping-cart${libsuffix} + +libcurrency_converter_la_SOURCES = currency-converter.cpp +libcurrency-converter${libsuffix}: + ln -s .libs/libcurrency-converter${libsuffix} + +libfruits_catalog_la_SOURCES = fruits-catalog.cpp +libfruits-catalog${libsuffix}: + ln -s .libs/libfruits-catalog${libsuffix} + +libshopping_cart_la_SOURCES = shopping-cart.cpp +libshopping-cart${libsuffix}: + ln -s .libs/libshopping-cart${libsuffix} + +dist_noinst_SCRIPTS = server-test +TESTS = server-test diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/currency-converter.cpp b/sca-cpp/branches/lightweight-sca/samples/store-cpp/currency-converter.cpp new file mode 100644 index 0000000000..5f0702490a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cpp/fruits-catalog.cpp b/sca-cpp/branches/lightweight-sca/samples/store-cpp/fruits-catalog.cpp new file mode 100644 index 0000000000..9907650316 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/index.html new file mode 100644 index 0000000000..0698a32cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cpp/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/items-request.txt b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/items-request.txt new file mode 100644 index 0000000000..09a7f8377b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/items-request.txt @@ -0,0 +1,6 @@ +{ + "id": 1, + "method": "items", + "params": [ + ] +} diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/items-result.txt b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/items-result.txt new file mode 100644 index 0000000000..0b456ea9d0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/items-result.txt @@ -0,0 +1,23 @@ +{ + "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/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/shopping-cart-entry.xml b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/shopping-cart-entry.xml new file mode 100644 index 0000000000..0d6e5b520a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cpp/htdocs/test/shopping-cart-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><content type="application/xml"><item><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content></entry> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/server-test b/sca-cpp/branches/lightweight-sca/samples/store-cpp/server-test new file mode 100755 index 0000000000..e621803f8d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/shopping-cart.cpp b/sca-cpp/branches/lightweight-sca/samples/store-cpp/shopping-cart.cpp new file mode 100644 index 0000000000..2771d7cd9c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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>("entry", cadr<value>(car<value>(item)), mklist<value>("id", id), cadddr<value>(car<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 mklist<value>(mklist<value>("entry", mklist<value>("title", string("Item")), mklist<value>("id", "0"))); + if (id == cadr<value>(caddr<value>(car(cart)))) + return mklist<value>(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(mklist<value>(append(mklist<value>("feed", mklist<value>("title", string("Your Cart")), mklist<value>("id", 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", cdr<value>(cadr<value>(cadddr(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/sca-cpp/branches/lightweight-sca/samples/store-cpp/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-cpp/ssl-start new file mode 100755 index 0000000000..3a96fe950c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/start b/sca-cpp/branches/lightweight-sca/samples/store-cpp/start new file mode 100755 index 0000000000..4ad506f7b5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cpp/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. + +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/stop b/sca-cpp/branches/lightweight-sca/samples/store-cpp/stop new file mode 100755 index 0000000000..3b4c74a587 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-cpp/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-cpp/store.composite new file mode 100644 index 0000000000..483fbfacc1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-cpp/store.composite @@ -0,0 +1,69 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.widget location="store.html"/> + <service name="Widget"> + <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"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.cpp path="." library="libshopping-cart"/> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.cpp path="." library="libcurrency-converter"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.cpp path="../../components/cache" library="libmemcache"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + <property name="server">localhost:11211</property> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-gae/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-gae/Makefile.am new file mode 100644 index 0000000000..09d5b516cf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/app.yaml b/sca-cpp/branches/lightweight-sca/samples/store-gae/app.yaml new file mode 100644 index 0000000000..6a4e6a2fab --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/currency-converter.py b/sca-cpp/branches/lightweight-sca/samples/store-gae/currency-converter.py new file mode 100644 index 0000000000..2fded8f616 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-backend.composite b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-backend.composite new file mode 100644 index 0000000000..13fa8406e2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-backend.composite @@ -0,0 +1,31 @@ +<?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" + targetNamespace="http://store" + name="store-backend"> + + <component name="Cache"> + <implementation.python script="gmemcache.py"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-frontend.composite b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-frontend.composite new file mode 100644 index 0000000000..181e86c100 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-frontend.composite @@ -0,0 +1,65 @@ +<?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" + targetNamespace="http://store" + name="store-frontend"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <service name="Cart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache"> + <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"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-single.composite b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-single.composite new file mode 100644 index 0000000000..79c5aca8e1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain-single.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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <service name="Cart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <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"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.python script="gmemcache.py"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-gae/domain.composite b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain.composite new file mode 100644 index 0000000000..79c5aca8e1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-gae/domain.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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <service name="Cart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <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"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.python script="gmemcache.py"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-gae/fruits-catalog.py b/sca-cpp/branches/lightweight-sca/samples/store-gae/fruits-catalog.py new file mode 100644 index 0000000000..4b2baca2ff --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/gmemcache.py b/sca-cpp/branches/lightweight-sca/samples/store-gae/gmemcache.py new file mode 100644 index 0000000000..61f1dc3486 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-gae/htdocs/index.html new file mode 100644 index 0000000000..7c9a9e9d6b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-gae/htdocs/index.html @@ -0,0 +1,175 @@ +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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/sca-cpp/branches/lightweight-sca/samples/store-gae/htdocs/test/items-result.txt b/sca-cpp/branches/lightweight-sca/samples/store-gae/htdocs/test/items-result.txt new file mode 100644 index 0000000000..bbc07e8917 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/htpasswd.py b/sca-cpp/branches/lightweight-sca/samples/store-gae/htpasswd.py new file mode 100644 index 0000000000..75d94f58b6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/server-test b/sca-cpp/branches/lightweight-sca/samples/store-gae/server-test new file mode 100755 index 0000000000..2235811556 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-gae/server-test @@ -0,0 +1,60 @@ +#!/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +curl_prefix=`cat $here/../../modules/http/curl.prefix` + +# Setup +./start 2>/dev/null +sleep 2 + +# Test HTTP GET (with authentication) +rm -rf tmp +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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-gae/shopping-cart.py b/sca-cpp/branches/lightweight-sca/samples/store-gae/shopping-cart.py new file mode 100644 index 0000000000..11a55a552a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = (("'entry", item[0][1], ("'id", id), item[0][3]),) + getcart(cartId, cache) + cache.put((cartId,), cart) + return (id,) + +# Find an item in the cart +def find(id, cart): + if cart == (): + return (("'entry", ("'title", "Item"), ("'id", 0)),) + elif id == cart[0][2][1]: + return (cart[0],) + else: + return find(id, cart[1:]) + +# Get items from the cart +def get(id, cache, host, email): + if id == (): + return ((("'feed", ("'title", "Your Cart"), ("'id", 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[3][1][1:])[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/sca-cpp/branches/lightweight-sca/samples/store-gae/start b/sca-cpp/branches/lightweight-sca/samples/store-gae/start new file mode 100755 index 0000000000..3c9644e656 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/stop b/sca-cpp/branches/lightweight-sca/samples/store-gae/stop new file mode 100755 index 0000000000..7c8a7e5551 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-gae/store.py b/sca-cpp/branches/lightweight-sca/samples/store-gae/store.py new file mode 100644 index 0000000000..ff82f1d327 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-java/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-java/Makefile.am new file mode 100644 index 0000000000..f32ae72812 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-java/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-java/htdocs/index.html new file mode 100644 index 0000000000..0698a32cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-java/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-java/server-test b/sca-cpp/branches/lightweight-sca/samples/store-java/server-test new file mode 100755 index 0000000000..fb629a6814 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-java/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-java/ssl-start new file mode 100755 index 0000000000..a585f717aa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-java/start b/sca-cpp/branches/lightweight-sca/samples/store-java/start new file mode 100755 index 0000000000..99a3f982b7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-java/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. + +rm -rf tmp +../../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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-java/stop b/sca-cpp/branches/lightweight-sca/samples/store-java/stop new file mode 100755 index 0000000000..c7a0bff857 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-java/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-java/store.composite new file mode 100644 index 0000000000..2795fe1769 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-java/store.composite @@ -0,0 +1,69 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.widget location="store.html"/> + <service name="Widget"> + <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"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.java class="store.ShoppingCartImpl"/> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.java class="store.CurrencyConverterImpl"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.cpp path="../../components/cache" library="libmemcache"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + <property name="server">localhost:11211</property> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-java/store/CurrencyConverter.java b/sca-cpp/branches/lightweight-sca/samples/store-java/store/CurrencyConverter.java new file mode 100644 index 0000000000..1ed15a670a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-java/store/CurrencyConverterImpl.java b/sca-cpp/branches/lightweight-sca/samples/store-java/store/CurrencyConverterImpl.java new file mode 100644 index 0000000000..a6d0fd00b3 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-java/store/FruitsCatalogImpl.java b/sca-cpp/branches/lightweight-sca/samples/store-java/store/FruitsCatalogImpl.java new file mode 100644 index 0000000000..8881543103 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-java/store/ShoppingCartImpl.java b/sca-cpp/branches/lightweight-sca/samples/store-java/store/ShoppingCartImpl.java new file mode 100644 index 0000000000..bd7678cce7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-java/store/ShoppingCartImpl.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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("'entry", cadr(car(item)), list("'id", id), cadddr(car(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 list(list("'entry", list("'title", "Item"), list("'id", "0"))); + if(id.equals(cadr(caddr(car(cart))))) + return list(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 list(append(list("'feed", list("'title", "Your Cart"), list("'id", 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) { + System.err.println("price!! " + cadr(cadddr(item))); + return Double.valueOf((String)cadr(assoc("'price", cdr(cadr(cadddr(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/sca-cpp/branches/lightweight-sca/samples/store-python/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-python/Makefile.am new file mode 100644 index 0000000000..8db150cc0e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-python/currency-converter.py b/sca-cpp/branches/lightweight-sca/samples/store-python/currency-converter.py new file mode 100644 index 0000000000..2fded8f616 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-python/fruits-catalog.py b/sca-cpp/branches/lightweight-sca/samples/store-python/fruits-catalog.py new file mode 100644 index 0000000000..8289afcac5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/index.html new file mode 100644 index 0000000000..0698a32cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/login/index.html b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/login/index.html new file mode 100644 index 0000000000..fd3bc21889 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/login/index.html @@ -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. +--> + +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign in</title> +</head> +<body> +<h1>Sign in</h1> +<br/> + +<script type="text/javascript"> +function submitFormSignin() { + clearauthcookie(); + 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/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/logout/index.html b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/logout/index.html new file mode 100644 index 0000000000..92fd2a084b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/logout/index.html @@ -0,0 +1,43 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT 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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<script type="text/javascript" src="/all-min.js"></script> +<title>Sign out</title> +</head> +<body> +<h1>Sign out</h1> +<br/> + +<form name="signout" action="/login" method="GET"> +<script type="text/javascript"> +function submitSignout() { + clearauthcookie(); + document.signout.submit(); + return true; +} +</script> +<input type="button" onclick="submitSignout()" value="Sign out"/> +</form> +</body></html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/test/items-result.txt b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/test/items-result.txt new file mode 100644 index 0000000000..d6aaf4d44a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/htdocs/test/items-result.txt @@ -0,0 +1,23 @@ +{ + "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/sca-cpp/branches/lightweight-sca/samples/store-python/server-test b/sca-cpp/branches/lightweight-sca/samples/store-python/server-test new file mode 100755 index 0000000000..8f52543c71 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-python/shopping-cart.py b/sca-cpp/branches/lightweight-sca/samples/store-python/shopping-cart.py new file mode 100644 index 0000000000..1dac82522f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = (("'entry", item[0][1], ("'id", id), item[0][3]),) + getcart(cartId, cache) + cache.put((cartId,), cart) + return (id,) + + +# Find an item in the cart +def find(id, cart): + if cart == (): + return (("'entry", ("'title", "Item"), ("'id", 0)),) + elif id == cart[0][2][1]: + return (cart[0],) + else: + return find(id, cart[1:]) + +# Get items from the cart +def get(id, cache): + if id == (): + return ((("'feed", ("'title", "Your Cart"), ("'id", 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[3][1][1:])[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/sca-cpp/branches/lightweight-sca/samples/store-python/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-python/ssl-start new file mode 100755 index 0000000000..2a9df09c2e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/ssl-start @@ -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. + +../../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-event-conf tmp +../../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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-python/start b/sca-cpp/branches/lightweight-sca/samples/store-python/start new file mode 100755 index 0000000000..d52a41ec13 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/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. + +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-python/stop b/sca-cpp/branches/lightweight-sca/samples/store-python/stop new file mode 100755 index 0000000000..3b4c74a587 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-python/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-python/store.composite new file mode 100644 index 0000000000..6de6f7af61 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/store.composite @@ -0,0 +1,69 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.cpp path="../../components/cache" library="libmemcache"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + <property name="server">localhost:11211</property> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-python/store.py b/sca-cpp/branches/lightweight-sca/samples/store-python/store.py new file mode 100644 index 0000000000..b71f505dd1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-python/uec2-start b/sca-cpp/branches/lightweight-sca/samples/store-python/uec2-start new file mode 100755 index 0000000000..feb4ae383e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-python/uec2-start @@ -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. + +# 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-event-conf tmp +../../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 tmp +../../modules/http/httpd-start tmp + diff --git a/sca-cpp/branches/lightweight-sca/samples/store-scheme/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-scheme/Makefile.am new file mode 100644 index 0000000000..2330d45422 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-scheme/currency-converter.scm b/sca-cpp/branches/lightweight-sca/samples/store-scheme/currency-converter.scm new file mode 100644 index 0000000000..fc506c3d73 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-scheme/fruits-catalog.scm b/sca-cpp/branches/lightweight-sca/samples/store-scheme/fruits-catalog.scm new file mode 100644 index 0000000000..d55394b96a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-scheme/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-scheme/htdocs/index.html new file mode 100644 index 0000000000..0698a32cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-scheme/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-scheme/script-test.cpp b/sca-cpp/branches/lightweight-sca/samples/store-scheme/script-test.cpp new file mode 100644 index 0000000000..0d5a9ccf9d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-scheme/script-test.scm b/sca-cpp/branches/lightweight-sca/samples/store-scheme/script-test.scm new file mode 100644 index 0000000000..50b587b8f1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-scheme/server-test b/sca-cpp/branches/lightweight-sca/samples/store-scheme/server-test new file mode 100755 index 0000000000..fb629a6814 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-scheme/shopping-cart.scm b/sca-cpp/branches/lightweight-sca/samples/store-scheme/shopping-cart.scm new file mode 100644 index 0000000000..e653f1e33c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 'entry (cadr (car item)) (list 'id id) (cadddr (car 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) + (list (list 'entry (list 'title "Item") (list 'id "0"))) + (if (= id (cadr (caddr (car cart)))) + (list (car cart)) + (find id (cdr cart)))) +) + +; Get items from the cart +(define (get id cache) + (if (nul id) + (list (append (list 'feed (list 'title "Your Cart") (list 'id 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 (cadr (cadddr 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/sca-cpp/branches/lightweight-sca/samples/store-scheme/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-scheme/ssl-start new file mode 100755 index 0000000000..cc0272c28f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-scheme/start b/sca-cpp/branches/lightweight-sca/samples/store-scheme/start new file mode 100755 index 0000000000..bef6f0372b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-scheme/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. + +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../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 tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-scheme/stop b/sca-cpp/branches/lightweight-sca/samples/store-scheme/stop new file mode 100755 index 0000000000..3b4c74a587 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-scheme/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-scheme/store.composite new file mode 100644 index 0000000000..0711328217 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-scheme/store.composite @@ -0,0 +1,69 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.scheme script="store.scm"/> + <service name="Widget"> + <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.scheme script="fruits-catalog.scm"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.scheme script="shopping-cart.scm"/> + <service name="Cart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.scheme script="currency-converter.scm"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.cpp path="../../components/cache" library="libmemcache"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + <property name="server">localhost:11211</property> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-scheme/store.scm b/sca-cpp/branches/lightweight-sca/samples/store-scheme/store.scm new file mode 100644 index 0000000000..f54257343e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-sql/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-sql/Makefile.am new file mode 100644 index 0000000000..3b738e3972 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-sql/currency-converter.scm b/sca-cpp/branches/lightweight-sca/samples/store-sql/currency-converter.scm new file mode 100644 index 0000000000..fc506c3d73 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-sql/fruits-catalog.scm b/sca-cpp/branches/lightweight-sca/samples/store-sql/fruits-catalog.scm new file mode 100644 index 0000000000..d55394b96a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-sql/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-sql/htdocs/index.html new file mode 100644 index 0000000000..0698a32cc5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-sql/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-sql/server-test b/sca-cpp/branches/lightweight-sca/samples/store-sql/server-test new file mode 100755 index 0000000000..fb629a6814 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-sql/shopping-cart.scm b/sca-cpp/branches/lightweight-sca/samples/store-sql/shopping-cart.scm new file mode 100644 index 0000000000..e653f1e33c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 'entry (cadr (car item)) (list 'id id) (cadddr (car 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) + (list (list 'entry (list 'title "Item") (list 'id "0"))) + (if (= id (cadr (caddr (car cart)))) + (list (car cart)) + (find id (cdr cart)))) +) + +; Get items from the cart +(define (get id cache) + (if (nul id) + (list (append (list 'feed (list 'title "Your Cart") (list 'id 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 (cadr (cadddr 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/sca-cpp/branches/lightweight-sca/samples/store-sql/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-sql/ssl-start new file mode 100755 index 0000000000..adfba0d761 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp +../../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/sca-cpp/branches/lightweight-sca/samples/store-sql/start b/sca-cpp/branches/lightweight-sca/samples/store-sql/start new file mode 100755 index 0000000000..f3d5e67a33 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-sql/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. + +rm -rf tmp +../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../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 tmp +../../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/sca-cpp/branches/lightweight-sca/samples/store-sql/stop b/sca-cpp/branches/lightweight-sca/samples/store-sql/stop new file mode 100755 index 0000000000..daf271cbfa --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-sql/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-sql/store.composite new file mode 100644 index 0000000000..bb6898140f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-sql/store.composite @@ -0,0 +1,89 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.scheme script="store.scm"/> + <service name="Widget"> + <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.scheme script="fruits-catalog.scm"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.scheme script="shopping-cart.scm"/> + <service name="Cart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.scheme script="currency-converter.scm"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + + <component name="Cache"> + <implementation.cpp path="../../components/cache" library="libdatacache"/> + <service name="Cache"> + <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"> + <binding.atom uri="memcache"/> + </service> + <property name="server">localhost:11211</property> + </component> + + <component name="Sqldb"> + <implementation.cpp path="../../components/sqldb" library="libsqldb"/> + <property name="conninfo">host=localhost port=6432 dbname=db</property> + <property name="table">store</property> + <service name="Sqldb"> + <binding.atom uri="sqldb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-sql/store.scm b/sca-cpp/branches/lightweight-sca/samples/store-sql/store.scm new file mode 100644 index 0000000000..f54257343e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/Makefile.am b/sca-cpp/branches/lightweight-sca/samples/store-vhost/Makefile.am new file mode 100644 index 0000000000..71dca3621d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 domains/*/htdocs/*.html domains/*/*.py domains/*/*.composite shared/*.composite + +dist_noinst_SCRIPTS = server-test +#TESTS = server-test + +endif diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/currency-converter.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/currency-converter.py new file mode 100644 index 0000000000..2fded8f616 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/fruits-catalog.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/fruits-catalog.py new file mode 100644 index 0000000000..fb20b4ff27 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/htdocs/index.html new file mode 100644 index 0000000000..832c0a1472 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Jane's Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/shopping-cart.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/shopping-cart.py new file mode 100644 index 0000000000..1dac82522f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = (("'entry", item[0][1], ("'id", id), item[0][3]),) + getcart(cartId, cache) + cache.put((cartId,), cart) + return (id,) + + +# Find an item in the cart +def find(id, cart): + if cart == (): + return (("'entry", ("'title", "Item"), ("'id", 0)),) + elif id == cart[0][2][1]: + return (cart[0],) + else: + return find(id, cart[1:]) + +# Get items from the cart +def get(id, cache): + if id == (): + return ((("'feed", ("'title", "Your Cart"), ("'id", 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[3][1][1:])[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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/store.composite new file mode 100644 index 0000000000..58e5832bcf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/store.composite @@ -0,0 +1,61 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/store.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/jane/store.py new file mode 100644 index 0000000000..ff82f1d327 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/currency-converter.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/currency-converter.py new file mode 100644 index 0000000000..2fded8f616 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/fruits-catalog.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/fruits-catalog.py new file mode 100644 index 0000000000..6644421683 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/htdocs/index.html new file mode 100644 index 0000000000..0caf8b3df1 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/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> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Joe's Store</title> + +<script type="text/javascript" src="/all-min.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(doc) { + if (doc != null) { + var feed = parseXML([doc]); + 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 = '<?xml version="1.0" encoding="UTF-8"?>\n' + + '<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> +<br/> +<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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/shopping-cart.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/shopping-cart.py new file mode 100644 index 0000000000..1dac82522f --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 = (("'entry", item[0][1], ("'id", id), item[0][3]),) + getcart(cartId, cache) + cache.put((cartId,), cart) + return (id,) + + +# Find an item in the cart +def find(id, cart): + if cart == (): + return (("'entry", ("'title", "Item"), ("'id", 0)),) + elif id == cart[0][2][1]: + return (cart[0],) + else: + return find(id, cart[1:]) + +# Get items from the cart +def get(id, cache): + if id == (): + return ((("'feed", ("'title", "Your Cart"), ("'id", 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[3][1][1:])[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/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/store.composite b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/store.composite new file mode 100644 index 0000000000..58e5832bcf --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/store.composite @@ -0,0 +1,61 @@ +<?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" + targetNamespace="http://store" + name="store"> + + <component name="Store"> + <implementation.python script="store.py"/> + <service name="Widget"> + <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.python script="fruits-catalog.py"/> + <property name="currencyCode">USD</property> + <service name="Catalog"> + <binding.jsonrpc uri="catalog"/> + </service> + <reference name="currencyConverter" target="CurrencyConverter"/> + </component> + + <component name="ShoppingCart"> + <implementation.python script="shopping-cart.py"/> + <service name="ShoppingCart"> + <binding.atom uri="shoppingCart"/> + </service> + <service name="Total"> + <binding.jsonrpc uri="total"/> + </service> + <reference name="cache" target="Cache"/> + </component> + + <component name="CurrencyConverter"> + <implementation.python script="currency-converter.py"/> + <service name="CurrencyConverter"> + <binding.jsonrpc uri="currencyConverter"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/store.py b/sca-cpp/branches/lightweight-sca/samples/store-vhost/domains/joe/store.py new file mode 100644 index 0000000000..ff82f1d327 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/samples/store-vhost/htdocs/index.html b/sca-cpp/branches/lightweight-sca/samples/store-vhost/htdocs/index.html new file mode 100644 index 0000000000..fc377e5b61 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/htdocs/index.html @@ -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. +--> +<html> +<head> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> +<title>Store</title> +</head> + +<body> +<h1>Store</h1> +<br/> +<p>For this sample to work, add the sample domain to your /etc/hosts as follows:<br/> +127.0.0.1 example.com jane.example.com joe.example.com</p> + +<p/> +<p>Jane's store at <a href="http://jane.example.com:8090/">jane.example.com</a> +<br/>Joe's store at <a href="http://joe.example.com:8090/">joe.example.com</a></p> + +</body> +</html> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/server-test b/sca-cpp/branches/lightweight-sca/samples/store-vhost/server-test new file mode 100755 index 0000000000..4d8c7a9129 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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 example.com joe.example.com joe.example.com + +# Test HTTP GET +$curl_prefix/bin/curl http://joe.example.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.example.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.example.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.example.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 +exit $rc diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/shared/shared.composite b/sca-cpp/branches/lightweight-sca/samples/store-vhost/shared/shared.composite new file mode 100644 index 0000000000..3183891ade --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/shared/shared.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" + targetNamespace="http://shared" + name="shared"> + + <component name="Cache"> + <implementation.cpp path="../../../components/cache" library="libmemcache"/> + <service name="Cache"> + <binding.atom uri="cache"/> + </service> + <property name="server">localhost:11211</property> + </component> + +</composite> diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/ssl-start b/sca-cpp/branches/lightweight-sca/samples/store-vhost/ssl-start new file mode 100755 index 0000000000..528c0a5e73 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/ssl-start @@ -0,0 +1,48 @@ +#!/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 example.com jane.example.com joe.example.com + +../../modules/http/ssl-ca-conf tmp example.com +../../modules/http/ssl-cert-conf tmp example.com server +../../modules/http/ssl-cert-conf tmp *.example.com vhost +../../modules/http/httpd-conf tmp example.com 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../modules/http/mass-host-conf tmp domains htdocs +../../modules/http/httpd-ssl-conf tmp 8453 +../../modules/http/mass-host-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 +SCAVirtualDomain example.com +SCAVirtualContribution `pwd`/domains/ +SCAVirtualComposite store.composite + +EOF + +../../components/cache/memcached-start tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/start b/sca-cpp/branches/lightweight-sca/samples/store-vhost/start new file mode 100755 index 0000000000..6a20a60762 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/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. + +rm -rf tmp +../../modules/http/httpd-conf tmp example.com 8090 htdocs +../../modules/http/httpd-event-conf tmp +../../modules/http/mass-host-conf tmp domains htdocs +../../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 +SCAVirtualDomain example.com +SCAVirtualContribution `pwd`/domains/ +SCAVirtualComposite store.composite + +EOF + +../../components/cache/memcached-start tmp +../../modules/http/httpd-start tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/stop b/sca-cpp/branches/lightweight-sca/samples/store-vhost/stop new file mode 100755 index 0000000000..3b4c74a587 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 tmp diff --git a/sca-cpp/branches/lightweight-sca/samples/store-vhost/uec2-start b/sca-cpp/branches/lightweight-sca/samples/store-vhost/uec2-start new file mode 100755 index 0000000000..f86ce0f56b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/samples/store-vhost/uec2-start @@ -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. + +# Pass your EC2 public host name +if [ "$1" != "" ]; then + host=$1 +else + # Default to dummy test domain + host="example.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/httpd-event-conf tmp +../../modules/http/mass-host-conf tmp domains htdocs +../../modules/http/httpd-ssl-conf tmp 8453/443 +../../modules/http/mass-host-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 +SCAVirtualDomain $host +SCAVirtualContribution `pwd`/domains/ +SCAVirtualComposite store.composite + +EOF + +../../components/cache/memcached-start tmp +../../modules/http/httpd-start tmp + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/Makefile.am b/sca-cpp/branches/lightweight-sca/ubuntu/Makefile.am new file mode 100644 index 0000000000..a1e092944c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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-image ubuntu-bin-all-image ubuntu-dev-image ubuntu-dev-all-image ubuntu-install ubuntu-install-dependencies ubuntu-backup ubuntu-install-all ubuntu-install-all-dependencies ubuntu-backup-all uec2-bin-image uec2-bin-all-image uec2-dev-image uec2-dev-all-image + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ip-redirect b/sca-cpp/branches/lightweight-sca/ubuntu/ip-redirect new file mode 100755 index 0000000000..f2f33e27ff --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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 DNAT" | 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 DNAT --to $dest:$tport + +# Redirect local traffic as well +sudo /sbin/iptables -t nat -S OUTPUT | grep "\-d $dest/" | grep "\-p tcp" | grep "\-\-dport $sport" | grep "\-j DNAT" | 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 DNAT --to $dest:$tport + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ip-redirect-all b/sca-cpp/branches/lightweight-sca/ubuntu/ip-redirect-all new file mode 100755 index 0000000000..c8743add5d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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-all 80 8090 + +here=`echo "import os; print os.path.realpath('$0')" | python`; 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/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-backup b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-backup new file mode 100755 index 0000000000..55c5f7e61b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-backup @@ -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. + +# Create backup archives of a minimal Tuscany SCA runtime distribution. + +# Display commands as they are executed +set -x + +# Create src archive +tar czf tuscany-sca-cpp-1.0-src.tar.gz apr-1.4.6.tar.gz apr-1.4.6 apr-1.4.6-bin apr-util-1.4.1.tar.gz apr-util-1.4.1 apr-util-1.4.1-bin curl-7.24.0 curl-7.24.0-bin curl-7.24.0.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz httpd-2.4.2 httpd-2.4.2.tar.gz httpd-2.4.2-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.13 memcached-1.4.13-bin memcached-1.4.13.tar.gz modsecurity-apache_2.6.6 modsecurity-apache-2.6.6-bin modsecurity-apache_2.6.6.tar.gz modsecurity-crs_2.2.5 modsecurity-crs_2.2.5.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem page-speed-1.9 page-speed-1.9-bin page-speed-sdk.zip pgbouncer-1.5 pgbouncer-1.5-bin pgbouncer-1.5.tar.gz postgresql-9.1.2 postgresql-9.1.2-bin postgresql-9.1.2.tar.gz Python-2.7.3 python-2.7.3-bin Python-2.7.3.tgz scribe scribe-2.2-bin scribe-2.2.tar.gz thrift-0.2.0 thrift-0.2.0-bin thrift-0.2.0-incubating.tar.gz tinycdb-0.77 tinycdb-0.77-bin tinycdb_0.77.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin + +# Create bin archive +tar czf tuscany-sca-cpp-1.0.tar.gz apr-1.4.6-bin apr-util-1.4.1-bin curl-7.24.0-bin expat-2.0.1-bin httpd-2.4.2-bin js-1.8.5-bin liboauth-0.9.1-bin libstrophe-bin libxml2-2.7.7-bin memcached-1.4.13-bin modsecurity-apache-2.6.6-bin nspr-4.8.8-bin nuvem/nuvem-parallel page-speed-1.9-bin pgbouncer-1.5-bin postgresql-9.1.2-bin python-2.7.3-bin scribe-2.2-bin thrift-0.2.0-bin tinycdb-0.77-bin tuscany-sca-cpp tuscany-sca-cpp-bin + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-backup-all b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-backup-all new file mode 100755 index 0000000000..9a740c46de --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-backup-all @@ -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. + +# Create backup archives of a complete Tuscany SCA runtime distribution. + +# Display commands as they are executed +set -x + +# Create src archive +tar czf tuscany-sca-cpp-all-1.0-src.tar.gz apache-libcloud-incubating-0.4.2 apache-libcloud-incubating-0.4.2.tar.bz2 apr-1.4.6 apr-1.4.6.tar.gz apr-1.4.6-bin apr-util-1.4.1 apr-util-1.4.1.tar.gz apr-util-1.4.1-bin axis2c-1.6.0-bin axis2c-src-1.6.0 axis2c-src-1.6.0.tar.gz curl-7.24.0 curl-7.24.0-bin curl-7.24.0.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz google_appengine google_appengine_1.4.0.zip htmltidy-bin httpd-2.3.15-beta httpd-2.3.15-beta.tar.gz httpd-2.3.15-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz libcloud-0.4.2-bin liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libopkele libopkele-bin libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.13 memcached-1.4.13-bin memcached-1.4.13.tar.gz mod_auth_openid mod-auth-openid-bin modsecurity-apache_2.6.6 modsecurity-apache-2.6.6-bin modsecurity-apache_2.6.6.tar.gz modsecurity-crs_2.2.5 modsecurity-crs_2.2.5.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem page-speed-1.9 page-speed-1.9-bin page-speed-sdk.zip pgbouncer-1.5 pgbouncer-1.5-bin pgbouncer-1.5.tar.gz postgresql-9.1.2 postgresql-9.1.2-bin postgresql-9.1.2.tar.gz Python-2.7.3 python-2.7.3-bin Python-2.7.3.tgz qpidc-0.6 qpidc-0.6-bin qpid-cpp-0.6.tar.gz scribe scribe-2.2-bin scribe-2.2.tar.gz thrift-0.2.0 thrift-0.2.0-bin thrift-0.2.0-incubating.tar.gz tidy tinycdb-0.77 tinycdb-0.77-bin tinycdb_0.77.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin vysper-0.6 vysper-0.6-bin.tar.gz + +# Create bin archive +tar czf tuscany-sca-cpp-all-1.0.tar.gz apr-1.4.6-bin apr-util-1.4.1-bin axis2c-1.6.0-bin curl-7.24.0-bin expat-2.0.1-bin google_appengine htmltidy-bin httpd-2.3.15-bin js-1.8.5-bin libcloud-0.4.2-bin liboauth-0.9.1-bin libopkele-bin libstrophe-bin libxml2-2.7.7-bin memcached-1.4.13-bin mod-auth-openid-bin modsecurity-apache-2.6.6-bin nspr-4.8.8-bin nuvem/nuvem-parallel page-speed-1.9-bin pgbouncer-1.5-bin postgresql-9.1.2-bin python-2.7.3-bin qpidc-0.6-bin scribe-2.2-bin thrift-0.2.0-bin tinycdb-0.77-bin tuscany-sca-cpp tuscany-sca-cpp-bin vysper-0.6 + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-bin-all-image b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-bin-all-image new file mode 100755 index 0000000000..ff1b75298c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-bin-all-image @@ -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. + +# Install a complete distribution, the required system tools and libraries, +# runtime dependencies and the Tuscany SCA runtime on Ubuntu Server 12.04. + +# 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 /opt/tuscany +sudo chown $u /opt/tuscany +sudo chgrp $g /opt/tuscany +cd /opt/tuscany + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache HTTP server dependencies +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Memcached dependencies +sudo apt-get -y install libevent-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the SpiderMonkey dependencies +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Qpid/C++ dependencies +sudo apt-get -y install libboost-dev libboost-program-options-dev libboost-filesystem-dev uuid-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Vysper dependencies +sudo apt-get -y install openjdk-6-jdk +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the HTML Tidy dependencies +sudo apt-get -y install cvs +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the PostgreSQL dependencies +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Thrift dependencies +sudo apt-get -y install bison flex +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Facebook Scribe dependencies +sudo apt-get -y install gawk +if [ "$?" != "0" ]; then + exit $? +fi + +# Download and install the Tuscany runtime +curl -OL 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/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-bin-image b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-bin-image new file mode 100755 index 0000000000..d9bd4a919c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-bin-image @@ -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. + +# Install a minimal distribution, the required system tools and libraries, +# runtime dependencies and the Tuscany SCA runtime on Ubuntu Server 12.04. + +# 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 /opt/tuscany +sudo chown $u /opt/tuscany +sudo chgrp $g /opt/tuscany +cd /opt/tuscany + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache HTTP server dependencies +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Memcached dependencies +sudo apt-get -y install libevent-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the SpiderMonkey dependencies +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the PostgreSQL dependencies +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Thrift dependencies +sudo apt-get -y install bison flex libboost-dev libboost-filesystem-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Facebook Scribe dependencies +sudo apt-get -y install gawk +if [ "$?" != "0" ]; then + exit $? +fi + +# Download and install the Tuscany runtime +curl -OL http://people.apache.org/~jsdelfino/tuscany/test/tuscany-sca-cpp-1.0.tar.gz +tar xzf tuscany-sca-cpp-1.0.tar.gz + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-dev-all-image b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-dev-all-image new file mode 100755 index 0000000000..4015550662 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-dev-all-image @@ -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. + +# Install a complete distribution, the required system tools and libraries, +# runtime dependencies and the Tuscany SCA runtime on Ubuntu Server 12.04. + +# 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 /opt/tuscany +sudo chown $u /opt/tuscany +sudo chgrp $g /opt/tuscany +cd /opt/tuscany + +# Download and run install script +sudo apt-get -y install curl +curl -OL 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/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-dev-image b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-dev-image new file mode 100755 index 0000000000..10f821a39b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-dev-image @@ -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. + +# Install a minimal distribution, the required system tools and libraries, +# runtime dependencies and the Tuscany SCA runtime on a Ubuntu Server 12.04. + +# 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 /opt/tuscany +sudo chown $u /opt/tuscany +sudo chgrp $g /opt/tuscany +cd /opt/tuscany + +# Download and run install script +sudo apt-get -y install curl +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-install +chmod +x ./ubuntu-install +./ubuntu-install + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install new file mode 100755 index 0000000000..fbd2587e13 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install @@ -0,0 +1,344 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 minimal distribution, the required system tools and libraries, +# runtime dependencies and the Tuscany SCA runtime on Ubuntu Server 12.04. + +# Display commands as they are executed +set -x + +# Build and install in the current directory +build=`pwd` + +# First update the system +sudo apt-get update + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Build Libexpat +curl -L http://sourceforge.net/projects/expat/files/expat/2.0.1/expat-2.0.1.tar.gz/download -o 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 APR and APR util +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://archive.apache.org/dist/apr/apr-1.4.6.tar.gz +tar xzf apr-1.4.6.tar.gz +cd apr-1.4.6 +./buildconf +./configure --prefix=$build/apr-1.4.6-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +curl -OL http://archive.apache.org/dist/apr/apr-util-1.4.1.tar.gz +tar xzf apr-util-1.4.1.tar.gz +cd apr-util-1.4.1 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/apr-util-1.4.1.patch +patch -p0 <apr-util-1.4.1.patch +./buildconf --with-apr=$build/apr-1.4.6 +./configure --with-apr=$build/apr-1.4.6-bin --with-openssl --with-crypto --with-expat=$build/expat-2.0.1-bin --prefix=$build/apr-util-1.4.1-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build HTTP server +curl -OL http://archive.apache.org/dist/httpd/httpd-2.4.2.tar.gz +tar xzf httpd-2.4.2.tar.gz +cd httpd-2.4.2 +./configure --enable-ssl --enable-proxy --enable-usertrack --enable-cgi --enable-session-crypto --enable-mods-shared=most --enable-mpms-shared="prefork worker event" --with-mpm=prefork --with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin --with-expat=$build/expat-2.0.1-bin --prefix=$build/httpd-2.4.2-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 +curl -OL http://memcached.googlecode.com/files/memcached-1.4.13.tar.gz +tar xzf memcached-1.4.13.tar.gz +cd memcached-1.4.13 +./configure --prefix=$build/memcached-1.4.13-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Tinycdb +curl -OL 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 +curl -OL http://curl.haxx.se/download/curl-7.24.0.tar.gz +tar xzf curl-7.24.0.tar.gz +cd curl-7.24.0 +./configure --enable-threaded-resolver --prefix=$build/curl-7.24.0-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Libxml2 +curl -OL 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 Mozilla Portable Runtime +curl -OL http://ftp.mozilla.org/pub/mozilla.org/nspr/releases/v4.8.8/src/nspr-4.8.8.tar.gz +tar xzf nspr-4.8.8.tar.gz +cd nspr-4.8.8/mozilla/nsprpub +./configure --prefix=$build/nspr-4.8.8-bin --enable-64bit +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build SpiderMonkey +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://ftp.mozilla.org/pub/mozilla.org/js/js185-1.0.0.tar.gz +tar xzf js185-1.0.0.tar.gz +cd js-1.8.5/js/src +export LD_RUN_PATH=$build/nspr-4.8.8-bin/lib +./configure --prefix=$build/js-1.8.5-bin --enable-threadsafe --with-system-nspr --with-nspr-prefix=$build/nspr-4.8.8-bin +make +make install +unset LD_RUN_PATH +ln -s $build/js-1.8.5-bin/lib/libmozjs185.so $build/js-1.8.5-bin/lib/libmozjs.so +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 + +# Build Liboauth +curl -OL 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.24.0-bin/include" CURL_LIBS="-L$build/curl-7.24.0-bin/lib -lcurl" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build mod_security +curl -OL http://people.apache.org/~jsdelfino/tuscany/cpp/dependencies/modsecurity-apache_2.6.6.tar.gz +tar xzf modsecurity-apache_2.6.6.tar.gz +cd modsecurity-apache_2.6.6 +./configure --prefix=$build/modsecurity-apache-2.6.6-bin --with-apxs=$build/httpd-2.4.2-bin/bin/apxs --with-apr=$build/apr-1.4.6-bin/bin/apr-1-config --with-apu=$build/apr-util-1.4.1-bin/bin/apu-1-config --with-libxml=$build/libxml2-2.7.7-bin --with-curl=$build/curl-7.24.0-bin LIBS="-L$build/expat-2.0.1-bin/lib" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build +curl -OL http://people.apache.org/~jsdelfino/tuscany/cpp/dependencies/modsecurity-crs_2.2.5.tar.gz +tar xzf modsecurity-crs_2.2.5.tar.gz +cd modsecurity-crs_2.2.5 +#curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/modsecurity-crs_2.2.5.patch +#patch -p0 <modsecurity-crs_2.2.2.patch +cp -R base_rules $build/modsecurity-apache-2.6.6-bin +cp -R optional_rules $build/modsecurity-apache-2.6.6-bin +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build PostgreSQL and PgBouncer +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://ftp.postgresql.org/pub/source/v9.1.2/postgresql-9.1.2.tar.gz +tar xzf postgresql-9.1.2.tar.gz +cd postgresql-9.1.2 +./configure --prefix=$build/postgresql-9.1.2-bin --enable-thread-safety +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build +curl -OL http://pgfoundry.org/frs/download.php/3197/pgbouncer-1.5.tar.gz +tar xzf pgbouncer-1.5.tar.gz +cd pgbouncer-1.5 +./configure --prefix=$build/pgbouncer-1.5-bin +make +cp install-sh doc +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Thrift +sudo apt-get -y install bison flex libboost-dev libboost-filesystem-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://archive.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 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/thrift-0.2.0.patch +patch -p0 <thrift-0.2.0.patch +./bootstrap.sh +./configure --prefix=$build/thrift-0.2.0-bin --with-java=no --with-erlang=no --with-py=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 +curl -OL http://github.com/downloads/facebook/scribe/scribe-2.2.tar.gz +tar xzf scribe-2.2.tar.gz +cd scribe +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/scribe-2.2.patch +patch -p0 <scribe-2.2.patch +autoreconf --force --verbose --install +./configure --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 CPPFLAGS="-DBOOST_FILESYSTEM_VERSION=2" LIBS="-lboost_system -lboost_filesystem" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cp src/lib/libscribe.so $build/scribe-2.2-bin/lib +cd $build + +# Build Python +curl -OL http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz +tar xzf Python-2.7.3.tgz +cd Python-2.7.3 +./configure --prefix=$build/python-2.7.3-bin --enable-shared --with-system-expat=$build/expat-2.0.1-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Google Page Speed +curl -OL https://dl-ssl.google.com/page-speed/sdk/current/page-speed-sdk.zip +unzip page-speed-sdk.zip +cd page-speed-1.9 +make builddir=$build/page-speed-1.9-bin CXXFLAGS="-Wno-unused-but-set-variable" +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Nuvem +git clone git://git.apache.org/nuvem.git +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Tuscany SCA +git clone git://git.apache.org/tuscany-sca-cpp.git +cd tuscany-sca-cpp +./bootstrap +./configure --prefix=$build/tuscany-sca-cpp-bin --with-curl=$build/curl-7.24.0-bin --with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin --with-httpd=$build/httpd-2.4.2-bin --with-memcached=$build/memcached-1.4.13-bin --with-tinycdb=$build/tinycdb-0.77-bin --with-js-include=$build/js-1.8.5-bin/include/js --with-js-lib=$build/js-1.8.5-bin/lib --enable-pagespeed --with-pagespeed=$build/page-speed-1.9-bin --enable-threads --enable-python --with-python=$build/python-2.7.3-bin --with-libxml2=$build/libxml2-2.7.7-bin --enable-chat --with-libstrophe=$build/libstrophe-bin --enable-sqldb --with-pgsql=$build/postgresql-9.1.2-bin --with-pgbouncer=$build/pgbouncer-1.5-bin --enable-log --with-thrift=$build/thrift-0.2.0-bin --with-scribe=$build/scribe-2.2-bin --enable-oauth --with-liboauth=$build/liboauth-0.9.1-bin --enable-mod-security --with-mod-security=$build/modsecurity-apache-2.6.6-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Create src archive +tar czf tuscany-sca-cpp-1.0-src.tar.gz apr-1.4.6 apr-1.4.6.tar.gz apr-1.4.6-bin apr-util-1.4.1 apr-util-1.4.1.tar.gz apr-util-1.4.1-bin curl-7.24.0 curl-7.24.0-bin curl-7.24.0.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz httpd-2.4.2 httpd-2.4.2.tar.gz httpd-2.4.2-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.13 memcached-1.4.13-bin memcached-1.4.13.tar.gz modsecurity-apache_2.6.6 modsecurity-apache-2.6.6-bin modsecurity-apache_2.6.6.tar.gz modsecurity-crs_2.2.5 modsecurity-crs_2.2.5.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem page-speed-1.9 page-speed-1.9-bin page-speed-sdk.zip pgbouncer-1.5 pgbouncer-1.5-bin pgbouncer-1.5.tar.gz postgresql-9.1.2 postgresql-9.1.2-bin postgresql-9.1.2.tar.gz Python-2.7.3 python-2.7.3-bin Python-2.7.3.tgz scribe scribe-2.2-bin scribe-2.2.tar.gz thrift-0.2.0 thrift-0.2.0-bin thrift-0.2.0-incubating.tar.gz tinycdb-0.77 tinycdb-0.77-bin tinycdb_0.77.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin + +# Create bin archive +tar czf tuscany-sca-cpp-1.0.tar.gz apr-1.4.6-bin apr-util-1.4.1-bin curl-7.24.0-bin expat-2.0.1-bin httpd-2.4.2-bin js-1.8.5-bin liboauth-0.9.1-bin libstrophe-bin libxml2-2.7.7-bin memcached-1.4.13-bin modsecurity-apache-2.6.6-bin nspr-4.8.8-bin nuvem/nuvem-parallel page-speed-1.9-bin pgbouncer-1.5-bin postgresql-9.1.2-bin python-2.7.3-bin scribe-2.2-bin thrift-0.2.0-bin tinycdb-0.77-bin tuscany-sca-cpp tuscany-sca-cpp-bin + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-all b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-all new file mode 100755 index 0000000000..00d3c54abc --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-all @@ -0,0 +1,458 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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, +# runtime dependencies and the Tuscany SCA runtime on Ubuntu Server 12.04. + +# Display commands as they are executed +set -x + +# Build and install in the current directory +build=`pwd` + +# First update the system +sudo apt-get update + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Build Libexpat +curl -L http://sourceforge.net/projects/expat/files/expat/2.0.1/expat-2.0.1.tar.gz/download -o 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 APR and APR util +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://archive.apache.org/dist/apr/apr-1.4.6.tar.gz +tar xzf apr-1.4.6.tar.gz +cd apr-1.4.6 +./buildconf +./configure --prefix=$build/apr-1.4.6-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +curl -OL http://archive.apache.org/dist/apr/apr-util-1.4.1.tar.gz +tar xzf apr-1.4.1.tar.gz +cd apr-util-1.4.1 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/apr-util-1.4.1.patch +patch -p0 <apr-util-1.4.1.patch +./buildconf --with-apr=$build/apr-1.4.6 +./configure --with-apr=$build/apr-1.4.6-bin --with-openssl --with-crypto --with-expat=$build/expat-2.0.1-bin --prefix=$build/apr-util-1.4.1-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build HTTP server +curl -OL http://archive.apache.org/dist/httpd/httpd-2.4.2.tar.gz +tar xzf httpd-2.4.2.tar.gz +cd httpd-2.4.2 +./configure --enable-ssl --enable-proxy --enable-usertrack --enable-cgi --enable-session-crypto --enable-mods-shared=most --enable-mpms-shared="prefork worker event" --with-mpm=prefork --with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin --with-expat=$build/expat-2.0.1-bin --prefix=$build/httpd-2.4.2-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 +curl -OL http://memcached.googlecode.com/files/memcached-1.4.13.tar.gz +tar xzf memcached-1.4.13.tar.gz +cd memcached-1.4.13 +./configure --prefix=$build/memcached-1.4.13-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Tinycdb +curl -OL 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 LevelDB +git clone https://code.google.com/p/leveldb/ +cd leveldb +make all +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Libcurl +curl -OL http://curl.haxx.se/download/curl-7.24.0.tar.gz +tar xzf curl-7.24.0.tar.gz +cd curl-7.24.0 +./configure --enable-threaded-resolver --prefix=$build/curl-7.24.0-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Libxml2 +curl -OL 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 Mozilla Portable Runtime +curl -OL http://ftp.mozilla.org/pub/mozilla.org/nspr/releases/v4.8.8/src/nspr-4.8.8.tar.gz +tar xzf nspr-4.8.8.tar.gz +cd nspr-4.8.8/mozilla/nsprpub +./configure --prefix=$build/nspr-4.8.8-bin --enable-64bit +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build SpiderMonkey +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://ftp.mozilla.org/pub/mozilla.org/js/js185-1.0.0.tar.gz +tar xzf js185-1.0.0.tar.gz +cd js-1.8.5/js/src +export LD_RUN_PATH=$build/nspr-4.8.8-bin/lib +./configure --prefix=$build/js-1.8.5-bin --enable-threadsafe --with-system-nspr --with-nspr-prefix=$build/nspr-4.8.8-bin +make +make install +unset LD_RUN_PATH +ln -s $build/js-1.8.5-bin/lib/libmozjs185.so $build/js-1.8.5-bin/lib/libmozjs.so +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Install Google AppEngine SDK +curl -OL http://googleappengine.googlecode.com/files/google_appengine_1.4.0.zip +unzip google_appengine_1.4.0.zip + +# Build Apache Axis2/C +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL 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-openssl --with-apache2=$build/httpd-2.4.2-bin/include --with-apr=$build/apr-1.4.6-bin/include/apr-1 --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 +curl -OL http://archive.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 +curl -OL http://archive.apache.org/dist/mina/vysper/0.6/vysper-0.6-bin.tar.gz +tar xzf vysper-0.6-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.24.0-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/apr-1.4.6-bin --with-httpd=$build/httpd-2.4.2-bin --with-curl=$build/curl-7.24.0-bin --with-libopkele=$build/libopkele-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Liboauth +curl -OL 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.24.0-bin/include" CURL_LIBS="-L$build/curl-7.24.0-bin/lib -lcurl" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build mod_security +curl -OL http://people.apache.org/~jsdelfino/tuscany/cpp/dependencies/modsecurity-apache_2.6.6.tar.gz +tar xzf modsecurity-apache_2.6.6.tar.gz +cd modsecurity-apache_2.6.6 +./configure --prefix=$build/modsecurity-apache-2.6.6-bin --with-apxs=$build/httpd-2.4.2-bin/bin/apxs --with-apr=$build/apr-1.4.6-bin/bin/apr-1-config --with-apu=$build/apr-util-1.4.1-bin/bin/apu-1-config --with-libxml=$build/libxml2-2.7.7-bin --with-curl=$build/curl-7.24.0-bin LIBS="-L$build/expat-2.0.1-bin/lib" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build +curl -OL http://people.apache.org/~jsdelfino/tuscany/cpp/dependencies/modsecurity-crs_2.2.5.tar.gz +tar xzf modsecurity-crs_2.2.5.tar.gz +cd modsecurity-crs_2.2.5 +#curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/modsecurity-crs_2.2.2.patch +#patch -p0 <modsecurity-crs_2.2.2.patch +cp -R base_rules $build/modsecurity-apache-2.6.6-bin +cp -R optional_rules $build/modsecurity-apache-2.6.6-bin +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build PostgreSQL and PgBouncer +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://ftp.postgresql.org/pub/source/v9.1.2/postgresql-9.1.2.tar.gz +tar xzf postgresql-9.1.2.tar.gz +cd postgresql-9.1.2 +./configure --prefix=$build/postgresql-9.1.2-bin --enable-thread-safety +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build +curl -OL http://pgfoundry.org/frs/download.php/3197/pgbouncer-1.5.tar.gz +tar xzf pgbouncer-1.5.tar.gz +cd pgbouncer-1.5 +./configure --prefix=$build/pgbouncer-1.5-bin +make +cp install-sh doc +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Thrift +sudo apt-get -y install bison flex libboost-dev libboost-filesystem-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://archive.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 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/thrift-0.2.0.patch +patch -p0 <thrift-0.2.0.patch +./bootstrap.sh +./configure --prefix=$build/thrift-0.2.0-bin --with-java=no --with-erlang=no --with-py=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 +curl -OL http://github.com/downloads/facebook/scribe/scribe-2.2.tar.gz +tar xzf scribe-2.2.tar.gz +cd scribe +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/scribe-2.2.patch +patch -p0 <scribe-2.2.patch +autoreconf --force --verbose --install +./configure --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 CPPFLAGS="-DBOOST_FILESYSTEM_VERSION=2" LIBS="-lboost_system -lboost_filesystem" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cp src/lib/libscribe.so $build/scribe-2.2-bin/lib +cd $build + +# Build Python +curl -OL http://www.python.org/ftp/python/2.6.6/Python-2.7.3.tgz +tar xzf Python-2.7.3.tgz +cd Python-2.7.3 +./configure --prefix=$build/python-2.7.3-bin --enable-shared --with-system-expat=$build/expat-2.0.1-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Libcloud +curl -OL http://archive.apache.org/dist/incubator/libcloud/apache-libcloud-incubating-0.4.2.tar.bz2 +tar xjf apache-libcloud-incubating-0.4.2.tar.bz2 +cd apache-libcloud-incubating-0.4.2 +python setup.py build +python setup.py install --home $build/libcloud-0.4.2-bin +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Google Page Speed +curl -OL https://dl-ssl.google.com/page-speed/sdk/current/page-speed-sdk.zip +unzip page-speed-sdk.zip +cd page-speed-1.9 +make builddir=$build/page-speed-1.9-bin CXXFLAGS="-Wno-unused-but-set-variable" +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Nuvem +git clone git://git.apache.org/nuvem.git +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Tuscany SCA +git clone git://git.apache.org/tuscany-sca-cpp.git +cd tuscany-sca-cpp +./bootstrap +./configure --prefix=$build/tuscany-sca-cpp-bin --with-curl=$build/curl-7.24.0-bin --with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin --with-httpd=$build/httpd-2.4.2-bin --with-memcached=$build/memcached-1.4.13-bin --with-tinycdb=$build/tinycdb-0.77-bin --with-js-include=$build/js-1.8.5-bin/include/js --with-js-lib=$build/js-1.8.5-bin/lib --enable-pagespeed --with-pagespeed=$build/page-speed-1.9-bin --enable-libcloud --with-libcloud=$build/libcloud-0.4.2-bin --enable-threads --enable-python --with-python=$build/python-2.7.3-bin --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.6 --enable-sqldb --with-pgsql=$build/postgresql-9.1.2-bin --with-pgbouncer=$build/pgbouncer-1.5-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 --enable-mod-security --with-mod-security=$build/modsecurity-apache-2.6.6-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Create src archive +tar czf tuscany-sca-cpp-all-1.0-src.tar.gz apache-libcloud-incubating-0.4.2 apache-libcloud-incubating-0.4.2.tar.bz2 apr-1.4.6 apr-1.4.6.tar.gz apr-1.4.6-bin apr-util-1.4.1 apr-util-1.4.1.tar.gz apr-util-1.4.1-bin axis2c-1.6.0-bin axis2c-src-1.6.0 axis2c-src-1.6.0.tar.gz curl-7.24.0 curl-7.24.0-bin curl-7.24.0.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz google_appengine google_appengine_1.4.0.zip htmltidy-bin httpd-2.4.2 httpd-2.4.2.tar.gz httpd-2.4.2-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz libcloud-0.4.2-bin liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libopkele libopkele-bin libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.13 memcached-1.4.13-bin memcached-1.4.13.tar.gz mod_auth_openid mod-auth-openid-bin modsecurity-apache_2.6.6 modsecurity-apache-2.6.6-bin modsecurity-apache_2.6.6.tar.gz modsecurity-crs_2.2.5 modsecurity-crs_2.2.5.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem page-speed-1.9 page-speed-1.9-bin page-speed-sdk.zip pgbouncer-1.5 pgbouncer-1.5-bin pgbouncer-1.5.tar.gz postgresql-9.1.2 postgresql-9.1.2-bin postgresql-9.1.2.tar.gz qpidc-0.6 qpidc-0.6-bin qpid-cpp-0.6.tar.gz Python-2.7.3 python-2.7.3-bin Python-2.7.3.tgz scribe scribe-2.2-bin scribe-2.2.tar.gz thrift-0.2.0 thrift-0.2.0-bin thrift-0.2.0-incubating.tar.gz tidy tinycdb-0.77 tinycdb-0.77-bin tinycdb_0.77.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin vysper-0.6 vysper-0.6-bin.tar.gz + +# Create bin archive +tar czf tuscany-sca-cpp-all-1.0.tar.gz apr-1.4.6-bin apr-util-1.4.1-bin axis2c-1.6.0-bin curl-7.24.0-bin expat-2.0.1-bin google_appengine htmltidy-bin httpd-2.4.2-bin js-1.8.5-bin libcloud-0.4.2-bin liboauth-0.9.1-bin libopkele-bin libstrophe-bin libxml2-2.7.7-bin memcached-1.4.13-bin mod-auth-openid-bin modsecurity-apache-2.6.6-bin nspr-4.8.8-bin nuvem/nuvem-parallel page-speed-1.9-bin postgresql-9.1.2-bin python-2.7.3-bin qpidc-0.6-bin scribe-2.2-bin thrift-0.2.0-bin tinycdb-0.77-bin tuscany-sca-cpp tuscany-sca-cpp-bin vysper-0.6 + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-all-dependencies b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-all-dependencies new file mode 100755 index 0000000000..87710309df --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-all-dependencies @@ -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. + +# Install the required system tools and libraries and runtime dependencies +# for a complete Tuscany SCA runtime distribution on Ubuntu Server 12.04. + +# Display commands as they are executed +set -x + +# First update the system +sudo apt-get update + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache HTTP server dependencies +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Memcached dependencies +sudo apt-get -y install libevent-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the SpiderMonkey dependencies +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Qpid/C++ dependencies +sudo apt-get -y install libboost-dev libboost-program-options-dev libboost-filesystem-dev uuid-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Vysper dependencies +sudo apt-get -y install openjdk-6-jdk +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the HTML Tidy dependencies +sudo apt-get -y install cvs +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the PostgreSQL dependencies +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Thrift dependencies +sudo apt-get -y install bison flex +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Facebook Scribe dependencies +sudo apt-get -y install gawk +if [ "$?" != "0" ]; then + exit $? +fi + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-dependencies b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-dependencies new file mode 100755 index 0000000000..c9c140564d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-dependencies @@ -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. + +# Install the required system tools and libraries and runtime dependencies +# for a minimal Tuscany SCA runtime distribution on Ubuntu Server 12.04. + +# Display commands as they are executed +set -x + +# First update the system +sudo apt-get update + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache HTTP server dependencies +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Memcached dependencies +sudo apt-get -y install libevent-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the SpiderMonkey dependencies +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the PostgreSQL dependencies +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Apache Thrift dependencies +sudo apt-get -y install bison flex libboost-dev libboost-filesystem-dev +if [ "$?" != "0" ]; then + exit $? +fi + +# Install the Facebook Scribe dependencies +sudo apt-get -y install gawk +if [ "$?" != "0" ]; then + exit $? +fi + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-nothreads b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-nothreads new file mode 100755 index 0000000000..9c17fbb3ef --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/ubuntu-install-nothreads @@ -0,0 +1,344 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 minimal distribution, the required system tools and libraries, +# runtime dependencies and the Tuscany SCA runtime on Ubuntu Server 12.04. + +# Display commands as they are executed +set -x + +# Build and install in the current directory +build=`pwd` + +# First update the system +sudo apt-get update + +# Install core dev tools +sudo apt-get -y install curl git-core subversion autoconf pkg-config automake libtool g++ make gdb vim +if [ "$?" != "0" ]; then + exit $? +fi + +# Build Libexpat +curl -L http://sourceforge.net/projects/expat/files/expat/2.0.1/expat-2.0.1.tar.gz/download -o 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 APR and APR util +sudo apt-get -y install libssl-dev libpcre3-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://archive.apache.org/dist/apr/apr-1.4.6.tar.gz +tar xzf apr-1.4.6.tar.gz +cd apr-1.4.6 +./buildconf +./configure --prefix=$build/apr-1.4.6-bin --disable-threads +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +curl -OL http://archive.apache.org/dist/apr/apr-util-1.4.1.tar.gz +tar xzf apr-1.4.1.tar.gz +cd apr-util-1.4.1 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/apr-util-1.4.1.patch +patch -p0 <apr-util-1.4.1.patch +./buildconf --with-apr=$build/apr-1.4.6 +./configure --with-apr=$build/apr-1.4.6-bin --with-openssl --with-crypto --with-expat=$build/expat-2.0.1-bin --prefix=$build/apr-util-1.4.1-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build HTTP server +curl -OL http://archive.apache.org/dist/httpd/httpd-2.4.2.tar.gz +tar xzf httpd-2.4.2.tar.gz +cd httpd-2.4.2 +./configure --enable-ssl --enable-proxy --enable-usertrack --enable-cgi --enable-session-crypto --enable-mods-shared=most --enable-mpms-shared="prefork worker event" --with-mpm=prefork --with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin --with-expat=$build/expat-2.0.1-bin --prefix=$build/httpd-2.4.2-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 +curl -OL http://memcached.googlecode.com/files/memcached-1.4.13.tar.gz +tar xzf memcached-1.4.13.tar.gz +cd memcached-1.4.13 +./configure --prefix=$build/memcached-1.4.13-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Tinycdb +curl -OL 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 +curl -OL http://curl.haxx.se/download/curl-7.24.0.tar.gz +tar xzf curl-7.24.0.tar.gz +cd curl-7.24.0 +./configure --prefix=$build/curl-7.24.0-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Libxml2 +curl -OL 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 --without-threads +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Mozilla Portable Runtime +curl -OL http://ftp.mozilla.org/pub/mozilla.org/nspr/releases/v4.8.8/src/nspr-4.8.8.tar.gz +tar xzf nspr-4.8.8.tar.gz +cd nspr-4.8.8/mozilla/nsprpub +./configure --prefix=$build/nspr-4.8.8-bin --enable-64bit +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build SpiderMonkey +sudo apt-get -y install zip unzip +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://ftp.mozilla.org/pub/mozilla.org/js/js185-1.0.0.tar.gz +tar xzf js185-1.0.0.tar.gz +cd js-1.8.5/js/src +export LD_RUN_PATH=$build/nspr-4.8.8-bin/lib +./configure --prefix=$build/js-1.8.5-bin --with-system-nspr --enable-gczeal --with-nspr-prefix=$build/nspr-4.8.8-bin +make +make install +unset LD_RUN_PATH +ln -s $build/js-1.8.5-bin/lib/libmozjs185.so $build/js-1.8.5-bin/lib/libmozjs.so +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 + +# Build Liboauth +curl -OL 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.24.0-bin/include" CURL_LIBS="-L$build/curl-7.24.0-bin/lib -lcurl" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build mod_security +curl -OL http://people.apache.org/~jsdelfino/tuscany/cpp/dependencies/modsecurity-apache_2.6.6.tar.gz +tar xzf modsecurity-apache_2.6.6.tar.gz +cd modsecurity-apache_2.6.6 +./configure --prefix=$build/modsecurity-apache-2.6.6-bin --with-apxs=$build/httpd-2.4.2-bin/bin/apxs --with-apr=$build/apr-1.4.6-bin/bin/apr-1-config --with-apu=$build/apr-util-1.4.1-bin/bin/apu-1-config --with-libxml=$build/libxml2-2.7.7-bin --with-curl=$build/curl-7.24.0-bin LIBS="-L$build/expat-2.0.1-bin/lib" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build +curl -OL http://people.apache.org/~jsdelfino/tuscany/cpp/dependencies/modsecurity-crs_2.2.5.tar.gz +tar xzf modsecurity-crs_2.2.5.tar.gz +cd modsecurity-crs_2.2.5 +#curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/modsecurity-crs_2.2.5.patch +#patch -p0 <modsecurity-crs_2.2.2.patch +cp -R base_rules $build/modsecurity-apache-2.6.6-bin +cp -R optional_rules $build/modsecurity-apache-2.6.6-bin +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build PostgreSQL and PgBouncer +sudo apt-get -y install libreadline-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://ftp.postgresql.org/pub/source/v9.1.2/postgresql-9.1.2.tar.gz +tar xzf postgresql-9.1.2.tar.gz +cd postgresql-9.1.2 +./configure --prefix=$build/postgresql-9.1.2-bin --disable-thread-safety +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build +curl -OL http://pgfoundry.org/frs/download.php/3197/pgbouncer-1.5.tar.gz +tar xzf pgbouncer-1.5.tar.gz +cd pgbouncer-1.5 +./configure --prefix=$build/pgbouncer-1.5-bin +make +cp install-sh doc +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Thrift +sudo apt-get -y install bison flex libboost-dev libboost-filesystem-dev +if [ "$?" != "0" ]; then + exit $? +fi +curl -OL http://archive.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 +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/thrift-0.2.0.patch +patch -p0 <thrift-0.2.0.patch +./bootstrap.sh +./configure --prefix=$build/thrift-0.2.0-bin --with-java=no --with-erlang=no --with-py=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 +curl -OL http://github.com/downloads/facebook/scribe/scribe-2.2.tar.gz +tar xzf scribe-2.2.tar.gz +cd scribe +curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/scribe-2.2.patch +patch -p0 <scribe-2.2.patch +autoreconf --force --verbose --install +./configure --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 CPPFLAGS="-DBOOST_FILESYSTEM_VERSION=2" LIBS="-lboost_system -lboost_filesystem" +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cp src/lib/libscribe.so $build/scribe-2.2-bin/lib +cd $build + +# Build Python +curl -OL http://www.python.org/ftp/python/2.6.6/Python-2.7.3.tgz +tar xzf Python-2.7.3.tgz +cd Python-2.7.3 +./configure --prefix=$build/python-2.7.3-bin --enable-shared --without-threads --with-system-expat=$build/expat-2.0.1-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Google Page Speed +curl -OL https://dl-ssl.google.com/page-speed/sdk/current/page-speed-sdk.zip +unzip page-speed-sdk.zip +cd page-speed-1.9 +make builddir=$build/page-speed-1.9-bin CXXFLAGS="-Wno-unused-but-set-variable" +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Apache Nuvem +git clone git://git.apache.org/nuvem.git +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Build Tuscany SCA +git clone git://git.apache.org/tuscany-sca-cpp.git +cd tuscany-sca-cpp +./bootstrap +./configure --prefix=$build/tuscany-sca-cpp-bin --with-curl=$build/curl-7.24.0-bin --with-apr=$build/apr-1.4.6-bin --with-apr-util=$build/apr-util-1.4.1-bin --with-httpd=$build/httpd-2.4.2-bin --with-memcached=$build/memcached-1.4.13-bin --with-tinycdb=$build/tinycdb-0.77-bin --with-js-include=$build/js-1.8.5-bin/include/js --with-js-lib=$build/js-1.8.5-bin/lib --enable-pagespeed --with-pagespeed=$build/page-speed-1.9-bin --disable-threads --enable-python --with-python=$build/python-2.7.3-bin --with-libxml2=$build/libxml2-2.7.7-bin --enable-chat --with-libstrophe=$build/libstrophe-bin --enable-sqldb --with-pgsql=$build/postgresql-9.1.2-bin --with-pgbouncer=$build/pgbouncer-1.5-bin --enable-log --with-thrift=$build/thrift-0.2.0-bin --with-scribe=$build/scribe-2.2-bin --enable-oauth --with-liboauth=$build/liboauth-0.9.1-bin --enable-mod-security --with-mod-security=$build/modsecurity-apache-2.6.6-bin +make +make install +if [ "$?" != "0" ]; then + exit $? +fi +cd $build + +# Create src archive +tar czf tuscany-sca-cpp-1.0-src.tar.gz apr-1.4.6 apr-1.4.6.tar.gz apr-1.4.6-bin apr-util-1.4.1 apr-util-1.4.1.tar.gz apr-util-1.4.1-bin curl-7.24.0 curl-7.24.0-bin curl-7.24.0.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz httpd-2.4.2 httpd-2.4.2.tar.gz httpd-2.4.2-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.13 memcached-1.4.13-bin memcached-1.4.13.tar.gz modsecurity-apache_2.6.6 modsecurity-apache-2.6.6-bin modsecurity-apache_2.6.6.tar.gz modsecurity-crs_2.2.5 modsecurity-crs_2.2.5.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem page-speed-1.9 page-speed-1.9-bin page-speed-sdk.zip pgbouncer-1.5 pgbouncer-1.5-bin pgbouncer-1.5.tar.gz postgresql-9.1.2 postgresql-9.1.2-bin postgresql-9.1.2.tar.gz Python-2.7.3 python-2.7.3-bin Python-2.7.3.tgz scribe scribe-2.2-bin scribe-2.2.tar.gz thrift-0.2.0 thrift-0.2.0-bin thrift-0.2.0-incubating.tar.gz tinycdb-0.77 tinycdb-0.77-bin tinycdb_0.77.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin + +# Create bin archive +tar czf tuscany-sca-cpp-1.0.tar.gz apr-1.4.6-bin apr-util-1.4.1-bin curl-7.24.0-bin expat-2.0.1-bin httpd-2.4.2-bin js-1.8.5-bin liboauth-0.9.1-bin libstrophe-bin libxml2-2.7.7-bin memcached-1.4.13-bin modsecurity-apache-2.6.6-bin nspr-4.8.8-bin nuvem/nuvem-parallel page-speed-1.9-bin pgbouncer-1.5-bin postgresql-9.1.2-bin python-2.7.3-bin scribe-2.2-bin thrift-0.2.0-bin tinycdb-0.77-bin tuscany-sca-cpp tuscany-sca-cpp-bin + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/uec2-bin-all-image b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-bin-all-image new file mode 100755 index 0000000000..f8b34e9083 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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-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/sca-cpp/branches/lightweight-sca/ubuntu/uec2-bin-image b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-bin-image new file mode 100755 index 0000000000..fbcbe091b5 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-bin-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-keypair.pem ubuntu@$host "wget http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-bin-image; chmod 700 ./ubuntu-bin-image; ./ubuntu-bin-image" + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/uec2-conf b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-conf new file mode 100755 index 0000000000..37d786896e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; 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-keypair.pem ]; then + ec2-add-keypair ec2-keypair --region us-west-1 > $HOME/.ec2/ec2-keypair.pem + chmod 600 $HOME/.ec2/ec2-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/sca-cpp/branches/lightweight-sca/ubuntu/uec2-dev-all-image b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-dev-all-image new file mode 100755 index 0000000000..d56f05cdda --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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-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/sca-cpp/branches/lightweight-sca/ubuntu/uec2-dev-image b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-dev-image new file mode 100755 index 0000000000..206443a7ae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-dev-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-keypair.pem ubuntu@$host "wget http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/ubuntu/ubuntu-dev-image; chmod 700 ./ubuntu-dev-image; ./ubuntu-dev-image" + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/uec2-setenv b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-setenv new file mode 100755 index 0000000000..67d57df83a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/ubuntu/uec2-ssh b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-ssh new file mode 100755 index 0000000000..41738df7e6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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-keypair.pem ubuntu@$host + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/uec2-start b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-start new file mode 100755 index 0000000000..ef3dc4efdb --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-start @@ -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. + +# Start an Ubuntu 10.10 64-bit EC2 instance for use with Tuscany + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +. $here/uec2-setenv + +# Here are the AMI IDs you can use in the different EC2 regions: + +# Ubuntu 10.10 32-bit instance storage, suitable for small instances +# AP s.east - ami-7c423c2e +# EU west 1 - ami-339ca947 +# US east 1 - ami-a6f504cf +# US west 1 - ami-957e2ed0 + +# More AMI IDs at http://uec-images.ubuntu.com + +# Here are some of the instance types you can use: +# t1.micro +# m1.small +# m1.large + +#ec2-run-instances "ami-ca1f4f8f" -t m1.large -k ec2-keypair --region us-west-1 +#ec2-run-instances "ami-ca1f4f8f" -t t1.micro -k ec2-keypair --region us-west-1 +ec2-run-instances "ami-957e2ed0" -t m1.small -k ec2-keypair --region us-west-1 + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/uec2-status b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-status new file mode 100755 index 0000000000..f7a0722fe9 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +. $here/uec2-setenv + +ec2-describe-instances --region us-west-1 + diff --git a/sca-cpp/branches/lightweight-sca/ubuntu/uec2-stop b/sca-cpp/branches/lightweight-sca/ubuntu/uec2-stop new file mode 100755 index 0000000000..575fb4e3cd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +. $here/uec2-setenv + +ec2-terminate-instances $instance --region us-west-1 + diff --git a/sca-cpp/branches/lightweight-sca/xsd/external/XMLSchema.dtd b/sca-cpp/branches/lightweight-sca/xsd/external/XMLSchema.dtd new file mode 100644 index 0000000000..e8e8f7625a --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/datatypes.dtd b/sca-cpp/branches/lightweight-sca/xsd/external/datatypes.dtd new file mode 100644 index 0000000000..685e89a57e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/oasis-200401-wss-wssecurity-secext-1.0.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/oasis-200401-wss-wssecurity-secext-1.0.xsd new file mode 100644 index 0000000000..6829a00f4b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/oasis-200401-wss-wssecurity-utility-1.0.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/oasis-200401-wss-wssecurity-utility-1.0.xsd new file mode 100644 index 0000000000..f8d74e9c6e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/ws-addr.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/ws-addr.xsd new file mode 100644 index 0000000000..f6fc9c53b0 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/ws-policy.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/ws-policy.xsd new file mode 100644 index 0000000000..71d5da4f5b --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/wsdl20-instance.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/wsdl20-instance.xsd new file mode 100644 index 0000000000..7fb8c1beed --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/external/xml.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/xml.xsd new file mode 100644 index 0000000000..ac4b0ec8e6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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: + <schema . . .> + . . . + <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. + + <type . . .> + . . . + <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/sca-cpp/branches/lightweight-sca/xsd/external/xmldsig-core-schema.xsd b/sca-cpp/branches/lightweight-sca/xsd/external/xmldsig-core-schema.xsd new file mode 100644 index 0000000000..c4e9808cfd --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-1.1-cd05.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-1.1-cd05.xsd new file mode 100644 index 0000000000..51cc513276 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-binding-sca-1.1-cd05.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-binding-sca-1.1-cd05.xsd new file mode 100644 index 0000000000..a337296d45 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-binding-ws-1.1-cd04.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-binding-ws-1.1-cd04.xsd new file mode 100644 index 0000000000..cf71892578 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-core-1.1-cd05.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-core-1.1-cd05.xsd new file mode 100644 index 0000000000..466a1466e7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-definitions-1.1-cd05.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-definitions-1.1-cd05.xsd new file mode 100644 index 0000000000..8f2f20db19 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-implementation-composite-1.1-cd05.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-implementation-composite-1.1-cd05.xsd new file mode 100644 index 0000000000..f2780f9895 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-implementation-cpp-1.1-cd04.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-implementation-cpp-1.1-cd04.xsd new file mode 100644 index 0000000000..b54ced4e4e --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-implementation-java-1.1-cd02.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-implementation-java-1.1-cd02.xsd new file mode 100644 index 0000000000..2856a51450 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-interface-cpp-1.1-cd04.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-interface-cpp-1.1-cd04.xsd new file mode 100644 index 0000000000..b07bf01f1d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-interface-java-1.1-cd04.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-interface-java-1.1-cd04.xsd new file mode 100644 index 0000000000..7b78e13749 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-interface-wsdl-1.1-cd05.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-interface-wsdl-1.1-cd05.xsd new file mode 100644 index 0000000000..8d3510be7d --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/sca-policy-1.1-cd03.xsd b/sca-cpp/branches/lightweight-sca/xsd/sca-policy-1.1-cd03.xsd new file mode 100644 index 0000000000..81d7eb346c --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-atom.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-atom.xsd new file mode 100644 index 0000000000..603455a1f2 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-http.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-http.xsd new file mode 100644 index 0000000000..67feb54963 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-jsonrpc.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-jsonrpc.xsd new file mode 100644 index 0000000000..d1bdcbdfae --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-rest.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-rest.xsd new file mode 100644 index 0000000000..f19a0c4248 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-rss.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-binding-rss.xsd new file mode 100644 index 0000000000..9857ec62b7 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-implementation-python.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-implementation-python.xsd new file mode 100644 index 0000000000..182111daa6 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-implementation-scheme.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-implementation-scheme.xsd new file mode 100644 index 0000000000..9282918612 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-implementation-widget.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1-implementation-widget.xsd new file mode 100644 index 0000000000..8ebc8fc477 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1.xsd b/sca-cpp/branches/lightweight-sca/xsd/tuscany-sca-1.1.xsd new file mode 100644 index 0000000000..1f6347ba98 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/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> |