summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/components/webservice
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-01-24 09:27:52 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-01-24 09:27:52 +0000
commit878131a50cf9651fc8de402420b8c94696328a3c (patch)
treed0112887a0204bbf6ad9e76ae062ca4b70bc094a /sca-cpp/trunk/components/webservice
parent1c21d758af81d880ad6e045d18f8bc62ad8be89e (diff)
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.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@902540 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/components/webservice')
-rw-r--r--sca-cpp/trunk/components/webservice/Makefile.am13
-rw-r--r--sca-cpp/trunk/components/webservice/axiom-test.cpp85
-rw-r--r--sca-cpp/trunk/components/webservice/axis2-test.cpp (renamed from sca-cpp/trunk/components/webservice/webservice-test.cpp)22
-rw-r--r--sca-cpp/trunk/components/webservice/client-test.cpp19
-rwxr-xr-xsca-cpp/trunk/components/webservice/echo-test35
-rwxr-xr-xsca-cpp/trunk/components/webservice/server-test49
-rw-r--r--sca-cpp/trunk/components/webservice/webservice.composite1
-rw-r--r--sca-cpp/trunk/components/webservice/webservice.cpp16
-rw-r--r--sca-cpp/trunk/components/webservice/webservice.hpp150
9 files changed, 380 insertions, 10 deletions
diff --git a/sca-cpp/trunk/components/webservice/Makefile.am b/sca-cpp/trunk/components/webservice/Makefile.am
index f4dc712b4f..fd85cf4cb0 100644
--- a/sca-cpp/trunk/components/webservice/Makefile.am
+++ b/sca-cpp/trunk/components/webservice/Makefile.am
@@ -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 @@ 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
+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
diff --git a/sca-cpp/trunk/components/webservice/axiom-test.cpp b/sca-cpp/trunk/components/webservice/axiom-test.cpp
new file mode 100644
index 0000000000..c52183ea9b
--- /dev/null
+++ b/sca-cpp/trunk/components/webservice/axiom-test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Web service Axiom support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "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;
+}
diff --git a/sca-cpp/trunk/components/webservice/webservice-test.cpp b/sca-cpp/trunk/components/webservice/axis2-test.cpp
index e544b193c8..8ab21bee29 100644
--- a/sca-cpp/trunk/components/webservice/webservice-test.cpp
+++ b/sca-cpp/trunk/components/webservice/axis2-test.cpp
@@ -20,13 +20,16 @@
/* $Rev$ $Date$ */
/**
- * Test WebService component.
+ * 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"
@@ -34,6 +37,23 @@ 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;
}
diff --git a/sca-cpp/trunk/components/webservice/client-test.cpp b/sca-cpp/trunk/components/webservice/client-test.cpp
index c2593e75d9..6e63c83ecb 100644
--- a/sca-cpp/trunk/components/webservice/client-test.cpp
+++ b/sca-cpp/trunk/components/webservice/client-test.cpp
@@ -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;
}
diff --git a/sca-cpp/trunk/components/webservice/echo-test b/sca-cpp/trunk/components/webservice/echo-test
new file mode 100755
index 0000000000..eedefed7ca
--- /dev/null
+++ b/sca-cpp/trunk/components/webservice/echo-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
+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
diff --git a/sca-cpp/trunk/components/webservice/server-test b/sca-cpp/trunk/components/webservice/server-test
new file mode 100755
index 0000000000..53765cca46
--- /dev/null
+++ b/sca-cpp/trunk/components/webservice/server-test
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+../../modules/http/httpd-conf tmp 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
diff --git a/sca-cpp/trunk/components/webservice/webservice.composite b/sca-cpp/trunk/components/webservice/webservice.composite
index a87bce03f6..ebb007b37e 100644
--- a/sca-cpp/trunk/components/webservice/webservice.composite
+++ b/sca-cpp/trunk/components/webservice/webservice.composite
@@ -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>
diff --git a/sca-cpp/trunk/components/webservice/webservice.cpp b/sca-cpp/trunk/components/webservice/webservice.cpp
index f4606afdd8..6427756b40 100644
--- a/sca-cpp/trunk/components/webservice/webservice.cpp
+++ b/sca-cpp/trunk/components/webservice/webservice.cpp
@@ -34,10 +34,20 @@ namespace tuscany {
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);
}
}
diff --git a/sca-cpp/trunk/components/webservice/webservice.hpp b/sca-cpp/trunk/components/webservice/webservice.hpp
index 5b7406f595..ba13b9ad7f 100644
--- a/sca-cpp/trunk/components/webservice/webservice.hpp
+++ b/sca-cpp/trunk/components/webservice/webservice.hpp
@@ -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;
+}
+
}
}