From e8fbcbd2e96c5fe66ee9a47b53c6884cccb8dc6c Mon Sep 17 00:00:00 2001 From: antelder Date: Mon, 30 Aug 2010 08:08:38 +0000 Subject: Start of the runtime code to support wireFormat.httpXml, still needs code to turn query parameters into xml git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@990723 13f79535-47bb-0310-9956-ffa450edef68 --- .../format/HTTPXMLWireFormatProviderFactory.java | 70 +++++++ .../HTTPXMLWireFormatServiceInterceptor.java | 225 +++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatProviderFactory.java create mode 100644 sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatServiceInterceptor.java (limited to 'sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca') diff --git a/sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatProviderFactory.java b/sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatProviderFactory.java new file mode 100644 index 0000000000..cb60101bb7 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatProviderFactory.java @@ -0,0 +1,70 @@ +/* + * 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.format; + +import org.apache.tuscany.sca.binding.http.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; + +public class HTTPXMLWireFormatProviderFactory implements WireFormatProviderFactory { + + private DOMHelper domHelper; + + public HTTPXMLWireFormatProviderFactory(ExtensionPointRegistry extensionPoints) { + this.domHelper = DOMHelper.getInstance(extensionPoints); + } + + @Override + public Class getModelType() { + return null; + } + + @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/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatServiceInterceptor.java b/sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatServiceInterceptor.java new file mode 100644 index 0000000000..48768096c5 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/format/HTTPXMLWireFormatServiceInterceptor.java @@ -0,0 +1,225 @@ +/* + * 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.format; + +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.binding.http.provider.HTTPContext; +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.interfacedef.DataType; +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; + +/** + * Handles the xml 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 HTTPXMLWireFormatServiceInterceptor implements Interceptor { + + private Invoker next; + private String jsonpCallbackName = "callback"; + 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 (IOException e) { + throw new ServiceRuntimeException(e); + } + } + + private Message invokeRequest(Message msg) throws IOException { + HTTPContext context = msg.getBindingContext(); + HttpServletRequest servletRequest = context.getRequest(); + if ("GET".equals(servletRequest.getMethod())) { + msg.setBody(getRequestFromQueryString(msg.getOperation(), servletRequest)); + } else { + msg.setBody(read(servletRequest)); + } + return msg; + } + + private Message invokeResponse(Message msg) throws IOException { + HTTPContext context = msg.getBindingContext(); + HttpServletRequest servletRequest = context.getRequest(); + HttpServletResponse servletResponse = context.getResponse(); + + 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. + * + * 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(); + return new Object[operation.getInputType().getLogical().size()]; + } + + /** + * 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; + } + + 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