You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by js...@apache.org on 2006/12/01 17:36:37 UTC
svn commit: r481282 - in
/incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest:
ModREST.cpp RESTServiceProxy.cpp
Author: jsdelfino
Date: Fri Dec 1 08:36:36 2006
New Revision: 481282
URL: http://svn.apache.org/viewvc?view=rev&rev=481282
Log:
Server side support for creation of REST resources using POST
Modified:
incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp
incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp
Modified: incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp
URL: http://svn.apache.org/viewvc/incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp?view=diff&rev=481282&r1=481281&r2=481282
==============================================================================
--- incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp (original)
+++ incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/ModREST.cpp Fri Dec 1 08:36:36 2006
@@ -92,6 +92,8 @@
DataObjectPtr createPayload(DataFactoryPtr dataFactory,
Operation& operation, const WSDLOperation& wsdlOperation);
+ void addPart(XMLHelper* xmlHelper, string& payload, Operation& operation);
+
int logHeaders(void* request, const char* key, const char* value);
/**
@@ -253,31 +255,28 @@
ap_rprintf(request, "<p>SCA component: %s", dir_conf->component);
}
- const char* protocol = request->protocol;
- if (protocol)
+ if (request->protocol)
{
- loginfo("Protocol: %s", protocol);
+ loginfo("Protocol: %s", request->protocol);
if (printRequest)
{
- ap_rprintf(request, "<p>Protocol: %s", protocol);
+ ap_rprintf(request, "<p>Protocol: %s", request->protocol);
}
}
- const char* method = request->method;
- if (method)
+ if (request->method)
{
- loginfo("HTTP method: %s", method);
+ loginfo("HTTP method: %s", request->method);
if (printRequest)
{
- ap_rprintf(request, "<p>HTTP method: %s", method);
+ ap_rprintf(request, "<p>HTTP method: %s", request->method);
}
}
- const int method_number = request->method_number;
- loginfo("HTTP method number: %d", method_number);
+ loginfo("HTTP method number: %d", request->method_number);
if (printRequest)
{
- ap_rprintf(request, "<p>HTTP method number: %d", method_number);
+ ap_rprintf(request, "<p>HTTP method number: %d", request->method_number);
}
const char* content_type = apr_table_get(request->headers_in, "Content-Type");
@@ -290,13 +289,12 @@
}
}
- const char* content_encoding = request->content_encoding;
- if (content_encoding)
+ if (request->content_encoding)
{
- loginfo("Content encoding: %s", content_encoding);
+ loginfo("Content encoding: %s", request->content_encoding);
if (printRequest)
{
- ap_rprintf(request, "<p>Content encoding: %s", content_encoding);
+ ap_rprintf(request, "<p>Content encoding: %s", request->content_encoding);
}
}
@@ -306,33 +304,30 @@
}
apr_table_do(logHeaders, request, request->headers_in, NULL);
- const char* uri = request->uri;
- if (uri)
+ if (request->uri)
{
- loginfo("URI: %s", uri);
+ loginfo("URI: %s", request->uri);
if (printRequest)
{
- ap_rprintf(request, "<p>URI: %s", uri);
+ ap_rprintf(request, "<p>URI: %s", request->uri);
}
}
- const char* path_info = request->path_info;
- if (path_info)
+ if (request->path_info)
{
- loginfo("Path info: %s", path_info);
+ loginfo("Path info: %s", request->path_info);
if (printRequest)
{
- ap_rprintf(request, "<p>Path info: %s", path_info);
+ ap_rprintf(request, "<p>Path info: %s", request->path_info);
}
}
- const char* queryArgs = request->args;
- if (queryArgs)
+ if (request->args)
{
- loginfo("Args: %s", queryArgs);
+ loginfo("Args: %s", request->args);
if (printRequest)
{
- ap_rprintf(request, "<p>Args: %s", queryArgs);
+ ap_rprintf(request, "<p>Args: %s", request->args);
}
}
@@ -341,66 +336,71 @@
ap_rputs("</body></html>", request);
}
- if (method_number == M_GET)
+ // Extract the service and component names from the HTTP URI path
+ string path;
+ if (strlen(request->path_info) != 0 && *(request->path_info) == '/')
{
- // Handle an HTTP GET
-
- // Extract the operation name, service and component names from
- // the HTTP URI path
- string path;
- if (strlen(path_info) != 0 && *path_info == '/')
- {
- path = path_info + 1;
- }
- else
- {
- path = 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, component.c_str(), service.c_str());
-
- if(!compositeService)
- {
- throwException(SystemConfigurationException,
- "Failed to initialize SCA runtime, could not initialize CompositeService");
- }
+ path = request->path_info + 1;
+ }
+ else
+ {
+ path = request->path_info;
+ }
+ string uri;
- DataFactoryPtr dataFactory = compositeService->getComposite()->getDataFactory();
- if (dataFactory == 0)
- {
- throwException(SystemConfigurationException,
- "Failed to initialize SCA runtime, could not get DataFactory");
- }
+ 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);
+ }
- // Get the REST binding
- Composite* composite = compositeService->getComposite();
- Reference* reference = compositeService->getReference();
- RESTReferenceBinding* binding = (RESTReferenceBinding*)reference->getBinding();
- Interface* iface = reference->getType()->getInterface();
-
+ 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, 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");
+ }
+ XMLHelper* 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 = "";
@@ -469,9 +469,6 @@
wsdlOperation.setOutputType(string("http://tempuri.org") + "#" + op_name + "Response");
}
- // Get the REST proxy
- RESTServiceProxy* proxy = (RESTServiceProxy*)binding->getServiceProxy();
-
// Create the input DataObject
Operation operation(op_name.c_str());
@@ -495,9 +492,9 @@
}
// Parse the query string
- if (queryArgs)
+ if (request->args)
{
- string query = queryArgs;
+ string query = request->args;
for (; query != ""; )
{
string param;
@@ -518,68 +515,280 @@
// Dispatch to the REST proxy
DataObjectPtr outputDataObject = proxy->invoke(wsdlOperation, inputDataObject);
- // Send the response back to the client
- if (outputDataObject == NULL)
+ // Send the output DataObject
+ char *str;
+ if (iface!=NULL &&
+ iface->getInterfaceTypeQName() == RESTInterface::typeQName)
{
- loginfo("Sending empty response");
+ // Set the content type
+ ap_set_content_type(request, "text/xml");
+
+ 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());
+ doc->setXMLDeclaration(false);
+ str = xm->save(doc);
+
+ loginfo("Sending response: %s", str);
+ ap_rputs(str, request);
+
+ return OK;
+ }
+ 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
// Set the content type
ap_set_content_type(request, "text/xml");
+
+ if (outputDataObject == NULL)
+ {
+ loginfo("Sending empty response");
+ return OK;
+ }
+ else
+ {
+ XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory);
+ XMLDocumentPtr doc = xm->createDocument(
+ outputDataObject,
+ wsdlOperation.getOutputTypeUri().c_str(),
+ wsdlOperation.getOutputTypeName().c_str());
+ doc->setXMLDeclaration(false);
+ str = xm->save(doc);
+
+ loginfo("Sending response: %s", str);
+ ap_rputs(str, request);
+
+ return OK;
+ }
+ }
+ }
+ else if (request->method_number == M_POST)
+ {
+ // Handle an HTTP POST
- return OK;
+ // 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 == "")
+ {
+ 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.setEncoded(false);
+ wsdlOperation.setInputType(string("http://tempuri.org") + "#" + op_name);
+ wsdlOperation.setOutputType(string("http://tempuri.org") + "#" + op_name + "Response");
+ }
+
+ // 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;
+ }
}
+ // 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();
+ 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
// Send the output DataObject
char *str;
if (iface!=NULL &&
iface->getInterfaceTypeQName() == RESTInterface::typeQName)
{
- // Pure REST, send the response document
- XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory);
+ // Pure REST, send the location of the created resource
+
+ // Set the content type
+ ap_set_content_type(request, "text/xml");
+
+ if (outputDataObject == NULL)
+ {
+ throwException(ServiceInvocationException, "Null output from REST create operation");
+ }
+
+ string location = "";
+
DataObjectList& l = outputDataObject->getList("return");
- DataObjectPtr resourceDataObject = l[0];
- XMLDocumentPtr doc = xm->createDocument(
- resourceDataObject,
- resourceDataObject->getType().getURI(),
- resourceDataObject->getType().getName());
- doc->setXMLDeclaration(false);
- str = xm->save(doc);
+ 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);
+
+ request->status = HTTP_CREATED;
+ return OK;
}
else
{
// Command style, send the response wrapper element
- XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory);
- XMLDocumentPtr doc = xm->createDocument(
- outputDataObject,
- wsdlOperation.getOutputTypeUri().c_str(),
- wsdlOperation.getOutputTypeName().c_str());
- doc->setXMLDeclaration(false);
- str = xm->save(doc);
+
+ // Set the content type
+ ap_set_content_type(request, "text/xml");
+
+ if (outputDataObject == NULL)
+ {
+ loginfo("Sending empty response");
+ return OK;
+ }
+ else
+ {
+ XMLHelperPtr xm = HelperProvider::getXMLHelper(dataFactory);
+ XMLDocumentPtr doc = xm->createDocument(
+ outputDataObject,
+ wsdlOperation.getOutputTypeUri().c_str(),
+ wsdlOperation.getOutputTypeName().c_str());
+ doc->setXMLDeclaration(false);
+ str = xm->save(doc);
+ }
}
- // Set the content type
- ap_set_content_type(request, "text/xml");
-
loginfo("Sending response: %s", str);
ap_rputs(str, request);
return OK;
}
- else if (method_number == M_POST)
- {
- }
- else if (method_number == M_PUT)
+ else if (request->method_number == M_PUT)
{
}
- else if (method_number == M_DELETE)
+ else if (request->method_number == M_DELETE)
{
}
else
{
- if (method)
+ if (request->method)
{
ostringstream msg;
- msg << "Unsupported HTTP method: %s" << method;
+ msg << "Unsupported HTTP method: %s" << request->method;
throwException(ServiceInvocationException, msg.str().c_str());
}
else
@@ -647,23 +856,109 @@
DataObjectList& l = inputDataObject->getList(pname.str());
const Operation::Parameter& parm = operation.getParameter(i);
- l.append((*(string*)parm.getValue()).c_str());
+ switch(parm.getType())
+ {
+ case Operation::STRING:
+ {
+ l.append((*(string*)parm.getValue()).c_str());
+ break;
+ }
+ case Operation::DATAOBJECT:
+ {
+ l.append(*(DataObjectPtr*)parm.getValue());
+ break;
+ }
+ default:
+ {
+ ostringstream msg;
+ msg << "Unsupported parameter type: " << parm.getType();
+ throwException(ServiceDataException, msg.str().c_str());
+ }
+ }
}
}
}
else {
// Each parameter in the operation should be a property on the request dataobject
- for (int i=0; i<operation.getNParms(); i++)
+ for (unsigned int i=0; i<operation.getNParms(); i++)
{
const Operation::Parameter& parm = operation.getParameter(i);
- inputDataObject->setCString(i, (*(string*)parm.getValue()).c_str());
+ 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:
+ ostringstream msg;
+ msg << "Unsupported parameter type: " << parm.getType();
+ throwException(ServiceDataException, msg.str().c_str());
+ }
}
}
return inputDataObject;
}
+ void addPart(XMLHelper* 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 of type OpenDataObject
+ string body =
+ "<Body xmlns=\"http://tempuri.org\" xmlns:tns=\"http://tempuri.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+ + payload
+ + "</Body>";
+
+ // Convert the body to an SDO DataObject
+ DataObjectPtr inputBodyDataObject = NULL;
+ XMLDocumentPtr theXMLDocument = xmlHelper->load(body.c_str(), NULL);
+ if (theXMLDocument != 0)
+ {
+ inputBodyDataObject = theXMLDocument->getRootDataObject();
+ }
+ if(!inputBodyDataObject)
+ {
+ 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 = inputBodyDataObject->getInstanceProperties();
+ if (bpl.size()!=0)
+ {
+ if (bpl[0].isMany())
+ {
+ DataObjectList& parts = inputBodyDataObject->getList((unsigned int)0);
+ inputDataObject = parts[0];
+ }
+ else
+ {
+ inputDataObject = inputBodyDataObject->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)
Modified: incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp
URL: http://svn.apache.org/viewvc/incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp?view=diff&rev=481282&r1=481281&r2=481282
==============================================================================
--- incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp (original)
+++ incubator/tuscany/cpp/sca/runtime/extensions/rest/service/httpd/src/tuscany/sca/rest/RESTServiceProxy.cpp Fri Dec 1 08:36:36 2006
@@ -226,7 +226,15 @@
case Type::DataObjectType:
{
DataObjectPtr* dataObjectData = new DataObjectPtr;
- *dataObjectData = inputDataObject->getDataObject(pl[i]);
+ 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);
@@ -234,7 +242,10 @@
else
{
(*dataObjectData)->detach();
+
+ std::cout << *dataObjectData;
}
+
operation.addParameter(dataObjectData);
}
break;
@@ -337,6 +348,8 @@
}
setOutputData(operation, outputDataObject, dataFactoryPtr);
+
+ std::cout << outputDataObject;
return outputDataObject;
---------------------------------------------------------------------
To unsubscribe, e-mail: tuscany-commits-unsubscribe@ws.apache.org
For additional commands, e-mail: tuscany-commits-help@ws.apache.org