summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/components/webservice/axis2.hpp
blob: 47813ccd6df71c63e5a30b67ad910d8a2b009730 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* $Rev$ $Date$ */

#ifndef tuscany_webservice_hpp
#define tuscany_webservice_hpp

/**
 * Web service invocation functions using Axis2.
 */
#include "config.hpp"

// Ignore redundant declarations in Axiom headers
#ifdef WANT_MAINTAINER_MODE
#pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
#include <axiom.h>
#include <axis2_client.h>
#include <axis2_module.h>
#include <axis2_addr_mod.h>
#include <axis2_conf_ctx.h>
#include <axis2_disp.h>
#include <axis2_http_out_transport_info.h>
#ifdef WANT_MAINTAINER_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("axis2.log", AXIS2_LOG_LEVEL_WARNING)), owner(true) {
        debug("webservice::axis2context");
    }

    Axis2Context(const Axis2Context& ax) : env(ax.env), owner(false) {
        debug("webservice::axis2context::copy");
    }

    Axis2Context(const axutil_env_t* env) : env(const_cast<axutil_env_t*>(env)), owner(false) {
        debug("webservice::axis2context::env");
    }

    ~Axis2Context() {
        debug("webservice::~axis2context");
        if (!owner || env == NULL)
            return;
        axutil_env_free(env);
    }

private:
    axutil_env_t* env;
    bool owner;

    friend const axutil_env_t* env(const Axis2Context& ax);
};

const axutil_env_t* env(const Axis2Context& ax) {
    return ax.env;
}

/**
 * Return the latest Axis2 error in an Axis2 context.
 */
const string axis2Error(const Axis2Context& ax) {
    ostringstream os;
    os << env(ax)->error->error_number << " : " << AXIS2_ERROR_GET_MESSAGE(env(ax)->error);
    return str(os);
}

/**
 * Convert a string to an Axiom node.
 */
const failable<axiom_node_t*> stringToAxiomNode(const string& s, const Axis2Context& ax) {
    axiom_node_t* node = axiom_node_create_from_buffer(env(ax), const_cast<axis2_char_t*>(c_str(s)));
    if (node == NULL)
        return mkfailure<axiom_node_t*>(string("Couldn't convert XML to Axiom node: ") + axis2Error(ax));
    return node;
}

/**
 * Convert a list of values representing XML elements to an Axiom node.
 */
const failable<axiom_node_t*> valuesToAxiomNode(const list<value>& l, const Axis2Context& ax) {
    const failable<list<string> > xml = writeXML(valuesToElements(l), false);
    if (!hasContent(xml))
        return mkfailure<axiom_node_t*>(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 failable<value> evalExpr(const value& expr, const Axis2Context& ax) {
    debug(expr, "webservice::evalExpr::input");

    // Extract func name and single argument
    const value func(car<value>(expr));
    const list<value> param(cadr<value>(expr));
    const value uri(caddr<value>(expr));

    // Create Axis2 client
    axis2_svc_client_t *client = axis2_svc_client_create(env(ax), getenv("AXIS2C_HOME"));
    if (client == NULL)
        return mkfailure<value>("Couldn't create Axis2 client: " + axis2Error(ax));
    axis2_endpoint_ref_t *epr = axis2_endpoint_ref_create(env(ax), c_str(uri));
    axis2_options_t *opt = axis2_options_create(env(ax));
    axis2_options_set_to(opt, env(ax), epr);
    axis2_options_set_action(opt, env(ax), (const axis2_char_t*)c_str(func));
    axis2_svc_client_set_options(client, env(ax), opt);
    axis2_svc_client_engage_module(client, env(ax), AXIS2_MODULE_ADDRESSING);

    // Construct request Axiom node
    const failable<axiom_node_t*> req = valuesToAxiomNode(param, ax);
    if (!hasContent(req))
        return mkfailure<value>(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;
}

}
}

#endif /* tuscany_webservice_hpp */