From e5b7380c874745c989d1816b8f552504f038e1bc Mon Sep 17 00:00:00 2001 From: lresende Date: Thu, 26 Sep 2013 20:33:20 +0000 Subject: 2.0 branch for possible maintenance release git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1526672 13f79535-47bb-0310-9956-ffa450edef68 --- .../HTTPDefaultWireFormatProviderFactory.java | 68 ++++++ .../HTTPDefaultWireFormatServiceInterceptor.java | 58 +++++ .../HTTPJSONWireFormatProviderFactory.java | 72 ++++++ .../HTTPJSONWireFormatServiceInterceptor.java | 252 +++++++++++++++++++++ .../provider/HTTPXMLWireFormatProviderFactory.java | 74 ++++++ .../HTTPXMLWireFormatServiceInterceptor.java | 182 +++++++++++++++ 6 files changed, 706 insertions(+) create mode 100644 sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatProviderFactory.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatServiceInterceptor.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatProviderFactory.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatServiceInterceptor.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatProviderFactory.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatServiceInterceptor.java (limited to 'sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat') diff --git a/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatProviderFactory.java b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatProviderFactory.java new file mode 100644 index 0000000000..4c605a62be --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatProviderFactory.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package org.apache.tuscany.sca.binding.http.wireformat.provider; + +import org.apache.tuscany.sca.binding.http.wireformat.HTTPDefaultWireFormat; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.provider.WireFormatProvider; +import org.apache.tuscany.sca.provider.WireFormatProviderFactory; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * + * @version $Rev$ $Date$ + */ +public class HTTPDefaultWireFormatProviderFactory implements WireFormatProviderFactory { + + public HTTPDefaultWireFormatProviderFactory(ExtensionPointRegistry extensionPoints) { + } + + @Override + public Class getModelType() { + return HTTPDefaultWireFormat.class; + } + + @Override + public WireFormatProvider createReferenceWireFormatProvider(RuntimeEndpointReference endpointReference) { + return null; + } + + @Override + public WireFormatProvider createServiceWireFormatProvider(final RuntimeEndpoint endpoint) { + return new WireFormatProvider() { + @Override + public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) { + return interfaceContract; + } + @Override + public Interceptor createInterceptor() { + return new HTTPDefaultWireFormatServiceInterceptor(endpoint); + } + @Override + public String getPhase() { + return Phase.SERVICE_BINDING_WIREFORMAT; + }}; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatServiceInterceptor.java b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatServiceInterceptor.java new file mode 100644 index 0000000000..0b6771e5bc --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPDefaultWireFormatServiceInterceptor.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package org.apache.tuscany.sca.binding.http.wireformat.provider; + +import org.apache.tuscany.sca.common.http.HTTPContext; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + +/** + * Handles the default wire format for the http binding + * by passing the HTTP request and response down to the + * actual component implementation that is a servlet. + * + */ +public class HTTPDefaultWireFormatServiceInterceptor implements Interceptor { + private Invoker next; + + public HTTPDefaultWireFormatServiceInterceptor(RuntimeEndpoint endpoint) { + + } + + @Override + public void setNext(Invoker next) { + this.next = next; + } + + @Override + public Invoker getNext() { + return next; + } + + @Override + public Message invoke(Message msg) { + HTTPContext context = msg.getBindingContext(); + + msg.setBody(new Object[] {context.getHttpRequest(), context.getHttpResponse()}); + return getNext().invoke(msg); + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatProviderFactory.java b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatProviderFactory.java new file mode 100644 index 0000000000..004941fdf5 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatProviderFactory.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.tuscany.sca.binding.http.wireformat.provider; + +import org.apache.tuscany.sca.binding.http.wireformat.HTTPJSONWireFormat; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.provider.WireFormatProvider; +import org.apache.tuscany.sca.provider.WireFormatProviderFactory; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * + * @version $Rev$ $Date$ + */ +public class HTTPJSONWireFormatProviderFactory implements WireFormatProviderFactory { + + public HTTPJSONWireFormatProviderFactory(ExtensionPointRegistry extensionPoints) { + } + + @Override + public Class getModelType() { + return HTTPJSONWireFormat.class; + } + + @Override + public WireFormatProvider createReferenceWireFormatProvider(RuntimeEndpointReference endpointReference) { + return null; + } + + @Override + public WireFormatProvider createServiceWireFormatProvider(final RuntimeEndpoint endpoint) { + return new WireFormatProvider() { + @Override + public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) { + // TODO: Ideally this wants to set the databinding on a per request basis from the + // http content type and accept headers and so support things like json or xml etc, + // for now to get started just use json + interfaceContract.getInterface().resetDataBinding("JSON"); + return interfaceContract; + } + @Override + public Interceptor createInterceptor() { + return new HTTPJSONWireFormatServiceInterceptor(endpoint); + } + @Override + public String getPhase() { + return Phase.SERVICE_BINDING_WIREFORMAT; + }}; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatServiceInterceptor.java b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatServiceInterceptor.java new file mode 100644 index 0000000000..3323fd34fe --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPJSONWireFormatServiceInterceptor.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +package org.apache.tuscany.sca.binding.http.wireformat.provider; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.tuscany.sca.common.http.HTTPContext; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Handles the default wire format for the http binding + * + * 1- determine the request and response format (xml, json, etc) from the + * binding config or content type header and accept headers + * - TODO: need a way to configure the databinding framework based on that format + * 2- get the request contents from the HttpServletRequest + * - for a post its just the request body + * - for a get need to convert the query string into a body based on the format (xml, json, etc) + * 3- send the request on down the wire + * 4- set the response contents in the HttpServletResponse + * (the databinding should already have put it in the correct format) + * + */ +public class HTTPJSONWireFormatServiceInterceptor implements Interceptor { + + private Invoker next; + private String jsonpCallbackName = "callback"; + + public HTTPJSONWireFormatServiceInterceptor(RuntimeEndpoint endpoint) { + } + + @Override + public void setNext(Invoker next) { + this.next = next; + } + + @Override + public Invoker getNext() { + return next; + } + + @Override + public Message invoke(Message msg) { + try { + return invokeResponse(getNext().invoke(invokeRequest(msg))); + } catch (IOException e) { + throw new ServiceRuntimeException(e); + } + } + + private Message invokeRequest(Message msg) throws IOException { + HTTPContext context = msg.getBindingContext(); + HttpServletRequest servletRequest = context.getHttpRequest(); + if ("GET".equals(servletRequest.getMethod())) { + msg.setBody(getRequestFromQueryString(msg.getOperation(), servletRequest)); + } else { + msg.setBody(getRequestFromPost(msg.getOperation(), servletRequest)); + } + return msg; + } + + /** + * The data binding seems to be expecting an Object array of json strings so if the + * post data is a json array convert that to an array of strings + * TODO: should this be being done by the data binding framework? + */ + private Object[] getRequestFromPost(Operation operation, HttpServletRequest servletRequest) throws IOException { + List os = new ArrayList(); + String data = read(servletRequest); + if (data.length() > 0) { + if (data.startsWith("[") && data.endsWith("]")) { + data = data.substring(1, data.length()-1); + StringTokenizer st = new StringTokenizer(data, ","); + while (st.hasMoreElements()) { + os.add(st.nextElement()); + } + } else { + os.add(data); + } + } + return os.toArray(); + } + + private Message invokeResponse(Message msg) throws IOException { + HTTPContext context = msg.getBindingContext(); + HttpServletRequest servletRequest = context.getHttpRequest(); + HttpServletResponse servletResponse = context.getHttpResponse(); + + if (msg.isFault()) { + servletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, String.valueOf(msg.getBody())); + } else { + String response = getResponseAsString(servletRequest, servletResponse, msg.getBody()); + servletResponse.getOutputStream().println(response); + } + + return msg; + } + + /** + * Turn the request into a string array of JSON structures. The data binding + * layer will then convert each of the individual parameters into the appropriate + * types for the implementation interface + * + * From ML thread: http://apache.markmail.org/message/ix3vvyomronellmi + * 1- if the binding configuration contains a mapping from query parameter name to operation parameter then use that. + * 2- if the service interface or impl uses jaxrs annotations to name the parameters then use that mapping + * 3- if the query parameters are name arg0, arg1 etc than use those names for the mapping, + * 4- otherwise use the order in the query string. + */ + protected Object[] getRequestFromQueryString(Operation operation, ServletRequest servletRequest) { + + List types = operation.getInputType().getLogical(); + int typesIndex = 0; + + List jsonRequestArray = new ArrayList(); + + for (String name : getOrderedParameterNames(servletRequest)) { + String jsonRequest = ""; + // quote string parameters so clients work in the usual javascript way + if (typesIndex < types.size() && String.class.equals(types.get(typesIndex++).getGenericType())) { + String x = servletRequest.getParameter(name); + if (x.startsWith("\"") || x.startsWith("'")) { + jsonRequest += x; + } else { + if (x.contains("\"")) { + jsonRequest += "'" + x + "'"; + } else { + jsonRequest += "\"" + x + "\""; + } + } + } else { + jsonRequest += servletRequest.getParameter(name); + } + jsonRequestArray.add(jsonRequest); + } + + return jsonRequestArray.toArray(); + } + + /** + * Get the request parameter names in the correct order. + * Either the query parameters are named arg0, arg1, arg2 etc or else use the order + * from the order in the query string. Eg, the url: + * http://localhost:8085/HelloWorldService/sayHello2?first=petra&last=arnold&callback=foo" + * should invoke: + * sayHello2("petra", "arnold") + * so the parameter names should be ordered: "first", "last" + */ + protected List getOrderedParameterNames(ServletRequest servletRequest) { + List orderedNames = new ArrayList(); + Set parameterNames = servletRequest.getParameterMap().keySet(); + if (parameterNames.contains("arg0")) { + for (int i=0; i sortedNames = new TreeSet(new Comparator(){ + public int compare(String o1, String o2) { + int i = queryString.indexOf(o1); + int j = queryString.indexOf(o2); + return i - j; + }}); + for (String name : parameterNames) { + // ignore system and jsonpCallbackName parameters + if (!name.startsWith("_") && !name.equals(jsonpCallbackName)) { + sortedNames.add(name); + } + } + orderedNames.addAll(sortedNames); + } + return orderedNames; + } + + /** + * The databinding layer will have converted the return type into a JSON string so simply + * add wrap it for return. + */ + protected String getResponseAsString(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Object response) { + String jsonResponse = response == null ? "" : response.toString(); + + if ("GET".equals(servletRequest.getMethod())) { + // handle JSONP callback name padding + String callback = servletRequest.getParameter(jsonpCallbackName); + if (callback != null && callback.length() > 1) { + jsonResponse = callback + "(" + jsonResponse + ");"; + } + } + + return jsonResponse; + } + + protected static String read(HttpServletRequest servletRequest) throws IOException { + InputStream is = servletRequest.getInputStream(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(is)); + StringBuffer sb = new StringBuffer(); + String str; + while ((str = reader.readLine()) != null) { + sb.append(str); + } + return sb.toString().trim(); + } finally { + if (reader != null) { + reader.close(); + } + } + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatProviderFactory.java b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatProviderFactory.java new file mode 100644 index 0000000000..d09ddc0ea5 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatProviderFactory.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.tuscany.sca.binding.http.wireformat.provider; + +import org.apache.tuscany.sca.binding.http.wireformat.HTTPXMLWireFormat; +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.databinding.xml.DOMDataBinding; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Phase; +import org.apache.tuscany.sca.provider.WireFormatProvider; +import org.apache.tuscany.sca.provider.WireFormatProviderFactory; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * + * @version $Rev$ $Date$ + */ +public class HTTPXMLWireFormatProviderFactory implements WireFormatProviderFactory { + + private DOMHelper domHelper; + + public HTTPXMLWireFormatProviderFactory(ExtensionPointRegistry extensionPoints) { + this.domHelper = DOMHelper.getInstance(extensionPoints); + } + + @Override + public Class getModelType() { + return HTTPXMLWireFormat.class; + } + + @Override + public WireFormatProvider createReferenceWireFormatProvider(RuntimeEndpointReference endpointReference) { + return null; + } + + @Override + public WireFormatProvider createServiceWireFormatProvider(final RuntimeEndpoint endpoint) { + return new WireFormatProvider() { + @Override + public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) { + interfaceContract.getInterface().resetDataBinding(DOMDataBinding.NAME); + return interfaceContract; + } + @Override + public Interceptor createInterceptor() { + return new HTTPXMLWireFormatServiceInterceptor(endpoint, domHelper); + } + @Override + public String getPhase() { + return Phase.SERVICE_BINDING_WIREFORMAT; + }}; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatServiceInterceptor.java b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatServiceInterceptor.java new file mode 100644 index 0000000000..93935a9f41 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/wireformat/provider/HTTPXMLWireFormatServiceInterceptor.java @@ -0,0 +1,182 @@ +/* + * 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. + */ + +package org.apache.tuscany.sca.binding.http.wireformat.provider; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.tuscany.sca.common.http.HTTPContext; +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.util.FaultException; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.ServiceRuntimeException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +/** + * Handles the xml wire format for the http binding + */ +public class HTTPXMLWireFormatServiceInterceptor implements Interceptor { + + private Invoker next; + private DOMHelper domHelper; + + public HTTPXMLWireFormatServiceInterceptor(RuntimeEndpoint endpoint, DOMHelper domHelper) { + this.domHelper = domHelper; + } + + @Override + public void setNext(Invoker next) { + this.next = next; + } + + @Override + public Invoker getNext() { + return next; + } + + @Override + public Message invoke(Message msg) { + try { + return invokeResponse(getNext().invoke(invokeRequest(msg))); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + private Message invokeRequest(Message msg) throws IOException, SAXException { + HTTPContext context = msg.getBindingContext(); + HttpServletRequest servletRequest = context.getHttpRequest(); + if ("GET".equals(servletRequest.getMethod())) { + msg.setBody(getRequestFromQueryString(msg.getOperation(), servletRequest)); + } else { + msg.setBody(new Object[]{domHelper.load(read(servletRequest))}); + } + return msg; + } + + private Message invokeResponse(Message msg) throws IOException { + HTTPContext context = msg.getBindingContext(); + HttpServletResponse servletResponse = context.getHttpResponse(); + + servletResponse.setContentType("text/xml"); + + Object o = msg.getBody(); + if (msg.isFault()) { + String xml = domHelper.saveAsString((Node)((FaultException)o).getFaultInfo()); + servletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, xml); + } else { + String xml = ""; + if (o instanceof Element) { + xml = domHelper.saveAsString((Node)o); + } else if ((o instanceof Object[]) && ((Object[])o)[0] instanceof Node) { + xml = domHelper.saveAsString((Node)((Object[])o)[0]); + } else if (o != null) { + throw new IllegalStateException("expecting Node payload: " + o); + } + servletResponse.getOutputStream().println(xml); + } + + return msg; + } + + /** + * Turn the query request into XML. + */ + protected Object[] getRequestFromQueryString(Operation operation, ServletRequest servletRequest) throws IOException, SAXException { + List xmlRequestArray = new ArrayList(); + for (String name : getOrderedParameterNames(servletRequest)) { + xmlRequestArray.add(domHelper.load("<" + name + ">" + servletRequest.getParameter(name) + "")); + } + return xmlRequestArray.toArray(); + } + + /** + * Get the request parameter names in the correct order. + * Either the query parameters are named arg0, arg1, arg2 etc or else use the order + * from the order in the query string. Eg, the url: + * http://localhost:8085/HelloWorldService/sayHello2?first=petra&last=arnold&callback=foo" + * should invoke: + * sayHello2("petra", "arnold") + * so the parameter names should be ordered: "first", "last" + */ + protected List getOrderedParameterNames(ServletRequest servletRequest) { + List orderedNames = new ArrayList(); + Set parameterNames = servletRequest.getParameterMap().keySet(); + if (parameterNames.contains("arg0")) { + for (int i=0; i sortedNames = new TreeSet(new Comparator(){ + public int compare(String o1, String o2) { + int i = queryString.indexOf(o1); + int j = queryString.indexOf(o2); + return i - j; + }}); + for (String name : parameterNames) { + sortedNames.add(name); + } + orderedNames.addAll(sortedNames); + } + return orderedNames; + } + + protected static String read(HttpServletRequest servletRequest) throws IOException { + InputStream is = servletRequest.getInputStream(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(is)); + StringBuffer sb = new StringBuffer(); + String str; + while ((str = reader.readLine()) != null) { + sb.append(str); + } + return sb.toString(); + } finally { + if (reader != null) { + reader.close(); + } + } + } +} -- cgit v1.2.3