diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-02-28 19:40:06 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-02-28 19:40:06 +0000 |
commit | e982b4ef38fd043c15e89bdd60763b10434a087e (patch) | |
tree | 6b9d9c3fc9aff22edb0f137040164c1cbf2359af /sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest | |
parent | 64e2486555a0a14f7d9690c2fc62c30bde803a91 (diff) |
Moving old inactive code to a branch as it's confusing code assist, searches and indexing in trunk.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@917273 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
30 files changed, 4503 insertions, 0 deletions
diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/Makefile.am new file mode 100644 index 0000000000..742a8152ad --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/Makefile.am @@ -0,0 +1,6 @@ +SUBDIRS = interface reference service +datadir=$(prefix)/extensions/rest + +nobase_data_DATA = xsd/*.xsd + +EXTRA_DIST = xsd
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/Makefile.am new file mode 100644 index 0000000000..f963effea2 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/Makefile.am new file mode 100644 index 0000000000..a2b7ac74e4 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/Makefile.am @@ -0,0 +1,23 @@ +libdir=$(prefix)/extensions/rest/interface/lib +lib_LTLIBRARIES = libtuscany_sca_rest_interface.la + +noinst_HEADERS = tuscany/sca/rest/*.h tuscany/sca/rest/model/*.h + +libtuscany_sca_rest_interface_la_SOURCES = \ +tuscany/sca/rest/RESTInterfaceExtension.cpp \ +tuscany/sca/rest/model/RESTInterface.cpp + +libtuscany_sca_rest_interface_la_LIBADD = \ + -L${TUSCANY_SDOCPP}/lib -ltuscany_sdo \ + -L$(top_builddir)/runtime/core/src -ltuscany_sca + +INCLUDES = -I$(top_builddir)/runtime/core/src \ + -I${TUSCANY_SDOCPP}/include + +moduledir=$(prefix)/extensions/rest/interface/module +extension = libtuscany_sca_rest_interface$(libsuffix) + +install-exec-hook: + test -z $(moduledir) || $(mkdir_p) $(moduledir); + -rm -f $(moduledir)/$(extension) + $(LN_S) $(libdir)/$(extension) $(moduledir)/$(extension) diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/RESTInterfaceExtension.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/RESTInterfaceExtension.cpp new file mode 100644 index 0000000000..c69febf39a --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/RESTInterfaceExtension.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$ */ + +#include "tuscany/sca/rest/RESTInterfaceExtension.h" +#include "tuscany/sca/rest/model/RESTInterface.h" +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/core/SCARuntime.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca::model; + +extern "C" +{ +#if defined(WIN32) || defined(_WINDOWS) + __declspec(dllexport) +#endif + void tuscany_sca_rest_interface_initialize() + { + tuscany::sca::rest::RESTInterfaceExtension::initialize(); + } +} + +namespace tuscany +{ + namespace sca + { + namespace rest + { + // =================================================================== + // Constructor for the RESTInterfaceExtension class. + // =================================================================== + RESTInterfaceExtension::RESTInterfaceExtension() + { + logentry(); + } + + // =================================================================== + // Destructor for the RESTInterfaceExtension class. + // =================================================================== + RESTInterfaceExtension::~RESTInterfaceExtension() + { + logentry(); + } + + const string RESTInterfaceExtension::extensionName("rest"); + const string RESTInterfaceExtension::typeQName("http://www.osoa.org/xmlns/sca/1.0#RESTInterface"); + + // =================================================================== + // loadModelElement - load the info from interface.rest + // =================================================================== + tuscany::sca::model::Interface* RESTInterfaceExtension::getInterface(Composite* composite, DataObjectPtr scdlInterface) + { + logentry(); + + return new RESTInterface(); + } + + void RESTInterfaceExtension::initialize() + { + logentry(); + SCARuntime::getCurrentRuntime()->registerInterfaceExtension(new RESTInterfaceExtension()); + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/RESTInterfaceExtension.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/RESTInterfaceExtension.h new file mode 100644 index 0000000000..de61ee5751 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/RESTInterfaceExtension.h @@ -0,0 +1,76 @@ +/* + * 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_sca_rest_restinterfaceextension_h +#define tuscany_sca_rest_restinterfaceextension_h + +#include "tuscany/sca/extension/InterfaceExtension.h" + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + class RESTInterfaceExtension : public InterfaceExtension + { + public: + /** + * Default constructor + */ + RESTInterfaceExtension(); + + /** + * Destructor + */ + virtual ~RESTInterfaceExtension(); + + /** + * return the name of the extension + */ + virtual const std::string& getExtensionName() {return extensionName;} + + /** + * return the QName of schema type for this interface extension + * (e.g. "http://www.osoa.org/xmlns/sca/1.0#interface.rest") + */ + virtual const std::string& getExtensionTypeQName() {return typeQName;} + + virtual tuscany::sca::model::Interface* getInterface( + tuscany::sca::model::Composite* composite, + commonj::sdo::DataObjectPtr scdlInterface); + + static void initialize(); + + private: + static const std::string extensionName; + static const std::string typeQName; + + }; + + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_rest_restinterfaceextension_h + diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/exportinterface.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/exportinterface.h new file mode 100644 index 0000000000..f3636f0d39 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/exportinterface.h @@ -0,0 +1,38 @@ +/* + * 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_sca_rest_exportinterface_h +#define tuscany_sca_rest_exportinterface_h + +#if defined(WIN32) || defined (_WINDOWS) +#pragma warning(disable: 4786) + +#ifdef TUSCANY_SCA_REST_INTERFACE_EXPORTS +#define SCA_REST_INTERFACE_API __declspec(dllexport) +#else +#define SCA_REST_INTERFACE_API __declspec(dllimport) +#endif + +#else +#define SCA_REST_INTERFACE_API +#endif + +#endif // tuscany_sca_rest_exportinterface_h diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/model/RESTInterface.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/model/RESTInterface.cpp new file mode 100644 index 0000000000..34feda2049 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/model/RESTInterface.cpp @@ -0,0 +1,51 @@ +/* + * 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$ */ + +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/util/Utils.h" +#include "tuscany/sca/rest/model/RESTInterface.h" + +using namespace std; + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + const string RESTInterface::typeQName("http://www.osoa.org/xmlns/sca/1.0#RESTInterface"); + + // Constructor + RESTInterface::RESTInterface() + : Interface(true, false) + { + logentry(); + } + + RESTInterface::~RESTInterface() + { + logentry(); + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/model/RESTInterface.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/model/RESTInterface.h new file mode 100644 index 0000000000..88aacecc16 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/interface/src/tuscany/sca/rest/model/RESTInterface.h @@ -0,0 +1,80 @@ +/* + * 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_sca_rest_model_restinterface_h +#define tuscany_sca_rest_model_restinterface_h + +#include <string> + +#include "tuscany/sca/model/Interface.h" +#include "tuscany/sca/rest/exportinterface.h" + + +namespace tuscany +{ + namespace sca + { + namespace rest + { + /** + * Holds information about a REST interface + */ + class RESTInterface : public tuscany::sca::model::Interface + { + + public: + /** + * Constuctor. + * @param header Name of the header file containing the class that + * describes the interface. + * @param className Name of the class in the header file that + * describes the interface. + * @param scope The scope of the interface (stateless or composite). + * @param remotable True if the interface is remotable. + */ + RESTInterface(); + + /** + * Destructor. + */ + virtual ~RESTInterface(); + + /** + * return the QName of the schema type for this interface type + * (e.g. "http://www.osoa.org/xmlns/sca/1.0#interface.rest") + */ + virtual const std::string& getInterfaceTypeQName() { return typeQName; }; + + /** + * The QName of the schema type for this interface type. + */ + SCA_REST_INTERFACE_API static const std::string typeQName; + + private: + + }; + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_rest_model_restinterface_h + diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/Makefile.am new file mode 100644 index 0000000000..2a0247f16f --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = curl
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/Makefile.am new file mode 100644 index 0000000000..f963effea2 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/Makefile.am new file mode 100644 index 0000000000..f6e6c28b55 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/Makefile.am @@ -0,0 +1,28 @@ +libdir=$(prefix)/extensions/rest/reference/lib +lib_LTLIBRARIES = libtuscany_sca_rest_reference.la + +noinst_HEADERS = tuscany/sca/rest/*.h tuscany/sca/rest/model/*.h + +libtuscany_sca_rest_reference_la_SOURCES = \ +tuscany/sca/rest/RESTServiceBindingExtension.cpp \ +tuscany/sca/rest/model/RESTServiceBinding.cpp \ +tuscany/sca/rest/RESTServiceWrapper.cpp + +libtuscany_sca_rest_reference_la_LIBADD = \ + -L${TUSCANY_SDOCPP}/lib -ltuscany_sdo \ + -L$(top_builddir)/runtime/core/src -ltuscany_sca \ + -L$(top_builddir)/runtime/extensions/rest/interface/src -ltuscany_sca_rest_interface \ + -L${CURL_LIB} -lcurl + +INCLUDES = -I$(top_builddir)/runtime/core/src \ + -I$(top_builddir)/runtime/extensions/rest/interface/src \ + -I${TUSCANY_SDOCPP}/include \ + -I${CURL_INCLUDE} + +moduledir=$(prefix)/extensions/rest/reference/module +extension = libtuscany_sca_rest_reference$(libsuffix) + +install-exec-hook: + test -z $(moduledir) || $(mkdir_p) $(moduledir); + -rm -f $(moduledir)/$(extension) + $(LN_S) $(libdir)/$(extension) $(moduledir)/$(extension) diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceBindingExtension.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceBindingExtension.cpp new file mode 100644 index 0000000000..f8eb9ad05c --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceBindingExtension.cpp @@ -0,0 +1,89 @@ +/* +* 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. +*/ + +#include "RESTServiceBindingExtension.h" +#include "model/RESTServiceBinding.h" +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/util/Utils.h" +#include "tuscany/sca/core/SCARuntime.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca::model; + + +extern "C" +{ +#if defined(WIN32) || defined(_WINDOWS) + __declspec(dllexport) +#endif + void tuscany_sca_rest_reference_initialize() + { + tuscany::sca::rest::RESTServiceBindingExtension::initialize(); + } +} + + +namespace tuscany +{ + namespace sca + { + namespace rest + { + // =================================================================== + // Constructor for the RESTServiceBinding class. + // =================================================================== + RESTServiceBindingExtension::RESTServiceBindingExtension() + { + logentry(); + } + + // =================================================================== + // Destructor for the RESTServiceBindingExtension class. + // =================================================================== + RESTServiceBindingExtension::~RESTServiceBindingExtension() + { + logentry(); + } + + const string RESTServiceBindingExtension::extensionName("rest"); + const string RESTServiceBindingExtension::typeQName("http://www.osoa.org/xmlns/sca/1.0#RESTBinding"); + + + // =================================================================== + // loadModelElement - load the info from binding.rest + // =================================================================== + ServiceBinding* RESTServiceBindingExtension::getServiceBinding(Composite *composite, Service* service, DataObjectPtr scdlBinding) + { + string uri = scdlBinding->getCString("uri"); + + RESTServiceBinding* serviceBinding = new RESTServiceBinding(service, uri); + + return serviceBinding; + } + + void RESTServiceBindingExtension::initialize() + { + logentry(); + SCARuntime::getCurrentRuntime()->registerServiceBindingExtension(new RESTServiceBindingExtension()); + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceBindingExtension.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceBindingExtension.h new file mode 100644 index 0000000000..ad1d861d95 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceBindingExtension.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef tuscany_sca_extension_rest_restservicebindingextension_h +#define tuscany_sca_extension_rest_restservicebindingextension_h + +#include "tuscany/sca/extension/ServiceBindingExtension.h" + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + class RESTServiceBindingExtension : public ServiceBindingExtension + { + public: + /** + * Default constructor + */ + RESTServiceBindingExtension(); + + /** + * Destructor + */ + virtual ~RESTServiceBindingExtension(); + + /** + * return the name of the extension + */ + virtual const std::string& getExtensionName() {return extensionName;} + + /** + * return the QName of schema elemant for this implementation extension + * (e.g. "http://www.osoa.org/xmlns/sca/1.0#binding.rest") + */ + virtual const std::string& getExtensionTypeQName() {return typeQName;} + + virtual tuscany::sca::model::ServiceBinding* getServiceBinding( + tuscany::sca::model::Composite* composite, + tuscany::sca::model::Service* service, + commonj::sdo::DataObjectPtr scdlBinding); + + static void initialize(); + + private: + static const std::string extensionName; + static const std::string typeQName; + + }; + + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif //tuscany_sca_extension_rest_restservicebindingextension_h + diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceWrapper.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceWrapper.cpp new file mode 100644 index 0000000000..e28e7976e8 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceWrapper.cpp @@ -0,0 +1,1225 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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$ */ +#if defined(WIN32) || defined (_WINDOWS) +#pragma warning(disable: 4091) +#endif + +#include <curl/curl.h> +#include <curl/types.h> +#include <curl/easy.h> + +#include "commonj/sdo/SDO.h" + +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/core/Exceptions.h" +#include "tuscany/sca/util/Utils.h" +#include "tuscany/sca/util/SDOUtils.h" +#include "RESTServiceWrapper.h" +#include "tuscany/sca/core/Operation.h" +#include "tuscany/sca/core/SCARuntime.h" +#include "tuscany/sca/model/Service.h" +#include "tuscany/sca/model/Component.h" +#include "tuscany/sca/model/Composite.h" +#include "tuscany/sca/model/ServiceType.h" +#include "tuscany/sca/model/CompositeReference.h" +#include "model/RESTServiceBinding.h" +#include "tuscany/sca/rest/model/RESTInterface.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca::model; +using namespace tuscany::sca::util; + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + class ResponseChunk { + public: + ResponseChunk() : memory(NULL), size(0) + { + } + + ~ResponseChunk() + { + if (memory) + { + free(memory); + } + } + + char *memory; + int size; + }; + + class RequestChunk { + public: + RequestChunk() : memory(NULL), size(0), read(0) + { + } + + ~RequestChunk() + { + } + + const char *memory; + int size; + int read; + }; + + class HeaderChunk { + public: + HeaderChunk() : location("") + { + } + + ~HeaderChunk() + { + } + + string location; + }; + + size_t write_callback(void *ptr, size_t size, size_t nmemb, void *data) + { + int realsize = size * nmemb; + ResponseChunk *mem = (ResponseChunk *)data; + + if (mem->memory != NULL) + { + mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); + } + else + { + mem->memory = (char *)malloc(mem->size + realsize + 1); + } + memcpy(&(mem->memory[mem->size]), ptr, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + return realsize; + } + + static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *data) + { + int realsize = size * nmemb; + RequestChunk *mem = (RequestChunk *)data; + + if (realsize > mem->size - mem->read) + { + realsize = mem->size - mem->read; + } + if (realsize != 0) + { + memcpy(ptr, &(mem->memory[mem->read]), realsize); + mem->read += realsize; + } + return realsize; + } + + size_t header_callback(void *ptr, size_t size, size_t nmemb, void *data) + { + int realsize = size * nmemb; + HeaderChunk* mem = (HeaderChunk*)data; + + char* str = new char[realsize + 1]; + memcpy(str, ptr, realsize); + str[realsize] = 0; + + if (strlen(str) > 10 && !strncmp(str, "Location: ", 10)) + { + string s = &str[10]; + mem->location = s.substr(0,s.find_last_not_of("\r\n")+1); + } + + delete str; + + return realsize; + } + + bool RESTServiceWrapper::initialized = false; + + RESTServiceWrapper::RESTServiceWrapper(Service* service) : ServiceWrapper(service) + { + logentry(); + + DataFactoryPtr dataFactory = service->getComponent()->getComposite()->getDataFactory(); + try { + const Type& tempType = dataFactory->getType("http://tempuri.org", "RootType"); + } catch (SDORuntimeException&) + { + dataFactory->addType("http://tempuri.org", "RootType", false, false, false); + dataFactory->addType("http://tempuri.org", "Wrapper", false, true, false); + dataFactory->addPropertyToType( + "http://tempuri.org", "RootType", + "Wrapper", + "http://tempuri.org", "Wrapper", + false, false, true); + dataFactory->addType("http://tempuri.org", "Part", false, true, false); + dataFactory->addPropertyToType( + "http://tempuri.org", "RootType", + "Part", + "http://tempuri.org", "Part", + false, false, true); + } + + if (!initialized) + { + curl_global_init(CURL_GLOBAL_ALL); + initialized = true; + } + } + + RESTServiceWrapper::~RESTServiceWrapper() + { + } + + /// + /// This method will be called when a service call needs to be made. + /// + void RESTServiceWrapper::invoke(Operation& operation) + { + logentry(); + + const string& operationName = operation.getName(); + + loginfo("Service: %s, operation: %s", getService()->getType()->getName().c_str() , operationName.c_str()); + + for (unsigned int i=0; i<operation.getNParms(); i++) + { + loginfo("Parameter: %p, type %u", operation.getParameterValue(i),(int) operation.getParameterType(i)); + } + + // Get the service, composite reference and composite + Service* service = getService(); + CompositeReference* compositeReference = (CompositeReference*)service->getComponent(); + Composite* composite = compositeReference->getComposite(); + XMLHelperPtr xmlHelper = composite->getXMLHelper(); + + // Get the REST binding + RESTServiceBinding* binding = (RESTServiceBinding *)service->getBinding(); + Interface* iface = service->getType()->getInterface(); + + // Init the curl session + CURL *curl_handle = curl_easy_init(); + + RequestChunk requestChunk; + ResponseChunk responseChunk; + HeaderChunk headerChunk; + + // Some servers don't like requests that are made without a user-agent + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + // Get the operation name + string opName = operation.getName(); + + // If we have a REST interface, the operation name translates to an HTTP verb + if (iface != NULL && iface->getInterfaceTypeQName() == RESTInterface::typeQName) + { + + // HTTP GET + if (opName == "retrieve") + { + // Build the request URL + bool firstParm = 0; + string uri; + if (operation.getNParms() !=0) + { + + // If the first parameter is a URI, then we'll use it, + // otherwise we'll use the binding URI + ostringstream s0; + writeParameter(xmlHelper, s0, operation.getParameter(0)); + string p0 = s0.str(); + if (p0.find("://") != string::npos) + { + firstParm = 1; + uri = p0; + } + else + { + uri = getBindingURI(); + } + } + else + { + uri = getBindingURI(); + } + // Add the parameters to the end of the URI + ostringstream os; + if (uri[uri.length()-1] == '?') + { + // If the URI ends with a "?" then we use the query + // form param=value& + os << uri; + for (unsigned int i = firstParm; i < operation.getNParms(); i++) + { + Operation::Parameter param = operation.getParameter(i); + + if(param.hasName()) + { + os << param.getName() << "="; + } + else + { + // No name - use "param1", etc + os << "param" << (i + 1) << "="; + } + writeParameter(xmlHelper, os, param); + if (i < operation.getNParms()-1) + os << "&"; + } + } + else + { + // Add the parameters in the form + // value1 / value2 / value3 + os << uri; + for (unsigned int i = firstParm; i < operation.getNParms(); i++) + { + os << "/"; + writeParameter(xmlHelper, os, operation.getParameter(i)); + } + } + + string url = os.str(); + //loginfo("RESTServiceWrapper: HTTP GET %s", url.c_str()); + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + + // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&responseChunk); + + // Send all headers to this function + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)&headerChunk); + + // Perform the HTTP GET + CURLcode rc = curl_easy_perform(curl_handle); + + if (rc) + { + throwException(ServiceInvocationException, curl_easy_strerror(rc)); + } + + // Get the output data out of the returned document + long httprc; + curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &httprc); + + string responsePayload = ""; + if (responseChunk.memory) + { + responsePayload = string((const char*)responseChunk.memory, responseChunk.size); + } + + if (httprc == 200) + { + if (responsePayload != "") + { + //TODO Remove this workaround once SDO supports loading of open top level content + // The workaround is to wrap the open content in a wrapper element + string xmldecl; + string xml; + Utils::rTokeniseString("?>", responsePayload, xmldecl, xml); + string part = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + part += "<Part xmlns=\"http://tempuri.org\" xmlns:tns=\"http://tempuri.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"; + part += xml; + part += "\n</Part>"; + + setReturn(xmlHelper, part, operation); + } + else + { + throwException(ServiceInvocationException, "Failed to retrieve resource, empty response"); + } + } + else + { + ostringstream msg; + msg << "Failed to retrieve REST resource, HTTP code: " << httprc; + if (responsePayload != "") + { + msg << ", payload: " << responsePayload; + } + throwException(ServiceInvocationException, msg.str().c_str()); + } + } + else if (opName == "create") + { + // HTTP POST + + // Set the target URL + string url = getBindingURI(); + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + + // Create the input payload + ostringstream spayload; + writeParameter(xmlHelper, spayload, operation.getParameter(0)); + const string& requestPayload = spayload.str(); + requestChunk.memory = requestPayload.c_str(); + requestChunk.size = requestPayload.size(); + + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, requestChunk.size); + + // Read all data using this function + curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_READDATA, (void *)&requestChunk); + + // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&responseChunk); + + // Send all headers to this function + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)&headerChunk); + + // Configure headers + curl_slist *requestHeaders = NULL; + requestHeaders = curl_slist_append(requestHeaders, "Expect:"); + requestHeaders = curl_slist_append(requestHeaders, "Content-Type: text/xml"); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, requestHeaders); + + // Perform the HTTP POST + curl_easy_setopt(curl_handle, CURLOPT_POST, true); + CURLcode rc = curl_easy_perform(curl_handle); + + curl_slist_free_all(requestHeaders); + + if (rc) + { + throwException(ServiceInvocationException, curl_easy_strerror(rc)); + } + + // Get the output and location of the created resource + string responsePayload = ""; + if (responseChunk.memory) + { + responsePayload = string((const char*)responseChunk.memory, responseChunk.size); + } + + long httprc; + curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &httprc); + if (httprc == 201) + { + string* location = new string; + *location = headerChunk.location; + operation.setReturnValue(location); + } + else + { + ostringstream msg; + msg << "Failed to create REST resource, HTTP code: " << httprc; + if (responsePayload != "") + { + msg << ", payload: " << responsePayload; + } + throwException(ServiceInvocationException, msg.str().c_str()); + } + } + else if (opName == "update") + { + // HTTP PUT + + // Build the request URL + bool firstParm = 0; + string uri; + if (operation.getNParms() > 1) + { + + // If the first parameter is a URI, then we'll use it, + // otherwise we'll use the binding URI + ostringstream s0; + writeParameter(xmlHelper, s0, operation.getParameter(0)); + string p0 = s0.str(); + if (p0.find("://") != string::npos) + { + firstParm = 1; + uri = p0; + } + else + { + uri = getBindingURI(); + } + } + else + { + uri = getBindingURI(); + } + // Add the parameters to the end of the URI + ostringstream os; + if (uri[uri.length()-1] == '?') + { + // If the URI ends with a "?" then we use the query + // form param=value& + os << uri; + for (unsigned int i = firstParm; i < operation.getNParms()-1; i++) + { + Operation::Parameter param = operation.getParameter(i); + if(param.hasName()) + { + os << param.getName() << "="; + } + else + { + // No name - use "param1", etc + os << "param" << (i + 1) << "="; + } + writeParameter(xmlHelper, os, param); + if (i < operation.getNParms()-1) + os << "&"; + } + } + else + { + // Add the parameters in the form + // value1 / value2 / value3 + os << uri; + for (unsigned int i = firstParm; i < operation.getNParms()-1; i++) + { + os << "/"; + writeParameter(xmlHelper, os, operation.getParameter(i)); + } + } + + string url = os.str(); + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + + // Create the input payload + ostringstream spayload; + writeParameter(xmlHelper, spayload, operation.getParameter(operation.getNParms()-1)); + const string& requestPayload = spayload.str(); + requestChunk.memory = requestPayload.c_str(); + requestChunk.size = requestPayload.size(); + + // Read all data using this function + curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_READDATA, (void *)&requestChunk); + + // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&responseChunk); + + // Send all headers to this function + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)&headerChunk); + + // Configure headers + curl_slist *requestHeaders = NULL; + requestHeaders = curl_slist_append(requestHeaders, "Expect:"); + requestHeaders = curl_slist_append(requestHeaders, "Content-Type: text/xml"); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, requestHeaders); + + // Perform the HTTP PUT + curl_easy_setopt(curl_handle, CURLOPT_PUT, true); + curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, true) ; + long size = (long)requestChunk.size; + curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE, size); + + CURLcode rc = curl_easy_perform(curl_handle); + + curl_slist_free_all(requestHeaders); + + if (rc) + { + throwException(ServiceInvocationException, curl_easy_strerror(rc)); + } + + // Get the output and location of the created resource + string responsePayload = ""; + if (responseChunk.memory) + { + responsePayload = string((const char*)responseChunk.memory, responseChunk.size); + } + + long httprc; + curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &httprc); + if (httprc != 200) + { + ostringstream msg; + msg << "Failed to update REST resource, HTTP code: " << httprc; + if (responsePayload != "") + { + msg << ", payload: " << responsePayload; + } + throwException(ServiceInvocationException, msg.str().c_str()); + } + } + else if (opName == "delete") + { + // HTTP DELETE + + // Build the request URL + bool firstParm = 0; + string uri; + if (operation.getNParms() !=0) + { + + // If the first parameter is a URI, then we'll use it, + // otherwise we'll use the binding URI + ostringstream s0; + writeParameter(xmlHelper, s0, operation.getParameter(0)); + string p0 = s0.str(); + if (p0.find("://") != string::npos) + { + firstParm = 1; + uri = p0; + } + else + { + uri = getBindingURI(); + } + } + else + { + uri = getBindingURI(); + } + // Add the parameters to the end of the URI + ostringstream os; + if (uri[uri.length()-1] == '?') + { + // If the URI ends with a "?" then we use the query + // form param=value& + os << uri; + for (unsigned int i = firstParm; i < operation.getNParms(); i++) + { + Operation::Parameter param = operation.getParameter(i); + + if(param.hasName()) + { + os << param.getName() << "="; + } + else + { + // No name - use "param1", etc + os << "param" << (i + 1) << "="; + } + writeParameter(xmlHelper, os, param); + if (i < operation.getNParms()-1) + os << "&"; + } + } + else + { + // Add the parameters in the form + // value1 / value2 / value3 + os << uri; + for (unsigned int i = firstParm; i < operation.getNParms(); i++) + { + os << "/"; + writeParameter(xmlHelper, os, operation.getParameter(i)); + } + } + + string url = os.str(); + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + + // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&responseChunk); + + // Send all headers to this function + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)&headerChunk); + + // Perform the HTTP DELETE + curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "DELETE"); + CURLcode rc = curl_easy_perform(curl_handle); + if (rc) + { + throwException(ServiceInvocationException, curl_easy_strerror(rc)); + } + + // Get the output data out of the returned document + string responsePayload = ""; + if (responseChunk.memory) + { + responsePayload = string((const char*)responseChunk.memory, responseChunk.size); + } + + long httprc; + curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &httprc); + if (httprc != 200) + { + ostringstream msg; + msg << "Failed to delete REST resource, HTTP code: " << httprc; + if (responsePayload != "") + { + msg << ", payload: " << responsePayload; + } + throwException(ServiceInvocationException, msg.str().c_str()); + } + } + else + { + string msg = "Unknown REST verb: " + opName; + throwException(ServiceInvocationException, msg.c_str()); + } + } + else + { + // Not a REST interface, XML / HTTP command style + curl_slist *requestHeaders = NULL; + struct curl_httppost *formpost = NULL; + ostringstream spayload; + string requestPayload; + string url; + + // If the request contains complex content then we'll use + // a POST, otherwise we use a GET with a query string + bool complexContent = false; + for (unsigned int i=0; i<operation.getNParms(); i++) + { + if (operation.getParameter(i).getType() == Operation::DATAOBJECT) + { + complexContent = true; + break; + } + } + + if (complexContent) + { + // Set the target URL + string uri = getBindingURI(); + ostringstream os; + os << uri << "/" << opName; + url = os.str(); + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + + // Disable the 100 continue handshake + requestHeaders = curl_slist_append(requestHeaders, "Expect:"); + + if (operation.getNParms() == 1) + { + // Single parameter, send it as the body of the POST + + // Create the input payload + writeParameter(xmlHelper, spayload, operation.getParameter(0)); + requestPayload = spayload.str(); + requestChunk.memory = requestPayload.c_str(); + requestChunk.size = requestPayload.size(); + + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, requestChunk.size); + + // Read all data using this function + curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_READDATA, (void *)&requestChunk); + + // Set the content type + requestHeaders = curl_slist_append(requestHeaders, "Content-Type: text/xml"); + + // This will be a POST + curl_easy_setopt(curl_handle, CURLOPT_POST, true); + } + else + { + + // Multiple parameters, use a form type POST + struct curl_httppost *lastptr = NULL; + for (unsigned int i=0; i<operation.getNParms(); i++) + { + ostringstream pname; + Operation::Parameter param = operation.getParameter(i); + + if(param.hasName()) + { + pname << param.getName(); + } + else + { + // No name - use "param1", etc + pname << "param" << (i+1); + } + + const char* ctype; + if (param.getType() == Operation::DATAOBJECT) + { + ctype ="text/xml"; + } + else + { + ctype = "text/plain"; + } + + ostringstream pvalue; + writeParameter(xmlHelper, pvalue, param); + + curl_formadd(&formpost, + &lastptr, + CURLFORM_CONTENTTYPE, ctype, + CURLFORM_COPYNAME, pname.str().c_str(), + CURLFORM_COPYCONTENTS, pvalue.str().c_str(), + CURLFORM_END); + } + + // Set the form into the request + curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost); + } + } + else + { + + // Build the request URL, uri / opName ? params + string uri = getBindingURI(); + ostringstream os; + os << uri << "/" << opName; + + // Add the parameters to the end of the URL in the form + // param=value& + for (unsigned int i=0; i<operation.getNParms(); i++) + { + if (i == 0) + os << "?"; + + Operation::Parameter param = operation.getParameter(i); + if(param.hasName()) + { + os << param.getName() << "="; + } + else + { + // No name - use "param1", etc + os << "param" << (i + 1) << "="; + } + writeParameter(xmlHelper, os, param); + if (i < operation.getNParms()-1) + os << "&"; + } + + url = os.str(); + loginfo("RESTServiceWrapper: HTTP GET %s", url.c_str()); + + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + } + + // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + + // Pass our 'chunk' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&responseChunk); + + // Configure the headers + if (requestHeaders) + { + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, requestHeaders); + } + + loginfo("RESTServiceWrapper: Performing HTTP request"); + // Perform the HTTP request + CURLcode rc = curl_easy_perform(curl_handle); + + loginfo("RESTServiceWrapper: Completed HTTP request"); + // Free any headers + if (requestHeaders) + { + curl_slist_free_all(requestHeaders); + } + + // Cleanup the form + if (complexContent) + { + curl_formfree(formpost); + } + + if (rc) + { + throwException(ServiceInvocationException, curl_easy_strerror(rc)); + } + + if (responseChunk.memory) + { + string responsePayload((const char*)responseChunk.memory, responseChunk.size); + + + loginfo("RESTServiceWrapper: responsePayload: %s", responsePayload.c_str()); + + //TODO Remove this workaround once SDO supports loading of open top level content + // The workaround is to wrap the open content in a wrapper element + string xmldecl; + string xml; + Utils::rTokeniseString("?>", responsePayload, xmldecl, xml); + string part = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + part += "<Part xmlns=\"http://tempuri.org\" xmlns:tns=\"http://tempuri.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"; + part += xml; + part += "\n</Part>"; + + setReturn(xmlHelper, part, operation); + } + } + + // Cleanup curl session + curl_easy_cleanup(curl_handle); + } + + + const string RESTServiceWrapper::getBindingURI() + { + string bindingURI = ""; + + // Get the binding URI configured on the top level component + Service* service = getService(); + CompositeReference* compositeReference = (CompositeReference*)service->getComponent(); + SCARuntime* runtime = SCARuntime::getCurrentRuntime(); + Component* component = runtime->getDefaultComponent(); + Reference* reference = component->findReference(compositeReference->getName()); + if (reference != NULL) + { + ReferenceBinding* binding = reference->getBinding(); + if (binding != NULL && binding->getURI() != "") + { + bindingURI = binding->getURI(); + } + } + if (bindingURI == "") + { + // Get the binding URI configured on the binding + RESTServiceBinding* binding = (RESTServiceBinding *)service->getBinding(); + bindingURI = binding->getURI(); + } + if (bindingURI != "") + { + + // Prepend the default base URI if the URI is not absolute + if (bindingURI.find("://") == string::npos) + { + bindingURI = runtime->getDefaultBaseURI() + string("/rest/") + bindingURI; + } + } + return bindingURI; + } + + + void RESTServiceWrapper::writeParameter(XMLHelperPtr xmlHelper, ostringstream& os, const Operation::Parameter& parm) + { + logentry(); + + switch(parm.getType()) + { + case Operation::BOOL: + { + os << *(bool*)parm.getValue(); + break; + } + case Operation::SHORT: + { + os << *(short*)parm.getValue(); + break; + } + case Operation::INT: + { + os << *(long*)parm.getValue(); + break; + } + case Operation::LONG: + { + os << *(long*)parm.getValue(); + break; + } + case Operation::USHORT: + { + os << *(short*)parm.getValue(); + break; + } + case Operation::UINT: + { + os << *(long*)parm.getValue(); + break; + } + case Operation::ULONG: + { + os << *(long*)parm.getValue(); + break; + } + case Operation::FLOAT: + { + os << *(float*)parm.getValue(); + break; + } + case Operation::DOUBLE: + { + os << *(long double*)parm.getValue(); + break; + } + case Operation::LONGDOUBLE: + { + os << *(long double*)parm.getValue(); + break; + } + case Operation::CHARS: + { + os << *(char**)parm.getValue(); + break; + } + case Operation::STRING: + { + os << (*(string*)parm.getValue()).c_str(); + break; + } + case Operation::DATAOBJECT: + { + DataObjectPtr dob = *(DataObjectPtr*)parm.getValue(); + XMLDocumentPtr doc = xmlHelper->createDocument(dob, NULL, NULL); + xmlHelper->save(doc, os); + break; + } + default: + { + break; + } + } + } + + void RESTServiceWrapper::setReturn(XMLHelperPtr xmlHelper, string& payload, + Operation& operation) + { + logentry(); + + //TODO Remove this workaround once SDO supports loading of open top level content + // The workaround is to wrap the open content in a wrapper element + string xmldecl; + string xml; + Utils::rTokeniseString("?>", payload, xmldecl, xml); + string body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + body += "<Wrapper xmlns=\"http://tempuri.org\" xmlns:tns=\"http://tempuri.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"; + body += xml; + body += "\n</Wrapper>"; + + // Convert the body to an SDO DataObject + DataObjectPtr outputWrapperDataObject = NULL; + XMLDocumentPtr theXMLDocument = xmlHelper->load(body.c_str(), NULL); + if (theXMLDocument != 0) + { + outputWrapperDataObject = theXMLDocument->getRootDataObject(); + } + if(!outputWrapperDataObject) + { + ostringstream msg; + msg << "Could not convert received document to SDO: " << body; + throwException(ServiceDataException, msg.str().c_str()); + } + + // Get the body part + DataObjectPtr outputDataObject = NULL; + PropertyList bpl = outputWrapperDataObject->getInstanceProperties(); + if (bpl.size()!=0) + { + if (bpl[0].isMany()) + { + DataObjectList& parts = outputWrapperDataObject->getList((unsigned int)0); + outputDataObject = parts[0]; + } + else + { + outputDataObject = outputWrapperDataObject->getDataObject(bpl[0]); + } + } + if (outputDataObject == NULL) + { + ostringstream msg; + msg << "Could not convert body part to SDO: " << body; + throwException(ServiceDataException, msg.str().c_str()); + } + + PropertyList pl = outputDataObject->getInstanceProperties(); + unsigned int i = 0; + + switch(pl[i].getTypeEnum()) + { + case Type::BooleanType: + { + bool* boolData = new bool; + *boolData = outputDataObject->getBoolean(pl[i]); + operation.setReturnValue(boolData); + } + break; + case Type::ByteType: + { + char* byteData = new char; + *byteData = outputDataObject->getByte(pl[i]); + operation.setReturnValue(byteData); + } + break; + case Type::BytesType: + { + int len = outputDataObject->getLength(pl[i]); + char* bytesData = new char[len+1]; + int bytesWritten = outputDataObject->getBytes(pl[i], bytesData, len); + // Ensure the bytes end with the null char. Not sure if this is neccessary + if(bytesWritten <= len) + { + bytesData[bytesWritten] = 0; + } + else + { + bytesData[len] = 0; + } + operation.setReturnValue(&bytesData); + } + break; + case Type::CharacterType: + { + // This code should work but won't be used as there is no mapping from an XSD type to the SDO CharacterType + wchar_t* charData = new wchar_t; + *charData = outputDataObject->getCharacter(pl[i]); + operation.setReturnValue(charData); + } + break; + case Type::DoubleType: + { + long double* doubleData = new long double; + *doubleData = outputDataObject->getDouble(pl[i]); + operation.setReturnValue(doubleData); + } + break; + case Type::FloatType: + { + float* floatData = new float; + *floatData = outputDataObject->getFloat(pl[i]); + operation.setReturnValue(floatData); + } + break; + case Type::IntType: + { + long* intData = new long; + *intData = outputDataObject->getInt(pl[i]); + operation.setReturnValue(intData); + } + break; + case Type::ShortType: + { + short* shortData = new short; + *shortData = outputDataObject->getShort(pl[i]); + operation.setReturnValue(shortData); + } + break; + case Type::StringType: + { + string* str = new string(outputDataObject->getCString(pl[i])); + operation.setReturnValue(str); + } + break; + case Type::DataObjectType: + { + if (!strcmp(pl[0].getType().getURI(), SDOUtils::sdoURI) && + !strcmp(pl[0].getType().getName(), "OpenDataObject")) { + + /* + * This code deals with xsd:any element parameters + * Get each element as a DataObject and add in to the parameter list + */ + DataObjectList& dataObjectList = outputDataObject->getList(pl[i]); + + for(unsigned int j=0; j<dataObjectList.size(); j++) + { + DataObjectPtr dob = dataObjectList[j]; + if(!dob) + { + DataObjectPtr* dataObjectData = new DataObjectPtr; + *dataObjectData = NULL; + operation.setReturnValue(dataObjectData); + loginfo("Null OpenDataObject return value"); + } + else + { + + SequencePtr sequence = dob->getSequence(); + if (sequence->size()!=0) + { + // Return a text element + if (sequence->isText(0)) + { + string* stringData = new string(sequence->getCStringValue(0)); + operation.setReturnValue(stringData); + } + else + { + // Return a DataObject representing a complex element + DataObjectPtr* dataObjectData = new DataObjectPtr; + *dataObjectData = sequence->getDataObjectValue(0); + if(!*dataObjectData) + { + loginfo("Null DataObject return value"); + } + else + { + (*dataObjectData)->detach(); + } + operation.setReturnValue(dataObjectData); + } + } + else + { + // Empty content, add an empty string + loginfo("Null OpenDataObject return value"); + string *stringData = new string(""); + operation.setReturnValue(stringData); + } + } + } + } + else { + DataObjectPtr* dataObjectData = new DataObjectPtr; + *dataObjectData = outputDataObject->getDataObject(pl[i]); + if(!*dataObjectData) + { + loginfo("Null SDO DataObject return value"); + } + else + { + (*dataObjectData)->detach(); + } + operation.setReturnValue(dataObjectData); + } + } + break; + default: + { + ostringstream msg; + msg << "Unsupported result type: " << pl[i].getTypeEnum(); + throwException(ServiceDataException, msg.str().c_str()); + } + } + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceWrapper.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceWrapper.h new file mode 100644 index 0000000000..42e136a5d4 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/RESTServiceWrapper.h @@ -0,0 +1,90 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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_sca_extension_rest_restservicewrapper_h +#define tuscany_sca_extension_rest_restservicewrapper_h + +#include <sstream> + +#include "commonj/sdo/SDO.h" + +#include "tuscany/sca/core/ServiceWrapper.h" +#include "tuscany/sca/core/Operation.h" +#include "tuscany/sca/model/Service.h" + + +namespace tuscany +{ + namespace sca + { + + namespace rest + { + + class RESTServiceWrapper : public ServiceWrapper + { + public: + + /** + * Constructor. + * @param target The service wrapper represents a Web service. + */ + RESTServiceWrapper(tuscany::sca::model::Service* service); + + /** + * Destructor + */ + virtual ~RESTServiceWrapper(); + + /** + * All business method calls on the target service are performed through + * this invoke method. + * @param operation The details of the method, paramaters and return value for the + * business method to be called on the target service. + */ + virtual void invoke(Operation& operation); + + private: + + /** + * Used to track initialization of the CURL library + */ + static bool initialized; + + /** + * Get the configured binding URI + */ + const std::string getBindingURI(); + + /** + * Write a parameter into a URL + */ + void writeParameter(commonj::sdo::XMLHelperPtr xmlHelper, std::ostringstream& os, const Operation::Parameter& parm); + + /** + * Set the return value on the given operation + */ + void setReturn(commonj::sdo::XMLHelperPtr xmlHelper, std::string& payload, Operation& operation); + + }; + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_rest_restservicewrapper_h diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/model/RESTServiceBinding.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/model/RESTServiceBinding.cpp new file mode 100644 index 0000000000..72701bfa65 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/model/RESTServiceBinding.cpp @@ -0,0 +1,59 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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$ */ + +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/rest/model/RESTServiceBinding.h" +#include "tuscany/sca/core/ServiceWrapper.h" +#include "tuscany/sca/rest/RESTServiceWrapper.h" + +using namespace std; +using namespace tuscany::sca::model; + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + // Constructor + RESTServiceBinding::RESTServiceBinding(Service* service, const string& uri) + : ServiceBinding(service, uri) + { + logentry(); + + serviceWrapper = new RESTServiceWrapper(service); + } + + // Destructor + RESTServiceBinding::~RESTServiceBinding() + { + logentry(); + } + + ServiceWrapper* RESTServiceBinding::getServiceWrapper() + { + logentry(); + + return serviceWrapper; + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/model/RESTServiceBinding.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/model/RESTServiceBinding.h new file mode 100644 index 0000000000..d19bcdacf5 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/reference/curl/src/tuscany/sca/rest/model/RESTServiceBinding.h @@ -0,0 +1,76 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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_sca_extension_rest_model_restservicebinding_h +#define tuscany_sca_extension_rest_model_restservicebinding_h + +#include <string> + +#include "tuscany/sca/model/ServiceBinding.h" +#include "tuscany/sca/model/Service.h" + +namespace tuscany +{ + namespace sca + { + namespace rest + { + /** + * Information about a REST binding for a service or a reference. + */ + class RESTServiceBinding : public tuscany::sca::model::ServiceBinding + { + public: + + /** + * Constructor. + * @param uri The uri of the binding. + */ + RESTServiceBinding(tuscany::sca::model::Service* service, const std::string& uri); + + /** + * Destructor. + */ + virtual ~RESTServiceBinding(); + + /** + * Returns the type of binding. + */ + virtual std::string getType() { return "http://www.osoa.org/xmlns/sca/1.0#RESTBinding"; }; + + /** + * Create a wrapper for the service configured by this + * binding. + */ + virtual ServiceWrapper* getServiceWrapper(); + + private: + + /** + * The wrapper for the service configured by this binding. + */ + ServiceWrapper* serviceWrapper; + + }; + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_extension_rest_model_restservicebinding_h diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/Makefile.am new file mode 100644 index 0000000000..2ecfda6c6c --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = httpd
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/Makefile.am new file mode 100644 index 0000000000..f963effea2 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/Makefile.am b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/Makefile.am new file mode 100644 index 0000000000..e5b3ce85bd --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/Makefile.am @@ -0,0 +1,42 @@ +libdir=$(prefix)/extensions/rest/service/lib +lib_LTLIBRARIES = \ +libtuscany_sca_rest_service.la \ +libtuscany_sca_mod_rest.la + +noinst_HEADERS = \ +tuscany/sca/rest/*.h \ +tuscany/sca/rest/model/*.h + +libtuscany_sca_rest_service_la_SOURCES = \ +tuscany/sca/rest/RESTReferenceBindingExtension.cpp \ +tuscany/sca/rest/model/RESTReferenceBinding.cpp \ +tuscany/sca/rest/RESTServiceProxy.cpp + +libtuscany_sca_rest_service_la_LIBADD = \ + -L${TUSCANY_SDOCPP}/lib -ltuscany_sdo \ + -L$(top_builddir)/runtime/core/src -ltuscany_sca \ + -L$(top_builddir)/runtime/extensions/rest/interface/src -ltuscany_sca_rest_interface + +rootdir=$(prefix)/extensions/rest/service + +libtuscany_sca_mod_rest_la_SOURCES = \ +tuscany/sca/rest/ModREST.cpp + +libtuscany_sca_mod_rest_la_LIBADD = \ + -L${TUSCANY_SDOCPP}/lib -ltuscany_sdo \ + -L$(top_builddir)/runtime/core/src -ltuscany_sca \ + -L$(top_builddir)/runtime/extensions/rest/service/httpd/src -ltuscany_sca_rest_service \ + -L$(top_builddir)/runtime/extensions/rest/interface/src -ltuscany_sca_rest_interface + +INCLUDES = -I$(top_builddir)/runtime/core/src \ + -I$(top_builddir)/runtime/extensions/rest/interface/src \ + -I${TUSCANY_SDOCPP}/include \ + -I${HTTPD_INCLUDE} -I${APR_INCLUDE} + +moduledir=$(prefix)/extensions/rest/service/module +extension = libtuscany_sca_rest_service$(libsuffix) + +install-exec-hook: + test -z $(moduledir) || $(mkdir_p) $(moduledir); + -rm -f $(moduledir)/$(extension) + $(LN_S) $(libdir)/$(extension) $(moduledir)/$(extension) diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp new file mode 100644 index 0000000000..4a63991515 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp @@ -0,0 +1,1372 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed 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. + */ + +#include <sstream> + +#include "apr_strings.h" +#include "apr_fnmatch.h" +#include "apr_lib.h" + +#define APR_WANT_STRFUNC +#include "apr_want.h" +#include "ap_config.h" +#include "httpd.h" + +// This section removes the windows/httpd build error "strtoul_is_not_a_portable_function_use_strtol_instead" +#if defined(WIN32) || defined (_WINDOWS) +#ifdef strtoul +#undef strtoul +#endif +#define strtoul strtoul +#endif + +#include "http_config.h" +#include "http_core.h" +#include "http_request.h" +#include "http_protocol.h" +#include "http_log.h" +#include "http_main.h" +#include "util_script.h" +#include "util_md5.h" + +#include "mod_core.h" + +#include "commonj/sdo/SDO.h" + +#include "tuscany/sca/core/Exceptions.h" +#include "tuscany/sca/util/Logging.h" +#include "RESTServiceProxy.h" +#include "model/RESTReferenceBinding.h" +#include "tuscany/sca/rest/model/RESTInterface.h" +#include "tuscany/sca/model/Composite.h" +#include "tuscany/sca/model/CompositeService.h" +#include "tuscany/sca/model/Component.h" +#include "tuscany/sca/model/Reference.h" +#include "tuscany/sca/model/ReferenceType.h" +#include "tuscany/sca/model/WSDLDefinition.h" +#include "tuscany/sca/model/WSDLOperation.h" +#include "tuscany/sca/model/WSDLMessagePart.h" +#include "tuscany/sca/model/WSDLInterface.h" +#include "tuscany/sca/model/Interface.h" +#include "tuscany/sca/core/SCARuntime.h" +#include "tuscany/sca/util/Utils.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca; +using namespace tuscany::sca::model; +using namespace tuscany::sca::util; + + +extern "C" +{ + extern module AP_MODULE_DECLARE_DATA sca_rest_module; +} + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + typedef struct rest_server_config_rec + { + char * home; + } rest_server_config_rec_t; + + typedef struct rest_dir_config_rec + { + char * root; + char * path; + char * base_uri; + char * component; + } rest_dir_config_rec_t; + + CompositeService* initializeSCARuntime(const char* home, const char* root, + const char* path, const char* baseURI, const char *component, const char* service); + + DataObjectPtr createPayload(DataFactoryPtr dataFactory, + Operation& operation, const WSDLOperation& wsdlOperation); + + void addPart(XMLHelperPtr xmlHelper, string& payload, Operation& operation); + + int logHeaders(void* request, const char* key, const char* value); + + /** + * Initialize the SCA runtime + */ + CompositeService* initializeSCARuntime(const char* home, const char* root, + const char* path, const char* baseURI, const char *component, const char* service) + { + logentry(); + loginfo("Home: %s", home); + loginfo("Root: %s", root); + loginfo("Path: %s", path); + loginfo("Base URI: %s", baseURI); + loginfo("Component: %s", component); + loginfo("Service: %s", service); + + try + { + SCARuntime* runtime = SCARuntime::initializeSharedRuntime(home, root, path, baseURI); + + string componentName; + if (strlen(component)) + { + componentName = component; + } + else + { + componentName = runtime->getDefaultComponentName(); + } + string serviceName = service; + + loginfo("Resolving composite: %s, service: %s", componentName.c_str(), serviceName.c_str()); + Component* compositeComponent = runtime->getSystem()->findComponent(componentName); + if (compositeComponent == NULL) + { + string msg = "Component not found " + componentName; + throwException(SystemConfigurationException, msg.c_str()); + } + runtime->setDefaultComponent(compositeComponent); + + Composite* composite = (Composite*)compositeComponent->getType(); + CompositeService* compositeService = (CompositeService*)composite->findComponent(serviceName); + if (compositeService == NULL) + { + string msg = "Composite service not found " + serviceName; + throwException(SystemConfigurationException, msg.c_str()); + } + + return compositeService; + } + catch(TuscanyRuntimeException &ex) + { + ostringstream msg; + msg << ex; + logerror("Failed to initialize SCA runtime: %s", msg.str().c_str()); + throw; + } + } + + bool printRequest = false; + + int logHeaders(void* request, const char* key, const char* value) + { + loginfo("Header key: %s, value: %s", key, value); + if (printRequest) + { + ap_rprintf((request_rec*)request, "<br>Header key: %s, value: %s", key, value); + } + return 1; + } + + int rest_handler(request_rec *request) + { + logentry(); + + if (strcmp(request->handler, "sca_rest_module")) + { + return DECLINED; + } + + try { + + // Set up the read policy + int rc = ap_setup_client_block(request, REQUEST_CHUNKED_DECHUNK); + if (rc != OK) + { + return rc; + } + ap_should_client_block(request); + if (request->read_chunked == true && request->remaining == 0) + { + request->chunked = true; + } + + apr_table_setn(request->headers_out, "Connection", "close"); + + if (printRequest) + { + // Set the content type + ap_set_content_type(request, "text/html"); + + // Send the response document + ap_rputs("<html><body><p>Tuscany Mod_rest works!", request); + } + + rest_server_config_rec_t* server_conf = (rest_server_config_rec_t*)ap_get_module_config(request->server->module_config, &sca_rest_module); + loginfo("Tuscany home: %s", server_conf->home); + if (printRequest) + { + ap_rprintf(request, "<p>Tuscany home: %s", server_conf->home); + } + + rest_dir_config_rec_t* dir_conf = (rest_dir_config_rec_t*)ap_get_module_config(request->per_dir_config, &sca_rest_module); + loginfo("Tuscany root: %s", dir_conf->root); + if (printRequest) + { + ap_rprintf(request, "<p>Tuscany root: %s", dir_conf->root); + } + loginfo("Tuscany path: %s", dir_conf->path); + if (printRequest) + { + ap_rprintf(request, "<p>Tuscany path: %s", dir_conf->path); + } + loginfo("SCA component: %s", dir_conf->component); + if (printRequest) + { + ap_rprintf(request, "<p>SCA component: %s", dir_conf->component); + } + + if (request->protocol) + { + loginfo("Protocol: %s", request->protocol); + if (printRequest) + { + ap_rprintf(request, "<p>Protocol: %s", request->protocol); + } + } + + if (request->method) + { + loginfo("HTTP method: %s", request->method); + if (printRequest) + { + ap_rprintf(request, "<p>HTTP method: %s", request->method); + } + } + + loginfo("HTTP method number: %d", request->method_number); + if (printRequest) + { + ap_rprintf(request, "<p>HTTP method number: %d", request->method_number); + } + + const char* content_type = apr_table_get(request->headers_in, "Content-Type"); + if (content_type) + { + loginfo("Content type: %s", content_type); + if (printRequest) + { + ap_rprintf(request, "<p>Content type: %s", content_type); + } + } + else + { + content_type = "text/plain"; + } + + if (request->content_encoding) + { + loginfo("Content encoding: %s", request->content_encoding); + if (printRequest) + { + ap_rprintf(request, "<p>Content encoding: %s", request->content_encoding); + } + } + + if (printRequest) + { + ap_rputs("<p>", request); + } + apr_table_do(logHeaders, request, request->headers_in, NULL); + + if (request->uri) + { + loginfo("URI: %s", request->uri); + if (printRequest) + { + ap_rprintf(request, "<p>URI: %s", request->uri); + } + } + + if (request->path_info) + { + loginfo("Path info: %s", request->path_info); + if (printRequest) + { + ap_rprintf(request, "<p>Path info: %s", request->path_info); + } + } + + if (request->args) + { + loginfo("Args: %s", request->args); + if (printRequest) + { + ap_rprintf(request, "<p>Args: %s", request->args); + } + } + + if (printRequest) + { + ap_rputs("</body></html>", request); + } + + // Extract the service and component names from the HTTP URI path + string path; + if (strlen(request->path_info) != 0 && *(request->path_info) == '/') + { + path = request->path_info + 1; + } + else + { + path = request->path_info; + } + string uri; + + string component; + string service; + if (strlen(dir_conf->component)) + { + // The path only specifies the service, the component name + // is configured in the directory/location configured + component = dir_conf->component; + Utils::tokeniseString("/", path, service, uri); + } + else + { + // The path must be in the form component / service + string path2; + Utils::tokeniseString("/", path, component, path2); + Utils::tokeniseString("/", path2, service, uri); + } + + loginfo("Component name: %s", component.c_str()); + loginfo("Service name: %s", service.c_str()); + + // Initialize the SCA runtime + CompositeService* compositeService = initializeSCARuntime( + server_conf->home, dir_conf->root, dir_conf->path, dir_conf->base_uri, component.c_str(), service.c_str()); + + if(!compositeService) + { + throwException(SystemConfigurationException, + "Failed to initialize SCA runtime, could not initialize CompositeService"); + } + + Composite* composite = compositeService->getComposite(); + DataFactoryPtr dataFactory = composite->getDataFactory(); + if (dataFactory == 0) + { + throwException(SystemConfigurationException, + "Failed to initialize SCA runtime, could not get DataFactory"); + } + XMLHelperPtr xmlHelper = composite->getXMLHelper(); + + // Get the REST binding + Reference* reference = compositeService->getReference(); + RESTReferenceBinding* binding = (RESTReferenceBinding*)reference->getBinding(); + + // Get the REST proxy + RESTServiceProxy* proxy = (RESTServiceProxy*)binding->getServiceProxy(); + + // Get the component interface + Interface* iface = reference->getType()->getInterface(); + + if (request->method_number == M_GET) + { + // Handle an HTTP GET + + // Determine the operation to invoke + WSDLOperation wsdlOperation; + string wsdlNamespace = ""; + string op_name = ""; + string uriArgs = ""; + if (iface != NULL) + { + // If we have a REST interface, the operation name is "retrieve" + if (iface->getInterfaceTypeQName() == RESTInterface::typeQName) + { + op_name = "retrieve"; + uriArgs = uri; + } + else if (iface->getInterfaceTypeQName() == WSDLInterface::typeQName) + { + // we have a WSDL interface, the operation name is part of the URI + Utils::tokeniseString("/", uri, op_name, uriArgs); + + // look for the WSDL operation definition + WSDLInterface* wsdlInterface = (WSDLInterface*)iface; + wsdlNamespace = wsdlInterface->getNamespaceURI(); + + if (wsdlNamespace != "") + { + WSDLDefinition* wsdl = composite->findWSDLDefinition(wsdlNamespace); + if (wsdl == 0) + { + string msg = "WSDL not found for: " + wsdlNamespace; + throwException(SystemConfigurationException, msg.c_str()); + } + try + { + wsdlOperation = wsdl->findOperation(wsdlInterface->getName(), op_name.c_str()); + } + catch(SystemConfigurationException&) + { + throw; + } + + if (!wsdlOperation.isDocumentStyle() || !wsdlOperation.isWrappedStyle()) + { + throwException(ServiceInvocationException, + "Only wrapped document style WSDL operations are currentlysupported"); + } + } + } + } + else + { + Utils::tokeniseString("/", uri, op_name, uriArgs); + } + + // Create a default document literal wrapped WSDL operation + if (wsdlNamespace == "") + { + WSDLMessagePart inPart(op_name, "", "http://tempuri.org"); + WSDLMessagePart outPart((op_name+"Response"), "", "http://tempuri.org"); + wsdlNamespace = compositeService->getName(); + wsdlOperation = WSDLOperation(); + wsdlOperation.setOperationName(op_name.c_str()); + wsdlOperation.setSoapAction(wsdlNamespace+ "#" +op_name); + wsdlOperation.setEndpoint(""); + wsdlOperation.setSoapVersion(WSDLOperation::SOAP11); + wsdlOperation.setDocumentStyle(true); + wsdlOperation.setWrappedStyle(true); + wsdlOperation.setInputEncoded(false); + wsdlOperation.setOutputEncoded(false); + wsdlOperation.setInputMessagePart(op_name, inPart); + wsdlOperation.setOutputMessagePart((op_name+"Response"), outPart); + } + + // Create the input DataObject + Operation operation(op_name.c_str()); + + // Parse the args part of the URI + if (uriArgs != "") + { + string args = uriArgs; + for (; args != ""; ) + { + string param; + string next; + Utils::tokeniseString("/", args, param, next); + if (param != "") + { + string* data = new string; + *data = param; + operation.addParameter(data); + } + args = next; + } + } + + // Parse the query string + if (request->args) + { + string query = request->args; + for (; query != ""; ) + { + string param; + string next; + Utils::tokeniseString("&", query, param, next); + if (param != "") + { + string n; + string* data = new string; + Utils::tokeniseString("=", param, n, *data); + operation.addParameter(data); + } + query = next; + } + } + DataObjectPtr inputDataObject = createPayload(dataFactory, operation, wsdlOperation); + + // Dispatch to the REST proxy + DataObjectPtr outputDataObject = proxy->invoke(wsdlOperation, inputDataObject); + + // Send the output DataObject + if (iface!=NULL && + iface->getInterfaceTypeQName() == RESTInterface::typeQName) + { + if (outputDataObject == NULL) + { + throwException(ServiceInvocationException, "Null output from REST create operation"); + } + else + { + + // Pure REST, send the response document + XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory); + DataObjectList& l = outputDataObject->getList("return"); + if (l.size() != 0) + { + DataObjectPtr resourceDataObject = l[0]; + XMLDocumentPtr doc = xm->createDocument( + resourceDataObject, + resourceDataObject->getType().getURI(), + resourceDataObject->getType().getName()); + char* str = xm->save(doc); + + // Calculate an Etag hash for the response + char* etag = ap_md5(request->pool, (const unsigned char*)str); + + // Handle a conditional GET, if the etag matches the etag + // sent by the client, we don't need to send the whole response + const char* match = apr_table_get(request->headers_in, "If-None-Match"); + if (match != NULL && !strcmp(etag, match)) + { + loginfo("REST resource matches ETag, sending HTTP 304 response code"); + request->status = HTTP_NOT_MODIFIED; + } + else + { + loginfo("Sending response: %s", str); + ap_set_content_type(request, "text/xml"); + apr_table_setn(request->headers_out, "ETag", etag); + + // Send an Etag header to allow caching and + // conditional gets + apr_table_setn(request->headers_out, "ETag", etag); + + ap_rputs(str, request); + } + } + else + { + loginfo("REST resource not found, sending HTTP 404 response code"); + request->status = HTTP_NOT_FOUND; + + return OK; + } + } + } + else + { + // Command style, send the response wrapper element + + if (outputDataObject == NULL) + { + loginfo("Sending empty response"); + //request->status = HTTP_NO_CONTENT; + } + else + { + XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory); + DataObjectList& l = outputDataObject->getList("return"); + if (l.size() != 0) + { + DataObjectPtr resultDataObject = l[0]; + XMLDocumentPtr doc = xm->createDocument( + resultDataObject, + resultDataObject->getType().getURI(), + resultDataObject->getType().getName()); + char* str = xm->save(doc); + + loginfo("Sending response: %s", str); + ap_set_content_type(request, "text/xml"); + ap_rputs(str, request); + } + else + { + loginfo("Sending empty response"); + //request->status = HTTP_NO_CONTENT; + } + } + } + + return OK; + } + else if (request->method_number == M_POST) + { + // Handle an HTTP POST + + // Determine the operation to invoke + WSDLOperation wsdlOperation; + string wsdlNamespace = ""; + string op_name = ""; + string uriArgs = ""; + if (iface != NULL) + { + // If we have a REST interface, the operation name is "create" + if (iface->getInterfaceTypeQName() == RESTInterface::typeQName) + { + op_name = "create"; + } + else if (iface->getInterfaceTypeQName() == WSDLInterface::typeQName) + { + // we have a WSDL interface, the operation name is part of the URI + Utils::tokeniseString("/", uri, op_name, uriArgs); + + // look for the WSDL operation definition + WSDLInterface* wsdlInterface = (WSDLInterface*)iface; + wsdlNamespace = wsdlInterface->getNamespaceURI(); + + if (wsdlNamespace != "") + { + WSDLDefinition* wsdl = composite->findWSDLDefinition(wsdlNamespace); + if (wsdl == 0) + { + string msg = "WSDL not found for: " + wsdlNamespace; + throwException(SystemConfigurationException, msg.c_str()); + } + try + { + wsdlOperation = wsdl->findOperation(wsdlInterface->getName(), op_name.c_str()); + } + catch(SystemConfigurationException&) + { + throw; + } + + if (!wsdlOperation.isDocumentStyle() || !wsdlOperation.isWrappedStyle()) + { + throwException(ServiceInvocationException, + "Only wrapped document style WSDL operations are currentlysupported"); + } + } + } + } + else + { + Utils::tokeniseString("/", uri, op_name, uriArgs); + } + + // Create a default document literal wrapped WSDL operation + if (wsdlNamespace == "") + { + WSDLMessagePart inPart(op_name, "", "http://tempuri.org"); + WSDLMessagePart outPart((op_name+"Response"), "", "http://tempuri.org"); + wsdlNamespace = compositeService->getName(); + wsdlOperation = WSDLOperation(); + wsdlOperation.setOperationName(op_name.c_str()); + wsdlOperation.setSoapAction(wsdlNamespace+ "#" +op_name); + wsdlOperation.setEndpoint(""); + wsdlOperation.setSoapVersion(WSDLOperation::SOAP11); + wsdlOperation.setDocumentStyle(true); + wsdlOperation.setWrappedStyle(true); + wsdlOperation.setInputEncoded(false); + wsdlOperation.setOutputEncoded(false); + wsdlOperation.setInputMessagePart(op_name, inPart); + wsdlOperation.setOutputMessagePart((op_name+"Response"), outPart); + } + + // Create the input DataObject + Operation operation(op_name.c_str()); + + // Parse the args part of the URI + if (uriArgs != "") + { + string args = uriArgs; + for (; args != ""; ) + { + string param; + string next; + Utils::tokeniseString("/", args, param, next); + if (param != "") + { + string* data = new string; + *data = param; + operation.addParameter(data); + } + args = next; + } + } + + // Parse the query string + if (request->args) + { + string query = request->args; + for (; query != ""; ) + { + string param; + string next; + Utils::tokeniseString("&", query, param, next); + if (param != "") + { + string n; + string* data = new string; + Utils::tokeniseString("=", param, n, *data); + operation.addParameter(data); + } + query = next; + } + } + + // Read the POST input + ostringstream sinput; + char buffer[2049]; + for ( ; ; ) + { + int size = ap_get_client_block(request, buffer, 2048); + if (size > 0) + { + buffer[size] = '\0'; + sinput << buffer; + } + else if (size == 0) + { + break; + } + else if (size < 0) + { + throwException(ServiceInvocationException, "Error reading POST input"); + } + } + string input = sinput.str(); + + string contentType = content_type; + if (contentType.find("multipart/form-data") == 0) + { + // This is a multipart POST, extract each part from the + // POST body + string begin; + string boundary; + Utils::tokeniseString("boundary=", contentType, begin, boundary); + + for (;;) + { + // Read each part + string part; + string next; + Utils::tokeniseString(boundary, input, part, next); + input = next; + + // Skip first and last empty parts + if (part.length() == 0 || part == "--") + continue; + + // Read headers + bool xml = false; + int empty = -1; + for (;;) + { + string header; + Utils::tokeniseString("\r\n", part, header, next); + part = next; + if (header == "") + { + // Two empty lines signal the beginning of the content + empty++; + if (empty == 1) + break; + } + else + { + empty = 0; + + // Detect XML content + if (header == "Content-Type: text/xml") + xml = true; + } + } + + // Read the part content + if (part.length()) + { + // Strip the trailer + string value; + Utils::tokeniseString("\r\n--", part, value, next); + + if (xml) + { + // Add an XML parameter to the operation + addPart(xmlHelper, value, operation); + } + else + { + // Add a text parameter to the operation + string* stringData = new string; + *stringData = value; + operation.addParameter(stringData); + } + } + + // Read till the end of the POST body + if (input.length() == 0) + break; + } + } + else + { + // The POST body represents a single part + addPart(xmlHelper, input, operation); + } + + DataObjectPtr inputDataObject = createPayload(dataFactory, operation, wsdlOperation); + + // Dispatch to the REST proxy + DataObjectPtr outputDataObject = proxy->invoke(wsdlOperation, inputDataObject); + + // Send the response back to the client + if (iface!=NULL && + iface->getInterfaceTypeQName() == RESTInterface::typeQName) + { + // Pure REST, send the location of the created resource + + if (outputDataObject == NULL) + { + throwException(ServiceInvocationException, "Null output from REST create operation"); + } + + string location = ""; + + DataObjectList& l = outputDataObject->getList("return"); + if (l.size()) + { + location = l.getCString(0); + } + + if (location == "") + { + loginfo("No resource location, sending HTTP 400 response code"); + request->status = HTTP_BAD_REQUEST; + + return OK; + } + + string locuri = request->uri; + locuri += '/'; + locuri += location; + + const char* loc = ap_construct_url(request->pool, locuri.c_str(), request); + loginfo("Sending resource location: %s", loc); + apr_table_setn(request->headers_out, "Location", loc); + apr_table_setn(request->headers_out, "Content-Location", loc); + request->status = HTTP_CREATED; + + // Send the created resource entity back to the client + ap_set_content_type(request, "text/xml"); + ap_rputs(input.c_str(), request); + + } + else + { + // Command style, send the response element + + if (outputDataObject == NULL) + { + loginfo("Sending empty response"); + //request->status = HTTP_NO_CONTENT; + } + else + { + XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory); + DataObjectList& l = outputDataObject->getList("return"); + if (l.size() != 0) + { + DataObjectPtr resultDataObject = l[0]; + XMLDocumentPtr doc = xm->createDocument( + resultDataObject, + resultDataObject->getType().getURI(), + resultDataObject->getType().getName()); + char* str = xm->save(doc); + + loginfo("Sending response: %s", str); + ap_set_content_type(request, "text/xml"); + ap_rputs(str, request); + } + else + { + loginfo("Sending empty response"); + //request->status = HTTP_NO_CONTENT; + } + } + } + + return OK; + } + else if (request->method_number == M_PUT) + { + + // Handle an HTTP PUT + + // Determine the operation to invoke + WSDLOperation wsdlOperation; + string wsdlNamespace = ""; + string op_name = "update"; + string uriArgs = uri; + + // Create a default document literal wrapped WSDL operation + WSDLMessagePart inputPart(op_name, "", "http://tempuri.org"); + WSDLMessagePart outputPart((op_name+"Response"), "", "http://tempuri.org"); + wsdlNamespace = compositeService->getName(); + wsdlOperation = WSDLOperation(); + wsdlOperation.setOperationName(op_name.c_str()); + wsdlOperation.setSoapAction(wsdlNamespace+ "#" +op_name); + wsdlOperation.setEndpoint(""); + wsdlOperation.setSoapVersion(WSDLOperation::SOAP11); + wsdlOperation.setDocumentStyle(true); + wsdlOperation.setWrappedStyle(true); + wsdlOperation.setInputEncoded(false); + wsdlOperation.setOutputEncoded(false); + wsdlOperation.setInputMessagePart(op_name, inputPart); + wsdlOperation.setOutputMessagePart((op_name+"Response"), outputPart); + + // Create the input DataObject + Operation operation(op_name.c_str()); + + // Parse the args part of the URI + if (uriArgs != "") + { + string args = uriArgs; + for (; args != ""; ) + { + string param; + string next; + Utils::tokeniseString("/", args, param, next); + if (param != "") + { + string* data = new string; + *data = param; + operation.addParameter(data); + } + args = next; + } + } + + // Parse the query string + if (request->args) + { + string query = request->args; + for (; query != ""; ) + { + string param; + string next; + Utils::tokeniseString("&", query, param, next); + if (param != "") + { + string n; + string* data = new string; + Utils::tokeniseString("=", param, n, *data); + operation.addParameter(data); + } + query = next; + } + } + + // Read the PUT input + ostringstream sinput; + char buffer[2049]; + for ( ; ; ) + { + int size = ap_get_client_block(request, buffer, 2048); + if (size > 0) + { + buffer[size] = '\0'; + sinput << buffer; + } + else if (size == 0) + { + break; + } + else if (size < 0) + { + throwException(ServiceInvocationException, "Error reading PUT input"); + } + } + string input = sinput.str(); + addPart(xmlHelper, input, operation); + + DataObjectPtr inputDataObject = createPayload(dataFactory, operation, wsdlOperation); + + // Dispatch to the REST proxy + DataObjectPtr outputDataObject = proxy->invoke(wsdlOperation, inputDataObject); + + // Empty response + //request->status = HTTP_NO_CONTENT; + return OK; + } + else if (request->method_number == M_DELETE) + { + + // Determine the operation to invoke + WSDLOperation wsdlOperation; + string wsdlNamespace = ""; + string op_name = "delete"; + string uriArgs = uri; + + // Create a default document literal wrapped WSDL operation + WSDLMessagePart inPart(op_name, "", "http://tempuri.org"); + WSDLMessagePart outPart((op_name+"Response"), "", "http://tempuri.org"); + wsdlNamespace = compositeService->getName(); + wsdlOperation = WSDLOperation(); + wsdlOperation.setOperationName(op_name.c_str()); + wsdlOperation.setSoapAction(wsdlNamespace+ "#" +op_name); + wsdlOperation.setEndpoint(""); + wsdlOperation.setSoapVersion(WSDLOperation::SOAP11); + wsdlOperation.setDocumentStyle(true); + wsdlOperation.setWrappedStyle(true); + wsdlOperation.setInputEncoded(false); + wsdlOperation.setOutputEncoded(false); + wsdlOperation.setInputMessagePart(op_name, inPart); + wsdlOperation.setOutputMessagePart((op_name+"Response"), outPart); + + // Create the input DataObject + Operation operation(op_name.c_str()); + + // Parse the args part of the URI + if (uriArgs != "") + { + string args = uriArgs; + for (; args != ""; ) + { + string param; + string next; + Utils::tokeniseString("/", args, param, next); + if (param != "") + { + string* data = new string; + *data = param; + operation.addParameter(data); + } + args = next; + } + } + + // Parse the query string + if (request->args) + { + string query = request->args; + for (; query != ""; ) + { + string param; + string next; + Utils::tokeniseString("&", query, param, next); + if (param != "") + { + string n; + string* data = new string; + Utils::tokeniseString("=", param, n, *data); + operation.addParameter(data); + } + query = next; + } + } + + DataObjectPtr inputDataObject = createPayload(dataFactory, operation, wsdlOperation); + + // Dispatch to the REST proxy + DataObjectPtr outputDataObject = proxy->invoke(wsdlOperation, inputDataObject); + + // Empty response + //request->status = HTTP_NO_CONTENT; + return OK; + } + else + { + if (request->method) + { + logerror("Unsupported HTTP method: %s", request->method); + } + else + { + logerror("Unsupported HTTP method: %d", request->method_number); + } + return HTTP_NOT_IMPLEMENTED; + } + } + catch(TuscanyRuntimeException& ex) + { + ostringstream msg; + msg << ex; + logerror("Failed to process REST request: %s", msg.str().c_str()); + return HTTP_INTERNAL_SERVER_ERROR; + } + } + + DataObjectPtr createPayload(DataFactoryPtr dataFactory, Operation& operation, const WSDLOperation& wsdlOperation) + { + logentry(); + + DataObjectPtr inputDataObject; + string inputTypeUri; + string inputTypeName; + try + { + // Since its Document wrapped, there will only be one part + std::list<std::string> partList = wsdlOperation.getInputMessagePartNames(); + const WSDLMessagePart &inputMessage = + wsdlOperation.getInputMessagePart(partList.front()); + inputTypeName = inputMessage.getPartType(); + inputTypeUri = inputMessage.getPartUri(); + + // Create the input wrapper + const Type& rootType = dataFactory->getType(inputTypeUri.c_str(), "RootType"); + const Property& prop = rootType.getProperty(inputTypeName.c_str()); + const Type& inputType = prop.getType(); + inputDataObject = dataFactory->create(inputType); + } + catch (SDORuntimeException&) + { + try + { + // Create the input wrapper + const Type& inputType = + dataFactory->getType(inputTypeUri.c_str(), inputTypeName.c_str()); + inputDataObject = dataFactory->create(inputType); + } + catch (SDORuntimeException&) + { + + // The input wrapper type is not known, create an open DataObject + inputDataObject = dataFactory->create("http://tempuri.org", "Wrapper"); + } + } + + // Go through data object to set the input parameters + PropertyList pl = inputDataObject->getType().getProperties(); + + if(pl.size() == 0) + { + if(inputDataObject->getType().isOpenType() && inputDataObject->getType().isDataObjectType()) + { + /* + * This code deals with sending xsd:any elements + */ + for (int i=0; i<operation.getNParms(); i++) + { + ostringstream pname; + pname << "param" << (i+1); + DataObjectList& l = inputDataObject->getList(pname.str()); + + const Operation::Parameter& parm = operation.getParameter(i); + switch(parm.getType()) + { + case Operation::STRING: + { + l.append((*(string*)parm.getValue()).c_str()); + break; + } + case Operation::DATAOBJECT: + { + l.append(*(DataObjectPtr*)parm.getValue()); + break; + } + default: + { + break; + } + } + } + } + } + else { + + // Each parameter in the operation should be a property on the request dataobject + for (unsigned int i=0; i<operation.getNParms(); i++) + { + const Operation::Parameter& parm = operation.getParameter(i); + switch(parm.getType()) + { + case Operation::STRING: + { + inputDataObject->setCString(i, (*(string*)parm.getValue()).c_str()); + break; + } + case Operation::DATAOBJECT: + { + inputDataObject->setDataObject(i, *(DataObjectPtr*)parm.getValue()); + break; + } + default: + { + break; + } + } + } + } + + return inputDataObject; + } + + void addPart(XMLHelperPtr xmlHelper, string& payload, Operation& operation) + { + logentry(); + + + //TODO Remove this workaround once SDO supports loading of open top level content + // The workaround is to wrap the open content in a wrapper element + string xmldecl; + string xml; + Utils::rTokeniseString("?>", payload, xmldecl, xml); + string body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + body += "<Wrapper xmlns=\"http://tempuri.org\" xmlns:tns=\"http://tempuri.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"; + body += xml; + body += "\n</Wrapper>"; + + // Convert the body to an SDO DataObject + DataObjectPtr inputWrapperDataObject = NULL; + XMLDocumentPtr theXMLDocument = xmlHelper->load(body.c_str(), NULL); + if (theXMLDocument != 0) + { + inputWrapperDataObject = theXMLDocument->getRootDataObject(); + } + if(!inputWrapperDataObject) + { + ostringstream msg; + msg << "Could not convert received document to SDO: " << body; + throwException(ServiceDataException, msg.str().c_str()); + } + + // Get the body part + DataObjectPtr inputDataObject = NULL; + PropertyList bpl = inputWrapperDataObject->getInstanceProperties(); + if (bpl.size()!=0) + { + if (bpl[0].isMany()) + { + DataObjectList& parts = inputWrapperDataObject->getList((unsigned int)0); + inputDataObject = parts[0]; + } + else + { + inputDataObject = inputWrapperDataObject->getDataObject(bpl[0]); + } + } + if (inputDataObject == NULL) + { + ostringstream msg; + msg << "Could not convert received document to SDO: " << body; + throwException(ServiceDataException, msg.str().c_str()); + } + + DataObjectPtr* dataObjectData = new DataObjectPtr; + *dataObjectData = inputDataObject; + (*dataObjectData)->detach(); + operation.addParameter(dataObjectData); + } + + const char *rest_set_home(cmd_parms *cmd, void *dummy, + const char *arg) + { + rest_server_config_rec_t *conf = (rest_server_config_rec_t*)ap_get_module_config( + cmd->server->module_config, &sca_rest_module); + conf->home = apr_pstrdup(cmd->pool, arg); + return NULL; + } + + const char *rest_set_path(cmd_parms *cmd, void *c, + const char *arg) + { + rest_dir_config_rec_t *conf = (rest_dir_config_rec_t*)c; + conf->path = apr_pstrdup(cmd->pool, arg); + return NULL; + } + + const char *rest_set_root(cmd_parms *cmd, void *c, + const char *arg) + { + rest_dir_config_rec_t *conf = (rest_dir_config_rec_t*)c; + conf->root = apr_pstrdup(cmd->pool, arg); + return NULL; + } + + const char *rest_set_base_uri(cmd_parms *cmd, void *c, + const char *arg) + { + rest_dir_config_rec_t *conf = (rest_dir_config_rec_t*)c; + conf->base_uri = apr_pstrdup(cmd->pool, arg); + return NULL; + } + + const char *rest_set_component(cmd_parms *cmd, void *c, + const char *arg) + { + rest_dir_config_rec_t *conf = (rest_dir_config_rec_t*)c; + conf->component = apr_pstrdup(cmd->pool, arg); + return NULL; + } + + const command_rec rest_module_cmds[] = + { + AP_INIT_TAKE1("TuscanyHome", (const char*(*)())tuscany::sca::rest::rest_set_home, NULL, RSRC_CONF, + "Tuscany home directory"), + AP_INIT_TAKE1("TuscanyPath", (const char*(*)())tuscany::sca::rest::rest_set_path, NULL, ACCESS_CONF, + "Tuscany SCA composite search path"), + AP_INIT_TAKE1("TuscanyRoot", (const char*(*)())tuscany::sca::rest::rest_set_root, NULL, ACCESS_CONF, + "Tuscany root SCA configuration path"), + AP_INIT_TAKE1("TuscanyBaseURI", (const char*(*)())tuscany::sca::rest::rest_set_base_uri, NULL, ACCESS_CONF, + "Tuscany SCA system base URI"), + AP_INIT_TAKE1("TuscanyComponent", (const char*(*)())tuscany::sca::rest::rest_set_component, NULL, ACCESS_CONF, + "SCA component name"), + {NULL} + }; + + int rest_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, + server_rec *s) + { + return OK; + } + + void rest_child_init(apr_pool_t* p, server_rec* svr_rec) + { + rest_server_config_rec_t *conf = (rest_server_config_rec_t*)ap_get_module_config( + svr_rec->module_config, &sca_rest_module); + + if(false) + { + fprintf(stderr, "[Tuscany] Due to one or more errors mod_rest loading" + " failed. Causing apache2 to stop loading\n"); + exit(APEXIT_CHILDFATAL); + } + } + + void register_hooks(apr_pool_t *p) + { + ap_hook_handler(rest_handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(rest_init, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(rest_child_init, NULL, NULL, APR_HOOK_MIDDLE); + } + + void *rest_create_dir_config(apr_pool_t *p, char *dirspec) + { + rest_dir_config_rec_t* conf = (rest_dir_config_rec_t* )apr_palloc(p, sizeof(*conf)); + conf->path = ""; + conf->root = ""; + conf->base_uri = ""; + conf->component = ""; + return conf; + } + + void* rest_create_server_config(apr_pool_t *p, server_rec *s) + { + rest_server_config_rec_t* conf = (rest_server_config_rec_t* )apr_palloc(p, sizeof(*conf)); + conf->home = ""; + return conf; + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +extern "C" +{ + + module AP_MODULE_DECLARE_DATA sca_rest_module = + { + STANDARD20_MODULE_STUFF, + tuscany::sca::rest::rest_create_dir_config, /* dir config */ + NULL, /* dir merger --- default is to override */ + tuscany::sca::rest::rest_create_server_config, /* server config */ + NULL, /* merge server config */ + tuscany::sca::rest::rest_module_cmds, /* command table */ + tuscany::sca::rest::register_hooks /* register_hooks */ + }; + +} diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTReferenceBindingExtension.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTReferenceBindingExtension.cpp new file mode 100644 index 0000000000..18720f42f5 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTReferenceBindingExtension.cpp @@ -0,0 +1,86 @@ +/* +* 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. +*/ + +#include "RESTReferenceBindingExtension.h" +#include "model/RESTReferenceBinding.h" +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/util/Utils.h" +#include "tuscany/sca/core/SCARuntime.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca::model; + +extern "C" +{ +#if defined(WIN32) || defined(_WINDOWS) + __declspec(dllexport) +#endif + void tuscany_sca_rest_service_initialize() + { + tuscany::sca::rest::RESTReferenceBindingExtension::initialize(); + } +} + +namespace tuscany +{ + namespace sca + { + namespace rest + { + // =================================================================== + // Constructor for the RESTReferenceBinding class. + // =================================================================== + RESTReferenceBindingExtension::RESTReferenceBindingExtension() + { + logentry(); + } + + // =================================================================== + // Destructor for the RESTReferenceBindingExtension class. + // =================================================================== + RESTReferenceBindingExtension::~RESTReferenceBindingExtension() + { + logentry(); + } + + const string RESTReferenceBindingExtension::extensionName("rest"); + const string RESTReferenceBindingExtension::typeQName("http://www.osoa.org/xmlns/sca/1.0#RESTBinding"); + + // =================================================================== + // loadModelElement - load the info from binding.rest + // =================================================================== + ReferenceBinding* RESTReferenceBindingExtension::getReferenceBinding(Composite *composite, Reference* reference, DataObjectPtr scdlBinding) + { + string uri = scdlBinding->getCString("uri"); + + RESTReferenceBinding* referenceBinding = new RESTReferenceBinding(reference, uri); + + return referenceBinding; + } + + void RESTReferenceBindingExtension::initialize() + { + logentry(); + SCARuntime::getCurrentRuntime()->registerReferenceBindingExtension(new RESTReferenceBindingExtension()); + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTReferenceBindingExtension.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTReferenceBindingExtension.h new file mode 100644 index 0000000000..0d9e41841b --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTReferenceBindingExtension.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef tuscany_sca_extension_rest_restreferencebindingextension_h +#define tuscany_sca_extension_rest_restreferencebindingextension_h + +#include "tuscany/sca/extension/ReferenceBindingExtension.h" + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + class RESTReferenceBindingExtension : public ReferenceBindingExtension + { + public: + /** + * Default constructor + */ + RESTReferenceBindingExtension(); + + /** + * Destructor + */ + virtual ~RESTReferenceBindingExtension(); + + /** + * return the name of the extension + */ + virtual const std::string& getExtensionName() {return extensionName;} + + /** + * return the QName of schema elemant for this implementation extension + * (e.g. "http://www.osoa.org/xmlns/sca/1.0#binding.rest") + */ + virtual const std::string& getExtensionTypeQName() {return typeQName;} + + virtual tuscany::sca::model::ReferenceBinding* getReferenceBinding( + tuscany::sca::model::Composite* composite, + tuscany::sca::model::Reference *reference, + commonj::sdo::DataObjectPtr scdlBinding); + + static void initialize(); + + private: + static const std::string extensionName; + static const std::string typeQName; + + }; + + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_extension_rest_restreferencebindingextension_h + diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp new file mode 100644 index 0000000000..95affe6202 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp @@ -0,0 +1,567 @@ +/* + * 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$ */ + +#include <sstream> + +#include "commonj/sdo/SDO.h" + +#include "RESTServiceProxy.h" +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/core/Exceptions.h" +#include "tuscany/sca/util/Utils.h" +#include "tuscany/sca/util/SDOUtils.h" +#include "tuscany/sca/core/SCARuntime.h" +#include "tuscany/sca/model/Reference.h" +#include "tuscany/sca/model/ReferenceType.h" +#include "tuscany/sca/model/Service.h" +#include "tuscany/sca/model/ServiceType.h" +#include "tuscany/sca/model/Component.h" +#include "tuscany/sca/model/ComponentType.h" +#include "tuscany/sca/core/ServiceWrapper.h" +#include "tuscany/sca/model/Composite.h" +#include "tuscany/sca/model/ServiceBinding.h" +#include "tuscany/sca/model/WSDLDefinition.h" +#include "tuscany/sca/model/WSDLInterface.h" +#include "tuscany/sca/model/WSDLOperation.h" +#include "tuscany/sca/model/WSDLMessagePart.h" +#include "model/RESTReferenceBinding.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca::model; +using namespace tuscany::sca::util; + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + // ============================ + // Constructor: Create a proxy + // ============================ + RESTServiceProxy::RESTServiceProxy(Reference* reference) + : ServiceProxy(reference) + { + logentry(); + + // Get the target service wrapper + RESTReferenceBinding* referenceBinding = (RESTReferenceBinding*)reference->getBinding(); + serviceWrapper = referenceBinding->getTargetServiceBinding()->getServiceWrapper(); + + DataFactoryPtr dataFactory = reference->getComponent()->getComposite()->getDataFactory(); + try { + const Type& tempType = dataFactory->getType("http://tempuri.org", "RootType"); + } catch (SDORuntimeException&) + { + dataFactory->addType("http://tempuri.org", "RootType", false, false, false); + dataFactory->addType("http://tempuri.org", "Wrapper", false, true, false); + dataFactory->addPropertyToType( + "http://tempuri.org", "RootType", + "Wrapper", + "http://tempuri.org", "Wrapper", + false, false, true); + dataFactory->addType("http://tempuri.org", "Part", false, true, false); + dataFactory->addPropertyToType( + "http://tempuri.org", "RootType", + "Part", + "http://tempuri.org", "Part", + false, false, true); + } + } + + // ========== + // Destructor + // ========== + RESTServiceProxy::~RESTServiceProxy() + { + logentry(); + } + + /// + /// This method will be called to process an operation invocation. + /// + DataObjectPtr RESTServiceProxy::invoke(const WSDLOperation& wsdlOperation, DataObjectPtr inputDataObject) + { + logentry(); + + Reference* reference = getReference(); + Component* component = reference->getComponent(); + Composite* composite = component ->getComposite(); + + RESTReferenceBinding* referenceBinding = (RESTReferenceBinding*)reference->getBinding(); + DataFactoryPtr dataFactoryPtr = reference->getComponent()->getComposite()->getDataFactory(); + + // Since its Document wrapped, there will only be one message part + std::list<std::string> partList = wsdlOperation.getOutputMessagePartNames(); + const WSDLMessagePart &part = wsdlOperation.getOutputMessagePart(partList.front()); + const char* outputTypeURI = part.getPartUri().c_str(); + const char* outputTypeName = part.getPartName().c_str(); + + loginfo("WSDLOperation input message Type: %s#%s", + wsdlOperation.getInputMessageUri().c_str(), + wsdlOperation.getInputMessageName().c_str()); + loginfo("WSDLOperation output part Type: %s#%s", + outputTypeURI, + outputTypeName); + + // Create new Operation object and set parameters and return value + Operation operation(wsdlOperation.getOperationName().c_str()); + + try + { + + // Go through the input data object to set the operation parameters + PropertyList pl = inputDataObject->getInstanceProperties(); + + for(int i=0; i<pl.size(); i++) + { + const char* name = pl[i].getName(); + + switch (pl[i].getTypeEnum()) + { + case Type::BooleanType: + { + bool* boolData = new bool; + *boolData = inputDataObject->getBoolean(pl[i]); + operation.addParameter(boolData); + } + break; + case Type::ByteType: + { + char* byteData = new char; + *byteData = inputDataObject->getByte(pl[i]); + operation.addParameter(byteData); + } + break; + case Type::BytesType: + { + int len = inputDataObject->getLength(pl[i]); + char** bytesData = new char*; + *bytesData = new char[len+1]; + int bytesWritten = inputDataObject->getBytes(pl[i], *bytesData, len); + // Ensure the bytes end with the null char. Not sure if this is neccessary + if(bytesWritten <= len) + { + (*bytesData)[bytesWritten] = 0; + } + else + { + (*bytesData)[len] = 0; + } + operation.addParameter(bytesData); + } + break; + case Type::CharacterType: + { + // This code should work but won't be used as there is no mapping from an XSD type to the SDO CharacterType + wchar_t* charData = new wchar_t; + *charData = inputDataObject->getCharacter(pl[i]); + operation.addParameter(charData); + } + break; + case Type::DoubleType: + { + long double* doubleData = new long double; + *doubleData = inputDataObject->getDouble(pl[i]); + operation.addParameter(doubleData); + } + break; + case Type::FloatType: + { + float* floatData = new float; + *floatData = inputDataObject->getFloat(pl[i]); + operation.addParameter(floatData); + } + break; + case Type::IntType: + { + long* intData = new long; + *intData = inputDataObject->getInt(pl[i]); + operation.addParameter(intData); + } + break; + case Type::ShortType: + { + short* shortData = new short; + *shortData = inputDataObject->getShort(pl[i]); + operation.addParameter(shortData); + } + break; + case Type::StringType: + { + string* stringData; + if (pl[i].isMany()) + { + DataObjectList& l = inputDataObject->getList(pl[i]); + stringData = new string(l.getCString(0)); + } + else + { + if(inputDataObject->isSet(pl[i])) + { + stringData = new string(inputDataObject->getCString(pl[i])); + } + else + { + // The data is not set, so pass an empty string as the parameter + stringData = new string(); + } + } + operation.addParameter(stringData); + } + break; + case Type::DataObjectType: + { + if (!strcmp(pl[i].getType().getURI(), SDOUtils::sdoURI) && + !strcmp(pl[i].getType().getName(), "OpenDataObject")) { + + /* + * This code deals with xsd:any element parameters + * Get each element as a DataObject and add in to the parameter list + */ + + DataObjectList& dataObjectList = inputDataObject->getList(pl[i]); + + for(int j=0; j<dataObjectList.size(); j++) + { + DataObjectPtr dob = dataObjectList[j]; + if(!dob) + { + + // Add a null DataObject ptr + DataObjectPtr* dataObjectData = new DataObjectPtr; + *dataObjectData = NULL; + loginfo("Null OpenDataObject parameter named %s[%d]", name, j); + operation.addParameter(dataObjectData); + } + else + { + + SequencePtr sequence = dob->getSequence(); + if (sequence->size()!=0) + { + // Add a text element + if (sequence->isText(0)) + { + string* stringData = new string(sequence->getCStringValue(0)); + operation.addParameter(stringData); + } + else + { + // Add a complex element DataObject + DataObjectPtr* dataObjectData =new DataObjectPtr; + *dataObjectData = sequence->getDataObjectValue(0); + if(!*dataObjectData) + { + loginfo("Null DataObject parameter named %s", name); + } + else + { + (*dataObjectData)->detach(); + } + operation.addParameter(dataObjectData); + } + } + else + { + // Empty content, add an empty string + loginfo("Empty OpenDataObject parameter named %s[%d]", name, j); + string* stringData = new string(""); + operation.addParameter(stringData); + } + } + } + } + else { + DataObjectPtr* dataObjectData = new DataObjectPtr; + if (pl[i].isMany()) + { + DataObjectList& l = inputDataObject->getList((unsigned int)i); + *dataObjectData = l[0]; + } + else + { + *dataObjectData = inputDataObject->getDataObject(pl[i]); + } + if(!*dataObjectData) + { + loginfo("Null DataObject parameter named %s", name); + } + else + { + (*dataObjectData)->detach(); + } + operation.addParameter(dataObjectData); + } + } + break; + default: + { + ostringstream msg; + msg << "Unsupported param type: " << pl[i].getTypeEnum(); + throwException(SystemConfigurationException, msg.str().c_str()); + } + } + } + + // Call into the target service wrapper + serviceWrapper->invoke(operation); + + // Set the data in the outputDataObject to be returned + DataObjectPtr outputDataObject; + try { + + // Create the output wrapper + const Type& rootType = dataFactoryPtr->getType(outputTypeURI, "RootType"); + const Property& prop = rootType.getProperty(outputTypeName); + const Type& outputType = prop.getType(); + outputDataObject = dataFactoryPtr->create(outputType); + } + catch (SDORuntimeException&) + { + try + { + + // Create the output wrapper + const Type& outputType = dataFactoryPtr->getType(outputTypeURI, outputTypeName); + outputDataObject = dataFactoryPtr->create(outputType); + } + catch (SDORuntimeException&) + { + // The output wrapper type is not known, create an open DataObject + outputDataObject = dataFactoryPtr->create("http://tempuri.org", "Wrapper"); + } + } + + setOutputData(operation, outputDataObject, dataFactoryPtr); + + return outputDataObject; + } + catch(SDORuntimeException& ex) + { + throwException(ServiceInvocationException, ex); + } + catch(TuscanyRuntimeException& ex) + { + throw; + } + } + + + void RESTServiceProxy::setOutputData(Operation& operation, DataObjectPtr outputDataObject, DataFactoryPtr dataFactoryPtr) + { + logentry(); + + // Go through data object to set the return value + PropertyList pl = outputDataObject->getType().getProperties(); + + if(pl.size() == 0) + { + if(outputDataObject->getType().isOpenType() && outputDataObject->getType().isDataObjectType()) + { + /* + * This code deals with returning xsd:any elements + */ + DataObjectList& l = outputDataObject->getList("return"); + Operation::ParameterType resultType = operation.getReturnType(); + switch(resultType) + { + case Operation::BOOL: + { + l.append(*(bool*)operation.getReturnValue()); + break; + } + case Operation::SHORT: + { + l.append(*(short*)operation.getReturnValue()); + break; + } + case Operation::INT: + { + l.append(*(long*)operation.getReturnValue()); + break; + } + case Operation::LONG: + { + l.append(*(long*)operation.getReturnValue()); + break; + } + case Operation::USHORT: + { + l.append(*(short*)operation.getReturnValue()); + break; + } + case Operation::UINT: + { + l.append(*(long*)operation.getReturnValue()); + break; + } + case Operation::ULONG: + { + l.append(*(long*)operation.getReturnValue()); + break; + } + case Operation::FLOAT: + { + l.append(*(float*)operation.getReturnValue()); + break; + } + case Operation::DOUBLE: + { + l.append(*(long double*)operation.getReturnValue()); + break; + } + case Operation::LONGDOUBLE: + { + l.append(*(long double*)operation.getReturnValue()); + break; + } + case Operation::CHARS: + { + l.append(*(char**)operation.getReturnValue()); + break; + } + case Operation::STRING: + { + l.append((*(string*)operation.getReturnValue()).c_str()); + break; + } + case Operation::DATAOBJECT: + { + l.append(*(DataObjectPtr*)operation.getReturnValue()); + break; + } + default: + { + break; + } + } + } + else + { + loginfo("No return values defined"); + } + } + else { + + // Should only be one return value.. This goes through all return values + for(int i=0; i<pl.size(); i++) + { + const char* name = pl[i].getName(); + + Operation::ParameterType resultType = operation.getReturnType(); + switch(resultType) + { + case Operation::BOOL: + { + outputDataObject->setBoolean(pl[i], *(bool*)operation.getReturnValue()); + break; + } + case Operation::SHORT: + { + outputDataObject->setShort(pl[i], *(short*)operation.getReturnValue()); + break; + } + case Operation::INT: + { + outputDataObject->setInt(pl[i], *(int*)operation.getReturnValue()); + break; + } + case Operation::LONG: + { + outputDataObject->setInt(pl[i], *(long*)operation.getReturnValue()); + break; + } + case Operation::USHORT: + { + outputDataObject->setInt(pl[i], *(unsigned short*)operation.getReturnValue()); + break; + } + case Operation::UINT: + { + outputDataObject->setInt(pl[i], *(unsigned int*)operation.getReturnValue()); + break; + } + case Operation::ULONG: + { + outputDataObject->setInt(pl[i], *(unsigned long*)operation.getReturnValue()); + break; + } + case Operation::FLOAT: + { + outputDataObject->setFloat(pl[i], *(float*)operation.getReturnValue()); + break; + } + case Operation::DOUBLE: + { + outputDataObject->setDouble(pl[i], *(double*)operation.getReturnValue()); + break; + } + case Operation::LONGDOUBLE: + { + outputDataObject->setDouble(pl[i], *(long double*)operation.getReturnValue()); + break; + } + case Operation::CHARS: + { + if(*(char**)operation.getReturnValue() != NULL) + { + outputDataObject->setCString(pl[i], *(char**)operation.getReturnValue()); + } + else + { + loginfo("Null return value, leaving property %s unset", pl[i].getName()); + } + break; + } + case Operation::STRING: + { + outputDataObject->setCString(pl[i], (*(string*)operation.getReturnValue()).c_str()); + break; + } + case Operation::DATAOBJECT: + { + + if(*(DataObjectPtr*)operation.getReturnValue() != NULL) + { + outputDataObject->setDataObject(pl[i], *(DataObjectPtr*)operation.getReturnValue()); + } + else + { + loginfo("Null return value, leaving property %s unset", pl[i].getName()); + } + + break; + } + default: + { + break; + } + } + } + } + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.h new file mode 100644 index 0000000000..387add3f35 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.h @@ -0,0 +1,95 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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_sca_extension_rest_restserviceproxy_h +#define tuscany_sca_extension_rest_restserviceproxy_h + +#include "commonj/sdo/SDO.h" + +#include "export.h" +#include "tuscany/sca/core/ServiceProxy.h" +#include "tuscany/sca/core/ServiceWrapper.h" +#include "tuscany/sca/model/Component.h" +#include "tuscany/sca/model/Reference.h" +#include "tuscany/sca/model/Service.h" +#include "tuscany/sca/model/WSDLOperation.h" +#include "model/RESTReferenceBinding.h" + + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + /** + * Holds a proxy for a given component and reference. + * The proxy which is held inside a ServiceProxy will be specific to the programming + * interface expected by the client. In this particular case the client is an Axis2 + * Web service skeleton. + */ + class RESTServiceProxy : public ServiceProxy + { + public: + /** + * Create a new service proxy for a reference. The proxy will contain a pointer to + * the target ServiceWrapper. + * @param reference The reference on the source component. + * @param target The wrapper of the service which is wired to this reference. + */ + RESTServiceProxy(tuscany::sca::model::Reference* reference); + + /** + * Create a new service proxy for a service. The proxy will contain a pointer to + * the target ServiceWrapper. + * @param reference The service on the target component. + * @param target The wrapper of the target service. + */ + RESTServiceProxy(tuscany::sca::model::Service* service); + + /** + * Destructor. + */ + virtual ~RESTServiceProxy(); + + /** + * Invoke the specified operation + */ + SCA_REST_SERVICE_API commonj::sdo::DataObjectPtr invoke( + const tuscany::sca::model::WSDLOperation& wsdlOperation, + commonj::sdo::DataObjectPtr inputDataObject); + + private: + + void setOutputData(Operation& operation, + commonj::sdo::DataObjectPtr outputDataObject, commonj::sdo::DataFactoryPtr dataFactoryPtr); + + /** + * The target service wrapper + */ + ServiceWrapper* serviceWrapper; + + }; + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_extension_rest_restserviceproxy_h diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/export.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/export.h new file mode 100644 index 0000000000..802218a2fe --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/export.h @@ -0,0 +1,38 @@ +/* + * 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_sca_rest_service_export_h +#define tuscany_sca_rest_service_export_h + +#if defined(WIN32) || defined (_WINDOWS) +#pragma warning(disable: 4786) + +#ifdef TUSCANY_SCA_REST_SERVICE_EXPORTS +#define SCA_REST_SERVICE_API __declspec(dllexport) +#else +#define SCA_REST_SERVICE_API __declspec(dllimport) +#endif + +#else +#define SCA_REST_SERVICE_API +#endif + +#endif // tuscany_sca_rest_service_export_h diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/model/RESTReferenceBinding.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/model/RESTReferenceBinding.cpp new file mode 100644 index 0000000000..877ee01178 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/model/RESTReferenceBinding.cpp @@ -0,0 +1,66 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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$ */ + +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/rest/model/RESTReferenceBinding.h" +#include "tuscany/sca/core/ServiceProxy.h" +#include "tuscany/sca/rest/RESTServiceProxy.h" + +using namespace std; +using namespace tuscany::sca::model; + +namespace tuscany +{ + namespace sca + { + namespace rest + { + + // Constructor + RESTReferenceBinding::RESTReferenceBinding(Reference* reference, const string& uri) + : ReferenceBinding(reference, uri) + { + logentry(); + } + + // Destructor + RESTReferenceBinding::~RESTReferenceBinding() + { + logentry(); + } + + void RESTReferenceBinding::configure(ServiceBinding *binding) + { + logentry(); + + setTargetServiceBinding(binding); + + serviceProxy = new RESTServiceProxy(getReference()); + } + + ServiceProxy* RESTReferenceBinding::getServiceProxy() + { + logentry(); + + return serviceProxy; + } + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/model/RESTReferenceBinding.h b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/model/RESTReferenceBinding.h new file mode 100644 index 0000000000..22fc04c356 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/model/RESTReferenceBinding.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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_sca_extension_rest_model_restreferencebinding_h +#define tuscany_sca_extension_rest_model_restreferencebinding_h + +#include <string> + +#include "tuscany/sca/model/ReferenceBinding.h" + +namespace tuscany +{ + namespace sca + { + namespace rest + { + /** + * Information about a web service binding for service or a reference. + */ + class RESTReferenceBinding : public tuscany::sca::model::ReferenceBinding + { + public: + + /** + * Constructor. + * @param uri The uri of the binding. + */ + RESTReferenceBinding(tuscany::sca::model::Reference* reference, const std::string& uri); + + /** + * Destructor. + */ + virtual ~RESTReferenceBinding(); + + /** + * Returns the type of binding. + */ + virtual std::string getType() { return "http://www.osoa.org/xmlns/sca/1.0#RESTBinding"; }; + + /** + * Configure this binding from a service binding. + */ + virtual void configure(tuscany::sca::model::ServiceBinding* serviceBinding); + + /** + * Create a proxy representing the reference to the + * client component. + */ + virtual ServiceProxy* getServiceProxy(); + + private: + + /** + * The proxy representing the reference to the client + * component. + */ + ServiceProxy* serviceProxy; + }; + + } // End namespace rest + } // End namespace sca +} // End namespace tuscany + +#endif // tuscany_sca_extension_rest_model_restreferencebinding_h diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/xsd/sca-binding-rest.xsd b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/xsd/sca-binding-rest.xsd new file mode 100644 index 0000000000..ace4c54a39 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/xsd/sca-binding-rest.xsd @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2006 The Apache Software Foundation or its licensors, as applicable. + + Licensed 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. + --> +<schema xmlns="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://www.osoa.org/xmlns/sca/1.0" + xmlns:sca="http://www.osoa.org/xmlns/sca/1.0" + elementFormDefault="qualified"> + + <include schemaLocation="../../../xsd/sca-core.xsd"/> + + <element name="binding.rest" type="sca:RESTBinding" substitutionGroup="sca:binding"/> + <complexType name="RESTBinding"> + <complexContent> + <extension base="sca:Binding"> + <sequence> + <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" /> + </sequence> + <anyAttribute namespace="##any" processContents="lax" /> + </extension> + </complexContent> + </complexType> + +</schema> diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/xsd/sca-interface-rest.xsd b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/xsd/sca-interface-rest.xsd new file mode 100644 index 0000000000..30422ab038 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/rest/xsd/sca-interface-rest.xsd @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> + +<schema xmlns="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://www.osoa.org/xmlns/sca/1.0" + xmlns:sca="http://www.osoa.org/xmlns/sca/1.0" + elementFormDefault="qualified"> + + <include schemaLocation="../../../xsd/sca-core.xsd"/> + + <element name="interface.rest" type="sca:RESTInterface" substitutionGroup="sca:interface"/> + <complexType name="RESTInterface"> + <complexContent> + <extension base="sca:Interface"> + <sequence> + <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" /> + </sequence> + <anyAttribute namespace="##any" processContents="lax" /> + </extension> + </complexContent> + </complexType> + +</schema> |