From 878131a50cf9651fc8de402420b8c94696328a3c Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sun, 24 Jan 2010 09:27:52 +0000 Subject: 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 --- sca-cpp/trunk/components/webservice/Makefile.am | 13 +- sca-cpp/trunk/components/webservice/axiom-test.cpp | 85 ++++++++++++ sca-cpp/trunk/components/webservice/axis2-test.cpp | 71 ++++++++++ .../trunk/components/webservice/client-test.cpp | 19 ++- sca-cpp/trunk/components/webservice/echo-test | 35 +++++ sca-cpp/trunk/components/webservice/server-test | 49 +++++++ .../components/webservice/webservice-test.cpp | 51 ------- .../components/webservice/webservice.composite | 1 + sca-cpp/trunk/components/webservice/webservice.cpp | 16 ++- sca-cpp/trunk/components/webservice/webservice.hpp | 150 +++++++++++++++++++++ 10 files changed, 430 insertions(+), 60 deletions(-) create mode 100644 sca-cpp/trunk/components/webservice/axiom-test.cpp create mode 100644 sca-cpp/trunk/components/webservice/axis2-test.cpp create mode 100755 sca-cpp/trunk/components/webservice/echo-test create mode 100755 sca-cpp/trunk/components/webservice/server-test delete mode 100644 sca-cpp/trunk/components/webservice/webservice-test.cpp (limited to 'sca-cpp/trunk/components/webservice') 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 +#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 = +"" +"jdoe" +"
san franciscoca
" +"12341000" +"67892000" +"45673000" +"
"; + +bool testAxiom() { + const Axis2Context ax; + { + const failable n = stringToAxiomNode(customerElement, ax); + assert(hasContent(n)); + const failable c = axiomNodeToString(content(n), ax); + assert(hasContent(c)); + assert(content(c) == customerElement); + } + { + const list arg = mklist( + list() + "ns1:echoString" + + (list() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + + (list() + "text" + string("Hello World!"))); + const failable n = valuesToAxiomNode(arg, ax); + assert(hasContent(n)); + const failable x = axiomNodeToString(content(n), ax); + assert(hasContent(x)); + assert(content(x) == "Hello World!"); + const failable > 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/axis2-test.cpp b/sca-cpp/trunk/components/webservice/axis2-test.cpp new file mode 100644 index 0000000000..8ab21bee29 --- /dev/null +++ b/sca-cpp/trunk/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 +#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 arg = mklist( + list() + "ns1:echoString" + + (list() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + + (list() + "text" + string("Hello World!"))); + + const failable rval = evalExpr(mklist(func, arg, string("http://localhost:9090/axis2/services/echo")), ax); + assert(hasContent(rval)); + + const list r = mklist( + list() + "ns1:echoString" + + (list() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples")) + + (list() + "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/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 arg = mklist( + list() + "ns1:echoString" + + (list() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + + (list() + "text" + string("Hello World!"))); + + const failable rval = http::evalExpr(mklist(func, arg), url, cs); + assert(hasContent(rval)); + + const list r = mklist( + list() + "ns1:echoString" + + (list() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples")) + + (list() + "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 < +SCAContribution `pwd`/ +SCAComposite webservice.composite + +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-test.cpp b/sca-cpp/trunk/components/webservice/webservice-test.cpp deleted file mode 100644 index e544b193c8..0000000000 --- a/sca-cpp/trunk/components/webservice/webservice-test.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR 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 component. - */ - -#include -#include "stream.hpp" -#include "string.hpp" -#include "list.hpp" -#include "perf.hpp" -#include "webservice.hpp" - -namespace tuscany { -namespace webservice { - -bool testEval() { - return true; -} - -} -} - -int main() { - tuscany::cout << "Testing..." << tuscany::endl; - - tuscany::webservice::testEval(); - - tuscany::cout << "OK" << tuscany::endl; - - return 0; -} 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 @@ + http://localhost:9090/axis2/services/echo 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 apply(const value& func, unused const list& params) { - return tuscany::mkfailure(tuscany::string("Function not supported: ") + func); +const failable apply(const value& func, const list& params) { + const Axis2Context ax; + + // Extract parameters + const value doc = car(params); + const lambda&)> l = cadr(params); + + // Call the URI property lambda function to get the configured URI + const value uri = l(list()); + + // Evaluate using Axis2 + return evalExpr(mklist(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 +#include +#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 stringToAxiomNode(const string& s, const Axis2Context& ax) { + axiom_node_t* node = axiom_node_create_from_buffer(env(ax), const_cast(c_str(s))); + if (node == NULL) + return mkfailure(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 valuesToAxiomNode(const list& l, const Axis2Context& ax) { + const failable > xml = writeXML(valuesToElements(l), false); + if (!hasContent(xml)) + return mkfailure(reason(xml)); + ostringstream os; + write(content(xml), os); + return stringToAxiomNode(str(os), ax); +} + +/** + * Convert an axiom node to a string. + */ +const failable axiomNodeToString(axiom_node_t* node, const Axis2Context& ax) { + const char* c = axiom_node_to_string(node, env(ax)); + if (c == NULL) + return mkfailure(string("Couldn't convert Axiom node to XML: ") + axis2Error(ax)); + const string s(c); + AXIS2_FREE(env(ax)->allocator, const_cast(c)); + return s; +} + +/** + * Convert an axiom node to a list of values representing XML elements. + */ +const failable > axiomNodeToValues(axiom_node_t* node, const Axis2Context& ax) { + const failable s = axiomNodeToString(node, ax); + if (!hasContent(s)) + return mkfailure >(reason(s)); + istringstream is(content(s)); + const failable > 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 evalExpr(const value& expr, const Axis2Context& ax) { + debug(expr, "webservice::evalExpr::input"); + + // Extract func name and single argument + const value func(car(expr)); + const list param(cadr(expr)); + const value uri(caddr(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("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 req = valuesToAxiomNode(param, ax); + if (!hasContent(req)) + return mkfailure(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("Couldn't invoke Axis2 service: " + axis2Error(ax)); + } + + // Parse result Axiom node + const failable > lval = axiomNodeToValues(res, ax); + if (!hasContent(lval)) + return mkfailure(reason(lval)); + const value rval = content(lval); + debug(rval, "webservice::evalExpr::result"); + + // Cleanup + axis2_svc_client_free(client, env(ax)); + + return rval; +} + } } -- cgit v1.2.3