Support CDATA for SOAP request and response; Rename Parameter to SoapParameter; Add book server and client example for SOAP.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
set(TARGET_NAME soap_book_client)
|
||||
|
||||
set(SRCS
|
||||
../common/book.cc
|
||||
../common/book.h
|
||||
../common/book_xml.cc
|
||||
../common/book_xml.h
|
||||
book_client.cc
|
||||
book_client.h
|
||||
main.cc)
|
||||
|
||||
add_executable(${TARGET_NAME} ${SRCS})
|
||||
|
||||
target_link_libraries(${TARGET_NAME} webcc pugixml ${Boost_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
|
||||
@@ -0,0 +1,136 @@
|
||||
#include "example/soap_book_client/book_client.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "webcc/logger.h"
|
||||
|
||||
#include "example/common/book_xml.h"
|
||||
|
||||
static void PrintSeparateLine() {
|
||||
std::cout << "--------------------------------";
|
||||
std::cout << "--------------------------------";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
BookClient::BookClient(const std::string& host, const std::string& port)
|
||||
: webcc::SoapClient(host, port), code_(0) {
|
||||
url_ = "/book";
|
||||
service_ns_ = { "ser", "http://www.example.com/book/" };
|
||||
result_name_ = "Result";
|
||||
|
||||
// Customize response XML format.
|
||||
format_raw_ = false;
|
||||
indent_str_ = " ";
|
||||
}
|
||||
|
||||
bool BookClient::CreateBook(const std::string& title, double price, std::string* id) {
|
||||
PrintSeparateLine();
|
||||
std::cout << "CreateBook: " << title << ", " << price << std::endl;
|
||||
|
||||
webcc::SoapParameter parameter{
|
||||
"book",
|
||||
BookToXmlString({ "", title, price }),
|
||||
true, // as_cdata
|
||||
};
|
||||
std::string result_xml;
|
||||
if (!Call1("CreateBook", std::move(parameter), &result_xml)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto callback = [id](pugi::xml_node xnode) {
|
||||
*id = xnode.child("book").child("id").text().as_string();
|
||||
return !id->empty();
|
||||
};
|
||||
return ParseResultXml(result_xml, callback);
|
||||
}
|
||||
|
||||
bool BookClient::GetBook(const std::string& id, Book* book) {
|
||||
PrintSeparateLine();
|
||||
std::cout << "GetBook: " << id << std::endl;
|
||||
|
||||
std::string result_xml;
|
||||
if (!Call1("GetBook", { "id", id }, &result_xml)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto callback = [book](pugi::xml_node xnode) {
|
||||
return XmlToBook(xnode.child("book"), book);
|
||||
};
|
||||
return ParseResultXml(result_xml, callback);
|
||||
}
|
||||
|
||||
bool BookClient::ListBooks(std::list<Book>* books) {
|
||||
PrintSeparateLine();
|
||||
std::cout << "ListBooks" << std::endl;
|
||||
|
||||
std::string result_xml;
|
||||
if (!Call0("ListBooks", &result_xml)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto callback = [books](pugi::xml_node xnode) {
|
||||
return XmlToBookList(xnode.child("books"), books);
|
||||
};
|
||||
return ParseResultXml(result_xml, callback);
|
||||
}
|
||||
|
||||
bool BookClient::DeleteBook(const std::string& id) {
|
||||
PrintSeparateLine();
|
||||
std::cout << "DeleteBook: " << id << std::endl;
|
||||
|
||||
std::string result_xml;
|
||||
if (!Call1("DeleteBook", { "id", id }, &result_xml)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ParseResultXml(result_xml, {});
|
||||
}
|
||||
|
||||
bool BookClient::Call0(const std::string& operation, std::string* result_str) {
|
||||
return CallX(operation, {}, result_str);
|
||||
}
|
||||
|
||||
|
||||
bool BookClient::Call1(const std::string& operation, webcc::SoapParameter&& parameter,
|
||||
std::string* result_str) {
|
||||
std::vector<webcc::SoapParameter> parameters{
|
||||
{ std::move(parameter) }
|
||||
};
|
||||
return CallX(operation, std::move(parameters), result_str);
|
||||
}
|
||||
|
||||
bool BookClient::CallX(const std::string& operation,
|
||||
std::vector<webcc::SoapParameter>&& parameters,
|
||||
std::string* result_str) {
|
||||
webcc::Error error = webcc::SoapClient::Call(operation,
|
||||
std::move(parameters),
|
||||
result_str);
|
||||
|
||||
if (error != webcc::kNoError) {
|
||||
LOG_ERRO("Operation '%s' failed: %s",
|
||||
operation, webcc::DescribeError(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookClient::ParseResultXml(const std::string& result_xml,
|
||||
std::function<bool(pugi::xml_node)> callback) {
|
||||
pugi::xml_document xdoc;
|
||||
if (!xdoc.load_string(result_xml.c_str())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pugi::xml_node xwebcc = xdoc.document_element();
|
||||
|
||||
pugi::xml_node xstatus = xwebcc.child("status");
|
||||
code_ = xstatus.attribute("code").as_int();
|
||||
message_ = xstatus.attribute("message").as_string();
|
||||
|
||||
if (callback) {
|
||||
return callback(xwebcc);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef EXAMPLE_SOAP_BOOK_CLIENT_H_
|
||||
#define EXAMPLE_SOAP_BOOK_CLIENT_H_
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "webcc/soap_client.h"
|
||||
|
||||
#include "example/common/book.h"
|
||||
|
||||
class BookClient : public webcc::SoapClient {
|
||||
public:
|
||||
BookClient(const std::string& host, const std::string& port);
|
||||
|
||||
~BookClient() override = default;
|
||||
|
||||
int code() const { return code_; }
|
||||
const std::string& message() const { return message_; }
|
||||
|
||||
// Create a book.
|
||||
bool CreateBook(const std::string& title, double price, std::string* id);
|
||||
|
||||
// Get a book by ID.
|
||||
bool GetBook(const std::string& id, Book* book);
|
||||
|
||||
// List all books.
|
||||
bool ListBooks(std::list<Book>* books);
|
||||
|
||||
// Delete a book by ID.
|
||||
bool DeleteBook(const std::string& id);
|
||||
|
||||
private:
|
||||
// Call with 0 parameter.
|
||||
bool Call0(const std::string& operation, std::string* result_str);
|
||||
|
||||
// Call with 1 parameter.
|
||||
bool Call1(const std::string& operation, webcc::SoapParameter&& parameter,
|
||||
std::string* result_str);
|
||||
|
||||
// Simple wrapper of webcc::SoapClient::Call() to log error if any.
|
||||
bool CallX(const std::string& operation,
|
||||
std::vector<webcc::SoapParameter>&& parameters,
|
||||
std::string* result_str);
|
||||
|
||||
bool ParseResultXml(const std::string& result_xml,
|
||||
std::function<bool(pugi::xml_node)> callback);
|
||||
|
||||
// Last status.
|
||||
int code_;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
#endif // EXAMPLE_SOAP_BOOK_CLIENT_H_
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "webcc/logger.h"
|
||||
|
||||
#include "example/soap_book_client/book_client.h"
|
||||
|
||||
void Help(const char* argv0) {
|
||||
std::cout << "Usage: " << argv0 << " <host> <port>" << std::endl;
|
||||
std::cout << " E.g.," << std::endl;
|
||||
std::cout << " " << argv0 << " localhost 8080" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
Help(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||
|
||||
std::string host = argv[1];
|
||||
std::string port = argv[2];
|
||||
|
||||
BookClient client(host, port);
|
||||
|
||||
std::string id1;
|
||||
if (!client.CreateBook("1984", 12.3, &id1)) {
|
||||
std::cerr << "Failed to create book." << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::cout << "Book ID: " << id1 << std::endl;
|
||||
|
||||
std::string id2;
|
||||
if (!client.CreateBook("1Q84", 32.1, &id2)) {
|
||||
std::cerr << "Failed to create book." << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::cout << "Book ID: " << id2 << std::endl;
|
||||
|
||||
Book book;
|
||||
if (!client.GetBook(id1, &book)) {
|
||||
std::cerr << "Failed to get book." << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::cout << "Book: " << book << std::endl;
|
||||
|
||||
std::list<Book> books;
|
||||
if (!client.ListBooks(&books)) {
|
||||
std::cerr << "Failed to list books." << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (const Book& book : books) {
|
||||
std::cout << "Book: " << book << std::endl;
|
||||
}
|
||||
|
||||
if (client.DeleteBook(id1)) {
|
||||
std::cout << "Book deleted: " << id1 << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user