You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by js...@apache.org on 2010/01/24 10:27:53 UTC

svn commit: r902540 - in /tuscany/sca-cpp/trunk: ./ components/webservice/ etc/ kernel/ modules/http/ modules/json/ modules/server/

Author: jsdelfino
Date: Sun Jan 24 09:27:52 2010
New Revision: 902540

URL: http://svn.apache.org/viewvc?rev=902540&view=rev
Log:
Working Web service component using Axis2C 1.6. Some fixes to the JSON conversion functions to correctly handle all cases of nested objects and arrays. Added support for component properties, the Web service component has a URI property that can be configured to the address of the target Web service.

Added:
    tuscany/sca-cpp/trunk/components/webservice/axiom-test.cpp
    tuscany/sca-cpp/trunk/components/webservice/axis2-test.cpp
    tuscany/sca-cpp/trunk/components/webservice/echo-test   (contents, props changed)
      - copied, changed from r902539, tuscany/sca-cpp/trunk/components/webservice/Makefile.am
    tuscany/sca-cpp/trunk/components/webservice/server-test   (contents, props changed)
      - copied, changed from r902539, tuscany/sca-cpp/trunk/components/webservice/Makefile.am
Removed:
    tuscany/sca-cpp/trunk/components/webservice/webservice-test.cpp
Modified:
    tuscany/sca-cpp/trunk/components/webservice/Makefile.am
    tuscany/sca-cpp/trunk/components/webservice/client-test.cpp
    tuscany/sca-cpp/trunk/components/webservice/webservice.composite
    tuscany/sca-cpp/trunk/components/webservice/webservice.cpp
    tuscany/sca-cpp/trunk/components/webservice/webservice.hpp
    tuscany/sca-cpp/trunk/configure.ac
    tuscany/sca-cpp/trunk/etc/git-exclude
    tuscany/sca-cpp/trunk/kernel/element.hpp
    tuscany/sca-cpp/trunk/kernel/xml-test.cpp
    tuscany/sca-cpp/trunk/kernel/xml.hpp
    tuscany/sca-cpp/trunk/modules/http/curl.hpp
    tuscany/sca-cpp/trunk/modules/json/json-test.cpp
    tuscany/sca-cpp/trunk/modules/json/json.hpp
    tuscany/sca-cpp/trunk/modules/server/mod-eval.hpp

Modified: tuscany/sca-cpp/trunk/components/webservice/Makefile.am
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/Makefile.am?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/Makefile.am (original)
+++ tuscany/sca-cpp/trunk/components/webservice/Makefile.am Sun Jan 24 09:27:52 2010
@@ -17,7 +17,7 @@
 
 if WANT_WEBSERVICE
 
-noinst_PROGRAMS = webservice-test client-test
+noinst_PROGRAMS = axiom-test axis2-test client-test
 
 INCLUDES = -I${AXIS2C_INCLUDE}
 
@@ -27,12 +27,15 @@
 libwebservice_la_SOURCES = webservice.cpp
 libwebservice_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
 
-webservice_test_SOURCES = webservice-test.cpp
-webservice_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
+axiom_test_SOURCES = axiom-test.cpp
+axiom_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
+
+axis2_test_SOURCES = axis2-test.cpp
+axis2_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
 
 client_test_SOURCES = client-test.cpp
-client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs 
 
-TESTS = webservice-test client-test
+TESTS = axiom-test echo-test server-test
 
 endif

Added: tuscany/sca-cpp/trunk/components/webservice/axiom-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/axiom-test.cpp?rev=902540&view=auto
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/axiom-test.cpp (added)
+++ tuscany/sca-cpp/trunk/components/webservice/axiom-test.cpp Sun Jan 24 09:27:52 2010
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Web service Axiom support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "webservice.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+const string customerElement =
+"<customer>"
+"<name>jdoe</name>"
+"<address><city>san francisco</city><state>ca</state></address>"
+"<account><id>1234</id><balance>1000</balance></account>"
+"<account><id>6789</id><balance>2000</balance></account>"
+"<account><id>4567</id><balance>3000</balance></account>"
+"</customer>";
+
+bool testAxiom() {
+    const Axis2Context ax;
+    {
+        const failable<axiom_node_t*> n = stringToAxiomNode(customerElement, ax);
+        assert(hasContent(n));
+        const failable<const string> c = axiomNodeToString(content(n), ax);
+        assert(hasContent(c));
+        assert(content(c) == customerElement);
+    }
+    {
+        const list<value> arg = mklist<value>(
+                list<value>() + "ns1:echoString"
+                + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+                + (list<value>() + "text" + string("Hello World!")));
+        const failable<axiom_node_t*> n = valuesToAxiomNode(arg, ax);
+        assert(hasContent(n));
+        const failable<const string> x = axiomNodeToString(content(n), ax);
+        assert(hasContent(x));
+        assert(content(x) == "<ns1:echoString xmlns:ns1=\"http://ws.apache.org/axis2/services/echo\"><text>Hello World!</text></ns1:echoString>");
+        const failable<const list<value> > l = axiomNodeToValues(content(n), ax);
+        assert(hasContent(l));
+        assert(l == arg);
+    }
+    return true;
+}
+
+}
+}
+
+int main() {
+    tuscany::cout << "Testing..." << tuscany::endl;
+
+    tuscany::webservice::testAxiom();
+
+    tuscany::cout << "OK" << tuscany::endl;
+
+    return 0;
+}

Added: tuscany/sca-cpp/trunk/components/webservice/axis2-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/axis2-test.cpp?rev=902540&view=auto
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/axis2-test.cpp (added)
+++ tuscany/sca-cpp/trunk/components/webservice/axis2-test.cpp Sun Jan 24 09:27:52 2010
@@ -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 "webservice.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;
+}

Modified: tuscany/sca-cpp/trunk/components/webservice/client-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/client-test.cpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/client-test.cpp (original)
+++ tuscany/sca-cpp/trunk/components/webservice/client-test.cpp Sun Jan 24 09:27:52 2010
@@ -27,6 +27,7 @@
 #include "stream.hpp"
 #include "string.hpp"
 #include "list.hpp"
+#include "element.hpp"
 #include "value.hpp"
 #include "monad.hpp"
 #include "perf.hpp"
@@ -35,9 +36,25 @@
 namespace tuscany {
 namespace webservice {
 
-const string url("http://localhost:8090/echo");
+const string url("http://localhost:8090/webservice");
 
 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), url, 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;
 }
 

Copied: tuscany/sca-cpp/trunk/components/webservice/echo-test (from r902539, tuscany/sca-cpp/trunk/components/webservice/Makefile.am)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/echo-test?p2=tuscany/sca-cpp/trunk/components/webservice/echo-test&p1=tuscany/sca-cpp/trunk/components/webservice/Makefile.am&r1=902539&r2=902540&rev=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/Makefile.am (original)
+++ tuscany/sca-cpp/trunk/components/webservice/echo-test Sun Jan 24 09:27:52 2010
@@ -1,3 +1,5 @@
+#!/bin/sh
+
 #  Licensed to the Apache Software Foundation (ASF) under one
 #  or more contributor license agreements.  See the NOTICE file
 #  distributed with this work for additional information
@@ -15,24 +17,19 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-if WANT_WEBSERVICE
-
-noinst_PROGRAMS = webservice-test client-test
-
-INCLUDES = -I${AXIS2C_INCLUDE}
-
-compdir=$(prefix)/components/webservice
-comp_LTLIBRARIES = libwebservice.la
-
-libwebservice_la_SOURCES = webservice.cpp
-libwebservice_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
-
-webservice_test_SOURCES = webservice-test.cpp
-webservice_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
-
-client_test_SOURCES = client-test.cpp
-client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
-
-TESTS = webservice-test client-test
-
-endif
+# Setup
+axis2="${AXIS2C_HOME}/bin/axis2_http_server"
+pwd=`pwd`
+cd $AXIS2C_HOME/bin
+$axis2 &
+cd $pwd
+sleep 1
+
+# Test
+./axis2-test
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "${axis2}" | awk '{ print $2 }'`
+sleep 1
+return $rc

Propchange: tuscany/sca-cpp/trunk/components/webservice/echo-test
------------------------------------------------------------------------------
    svn:executable = *

Copied: tuscany/sca-cpp/trunk/components/webservice/server-test (from r902539, tuscany/sca-cpp/trunk/components/webservice/Makefile.am)
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/server-test?p2=tuscany/sca-cpp/trunk/components/webservice/server-test&p1=tuscany/sca-cpp/trunk/components/webservice/Makefile.am&r1=902539&r2=902540&rev=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/Makefile.am (original)
+++ tuscany/sca-cpp/trunk/components/webservice/server-test Sun Jan 24 09:27:52 2010
@@ -1,3 +1,5 @@
+#!/bin/sh
+
 #  Licensed to the Apache Software Foundation (ASF) under one
 #  or more contributor license agreements.  See the NOTICE file
 #  distributed with this work for additional information
@@ -15,24 +17,33 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-if WANT_WEBSERVICE
-
-noinst_PROGRAMS = webservice-test client-test
-
-INCLUDES = -I${AXIS2C_INCLUDE}
-
-compdir=$(prefix)/components/webservice
-comp_LTLIBRARIES = libwebservice.la
-
-libwebservice_la_SOURCES = webservice.cpp
-libwebservice_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
-
-webservice_test_SOURCES = webservice-test.cpp
-webservice_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine
-
-client_test_SOURCES = client-test.cpp
-client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
-
-TESTS = webservice-test client-test
-
-endif
+# Setup
+../../modules/http/httpd-conf tmp 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+
+<Location />
+SCAContribution `pwd`/
+SCAComposite webservice.composite
+</Location>
+EOF
+
+apachectl -k start -d `pwd`/tmp
+
+axis2="${AXIS2C_HOME}/bin/axis2_http_server"
+pwd=`pwd`
+cd $AXIS2C_HOME/bin
+$axis2 &
+cd $pwd
+sleep 2
+
+# Test
+./client-test
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "${axis2}" | awk '{ print $2 }'`
+apachectl -k stop -d `pwd`/tmp
+sleep 2
+return $rc

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

Modified: tuscany/sca-cpp/trunk/components/webservice/webservice.composite
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/webservice.composite?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/webservice.composite (original)
+++ tuscany/sca-cpp/trunk/components/webservice/webservice.composite Sun Jan 24 09:27:52 2010
@@ -24,6 +24,7 @@
         
     <component name="webservice">
         <implementation.cpp path=".libs" library="libwebservice"/>
+        <property name="uri">http://localhost:9090/axis2/services/echo</property>
         <service name="webservice">
             <t:binding.http uri="webservice"/>
         </service>

Modified: tuscany/sca-cpp/trunk/components/webservice/webservice.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/webservice.cpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/webservice.cpp (original)
+++ tuscany/sca-cpp/trunk/components/webservice/webservice.cpp Sun Jan 24 09:27:52 2010
@@ -34,10 +34,20 @@
 namespace webservice {
 
 /**
- * Apply a Web service function / operation.
+ * Apply a Web service function / operation using Axis2.
  */
-const failable<value> apply(const value& func, unused const list<value>& params) {
-    return tuscany::mkfailure<tuscany::value>(tuscany::string("Function not supported: ") + func);
+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);
 }
 
 }

Modified: tuscany/sca-cpp/trunk/components/webservice/webservice.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/components/webservice/webservice.hpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/components/webservice/webservice.hpp (original)
+++ tuscany/sca-cpp/trunk/components/webservice/webservice.hpp Sun Jan 24 09:27:52 2010
@@ -26,14 +26,164 @@
  * Web service invocation functions using Axis2.
  */
 
+// Ignore redundant declarations in Axiom headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+#include <axiom.h>
+#include <axis2_client.h>
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wredundant-decls"
+#endif
+
 #include "string.hpp"
+#include "sstream.hpp"
 #include "list.hpp"
 #include "value.hpp"
+#include "xml.hpp"
 #include "monad.hpp"
 
 namespace tuscany {
 namespace webservice {
 
+/**
+ * Represents an Axis2 runtime context.
+ */
+class Axis2Context {
+public:
+    Axis2Context() : env(axutil_env_create_all("tuscany.log", AXIS2_LOG_LEVEL_WARNING)), owner(true) {
+    }
+
+    Axis2Context(const Axis2Context& ax) : env(ax.env), owner(false) {
+    }
+
+    ~Axis2Context() {
+        if (!owner || env == NULL)
+            return;
+        axutil_env_free(env);
+    }
+
+private:
+    axutil_env_t* env;
+    bool owner;
+
+    friend const axutil_env_t* env(const Axis2Context& ax);
+};
+
+const axutil_env_t* env(const Axis2Context& ax) {
+    return ax.env;
+}
+
+/**
+ * Return the latest Axis2 error in an Axis2 context.
+ */
+const string axis2Error(const Axis2Context& ax) {
+    ostringstream os;
+    os << env(ax)->error->error_number << " : " << AXIS2_ERROR_GET_MESSAGE(env(ax)->error);
+    return str(os);
+}
+
+/**
+ * Convert a string to an Axiom node.
+ */
+const failable<axiom_node_t*> stringToAxiomNode(const string& s, const Axis2Context& ax) {
+    axiom_node_t* node = axiom_node_create_from_buffer(env(ax), const_cast<axis2_char_t*>(c_str(s)));
+    if (node == NULL)
+        return mkfailure<axiom_node_t*>(string("Couldn't convert XML to Axiom node: ") + axis2Error(ax));
+    return node;
+}
+
+/**
+ * Convert a list of values representing XML elements to an Axiom node.
+ */
+const failable<axiom_node_t*> valuesToAxiomNode(const list<value>& l, const Axis2Context& ax) {
+    const failable<list<string> > xml = writeXML(valuesToElements(l), false);
+    if (!hasContent(xml))
+        return mkfailure<axiom_node_t*>(reason(xml));
+    ostringstream os;
+    write(content(xml), os);
+    return stringToAxiomNode(str(os), ax);
+}
+
+/**
+ * Convert an axiom node to a string.
+ */
+const failable<const string> axiomNodeToString(axiom_node_t* node, const Axis2Context& ax) {
+    const char* c = axiom_node_to_string(node, env(ax));
+    if (c == NULL)
+        return mkfailure<const string>(string("Couldn't convert Axiom node to XML: ") + axis2Error(ax));
+    const string s(c);
+    AXIS2_FREE(env(ax)->allocator, const_cast<char*>(c));
+    return s;
+}
+
+/**
+ * Convert an axiom node to a list of values representing XML elements.
+ */
+const failable<const list<value> > axiomNodeToValues(axiom_node_t* node, const Axis2Context& ax) {
+    const failable<const string> s = axiomNodeToString(node, ax);
+    if (!hasContent(s))
+        return mkfailure<const list<value> >(reason(s));
+    istringstream is(content(s));
+    const failable<const list<value> > l = readXML(streamList(is));
+    if (!hasContent(l))
+        return l;
+    return elementsToValues(content(l));
+}
+
+/**
+ * Evaluate an expression in the form (soap-action-string, document, uri). Send the
+ * SOAP action and document to the Web Service at the given URI using Axis2.
+ */
+const char* axis2Home = getenv("AXIS2C_HOME");
+
+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_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_t *client = axis2_svc_client_create(env(ax), axis2Home);
+    if (client == NULL) {
+        axis2_endpoint_ref_free(epr, env(ax));
+        axis2_options_free(opt, env(ax));
+        return mkfailure<value>("Couldn't create Axis2 client: " + axis2Error(ax));
+    }
+    axis2_svc_client_set_options(client, env(ax), opt);
+    axis2_svc_client_engage_module(client, env(ax), AXIS2_MODULE_ADDRESSING);
+
+    // Construct request Axiom node
+    const failable<axiom_node_t*> req = valuesToAxiomNode(param, ax);
+    if (!hasContent(req))
+        return mkfailure<value>(reason(req));
+
+    // Call the Web service
+    axiom_node_t* res = axis2_svc_client_send_receive(client, env(ax), content(req));
+    if (res == NULL) {
+        axis2_svc_client_free(client, env(ax));
+        return mkfailure<value>("Couldn't invoke Axis2 service: " + axis2Error(ax));
+    }
+
+    // Parse result Axiom node
+    const failable<const list<value> > lval = axiomNodeToValues(res, ax);
+    if (!hasContent(lval))
+        return mkfailure<value>(reason(lval));
+    const value rval = content(lval);
+    debug(rval, "webservice::evalExpr::result");
+
+    // Cleanup
+    axis2_svc_client_free(client, env(ax));
+
+    return rval;
+}
+
 }
 }
 

Modified: tuscany/sca-cpp/trunk/configure.ac
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/configure.ac?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/configure.ac (original)
+++ tuscany/sca-cpp/trunk/configure.ac Sun Jan 24 09:27:52 2010
@@ -349,11 +349,11 @@
 # Configure path to Axis2C includes and lib.
 AC_MSG_CHECKING([for axis2c])
 AC_ARG_WITH([axis2c], [AC_HELP_STRING([--with-axis2c=PATH], [path to installed Axis2C [default=/usr/local/axis2c]])], [
-  AXIS2C_INCLUDE="${withval}/include"
+  AXIS2C_INCLUDE="${withval}/include/axis2-1.6.0"
   AXIS2C_LIB="${withval}/lib"
   AC_MSG_RESULT("${withval}")
 ], [
-  AXIS2C_INCLUDE="/usr/local/axis2c/include"
+  AXIS2C_INCLUDE="/usr/local/axis2c/include/axis2-1.6.0"
   AXIS2C_LIB="/usr/local/axis2c/lib"
   AC_MSG_RESULT(/usr/local/axis2c)
 ])

Modified: tuscany/sca-cpp/trunk/etc/git-exclude
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/etc/git-exclude?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/etc/git-exclude (original)
+++ tuscany/sca-cpp/trunk/etc/git-exclude Sun Jan 24 09:27:52 2010
@@ -81,5 +81,6 @@
 java-test
 java-shell
 script-test
-webservice-test
+axiom-test
+axis2-test
 

Modified: tuscany/sca-cpp/trunk/kernel/element.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/kernel/element.hpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/kernel/element.hpp (original)
+++ tuscany/sca-cpp/trunk/kernel/element.hpp Sun Jan 24 09:27:52 2010
@@ -37,6 +37,7 @@
  */
 const value attribute("attribute");
 const value element("element");
+const string atsign("@");
 
 /**
  * Returns true if a value is an element.
@@ -125,7 +126,7 @@
 
     // Convert an attribute
     if (isTaggedList(t, attribute))
-        return mklist(attributeName(t), attributeValue(t));
+        return mklist<value>(c_str(atsign + attributeName(t)), attributeValue(t));
 
     // Convert an element
     if (isTaggedList(t, element)) {
@@ -196,9 +197,12 @@
         const value n = car<value>(t);
         const value v = cadr<value>(t);
 
-        // Convert a single value
-        if (!isList(v))
+        // Convert a single value to an attribute or an element
+        if (!isList(v)) {
+            if (substr(n, 0, 1) == atsign)
+                return mklist<value>(attribute, substr(n, 1), v);
             return mklist(element, n, v);
+        }
 
         // Convert a list value
         if (isNil((list<value>)v) || !isSymbol(car<value>(v)))

Modified: tuscany/sca-cpp/trunk/kernel/xml-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/kernel/xml-test.cpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/kernel/xml-test.cpp (original)
+++ tuscany/sca-cpp/trunk/kernel/xml-test.cpp Sun Jan 24 09:27:52 2010
@@ -111,7 +111,7 @@
     return true;
 }
 
-bool testElement() {
+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));
@@ -149,6 +149,21 @@
     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() {
@@ -156,7 +171,8 @@
 
     tuscany::testReadXML();
     tuscany::testWriteXML();
-    tuscany::testElement();
+    tuscany::testElements();
+    tuscany::testValues();
 
     tuscany::cout << "OK" << tuscany::endl;
 

Modified: tuscany/sca-cpp/trunk/kernel/xml.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/kernel/xml.hpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/kernel/xml.hpp (original)
+++ tuscany/sca-cpp/trunk/kernel/xml.hpp Sun Jan 24 09:27:52 2010
@@ -290,16 +290,20 @@
 /**
  * Write a list of values to a libxml2 XML writer.
  */
-const failable<bool> write(const list<value>& l, const xmlTextWriterPtr xml) {
-    if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0)
-        return mkfailure<bool>(string("xmlTextWriterStartDocument failed"));
+const failable<bool> write(const list<value>& l, const xmlTextWriterPtr xml, bool xmlTag) {
+    if (xmlTag) {
+        if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0)
+            return mkfailure<bool>(string("xmlTextWriterStartDocument failed"));
+    }
 
     const failable<bool> w = writeList(l, xml);
     if (!hasContent(w))
         return w;
 
-    if (xmlTextWriterEndDocument(xml) < 0)
-        return mkfailure<bool>("xmlTextWriterEndDocument failed");
+    if (xmlTag) {
+        if (xmlTextWriterEndDocument(xml) < 0)
+            return mkfailure<bool>("xmlTextWriterEndDocument failed");
+    }
     return true;
 }
 
@@ -326,7 +330,7 @@
 /**
  * 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) {
+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)
@@ -335,7 +339,7 @@
     if (xml == NULL)
         return mkfailure<R>("xmlNewTextWriter failed");
 
-    const failable<bool> w = write(l, xml);
+    const failable<bool> w = write(l, xml, xmlTag);
     xmlFreeTextWriter(xml);
     if (!hasContent(w)) {
         return mkfailure<R>(reason(w));
@@ -343,15 +347,23 @@
     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 failable<list<string> > ls = writeXML<list<string> >(rcons<string>, list<string>(), l);
+const failable<list<string> > writeXML(const list<value>& l, const bool xmlTag) {
+    const failable<list<string> > ls = writeXML<list<string> >(rcons<string>, list<string>(), l, xmlTag);
     if (!hasContent(ls))
         return ls;
     return reverse(list<string>(content(ls)));
 }
 
+const failable<list<string> > writeXML(const list<value>& l) {
+    return writeXML(l, true);
+}
+
 }
 #endif /* tuscany_xml_hpp */

Modified: tuscany/sca-cpp/trunk/modules/http/curl.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/http/curl.hpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/http/curl.hpp (original)
+++ tuscany/sca-cpp/trunk/modules/http/curl.hpp Sun Jan 24 09:27:52 2010
@@ -73,7 +73,7 @@
 
 private:
     CURL* h;
-    bool owner;
+    const bool owner;
 
     friend CURL* handle(const CURLSession& c);
 };
@@ -217,15 +217,12 @@
     if (!hasContent(res))
         return mkfailure<value>(reason(res));
 
-    // Return result
-    failable<list<value> > jsres = json::readJSON(cadr<list<string> >(content(res)), cx);
-    if (!hasContent(jsres))
-        return mkfailure<value>(reason(jsres));
-    const list<value> val = elementsToValues(content(jsres));
-
-    const value rval(cadr<value>(cadr<value>(val)));
-    debug(rval, "http::evalExpr::result");
-    return rval;
+    // Parse and return JSON-RPC result
+    const failable<value> rval = json::jsonResultValue(cadr<list<string> >(content(res)), cx);
+    if (!hasContent(rval))
+        return mkfailure<value>(reason(rval));
+    debug(content(rval), "http::evalExpr::result");
+    return content(rval);
 }
 
 /**

Modified: tuscany/sca-cpp/trunk/modules/json/json-test.cpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/json/json-test.cpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/json/json-test.cpp (original)
+++ tuscany/sca-cpp/trunk/modules/json/json-test.cpp Sun Jan 24 09:27:52 2010
@@ -54,17 +54,18 @@
         const list<value> ac = mklist<value>(mklist<value>(element, "id", string("1234")), mklist<value>(attribute, "balance", 1000));
         const list<value> cr = mklist<value>(mklist<value> (attribute, "name", string("jdoe")), cons<value>(element, cons<value>("address", ad)), cons<value>(element, cons<value>("account", ac)));
         const list<value> c = mklist<value>(cons<value>(element, cons<value>("customer", cr)));
+
         ostringstream os;
         writeJSON<ostream*>(jsonWriter, &os, c, cx);
-        assert(str(os) == "{\"customer\":{\"name\":\"jdoe\",\"address\":{\"city\":\"san francisco\",\"state\":\"ca\"},\"account\":{\"id\":\"1234\",\"balance\":1000}}}");
+        assert(str(os) == "{\"customer\":{\"@name\":\"jdoe\",\"address\":{\"@city\":\"san francisco\",\"@state\":\"ca\"},\"account\":{\"id\":\"1234\",\"@balance\":1000}}}");
     }
     {
         const list<value> phones = mklist<value> (string("408-1234"), string("650-1234"));
-        const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (element, "lastName", string("test\ttab")), mklist<value> (element, "firstName", string("test1")));
+        const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (element, "lastName", string("test\ttab")), mklist<value> (attribute, "firstName", string("test1")));
 
         ostringstream os;
         writeJSON<ostream*>(jsonWriter, &os, l, cx);
-        assert(str(os) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"firstName\":\"test1\"}");
+        assert(str(os) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"@firstName\":\"test1\"}");
 
         istringstream is(str(os));
         const list<string> il = streamList(is);
@@ -75,6 +76,18 @@
         write(content(writeJSON(r, cx)), wos);
         assert(str(wos) == str(os));
     }
+    {
+        const list<value> l = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
+        cout << "l: " << l << endl;
+        ostringstream wos;
+        write(content(writeJSON(valuesToElements(l), cx)), wos);
+        assert(str(wos) == "{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}");
+
+        istringstream is(str(wos));
+        const list<string> il = streamList(is);
+        const list<value> r = elementsToValues(content(readJSON(il, cx)));
+        assert(r == l);
+    }
     return true;
 }
 
@@ -121,6 +134,30 @@
         write(content(writeJSON(e, cx)), os);
         assert(str(os) == f);
     }
+    {
+        const list<value> arg = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!")));
+        const failable<list<string> > r = jsonRequest(1, "echo", mklist<value>(arg), cx);
+        ostringstream os;
+        write(content(r), os);
+        assert(str(os) == "{\"id\":1,\"method\":\"echo\",\"params\":[{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}]}");
+
+        istringstream is(str(os));
+        const list<string> il = streamList(is);
+        const list<value> ir = elementsToValues(content(readJSON(il, cx)));
+        assert(car<value>(cadr<value>(caddr<value>(ir))) == arg);
+    }
+    {
+        const list<value> res = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples")) + (list<value>() + "text" + string("Hello World!")));
+        const failable<list<string> > r = jsonResult(1, res, cx);
+        ostringstream os;
+        write(content(r), os);
+        assert(str(os) == "{\"id\":1,\"result\":{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/c/samples\",\"text\":\"Hello World!\"}}}");
+
+        istringstream is(str(os));
+        const list<string> il = streamList(is);
+        const list<value> ir = elementsToValues(content(readJSON(il, cx)));
+        assert(cdr<value>(cadr<value>(ir)) == res);
+    }
     return true;
 }
 

Modified: tuscany/sca-cpp/trunk/modules/json/json.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/json/json.hpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/json/json.hpp (original)
+++ tuscany/sca-cpp/trunk/modules/json/json.hpp Sun Jan 24 09:27:52 2010
@@ -131,6 +131,22 @@
 };
 
 /**
+ * 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(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 JSONContext& cx) {
@@ -144,11 +160,16 @@
     if(!JS_GetPropertyById(cx, o, id, &jsv))
         return propertiesSoFar;
     const value val = jsValToValue(jsv, cx);
+
     jsval idv;
     JS_IdToValue(cx, id, &idv);
     if(JSVAL_IS_STRING(idv)) {
-        const value type = isList(val)? element : element;
-        return jsPropertiesToValues(cons<value> (mklist<value> (type, JS_GetStringBytes(JSVAL_TO_STRING(idv)), val), propertiesSoFar), o, i, cx);
+        const string name = JS_GetStringBytes(JSVAL_TO_STRING(idv));
+        if (substr(name, 0, 1) == atsign)
+            return jsPropertiesToValues(cons<value>(mklist<value>(attribute, c_str(substr(name, 1)), val), propertiesSoFar), o, i, cx);
+        if (isList(val) && !isJSArray(val))
+            return jsPropertiesToValues(cons<value>(cons<value>(element, cons<value>(c_str(name), list<value>(val))), propertiesSoFar), o, i, cx);
+        return jsPropertiesToValues(cons<value> (mklist<value> (element, c_str(name), val), propertiesSoFar), o, i, cx);
     }
     return jsPropertiesToValues(cons(val, propertiesSoFar), o, i, cx);
 }
@@ -227,39 +248,11 @@
 }
 
 /**
- * Returns true if a list represents a JS array.
- */
-const bool isJSArray(const list<value>& l) {
-    if(isNil(l))
-        return false;
-    const value v = car(l);
-    if(isList(v)) {
-        const list<value> p = v;
-        if(isSymbol(car(p)))
-            return false;
-    }
-    return true;
-}
-
-
-
-/**
- * Converts a list of values to JS properties.
- */
-JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const JSONContext& cx) {
-    const jsval valueToJSVal(const value& val, const JSONContext& cx);
-    if(isNil(l))
-        return o;
-    const list<value> p = car(l);
-    jsval pv = valueToJSVal(caddr(p), cx);
-    JS_SetProperty(cx, o, c_str((string)cadr(p)), &pv);
-    return valuesToJSProperties(o, cdr(l), cx);
-}
-
-/**
  * Converts a value to a JS val.
  */
 const jsval valueToJSVal(const value& val, const JSONContext& cx) {
+    JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const JSONContext& cx);
+
     switch(type(val)) {
     case value::String:
     case value::Symbol: {
@@ -282,16 +275,19 @@
     }
 }
 
-const failable<bool> writeList(const list<value>& l, JSObject* o, const JSONContext& cx) {
+/**
+ * Converts a list of values to JS properties.
+ */
+JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const JSONContext& cx) {
     if (isNil(l))
-        return true;
+        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(string(attributeName(token))), &pv);
+        JS_SetProperty(cx, o, c_str(atsign + string(attributeName(token))), &pv);
 
     } else if (isTaggedList(token, element)) {
 
@@ -308,14 +304,12 @@
             JS_SetProperty(cx, o, c_str(string(elementName(token))), &pv);
 
             // Write its children
-            const failable<bool> w = writeList(elementChildren(token), child, cx);
-            if (!hasContent(w))
-                return w;
+            valuesToJSProperties(child, elementChildren(token), cx);
         }
     }
 
     // Go on
-    return writeList(cdr(l), o, cx);
+    return valuesToJSProperties(o, cdr(l), cx);
 }
 
 /**
@@ -344,11 +338,7 @@
  * Convert a list of values to a JSON document.
  */
 template<typename R> const failable<R> writeJSON(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const JSONContext& cx) {
-    JSObject* o = JS_NewObject(cx, NULL, NULL, NULL);
-    jsval val = OBJECT_TO_JSVAL(o);
-    const failable<bool> w = writeList(l, o, cx);
-    if (!hasContent(w))
-        return mkfailure<R>(reason(w));
+    jsval val = OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), l, cx));
 
     WriteContext<R> wcx(reduce, initial, cx);
     if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx))
@@ -367,7 +357,7 @@
 }
 
 /**
- * Convert a function + params to a JSON request.
+ * Convert a list of function + params to a JSON-RPC request.
  */
 const failable<list<string> > jsonRequest(const value& id, const value& func, const value& params, json::JSONContext& cx) {
     const list<value> r = mklist<value>(mklist<value>("id", id), mklist<value>("method", string(func)), mklist<value>("params", params));
@@ -375,13 +365,27 @@
 }
 
 /**
- * Convert a value to a JSON result.
+ * Convert a value to a JSON-RPC result.
  */
 const failable<list<string> > jsonResult(const value& id, const value& val, JSONContext& cx) {
     return writeJSON(valuesToElements(mklist<value>(mklist<value>("id", id), mklist<value>("result", val))), cx);
 }
 
 /**
+ * Convert a JSON-RPC result to a value.
+ */
+const failable<value> jsonResultValue(const list<string>& s, JSONContext& cx) {
+    const failable<list<value> > jsres = json::readJSON(s, cx);
+    if (!hasContent(jsres))
+        return mkfailure<value>(reason(jsres));
+    const list<value> rval(cadr<value>(elementsToValues(content(jsres))));
+    const value val = cadr(rval);
+    if (isList(val) && !isJSArray(val))
+        return value(mklist<value>(val));
+    return val;
+}
+
+/**
  * Return a portable function name from a JSON-RPC function name.
  * Strip the "system." and "Service." prefixes added by some JSON-RPC clients.
  */

Modified: tuscany/sca-cpp/trunk/modules/server/mod-eval.hpp
URL: http://svn.apache.org/viewvc/tuscany/sca-cpp/trunk/modules/server/mod-eval.hpp?rev=902540&r1=902539&r2=902540&view=diff
==============================================================================
--- tuscany/sca-cpp/trunk/modules/server/mod-eval.hpp (original)
+++ tuscany/sca-cpp/trunk/modules/server/mod-eval.hpp Sun Jan 24 09:27:52 2010
@@ -269,19 +269,45 @@
 /**
  * Convert a list of component references to a list of HTTP proxy lambdas.
  */
-const value mkproxy(const value& ref, const string& base) {
+const value mkrefProxy(const value& ref, const string& base) {
     return lambda<value(const list<value>&)>(http::proxy(base + string(scdl::name(ref))));
 }
 
-const list<value> proxies(const list<value>& refs, const string& base) {
+const list<value> refProxies(const list<value>& refs, const string& base) {
     if (isNil(refs))
         return refs;
-    return cons(mkproxy(car(refs), base), proxies(cdr(refs), base));
+    return cons(mkrefProxy(car(refs), base), refProxies(cdr(refs), base));
 }
 
-extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px);
+/**
+ * Convert a list of component properties to a list of lambda functions that just return
+ * the property value.
+ */
+struct propProxy {
+    const value v;
+    propProxy(const value& v) : v(v) {
+    }
+    const value operator()(unused const list<value>& params) const {
+        return v;
+    }
+};
+
+const value mkpropProxy(const value& prop) {
+    return lambda<value(const list<value>&)>(propProxy(elementValue(prop)));
+}
+
+const list<value> propProxies(const list<value>& props) {
+    if (isNil(props))
+        return props;
+    return cons(mkpropProxy(car(props)), propProxies(cdr(props)));
+}
+
+/**
+ * Evaluate a component and convert it to an applicable lambda function.
+ */
+const value evalComponent(DirConf& dc, ServerConf& sc, server_rec& server, const value& comp) {
+    extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px);
 
-const value confImplementation(DirConf& dc, ServerConf& sc, server_rec& server, const value& comp) {
     const value impl = scdl::implementation(comp);
 
     // Convert component references to configured proxy lambdas
@@ -293,11 +319,13 @@
             << "/references/" << string(scdl::name(comp)) << "/";
     else
         base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/";
-    const list<value> px(proxies(scdl::references(comp), str(base)));
+    const list<value> rpx(refProxies(scdl::references(comp), str(base)));
+
+    // Convert component proxies to configured proxy lambdas
+    const list<value> ppx(propProxies(scdl::properties(comp)));
 
-    // Evaluate the component implementation and convert it to an
-    // applicable lambda function
-    const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(dc.contributionPath, impl, px));
+    // Evaluate the component implementation and convert it to an applicable lambda function
+    const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(dc.contributionPath, impl, append(rpx, ppx)));
     if (!hasContent(cimpl))
         return reason(cimpl);
     return content(cimpl);
@@ -309,7 +337,7 @@
 const list<value> componentToImplementationAssoc(DirConf& dc, ServerConf& sc, server_rec& server, const list<value>& c) {
     if (isNil(c))
         return c;
-    return cons<value>(mklist<value>(scdl::name(car(c)), confImplementation(dc, sc, server, car(c))), componentToImplementationAssoc(dc, sc, server, cdr(c)));
+    return cons<value>(mklist<value>(scdl::name(car(c)), evalComponent(dc, sc, server, car(c))), componentToImplementationAssoc(dc, sc, server, cdr(c)));
 }
 
 const list<value> componentToImplementationTree(DirConf& dc, ServerConf& sc, server_rec& server, const list<value>& c) {