diff options
Diffstat (limited to 'sca-cpp/trunk/components/webservice')
-rw-r--r-- | sca-cpp/trunk/components/webservice/Makefile.am | 13 | ||||
-rw-r--r-- | sca-cpp/trunk/components/webservice/axiom-test.cpp | 85 | ||||
-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.cpp | 19 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/webservice/echo-test | 35 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/webservice/server-test | 49 | ||||
-rw-r--r-- | sca-cpp/trunk/components/webservice/webservice.composite | 1 | ||||
-rw-r--r-- | sca-cpp/trunk/components/webservice/webservice.cpp | 16 | ||||
-rw-r--r-- | sca-cpp/trunk/components/webservice/webservice.hpp | 150 |
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; +} + } } |