summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest')
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/js/dojo/RESTBindingJavascriptProxyFactory.java77
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorInterceptor.java260
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorProviderFactory.java52
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorReferenceProvider.java50
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorServiceProvider.java57
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorInterceptor.java203
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorProviderFactory.java52
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorReferenceProvider.java50
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorServiceProvider.java57
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSProvider.java206
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java90
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java91
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/JAXRSHelper.java80
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java308
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingListenerServlet.java583
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingProviderFactory.java63
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTReferenceBindingProvider.java75
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java376
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceListenerServlet.java122
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/TuscanyRESTServlet.java258
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatInterceptor.java159
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatProviderFactory.java52
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatReferenceProvider.java54
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatServiceProvider.java138
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatInterceptor.java143
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatProviderFactory.java52
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatReferenceProvider.java54
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatServiceProvider.java139
28 files changed, 3901 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/js/dojo/RESTBindingJavascriptProxyFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/js/dojo/RESTBindingJavascriptProxyFactory.java
new file mode 100644
index 0000000000..68cd6fa0e3
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/js/dojo/RESTBindingJavascriptProxyFactory.java
@@ -0,0 +1,77 @@
+/*
+ * 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.rest.js.dojo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.Endpoint;
+import org.apache.tuscany.sca.assembly.EndpointReference;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+import org.apache.tuscany.sca.web.javascript.JavascriptProxyFactory;
+
+public class RESTBindingJavascriptProxyFactory implements JavascriptProxyFactory {
+ private static final QName NAME = RESTBinding.TYPE;
+
+ public Class<?> getModelType() {
+ return RESTBinding.class;
+ }
+
+ public QName getQName() {
+ return NAME;
+ }
+
+ public String getJavascriptProxyFile() {
+ return null;
+ }
+
+ public InputStream getJavascriptProxyFileAsStream() throws IOException {
+ return null;
+ }
+
+ public String createJavascriptHeader(ComponentReference componentReference) throws IOException {
+ return "dojo.require('tuscany.RestService');";
+ }
+
+ public String createJavascriptReference(ComponentReference componentReference) throws IOException {
+ EndpointReference epr = componentReference.getEndpointReferences().get(0);
+ Endpoint targetEndpoint = epr.getTargetEndpoint();
+ if (targetEndpoint.isUnresolved()) {
+ //force resolution and targetEndpoint binding calculations
+ //by calling the getInvocationChain
+ ((RuntimeEndpointReference) epr).getInvocationChains();
+ targetEndpoint = epr.getTargetEndpoint();
+ }
+
+ Binding binding = targetEndpoint.getBinding();
+
+ URI targetURI = URI.create(binding.getURI());
+ String targetPath = targetURI.getPath();
+
+ return "tuscany.RestService(\"" + targetPath + "\")";
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorInterceptor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorInterceptor.java
new file mode 100644
index 0000000000..c47473b3ee
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorInterceptor.java
@@ -0,0 +1,260 @@
+/*
+ * 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.rest.operationselector.jaxrs.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.net.URLDecoder;
+import java.util.List;
+
+import javax.activation.DataSource;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.common.http.HTTPUtils;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+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.RuntimeComponentService;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+
+/**
+ * JAXRS operation selector Interceptor.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JAXRSOperationSelectorInterceptor implements Interceptor {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpoint endpoint;
+
+ private RuntimeComponentService service;
+ private InterfaceContract interfaceContract;
+ private List<Operation> serviceOperations;
+
+ private Invoker next;
+
+ public JAXRSOperationSelectorInterceptor(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.extensionPoints = extensionPoints;
+ this.endpoint = endpoint;
+
+ this.service = (RuntimeComponentService)endpoint.getService();
+ this.interfaceContract = service.getInterfaceContract();
+ this.serviceOperations = service.getInterfaceContract().getInterface().getOperations();
+ }
+
+ public Invoker getNext() {
+ return next;
+ }
+
+ public void setNext(Invoker next) {
+ this.next = next;
+ }
+
+ public Message invoke(Message msg) {
+
+ HTTPContext bindingContext = (HTTPContext)msg.getBindingContext();
+
+ // By-pass the operation selector
+ if (bindingContext == null) {
+ return getNext().invoke(msg);
+ }
+
+ String path = null;
+ try {
+ path = URLDecoder.decode(HTTPUtils.getRequestPath(bindingContext.getHttpRequest()), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ if (path.startsWith("/")) {
+ path = path.substring(1);
+ }
+
+ List<Operation> operations =
+ filterOperationsByHttpMethod(interfaceContract, bindingContext.getHttpRequest().getMethod());
+
+ Operation operation = findOperation(path, operations);
+
+ final JavaOperation javaOperation = (JavaOperation)operation;
+ final Method method = javaOperation.getJavaMethod();
+
+ if (path != null && path.length() > 0) {
+ if (method.getAnnotation(Path.class) != null) {
+ msg.setBody(new Object[] {path});
+ }
+ }
+
+ // FIXME: [rfeng] We should follow JAX-RS rules to identify the entity parameter
+ Class<?>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length == 1) {
+ Class<?> type = paramTypes[0];
+ InputStream is = (InputStream)((Object[])msg.getBody())[0];
+ Object target = convert(is, bindingContext.getHttpRequest().getContentType(), type);
+ msg.setBody(new Object[] {target});
+ } else if (paramTypes.length == 0) {
+ msg.setBody(null);
+ }
+
+ msg.setOperation(operation);
+
+ return getNext().invoke(msg);
+
+ }
+
+ private Object convert(InputStream content, String contentType, Class<?> type) {
+ if (type == DataSource.class) {
+ return type.cast(new InputStreamDataSource(content, contentType));
+ } else if (type == InputStream.class) {
+ return type.cast(content);
+ } else if (type == String.class) {
+ try {
+ StringWriter sw = new StringWriter();
+ InputStreamReader reader = new InputStreamReader(content, "UTF-8");
+ char[] buf = new char[8192];
+ while (true) {
+ int size = reader.read(buf);
+ if (size < 0) {
+ break;
+ }
+ sw.write(buf, 0, size);
+ }
+ return type.cast(sw.toString());
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ } else if (type == byte[].class) {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] buf = new byte[8192];
+ while (true) {
+ int size = content.read(buf);
+ if (size < 0) {
+ break;
+ }
+ bos.write(buf, 0, size);
+ }
+ return type.cast(bos.toByteArray());
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ } else {
+ return content;
+ }
+ }
+
+ public static final class InputStreamDataSource implements DataSource {
+
+ public static final String DEFAULT_TYPE = "application/octet-stream";
+
+ private final InputStream in;
+ private final String ctype;
+
+ public InputStreamDataSource(InputStream in) {
+ this(in, null);
+ }
+
+ public InputStreamDataSource(InputStream in, String ctype) {
+ this.in = in;
+ this.ctype = (ctype != null) ? ctype : DEFAULT_TYPE;
+ }
+
+ public String getContentType() {
+ return ctype;
+ }
+
+ public String getName() {
+ return null;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return in;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ }
+
+ /**
+ * Find the operation from the component service contract
+ * @param componentService
+ * @param http_method
+ * @return
+ */
+ private static List<Operation> filterOperationsByHttpMethod(InterfaceContract interfaceContract, String http_method) {
+ List<Operation> operations = null;
+
+ if (http_method.equalsIgnoreCase("get")) {
+ operations = (List<Operation>)interfaceContract.getInterface().getAttributes().get(GET.class);
+ } else if (http_method.equalsIgnoreCase("put")) {
+ operations = (List<Operation>)interfaceContract.getInterface().getAttributes().get(PUT.class);
+ } else if (http_method.equalsIgnoreCase("post")) {
+ operations = (List<Operation>)interfaceContract.getInterface().getAttributes().get(POST.class);
+ } else if (http_method.equalsIgnoreCase("delete")) {
+ operations = (List<Operation>)interfaceContract.getInterface().getAttributes().get(DELETE.class);
+ }
+
+ return operations;
+ }
+
+ /**
+ * Find the operation from the component service contract
+ * @param componentService
+ * @param http_method
+ * @return
+ */
+ private Operation findOperation(String path, List<Operation> operations) {
+ Operation operation = null;
+
+ for (Operation op : operations) {
+ final JavaOperation javaOperation = (JavaOperation)op;
+ final Method method = javaOperation.getJavaMethod();
+
+ if (path != null && path.length() > 0) {
+ if (method.getAnnotation(Path.class) != null) {
+ operation = op;
+ break;
+ }
+ } else {
+ if (method.getAnnotation(Path.class) == null) {
+ operation = op;
+ break;
+ }
+ }
+ }
+
+ return operation;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorProviderFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorProviderFactory.java
new file mode 100644
index 0000000000..d057f1a852
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rest.operationselector.jaxrs.provider;
+
+import org.apache.tuscany.sca.binding.rest.operationselector.jaxrs.JAXRSOperationSelector;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.provider.OperationSelectorProviderFactory;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+
+/**
+ * JAXRS operation selector Provider Factory.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JAXRSOperationSelectorProviderFactory implements OperationSelectorProviderFactory<JAXRSOperationSelector>{
+ private ExtensionPointRegistry extensionPoints;
+
+ public JAXRSOperationSelectorProviderFactory(ExtensionPointRegistry extensionPoints) {
+ this.extensionPoints = extensionPoints;
+ }
+ public OperationSelectorProvider createReferenceOperationSelectorProvider(RuntimeEndpointReference endpointReference) {
+ return new JAXRSOperationSelectorReferenceProvider(extensionPoints, endpointReference);
+ }
+
+ public OperationSelectorProvider createServiceOperationSelectorProvider(RuntimeEndpoint endpoint) {
+ return new JAXRSOperationSelectorServiceProvider(extensionPoints, endpoint);
+ }
+
+ public Class<JAXRSOperationSelector> getModelType() {
+ return JAXRSOperationSelector.class;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorReferenceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorReferenceProvider.java
new file mode 100644
index 0000000000..c560a13ae2
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorReferenceProvider.java
@@ -0,0 +1,50 @@
+/*
+ * 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.rest.operationselector.jaxrs.provider;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.Phase;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+
+/**
+ * JAXRS operation selector Reference Provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JAXRSOperationSelectorReferenceProvider implements OperationSelectorProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpointReference endpointReference;
+
+ public JAXRSOperationSelectorReferenceProvider(ExtensionPointRegistry extensionPoints, RuntimeEndpointReference endpointReference ) {
+ this.extensionPoints = extensionPoints;
+ this.endpointReference = endpointReference;
+ }
+
+ public Interceptor createInterceptor() {
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.SERVICE_BINDING_OPERATION_SELECTOR;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorServiceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorServiceProvider.java
new file mode 100644
index 0000000000..105c84ebda
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/jaxrs/provider/JAXRSOperationSelectorServiceProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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.rest.operationselector.jaxrs.provider;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.operationselector.jaxrs.JAXRSOperationSelector;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.Phase;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+
+/**
+ * JAXRS operation selector Service Provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JAXRSOperationSelectorServiceProvider implements OperationSelectorProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpoint endpoint;
+
+ private Binding binding;
+
+ public JAXRSOperationSelectorServiceProvider(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.extensionPoints = extensionPoints;
+ this.endpoint = endpoint;
+ this.binding = endpoint.getBinding();
+ }
+
+ public Interceptor createInterceptor() {
+ if(binding.getOperationSelector() != null && binding.getOperationSelector() instanceof JAXRSOperationSelector) {
+ return new JAXRSOperationSelectorInterceptor(extensionPoints, endpoint);
+ }
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.SERVICE_BINDING_OPERATION_SELECTOR;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorInterceptor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorInterceptor.java
new file mode 100644
index 0000000000..53be473416
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorInterceptor.java
@@ -0,0 +1,203 @@
+/*
+ * 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.rest.operationselector.rpc.provider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.QueryParam;
+
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.common.http.HTTPUtils;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.databinding.SimpleTypeMapper;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+import org.apache.tuscany.sca.interfacedef.util.TypeInfo;
+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.RuntimeComponentService;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+
+/**
+ * RPC operation selector Interceptor.
+ *
+ * @version $Rev$ $Date$
+*/
+public class RPCOperationSelectorInterceptor implements Interceptor {
+ private ExtensionPointRegistry extensionPoints;
+ private SimpleTypeMapper simpleTypeMapper;
+
+ private RuntimeEndpoint endpoint;
+
+ private RuntimeComponentService service;
+ private InterfaceContract interfaceContract;
+ private List<Operation> serviceOperations;
+
+ private Invoker next;
+
+ public RPCOperationSelectorInterceptor(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.extensionPoints = extensionPoints;
+
+ UtilityExtensionPoint utilityExtensionPoint = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class);
+ this.simpleTypeMapper = utilityExtensionPoint.getUtility(SimpleTypeMapper.class);
+
+ this.endpoint = endpoint;
+
+ this.service = (RuntimeComponentService)endpoint.getService();
+ this.interfaceContract = service.getInterfaceContract();
+ this.serviceOperations = service.getInterfaceContract().getInterface().getOperations();
+ }
+
+ public Invoker getNext() {
+ return next;
+ }
+
+ public void setNext(Invoker next) {
+ this.next = next;
+ }
+
+ public Message invoke(Message msg) {
+ try {
+ HTTPContext bindingContext = (HTTPContext)msg.getBindingContext();
+
+ if(! "get".equalsIgnoreCase(bindingContext.getHttpRequest().getMethod())) {
+ throw new RuntimeException("RPC Invocation only allowed over HTTP GET operations");
+ }
+
+ String path = URLDecoder.decode(HTTPUtils.getRequestPath(bindingContext.getHttpRequest()), "UTF-8");
+
+ if (path.startsWith("/")) {
+ path = path.substring(1);
+ }
+
+
+ String operationName = bindingContext.getHttpRequest().getParameter("method");
+ Operation operation = findOperation( operationName );
+
+ if (operation == null) {
+ throw new RuntimeException("Invalid Operation '" + operationName + "'" );
+ }
+
+ final JavaOperation javaOperation = (JavaOperation)operation;
+ final Method method = javaOperation.getJavaMethod();
+
+ List<Object> messageParameters = new ArrayList<Object>();
+ for(int i=0; i<method.getParameterTypes().length; i++) {
+ for(Annotation annotation : method.getParameterAnnotations()[i]) {
+ if (annotation instanceof QueryParam) {
+ QueryParam queryParam = (QueryParam) annotation;
+ String name = queryParam.value();
+ String[] values = bindingContext.getHttpRequest().getParameterValues(name);
+
+ if(values.length == 1) {
+ //process value, making necessary map from string to expected value
+ Class<?> clazz = method.getParameterTypes()[i];
+ TypeInfo typeInfo = simpleTypeMapper.getXMLType(clazz);
+ Object v = simpleTypeMapper.toJavaObject(typeInfo.getQName(), values[0], null);
+ messageParameters.add(v);
+ } else {
+ //process value, making necessary map from string to expected value
+ Class<?> clazz = (method.getParameterTypes()[i]).getComponentType();
+ TypeInfo typeInfo = simpleTypeMapper.getXMLType(clazz);
+
+
+ Object objectArray = Array.newInstance(clazz, values.length);
+ for (int count = 0; count < values.length; ++count) {
+ Object v = simpleTypeMapper.toJavaObject(typeInfo.getQName(), values[count], null);
+ Array.set(objectArray, count, v);
+ }
+
+ messageParameters.add(objectArray);
+ }
+ }
+ }
+ }
+
+ Object[] body = new Object[messageParameters.size()];
+ messageParameters.toArray(body);
+
+ msg.setBody(body);
+ msg.setOperation(operation);
+
+ Message responseMessage = getNext().invoke(msg);
+
+ //set Cache-Control to no-cache to avoid intermediary
+ //proxy/reverse-proxy caches and always hit the server
+ //that would identify if the value was current or not
+ bindingContext.getHttpResponse().setHeader("Cache-Control", "no-cache");
+ bindingContext.getHttpResponse().setHeader("Expires", new Date(0).toGMTString());
+
+
+ String eTag = HTTPUtils.calculateHashETag(responseMessage.getBody().toString().getBytes("UTF-8"));
+
+ // Test request for predicates.
+ String predicate = bindingContext.getHttpRequest().getHeader( "If-Match" );
+ if (( predicate != null ) && ( !predicate.equals(eTag) )) {
+ // No match, should short circuit
+ bindingContext.getHttpResponse().sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+ }
+ predicate = bindingContext.getHttpRequest().getHeader( "If-None-Match" );
+ if (( predicate != null ) && ( predicate.equals(eTag) )) {
+ // Match, should short circuit
+ bindingContext.getHttpResponse().sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ }
+
+ bindingContext.getHttpResponse().addHeader("ETag", eTag);
+
+ return responseMessage;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Find the operation from the component service contract
+ * @param componentService
+ * @param method
+ * @return
+ */
+ private Operation findOperation(String method) {
+ if (method.contains(".")) {
+ method = method.substring(method.lastIndexOf(".") + 1);
+ }
+
+ List<Operation> operations = endpoint.getComponentServiceInterfaceContract().getInterface().getOperations();
+
+ Operation result = null;
+ for (Operation o : operations) {
+ if (o.getName().equalsIgnoreCase(method)) {
+ result = o;
+ break;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorProviderFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorProviderFactory.java
new file mode 100644
index 0000000000..011e89e7cc
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rest.operationselector.rpc.provider;
+
+import org.apache.tuscany.sca.binding.rest.operationselector.rpc.RPCOperationSelector;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.provider.OperationSelectorProviderFactory;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+
+/**
+ * RPC operation selector Provider Factory.
+ *
+ * @version $Rev$ $Date$
+*/
+public class RPCOperationSelectorProviderFactory implements OperationSelectorProviderFactory<RPCOperationSelector>{
+ private ExtensionPointRegistry extensionPoints;
+
+ public RPCOperationSelectorProviderFactory(ExtensionPointRegistry extensionPoints) {
+ this.extensionPoints = extensionPoints;
+ }
+ public OperationSelectorProvider createReferenceOperationSelectorProvider(RuntimeEndpointReference endpointReference) {
+ return new RPCOperationSelectorReferenceProvider(extensionPoints, endpointReference);
+ }
+
+ public OperationSelectorProvider createServiceOperationSelectorProvider(RuntimeEndpoint endpoint) {
+ return new RPCOperationSelectorServiceProvider(extensionPoints, endpoint);
+ }
+
+ public Class<RPCOperationSelector> getModelType() {
+ return RPCOperationSelector.class;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorReferenceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorReferenceProvider.java
new file mode 100644
index 0000000000..c87b2fc21d
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorReferenceProvider.java
@@ -0,0 +1,50 @@
+/*
+ * 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.rest.operationselector.rpc.provider;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.Phase;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+
+/**
+ * RPC operation selector Reference Provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class RPCOperationSelectorReferenceProvider implements OperationSelectorProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpointReference endpointReference;
+
+ public RPCOperationSelectorReferenceProvider(ExtensionPointRegistry extensionPoints, RuntimeEndpointReference endpointReference ) {
+ this.extensionPoints = extensionPoints;
+ this.endpointReference = endpointReference;
+ }
+
+ public Interceptor createInterceptor() {
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.SERVICE_BINDING_OPERATION_SELECTOR;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorServiceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorServiceProvider.java
new file mode 100644
index 0000000000..e4a003d4b5
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/operationselector/rpc/provider/RPCOperationSelectorServiceProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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.rest.operationselector.rpc.provider;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.operationselector.rpc.RPCOperationSelector;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.Phase;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+
+/**
+ * RPC operation selector Service Provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class RPCOperationSelectorServiceProvider implements OperationSelectorProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpoint endpoint;
+
+ private Binding binding;
+
+ public RPCOperationSelectorServiceProvider(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.extensionPoints = extensionPoints;
+ this.endpoint = endpoint;
+ this.binding = endpoint.getBinding();
+ }
+
+ public Interceptor createInterceptor() {
+ if(binding.getOperationSelector() != null && binding.getOperationSelector() instanceof RPCOperationSelector) {
+ return new RPCOperationSelectorInterceptor(extensionPoints, endpoint);
+ }
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.SERVICE_BINDING_OPERATION_SELECTOR;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSProvider.java
new file mode 100644
index 0000000000..7d6d1adbec
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSProvider.java
@@ -0,0 +1,206 @@
+/*
+ * 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.rest.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.activation.DataSource;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.Provider;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+
+/**
+ * A JAX-RS provider that leverages Tuscany's databinding framework to handle read/write
+ * for JAX-RS runtime
+ */
+@Provider
+public abstract class DataBindingJAXRSProvider {
+ protected DataBindingExtensionPoint dataBindingExtensionPoint;
+ protected Mediator mediator;
+
+ public DataBindingJAXRSProvider(ExtensionPointRegistry registry) {
+ this.dataBindingExtensionPoint = registry.getExtensionPoint(DataBindingExtensionPoint.class);
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ this.mediator = utilities.getUtility(Mediator.class);
+ }
+
+ protected <A extends Annotation> A getAnnotation(Annotation[] annotations, Class<A> type) {
+ if(annotations == null) {
+ return null;
+ }
+ for (Annotation a : annotations) {
+ if (a.annotationType() == type) {
+ return type.cast(a);
+ }
+ }
+ return null;
+ }
+
+ protected void introspectAnnotations(Annotation[] annotations, DataType targetDataType) {
+ WebResult result = getAnnotation(annotations, WebResult.class);
+ if (result != null) {
+ QName name = new QName(result.targetNamespace(), result.name());
+ targetDataType.setLogical(new XMLType(name, null));
+ }
+
+ WebParam param = getAnnotation(annotations, WebParam.class);
+ if (param != null) {
+ QName name = new QName(param.targetNamespace(), param.name());
+ targetDataType.setLogical(new XMLType(name, null));
+ }
+ }
+
+ protected DataType createDataType(Class<?> type, Type genericType) {
+ DataType dataType = new DataTypeImpl(null, type, genericType, genericType);
+ dataBindingExtensionPoint.introspectType(dataType, null);
+ return dataType;
+ }
+
+ protected boolean supports(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ // Some media types have parameters
+ mediaType = new MediaType(mediaType.getType(), mediaType.getSubtype());
+ return MediaType.APPLICATION_JSON_TYPE.isCompatible(mediaType) || MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)
+ || MediaType.TEXT_XML_TYPE.isCompatible(mediaType);
+ }
+
+ protected Object convert(InputStream content, String contentType, Class<?> type) throws IOException {
+ if (type == DataSource.class) {
+ return type.cast(new InputStreamDataSource(content, contentType));
+ } else if (type == InputStream.class) {
+ return type.cast(content);
+ } else if (type == Reader.class) {
+ return type.cast(new InputStreamReader(content, "UTF-8"));
+ } else if (type == String.class) {
+ try {
+ StringWriter sw = new StringWriter();
+ InputStreamReader reader = new InputStreamReader(content, "UTF-8");
+ char[] buf = new char[8192];
+ while (true) {
+ int size = reader.read(buf);
+ if (size < 0) {
+ break;
+ }
+ sw.write(buf, 0, size);
+ }
+ return type.cast(sw.toString());
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ } else if (type == byte[].class) {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] buf = new byte[8192];
+ while (true) {
+ int size = content.read(buf);
+ if (size < 0) {
+ break;
+ }
+ bos.write(buf, 0, size);
+ }
+ return type.cast(bos.toByteArray());
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ } else {
+ return content;
+ }
+ }
+
+ protected void write(OutputStream out, Object content, Class<?> type) throws IOException {
+ if (content == null) {
+ return;
+ }
+ InputStream in = null;
+ if (DataSource.class.isAssignableFrom(type)) {
+ in = ((DataSource)content).getInputStream();
+ } else if (InputStream.class.isAssignableFrom(type)) {
+ in = (InputStream)content;
+ } else if (type == String.class) {
+ in = new ByteArrayInputStream(((String)content).getBytes("UTF-8"));
+ } else if (type == byte[].class) {
+ in = new ByteArrayInputStream((byte[])content);
+ }
+ if (in == null) {
+ throw new IllegalArgumentException("Type is not supported: " + type);
+ }
+ byte[] buf = new byte[8192];
+ while (true) {
+ int len = in.read(buf);
+ if (len < 0) {
+ in.close();
+ break;
+ }
+ out.write(buf, 0, len);
+ }
+ }
+
+ public static final class InputStreamDataSource implements DataSource {
+
+ public static final String DEFAULT_TYPE = "application/octet-stream";
+
+ private final InputStream in;
+ private final String ctype;
+
+ public InputStreamDataSource(InputStream in) {
+ this(in, null);
+ }
+
+ public InputStreamDataSource(InputStream in, String ctype) {
+ this.in = in;
+ this.ctype = (ctype != null) ? ctype : DEFAULT_TYPE;
+ }
+
+ public String getContentType() {
+ return ctype;
+ }
+
+ public String getName() {
+ return null;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return in;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java
new file mode 100644
index 0000000000..d2304b79f4
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java
@@ -0,0 +1,90 @@
+/*
+ * 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.rest.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+
+/**
+ * The generic JAX-RS message body reader based on Tuscany's databindingframework
+ */
+@Provider
+@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.WILDCARD})
+public class DataBindingJAXRSReader<T> extends DataBindingJAXRSProvider implements MessageBodyReader<T> {
+
+ public DataBindingJAXRSReader(ExtensionPointRegistry registry) {
+ super(registry);
+ }
+
+ public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+// DataType dataType = createDataType(type, genericType);
+ return supports(type, genericType, annotations, mediaType);
+ }
+
+ public T readFrom(Class<T> type,
+ Type genericType,
+ Annotation[] annotations,
+ MediaType mediaType,
+ MultivaluedMap<String, String> httpHeaders,
+ InputStream entityStream) throws IOException, WebApplicationException {
+
+ Object source = entityStream;
+ DataType targetDataType = createDataType(type, genericType);
+
+ String dataBinding = null;
+
+ mediaType = new MediaType(mediaType.getType(), mediaType.getSubtype());
+ // FIXME: [rfeng] This is a hack to handle application/json
+ if (MediaType.APPLICATION_JSON_TYPE.equals(mediaType)) {
+ dataBinding = mediaType.toString() + "#" + InputStream.class.getName();
+ } else if ("application/x-protobuf".equals(mediaType.toString())) {
+ dataBinding = mediaType.toString() + "#" + InputStream.class.getName();
+ }
+ else if (MediaType.APPLICATION_XML_TYPE.equals(mediaType) || MediaType.TEXT_XML_TYPE.equals(mediaType)) {
+ dataBinding = InputStream.class.getName();
+ } else {
+ dataBinding = targetDataType.getDataBinding();
+ source = convert(entityStream, mediaType.toString(), type);
+ return (T) source;
+ }
+ DataType sourceDataType =
+ new DataTypeImpl(dataBinding, InputStream.class, InputStream.class, InputStream.class);
+
+ Object result = mediator.mediate(source, sourceDataType, targetDataType, Collections.<String, Object>emptyMap());
+ return (T)result;
+ }
+
+
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java
new file mode 100644
index 0000000000..ab4173939e
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java
@@ -0,0 +1,91 @@
+/*
+ * 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.rest.provider;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+
+/**
+ * The generic JAX-RS message body writer based on Tuscany's databindingframework
+ */
+@Provider
+@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.WILDCARD})
+public class DataBindingJAXRSWriter<T> extends DataBindingJAXRSProvider implements MessageBodyWriter<T> {
+
+ public DataBindingJAXRSWriter(ExtensionPointRegistry registry) {
+ super(registry);
+ }
+
+ public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return -1;
+ }
+
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ // DataType dataType = createDataType(type, genericType);
+ return supports(type, genericType, annotations, mediaType);
+ }
+
+ public void writeTo(T t,
+ Class<?> type,
+ Type genericType,
+ Annotation[] annotations,
+ MediaType mediaType,
+ MultivaluedMap<String, Object> httpHeaders,
+ OutputStream entityStream) throws IOException, WebApplicationException {
+ DataType dataType = createDataType(type, genericType);
+ mediaType = new MediaType(mediaType.getType(), mediaType.getSubtype());
+ String dataBinding = OutputStream.class.getName();
+ // FIXME: [rfeng] This is a hack to handle application/json
+ if (MediaType.APPLICATION_JSON_TYPE.equals(mediaType)) {
+ dataBinding = mediaType.toString() + "#" + OutputStream.class.getName();
+ } else if (MediaType.APPLICATION_XML_TYPE.equals(mediaType) || MediaType.TEXT_XML_TYPE.equals(mediaType)) {
+ dataBinding = OutputStream.class.getName();
+ } else if ("application/x-protobuf".equals(mediaType.toString())) {
+ dataBinding = mediaType.toString() + "#" + OutputStream.class.getName();
+ }
+ else {
+ dataBinding = dataType.getDataBinding();
+ write(entityStream, t, type);
+ return;
+ }
+ DataType targetDataType =
+ new DataTypeImpl(dataBinding, OutputStream.class, OutputStream.class, OutputStream.class);
+ // dataBindingExtensionPoint.introspectType(targetDataType, null);
+
+ introspectAnnotations(annotations, targetDataType);
+
+ mediator.mediate(t, entityStream, dataType, targetDataType, Collections.<String, Object> emptyMap());
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/JAXRSHelper.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/JAXRSHelper.java
new file mode 100644
index 0000000000..2bf95f0677
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/JAXRSHelper.java
@@ -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.
+ */
+
+package org.apache.tuscany.sca.binding.rest.provider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.Path;
+
+/**
+ * A utility class that deals with JAX-RS annotations
+ */
+public class JAXRSHelper {
+ private JAXRSHelper() {
+
+ }
+
+ /**
+ * A resource class is a Java class that uses JAX-RS annotations to implement a corresponding Web resource.
+ * Resource classes are POJOs that have at least one method annotated with @Path or a request method designator.
+ * @param cls
+ * @return
+ */
+ public static boolean isJAXRSResource(Class<?> cls) {
+ for (Method method : cls.getMethods()) {
+ if (method.isAnnotationPresent(Path.class)) {
+ return true;
+ }
+ if (isResourceMethod(method)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Root resource class is a resource class annotated with @Path. Root resource classes provide the roots of the
+ * resource class tree and provide access to sub-resources
+ * @param cls
+ * @return
+ */
+ public static boolean isJAXRSRootResource(Class<?> cls) {
+ return cls.isAnnotationPresent(Path.class) && isJAXRSResource(cls);
+ }
+
+ public static boolean isResourceMethod(Method method) {
+ for (Annotation a : method.getAnnotations()) {
+ Class<?> annotationType = a.annotationType();
+ if (annotationType == HttpMethod.class) {
+ return true;
+ }
+ // Http method related annotations such as @GET, @POST will have itself annotated with
+ // @HttpMethod
+ HttpMethod m = a.annotationType().getAnnotation(HttpMethod.class);
+ if (m != null) {
+ return true;
+ }
+ }
+ return false;
+
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java
new file mode 100644
index 0000000000..7827092501
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java
@@ -0,0 +1,308 @@
+/*
+ * 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.rest.provider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.http.client.HttpClient;
+import org.apache.tuscany.sca.assembly.EndpointReference;
+import org.apache.tuscany.sca.assembly.WireFormat;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.binding.rest.wireformat.json.JSONWireFormat;
+import org.apache.tuscany.sca.binding.rest.wireformat.xml.XMLWireFormat;
+import org.apache.tuscany.sca.common.http.HTTPCacheContext;
+import org.apache.tuscany.sca.common.http.HTTPHeader;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.wink.client.ApacheHttpClientConfig;
+import org.apache.wink.client.ClientConfig;
+import org.apache.wink.client.Resource;
+import org.apache.wink.client.RestClient;
+import org.apache.wink.client.handlers.BasicAuthSecurityHandler;
+
+/**
+ *
+ */
+public class RESTBindingInvoker implements Invoker {
+ private ExtensionPointRegistry registry;
+ private EndpointReference endpointReference;
+ private RESTBinding binding;
+ private Operation operation;
+ private RestClient restClient;
+ private String httpMethod;
+ private Class<?> responseType;
+
+ public RESTBindingInvoker(ExtensionPointRegistry registry, EndpointReference endpointReference, RESTBinding binding, Operation operation, HttpClient httpClient) {
+ super();
+ this.registry = registry;
+ this.endpointReference = endpointReference;
+ this.binding = binding;
+ this.operation = operation;
+ this.restClient = createRestClient(httpClient);
+ }
+
+ private static Map<Class<?>, String> mapping = new HashMap<Class<?>, String>();
+ static {
+ mapping.put(GET.class, HttpMethod.GET);
+ mapping.put(POST.class, HttpMethod.POST);
+ mapping.put(PUT.class, HttpMethod.PUT);
+ mapping.put(DELETE.class, HttpMethod.DELETE);
+ mapping.put(HEAD.class, HttpMethod.HEAD);
+ mapping.put(OPTIONS.class, HttpMethod.OPTIONS);
+ }
+
+ private static <T extends Annotation> T getAnnotation(Annotation[] annotations, Class<T> type) {
+ for (Annotation a : annotations) {
+ if (a.annotationType() == type) {
+ return type.cast(a);
+ }
+ }
+ return null;
+ }
+
+ private RestClient createRestClient(HttpClient httpClient) {
+ ClientConfig config = new ApacheHttpClientConfig(httpClient);
+
+ // configureBasicAuth(config, userName, password);
+
+ config.applications(new Application() {
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<Object> getSingletons() {
+ Set<Object> providers = new HashSet<Object>();
+ providers.add(new DataBindingJAXRSReader(registry));
+ providers.add(new DataBindingJAXRSWriter(registry));
+ return providers;
+ }
+
+ });
+
+ config.readTimeout(binding.getReadTimeout());
+ RestClient client = new RestClient(config);
+
+ // Default to GET for RPC
+ httpMethod = HttpMethod.GET;
+
+ for (Map.Entry<Class<?>, String> e : mapping.entrySet()) {
+ if (operation.getAttributes().get(e.getKey()) != null) {
+ httpMethod = e.getValue();
+ break;
+ }
+ }
+
+ if (operation.getOutputType() != null && !operation.getOutputType().getLogical().isEmpty()) {
+ responseType = operation.getOutputType().getLogical().get(0).getPhysical();
+ } else {
+ responseType = null;
+ }
+ return client;
+ }
+
+ private void configureBasicAuth(ClientConfig config, String userName, String password) {
+ BasicAuthSecurityHandler basicAuthSecurityHandler = new BasicAuthSecurityHandler();
+ basicAuthSecurityHandler.setUserName(userName);
+ basicAuthSecurityHandler.setPassword(password);
+ config.handlers(basicAuthSecurityHandler);
+ }
+
+ public Message invoke(Message msg) {
+
+ Object entity = null;
+ Object[] args = msg.getBody();
+
+ URI uri = URI.create(endpointReference.getDeployedURI());
+ UriBuilder uriBuilder = UriBuilder.fromUri(uri);
+
+ Method method = ((JavaOperation)operation).getJavaMethod();
+
+ if (method.isAnnotationPresent(Path.class)) {
+ // Only for resource method
+ uriBuilder.path(method);
+ }
+
+ if (!JAXRSHelper.isResourceMethod(method)) {
+ // This is RPC over GET
+ uriBuilder.replaceQueryParam("method", method.getName());
+ }
+
+ Map<String, Object> pathParams = new HashMap<String, Object>();
+ Map<String, Object> matrixParams = new HashMap<String, Object>();
+ Map<String, Object> queryParams = new HashMap<String, Object>();
+ Map<String, Object> headerParams = new HashMap<String, Object>();
+ Map<String, Object> formParams = new HashMap<String, Object>();
+ Map<String, Object> cookieParams = new HashMap<String, Object>();
+
+ for (int i = 0; i < method.getParameterTypes().length; i++) {
+ boolean isEntity = true;
+ Annotation[] annotations = method.getParameterAnnotations()[i];
+ PathParam pathParam = getAnnotation(annotations, PathParam.class);
+ if (pathParam != null) {
+ isEntity = false;
+ pathParams.put(pathParam.value(), args[i]);
+ }
+ MatrixParam matrixParam = getAnnotation(annotations, MatrixParam.class);
+ if (matrixParam != null) {
+ isEntity = false;
+ matrixParams.put(matrixParam.value(), args[i]);
+ }
+ QueryParam queryParam = getAnnotation(annotations, QueryParam.class);
+ if (queryParam != null) {
+ isEntity = false;
+ queryParams.put(queryParam.value(), args[i]);
+ }
+ HeaderParam headerParam = getAnnotation(annotations, HeaderParam.class);
+ if (headerParam != null) {
+ isEntity = false;
+ headerParams.put(headerParam.value(), args[i]);
+ }
+ FormParam formParam = getAnnotation(annotations, FormParam.class);
+ if (formParam != null) {
+ isEntity = false;
+ formParams.put(formParam.value(), args[i]);
+ }
+ CookieParam cookieParam = getAnnotation(annotations, CookieParam.class);
+ if (cookieParam != null) {
+ isEntity = false;
+ cookieParams.put(cookieParam.value(), args[i]);
+ }
+ isEntity = (getAnnotation(annotations, Context.class) == null);
+ if (isEntity) {
+ entity = args[i];
+ }
+ }
+
+ for (Map.Entry<String, Object> p : queryParams.entrySet()) {
+ uriBuilder.replaceQueryParam(p.getKey(), p.getValue());
+ }
+ for (Map.Entry<String, Object> p : matrixParams.entrySet()) {
+ uriBuilder.replaceMatrixParam(p.getKey(), p.getValue());
+ }
+
+ uri = uriBuilder.buildFromMap(pathParams);
+ Resource resource = restClient.resource(uri);
+
+ for (Map.Entry<String, Object> p : headerParams.entrySet()) {
+ resource.header(p.getKey(), String.valueOf(p.getValue()));
+ }
+
+ for (Map.Entry<String, Object> p : cookieParams.entrySet()) {
+ Cookie cookie = new Cookie(p.getKey(), String.valueOf(p.getValue()));
+ resource.cookie(cookie);
+ }
+
+ resource.contentType(getContentType());
+ resource.accept(getAccepts());
+
+ //handles declarative headers configured on the composite
+ for (HTTPHeader header : binding.getHttpHeaders()) {
+ //treat special headers that need to be calculated
+ if (header.getName().equalsIgnoreCase("Expires")) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(new Date());
+
+ calendar.add(Calendar.HOUR, Integer.parseInt(header.getValue()));
+
+ resource.header("Expires", HTTPCacheContext.RFC822DateFormat.format(calendar.getTime()));
+ } else {
+ //default behaviour to pass the header value to HTTP response
+ resource.header(header.getName(), header.getValue());
+ }
+ }
+
+ Object result = resource.invoke(httpMethod, responseType, entity);
+ msg.setBody(result);
+ return msg;
+ }
+
+ private String getContentType() {
+ String contentType = MediaType.APPLICATION_OCTET_STREAM;
+ Consumes consumes = ((JavaOperation)operation).getJavaMethod().getAnnotation(Consumes.class);
+ if (consumes != null && consumes.value().length > 0) {
+ contentType = consumes.value()[0];
+ }
+ WireFormat wf = binding.getRequestWireFormat();
+ if (wf != null) {
+ if (XMLWireFormat.REST_WIREFORMAT_XML_QNAME.equals(wf.getSchemaName())) {
+ contentType = MediaType.APPLICATION_XML;
+ } else if (JSONWireFormat.REST_WIREFORMAT_JSON_QNAME.equals(wf.getSchemaName())) {
+ contentType = MediaType.APPLICATION_JSON;
+ }
+ }
+ return contentType;
+ }
+
+ private String[] getAccepts() {
+ String accepts[] = {MediaType.APPLICATION_OCTET_STREAM};
+ Produces produces = ((JavaOperation)operation).getJavaMethod().getAnnotation(Produces.class);
+ if (produces != null) {
+ accepts = produces.value();
+ }
+ WireFormat wf = binding.getResponseWireFormat();
+ if (wf != null) {
+ if (XMLWireFormat.REST_WIREFORMAT_XML_QNAME.equals(wf.getSchemaName())) {
+ accepts = new String[] {MediaType.APPLICATION_XML};
+ } else if (JSONWireFormat.REST_WIREFORMAT_JSON_QNAME.equals(wf.getSchemaName())) {
+ accepts = new String[] {MediaType.APPLICATION_JSON};
+ }
+ }
+ return accepts;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingListenerServlet.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingListenerServlet.java
new file mode 100644
index 0000000000..6612ca8df6
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingListenerServlet.java
@@ -0,0 +1,583 @@
+/*
+ * 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.rest.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLDecoder;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.common.http.HTTPCacheContext;
+import org.apache.tuscany.sca.common.http.HTTPContentTypeMapper;
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.common.http.HTTPHeader;
+import org.apache.tuscany.sca.common.http.cors.CORSHeaderProcessor;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+
+/**
+ * Servlet responsible for dispatching HTTP requests to the
+ * target component implementation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class RESTBindingListenerServlet extends HttpServlet {
+ private static final long serialVersionUID = 2865466417329430610L;
+
+ transient private MessageFactory messageFactory;
+
+ transient private RESTBinding binding;
+ transient private Invoker bindingInvoker;
+
+ private Invoker invoker;
+ private Invoker getInvoker;
+ private Invoker conditionalGetInvoker;
+ private Invoker putInvoker;
+ private Invoker conditionalPutInvoker;
+ private Invoker postInvoker;
+ private Invoker conditionalPostInvoker;
+ private Invoker deleteInvoker;
+ private Invoker conditionalDeleteInvoker;
+
+ /**
+ * Constructs a new RESTServiceListenerServlet.
+ */
+ public RESTBindingListenerServlet(Binding binding, Invoker bindingInvoker, MessageFactory messageFactory) {
+ this.binding = (RESTBinding) binding;
+ this.bindingInvoker = bindingInvoker;
+ this.messageFactory = messageFactory;
+ }
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (binding.isCORS()) {
+ CORSHeaderProcessor.processCORS(binding.getCORSConfiguration(), request, response);
+ }
+ if( binding.getOperationSelector() != null || binding.getRequestWireFormat() != null) {
+ HTTPContext bindingContext = new HTTPContext();
+ bindingContext.setHttpRequest(request);
+ bindingContext.setHttpResponse(response);
+
+ // Dispatch the service interaction to the service invoker
+ Message requestMessage = messageFactory.createMessage();
+ requestMessage.setBindingContext(bindingContext);
+
+ requestMessage.setBody(new Object[] {request.getInputStream()});
+
+ Message responseMessage = bindingInvoker.invoke(requestMessage);
+
+ // return response to client
+ if (responseMessage.isFault()) {
+ // Turn a fault into an exception
+ Throwable e = (Throwable)responseMessage.getBody();
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+ } else {
+
+ for(HTTPHeader header : binding.getHttpHeaders()) {
+ //treat special headers that need to be calculated
+ if(header.getName().equalsIgnoreCase("Expires")) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(new Date());
+
+ calendar.add(Calendar.HOUR, Integer.parseInt(header.getValue()));
+
+ response.setHeader("Expires", HTTPCacheContext.RFC822DateFormat.format( calendar.getTime() ));
+ } else {
+ //default behaviour to pass the header value to HTTP response
+ response.setHeader(header.getName(), header.getValue());
+ }
+
+ }
+
+ //handle void operations
+ write(response.getOutputStream(), responseMessage.getBody());
+ response.getOutputStream().flush();
+ response.getOutputStream().close();
+ }
+ } else {
+ super.service(request, response);
+ }
+
+
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ // Get the request path
+ String pathInfo = request.getPathInfo();
+ if (pathInfo == null || pathInfo.length() == 0) {
+ // Redirect to a URL ending with / to make relative hrefs work
+ // relative to the served resource.
+ response.sendRedirect(request.getRequestURL().append('/').toString());
+ return;
+ }
+ String path = URLDecoder.decode(pathInfo, "UTF-8");
+
+ // Invoke the get operation on the service implementation
+ Message requestMessage = messageFactory.createMessage();
+
+ String id = path.substring(1);
+
+ Message responseMessage = null;
+ HTTPCacheContext cacheContext = null;
+ try {
+ cacheContext = HTTPCacheContext.createCacheContextFromRequest(request);
+ } catch (ParseException e) {
+
+ }
+
+ // Route message based on availability of cache info and cache methods
+ if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalGetInvoker != null )) {
+ if(id != null && id.length() > 0) {
+ requestMessage.setBody(new Object[] {id, cacheContext});
+ } else {
+ requestMessage.setBody(new Object[] {cacheContext});
+ }
+
+ responseMessage = conditionalGetInvoker.invoke(requestMessage);
+ } else {
+ if(id != null && id.length() > 0) {
+ requestMessage.setBody(new Object[] {id});
+ } else {
+ //requestMessage.setBody(new Object[] {id});
+ }
+
+ responseMessage = getInvoker.invoke(requestMessage);
+ }
+
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+
+ int index = -1;
+ if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) {
+ if ( index > -1 ) {
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index ));
+ } else {
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED );
+ }
+ return;
+ } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) {
+ if ( index > -1 ) {
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index ));
+ } else {
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED );
+ }
+ return;
+ }
+
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+
+ if(response.getContentType() == null || response.getContentType().length() == 0){
+ // Calculate content-type based on extension
+ String contentType = HTTPContentTypeMapper.getContentType(id);
+ if(contentType != null && contentType.length() >0) {
+ response.setContentType(contentType);
+ }
+ }
+
+ // Write the response from the service implementation to the response
+ // output stream
+ InputStream is = (InputStream)responseMessage.getBody();
+ OutputStream os = response.getOutputStream();
+ byte[] buffer = new byte[2048];
+ for (;;) {
+ int n = is.read(buffer);
+ if (n <= 0)
+ break;
+ os.write(buffer, 0, n);
+ }
+ os.flush();
+ os.close();
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ if (path.length() ==0) {
+ // Redirect to a URL ending with / to make relative hrefs work
+ // relative to the served resource.
+ response.sendRedirect(request.getRequestURL().append('/').toString());
+ return;
+ }
+
+ // Invoke the get operation on the service implementation
+ Message requestMessage = messageFactory.createMessage();
+ String id = path.substring(1);
+
+ Message responseMessage = null;
+ HTTPCacheContext cacheContext = null;
+ try {
+ cacheContext = HTTPCacheContext.createCacheContextFromRequest(request);
+ } catch (ParseException e) {
+ }
+
+ // Route message based on availability of cache info and cache methods
+ if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalDeleteInvoker != null )) {
+ requestMessage.setBody(new Object[] {id, cacheContext});
+ responseMessage = conditionalDeleteInvoker.invoke(requestMessage);
+ } else {
+ requestMessage.setBody(new Object[] {id});
+ responseMessage = deleteInvoker.invoke(requestMessage);
+ }
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+
+ int index = -1;
+ if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) {
+ if ( index > -1 ) {
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index ));
+ } else {
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED );
+ }
+ return;
+ } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) {
+ if ( index > -1 ) {
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index ));
+ } else {
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED );
+ }
+ return;
+ }
+
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+
+ // Write the response from the service implementation to the response
+ // output stream
+ InputStream is = (InputStream)responseMessage.getBody();
+ OutputStream os = response.getOutputStream();
+ byte[] buffer = new byte[2048];
+ for (;;) {
+ int n = is.read(buffer);
+ if (n <= 0)
+ break;
+ os.write(buffer, 0, n);
+ }
+ os.flush();
+ os.close();
+ }
+
+ @Override
+ protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ if (path.length() ==0) {
+ // Redirect to a URL ending with / to make relative hrefs work
+ // relative to the served resource.
+ response.sendRedirect(request.getRequestURL().append('/').toString());
+ return;
+ }
+
+ // Invoke the get operation on the service implementation
+ Message requestMessage = messageFactory.createMessage();
+ String id = path.substring(1);
+
+ Message responseMessage = null;
+ HTTPCacheContext cacheContext = null;
+ try {
+ cacheContext = HTTPCacheContext.createCacheContextFromRequest(request);
+ } catch (ParseException e) {
+ }
+
+ // Route message based on availability of cache info and cache methods
+ if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalPutInvoker != null )) {
+ requestMessage.setBody(new Object[] {id, cacheContext});
+ responseMessage = conditionalPutInvoker.invoke(requestMessage);
+ } else {
+ requestMessage.setBody(new Object[] {id});
+ responseMessage = putInvoker.invoke(requestMessage);
+ }
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+
+ int index = -1;
+ if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) {
+ if ( index > -1 ) {
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index ));
+ } else {
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED );
+ }
+ return;
+ } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) {
+ if ( index > -1 ) {
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index ));
+ } else {
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED );
+ }
+ return;
+ }
+
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+
+ // Write the response from the service implementation to the response
+ // output stream
+ InputStream is = (InputStream)responseMessage.getBody();
+ OutputStream os = response.getOutputStream();
+ byte[] buffer = new byte[2048];
+ for (;;) {
+ int n = is.read(buffer);
+ if (n <= 0)
+ break;
+ os.write(buffer, 0, n);
+ }
+ os.flush();
+ os.close();
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ if (path.length() ==0) {
+ // Redirect to a URL ending with / to make relative hrefs work
+ // relative to the served resource.
+ response.sendRedirect(request.getRequestURL().append('/').toString());
+ return;
+ }
+
+ // Invoke the get operation on the service implementation
+ Message requestMessage = messageFactory.createMessage();
+ // String id = path.substring(1);
+
+ Message responseMessage = null;
+ HTTPCacheContext cacheContext = null;
+ try {
+ cacheContext = HTTPCacheContext.createCacheContextFromRequest(request);
+ } catch (ParseException e) {
+ }
+
+ // Route message based on availability of cache info and cache methods
+ if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalPostInvoker != null )) {
+ requestMessage.setBody(new Object[] {cacheContext});
+ responseMessage = conditionalPostInvoker.invoke(requestMessage);
+ } else {
+ requestMessage.setBody(new Object[] {});
+ responseMessage = postInvoker.invoke(requestMessage);
+ }
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+
+ int index = -1;
+ if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) {
+ if ( index > -1 )
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index ));
+ else
+ response.sendError( HttpServletResponse.SC_NOT_MODIFIED );
+ return;
+ } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) {
+ if ( index > -1 )
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index ));
+ else
+ response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED );
+ return;
+ }
+
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+
+
+ // Test if the ETag and LastModified are returned as a cache context.
+ Object body = responseMessage.getBody();
+ if ( body.getClass() == HTTPCacheContext.class ) {
+ // Transfer to header if so.
+ HTTPCacheContext cc = (HTTPCacheContext)responseMessage.getBody();
+ if (( cc != null ) && ( cc.isEnabled() )) {
+ String eTag = cc.getETag();
+ if ( eTag != null ) {
+ response.setHeader( "ETag", cc.getETag() );
+ }
+ String lastModified = cc.getLastModified();
+ if ( lastModified != null) {
+ response.setHeader( "LastModified", cc.getLastModified() );
+ }
+ }
+ }
+ }
+
+
+ public void setInvoker(Invoker invoker) {
+ this.invoker = invoker;
+ }
+
+ public Invoker getInvoker() {
+ return invoker;
+ }
+
+
+ /**
+ * @return the getInvoker
+ */
+ public Invoker getGetInvoker() {
+ return getInvoker;
+ }
+
+ /**
+ * @param getInvoker the getInvoker to set
+ */
+ public void setGetInvoker(Invoker getInvoker) {
+ this.getInvoker = getInvoker;
+ }
+
+ /**
+ * @return the conditionalGetInvoker
+ */
+ public Invoker getConditionalGetInvoker() {
+ return conditionalGetInvoker;
+ }
+
+ /**
+ * @param conditionalGetInvoker the conditionalGetInvoker to set
+ */
+ public void setConditionalGetInvoker(Invoker conditionalGetInvoker) {
+ this.conditionalGetInvoker = conditionalGetInvoker;
+ }
+
+ /**
+ * @return the putInvoker
+ */
+ public Invoker getPutInvoker() {
+ return putInvoker;
+ }
+
+ /**
+ * @param putInvoker the putInvoker to set
+ */
+ public void setPutInvoker(Invoker putInvoker) {
+ this.putInvoker = putInvoker;
+ }
+
+ /**
+ * @return the conditionalPutInvoker
+ */
+ public Invoker getConditionalPutInvoker() {
+ return conditionalPutInvoker;
+ }
+
+ /**
+ * @param conditionalPutInvoker the conditionalPutInvoker to set
+ */
+ public void setConditionalPutInvoker(Invoker conditionalPutInvoker) {
+ this.conditionalPutInvoker = conditionalPutInvoker;
+ }
+
+ /**
+ * @return the postInvoker
+ */
+ public Invoker getPostInvoker() {
+ return postInvoker;
+ }
+
+ /**
+ * @param postInvoker the postInvoker to set
+ */
+ public void setPostInvoker(Invoker postInvoker) {
+ this.postInvoker = postInvoker;
+ }
+
+ /**
+ * @return the conditionalPostInvoker
+ */
+ public Invoker getConditionalPostInvoker() {
+ return conditionalPostInvoker;
+ }
+
+ /**
+ * @param conditionalPostInvoker the conditionalPostInvoker to set
+ */
+ public void setConditionalPostInvoker(Invoker conditionalPostInvoker) {
+ this.conditionalPostInvoker = conditionalPostInvoker;
+ }
+
+ /**
+ * @return the deleteInvoker
+ */
+ public Invoker getDeleteInvoker() {
+ return deleteInvoker;
+ }
+
+ /**
+ * @param deleteInvoker the deleteInvoker to set
+ */
+ public void setDeleteInvoker(Invoker deleteInvoker) {
+ this.deleteInvoker = deleteInvoker;
+ }
+
+ /**
+ * @return the conditionalDeleteInvoker
+ */
+ public Invoker getConditionalDeleteInvoker() {
+ return conditionalDeleteInvoker;
+ }
+
+ /**
+ * @param conditionalDeleteInvoker the conditionalDeleteInvoker to set
+ */
+ public void setConditionalDeleteInvoker(Invoker conditionalDeleteInvoker) {
+ this.conditionalDeleteInvoker = conditionalDeleteInvoker;
+ }
+
+ /**
+ *
+ * Utility methods
+ *
+ */
+
+
+
+ private void write(OutputStream out, Object obj) throws IOException {
+ if (obj == null) {
+ return;
+ }
+ if (obj instanceof String) {
+ out.write(((String)obj).getBytes("UTF-8"));
+ } else if (obj instanceof byte[]) {
+ out.write((byte[])obj);
+ } else if (obj instanceof InputStream) {
+ byte[] buf = new byte[8192];
+ InputStream in = (InputStream)obj;
+ while (true) {
+ int size = in.read(buf);
+ if (size < 0) {
+ break;
+ }
+ out.write(buf, 0, size);
+ }
+ } else {
+ out.write(obj.toString().getBytes("UTF-8"));
+ }
+ }
+
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingProviderFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingProviderFactory.java
new file mode 100644
index 0000000000..0f5047deef
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingProviderFactory.java
@@ -0,0 +1,63 @@
+/*
+ * 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.rest.provider;
+
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.host.http.ServletHost;
+import org.apache.tuscany.sca.host.http.ServletHostHelper;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.provider.BindingProviderFactory;
+import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.provider.ServiceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+
+
+/**
+ * Factory for REST binding providers.
+ *
+ * @version $Rev$ $Date$
+ */
+public class RESTBindingProviderFactory implements BindingProviderFactory<RESTBinding> {
+ private ExtensionPointRegistry extensionPoints;
+ private MessageFactory messageFactory;
+ private ServletHost servletHost;
+
+ public RESTBindingProviderFactory(ExtensionPointRegistry extensionPoints) {
+ this.extensionPoints = extensionPoints;
+ this.servletHost = ServletHostHelper.getServletHost(extensionPoints);
+ FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class);
+ messageFactory = modelFactories.getFactory(MessageFactory.class);
+ }
+
+ public ReferenceBindingProvider createReferenceBindingProvider(RuntimeEndpointReference endpointReference) {
+ return new RESTReferenceBindingProvider(extensionPoints, endpointReference);
+ }
+
+ public ServiceBindingProvider createServiceBindingProvider(RuntimeEndpoint endpoint) {
+ return new RESTServiceBindingProvider(endpoint, extensionPoints, messageFactory, servletHost);
+ }
+
+ public Class<RESTBinding> getModelType() {
+ return RESTBinding.class;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTReferenceBindingProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTReferenceBindingProvider.java
new file mode 100644
index 0000000000..07dbeafce6
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTReferenceBindingProvider.java
@@ -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.
+ */
+
+package org.apache.tuscany.sca.binding.rest.provider;
+
+import org.apache.http.client.HttpClient;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.host.http.client.HttpClientFactory;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.provider.EndpointReferenceProvider;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+
+/**
+ *
+ */
+public class RESTReferenceBindingProvider implements EndpointReferenceProvider {
+ private ExtensionPointRegistry registry;
+ private RuntimeEndpointReference endpointReference;
+
+ private HttpClientFactory httpClientFactory;
+ private HttpClient httpClient;
+
+ public RESTReferenceBindingProvider(ExtensionPointRegistry registry, RuntimeEndpointReference endpointReference) {
+ super();
+ this.registry = registry;
+ this.endpointReference = endpointReference;
+ this.httpClientFactory = HttpClientFactory.getInstance(registry);
+ }
+
+ public void configure() {
+ }
+
+ public Invoker createInvoker(Operation operation) {
+ return new RESTBindingInvoker(registry, endpointReference, (RESTBinding)endpointReference.getBinding(), operation, httpClient);
+ }
+
+ public InterfaceContract getBindingInterfaceContract() {
+ return endpointReference.getComponentReferenceInterfaceContract();
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+ public void start() {
+ // Create an HTTP client
+ httpClient = httpClientFactory.createHttpClient();
+ }
+
+ public void stop() {
+ if (httpClient != null) {
+ httpClient.getConnectionManager().shutdown();
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java
new file mode 100644
index 0000000000..2b3d0f7e41
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java
@@ -0,0 +1,376 @@
+/*
+ * 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.rest.provider;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Servlet;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.binding.rest.wireformat.json.JSONWireFormat;
+import org.apache.tuscany.sca.binding.rest.wireformat.xml.XMLWireFormat;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.host.http.ServletHost;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.jaxrs.RootResourceClassGenerator;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.InvocationChain;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.invocation.Phase;
+import org.apache.tuscany.sca.provider.EndpointProvider;
+import org.apache.tuscany.sca.provider.OperationSelectorProvider;
+import org.apache.tuscany.sca.provider.OperationSelectorProviderFactory;
+import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint;
+import org.apache.tuscany.sca.provider.WireFormatProvider;
+import org.apache.tuscany.sca.provider.WireFormatProviderFactory;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+import org.apache.wink.server.utils.RegistrationUtils;
+import org.oasisopen.sca.ServiceRuntimeException;
+
+/**
+ * Implementation of an HTTP binding provider.
+ *
+ * @version $Rev$ $Date$
+ */
+public class RESTServiceBindingProvider implements EndpointProvider {
+ private static Map<QName, String> wireFormatToMediaTypeMapping = new HashMap<QName, String>();
+
+ static {
+ wireFormatToMediaTypeMapping.put(JSONWireFormat.REST_WIREFORMAT_JSON_QNAME, MediaType.APPLICATION_JSON);
+ wireFormatToMediaTypeMapping.put(XMLWireFormat.REST_WIREFORMAT_XML_QNAME, MediaType.APPLICATION_XML);
+ }
+
+ private ExtensionPointRegistry extensionPoints;
+
+ private RuntimeEndpoint endpoint;
+ private RuntimeComponent component;
+ private RuntimeComponentService service;
+ private InterfaceContract serviceContract;
+ private RESTBinding binding;
+ private MessageFactory messageFactory;
+
+ private OperationSelectorProvider osProvider;
+ private WireFormatProvider wfProvider;
+ private WireFormatProvider wfResponseProvider;
+
+ private ServletHost servletHost;
+ private String servletMapping;
+ private RESTBindingListenerServlet bindingListenerServlet;
+
+ private SimpleApplication application;
+
+ public RESTServiceBindingProvider(RuntimeEndpoint endpoint,
+ ExtensionPointRegistry extensionPoints,
+ MessageFactory messageFactory,
+ ServletHost servletHost) {
+
+ this.endpoint = endpoint;
+ this.component = (RuntimeComponent)endpoint.getComponent();
+ this.service = (RuntimeComponentService)endpoint.getService();
+ this.binding = (RESTBinding)endpoint.getBinding();
+
+ this.extensionPoints = extensionPoints;
+ this.messageFactory = messageFactory;
+ this.servletHost = servletHost;
+
+ // retrieve operation selector and wire format service providers
+
+ ProviderFactoryExtensionPoint providerFactories =
+ extensionPoints.getExtensionPoint(ProviderFactoryExtensionPoint.class);
+
+ if (binding.getOperationSelector() != null) {
+ // Configure the interceptors for operation selection
+ OperationSelectorProviderFactory osProviderFactory =
+ (OperationSelectorProviderFactory)providerFactories.getProviderFactory(binding.getOperationSelector()
+ .getClass());
+ if (osProviderFactory != null) {
+ this.osProvider = osProviderFactory.createServiceOperationSelectorProvider(endpoint);
+ }
+ }
+
+ if (binding.getRequestWireFormat() != null) {
+ // Configure the interceptors for wire format
+ WireFormatProviderFactory wfProviderFactory =
+ (WireFormatProviderFactory)providerFactories.getProviderFactory(binding.getRequestWireFormat()
+ .getClass());
+ if (wfProviderFactory != null) {
+ this.wfProvider = wfProviderFactory.createServiceWireFormatProvider(endpoint);
+ }
+ }
+
+ if (binding.getResponseWireFormat() != null) {
+ // Configure the interceptors for wire format
+ WireFormatProviderFactory wfProviderFactory =
+ (WireFormatProviderFactory)providerFactories.getProviderFactory(binding.getResponseWireFormat()
+ .getClass());
+ if (wfProviderFactory != null) {
+ this.wfResponseProvider = wfProviderFactory.createServiceWireFormatProvider(endpoint);
+ }
+ }
+
+ //clone the service contract to avoid databinding issues
+ try {
+ this.serviceContract = (InterfaceContract)service.getInterfaceContract().clone();
+
+ // configure data binding
+ if (wfProvider != null) {
+ wfProvider.configureWireFormatInterfaceContract(serviceContract);
+ }
+
+ if (wfResponseProvider != null) {
+ wfResponseProvider.configureWireFormatInterfaceContract(serviceContract);
+ }
+ } catch (CloneNotSupportedException e) {
+ this.serviceContract = service.getInterfaceContract();
+ }
+
+ }
+
+ public InterfaceContract getBindingInterfaceContract() {
+ return serviceContract;
+ }
+
+
+ /**
+ * Add specific rest interceptor to invocation chain
+ */
+ public void configure() {
+
+ InvocationChain bindingChain = endpoint.getBindingInvocationChain();
+
+ if (wfProvider != null) {
+ Interceptor interceptor = wfProvider.createInterceptor();
+ if (interceptor != null) {
+ bindingChain.addInterceptor(Phase.SERVICE_BINDING_WIREFORMAT, interceptor);
+ }
+ }
+
+ if (wfResponseProvider != null) {
+ Interceptor interceptor = wfResponseProvider.createInterceptor();
+ if (interceptor != null) {
+ bindingChain.addInterceptor(Phase.SERVICE_BINDING_WIREFORMAT, interceptor);
+ }
+
+ }
+
+ if (osProvider != null) {
+ Interceptor interceptor = osProvider.createInterceptor();
+ if (interceptor != null) {
+ bindingChain.addInterceptor(Phase.SERVICE_BINDING_OPERATION_SELECTOR, interceptor);
+ }
+ }
+
+ }
+
+ public void start() {
+ InvocationChain bindingChain = endpoint.getBindingInvocationChain();
+
+ application = registerWithJAXRS();
+ if (application != null) {
+ return;
+ }
+
+ // Get the invokers for the supported operations
+ Servlet servlet = null;
+ Invoker bindingInvoker = bindingChain.getHeadInvoker();
+ bindingListenerServlet = new RESTBindingListenerServlet(binding, bindingInvoker, messageFactory);
+ for (InvocationChain invocationChain : endpoint.getInvocationChains()) {
+
+ Operation operation = invocationChain.getTargetOperation();
+ Invoker serviceInvoker = invocationChain.getHeadInvoker();
+ String operationName = operation.getName();
+
+ if (binding.getOperationSelector() != null || binding.getRequestWireFormat() != null) {
+ bindingListenerServlet.setInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("get")) {
+ bindingListenerServlet.setGetInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("conditionalGet")) {
+ bindingListenerServlet.setConditionalGetInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("delete")) {
+ bindingListenerServlet.setDeleteInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("conditionalDelete")) {
+ bindingListenerServlet.setConditionalDeleteInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("put")) {
+ bindingListenerServlet.setPutInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("conditionalPut")) {
+ bindingListenerServlet.setConditionalPutInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("post")) {
+ bindingListenerServlet.setPostInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("conditionalPost")) {
+ bindingListenerServlet.setConditionalPostInvoker(serviceInvoker);
+ servlet = bindingListenerServlet;
+ } else if (operationName.equals("service")) {
+ servlet = new RESTServiceListenerServlet(binding, serviceInvoker, messageFactory);
+ break;
+ }
+ }
+ if (servlet == null) {
+ throw new IllegalStateException("No get or service method found on the service");
+ }
+
+ servletMapping = registerServlet(servlet);
+ }
+
+ public void stop() {
+ if (application != null) {
+ application.destroy();
+ }
+ // Unregister the Servlet from the Servlet host
+ servletHost.removeServletMapping(servletMapping);
+ }
+
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+
+ private String registerServlet(Servlet servlet) {
+ // Create our HTTP service listener Servlet and register it with the
+ // Servlet host
+ String servletMapping = binding.getURI();
+ if (!servletMapping.endsWith("/")) {
+ servletMapping += "/";
+ }
+ if (!servletMapping.endsWith("*")) {
+ servletMapping += "*";
+ }
+
+ String mappedURI = servletHost.addServletMapping(servletMapping, servlet);
+ String deployedURI = mappedURI;
+ if (deployedURI.endsWith("*")) {
+ deployedURI = deployedURI.substring(0, deployedURI.length() - 1);
+ }
+ binding.setURI(deployedURI);
+ endpoint.setDeployedURI(deployedURI);
+ return mappedURI;
+ }
+
+ /**
+ * Register a Tuscany REST Servlet to handle JAX-RS Resources on a binding endpoint
+ * @return
+ */
+ private SimpleApplication registerWithJAXRS() {
+ try {
+ SimpleApplication application = null;
+
+ JavaInterface javaInterface = (JavaInterface)endpoint.getComponentServiceInterfaceContract().getInterface();
+ Class<?> interfaze = javaInterface.getJavaClass();
+
+ // The @Path annotation can be from the binding uri
+ boolean isJAXRS = JAXRSHelper.isJAXRSResource(interfaze);
+ if (isJAXRS) {
+ application = new SimpleApplication(interfaze);
+
+ TuscanyRESTServlet restServlet = new TuscanyRESTServlet(extensionPoints, binding, application.resourceClass);
+
+ servletMapping = registerServlet(restServlet);
+
+ RegistrationUtils.registerApplication(application, restServlet.getServletContext());
+ return application;
+ } else {
+ return null;
+ }
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ private class SimpleApplication extends Application {
+ private Class<?> resourceClass;
+
+ public SimpleApplication(Class<?> resourceClass) {
+ super();
+ if (resourceClass.isInterface()) {
+ this.resourceClass = generateResourceClass(resourceClass);
+ } else {
+ this.resourceClass = resourceClass;
+ }
+ }
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ classes.add(resourceClass);
+ return classes;
+ }
+
+ private Class<?> generateResourceClass(Class<?> interfaze) {
+ try {
+ QName requestWireFormat = null;
+ if (binding.getRequestWireFormat() != null) {
+ requestWireFormat = binding.getRequestWireFormat().getSchemaName();
+ }
+ QName responeWireFormat = null;
+ if (binding.getResponseWireFormat() != null) {
+ responeWireFormat = binding.getRequestWireFormat().getSchemaName();
+ }
+ String requestMediaType = wireFormatToMediaTypeMapping.get(requestWireFormat);
+ String responseMediaType = wireFormatToMediaTypeMapping.get(responeWireFormat);
+
+ String uri = endpoint.getBinding().getURI();
+ String path = URI.create(uri).getPath();
+
+ // FIXME: [rfeng] We need to have a better way to deal with URI template for bindings
+ if (path.startsWith(servletHost.getContextPath())) {
+ path = path.substring(servletHost.getContextPath().length());
+ }
+ Class<?> cls =
+ RootResourceClassGenerator.generateRootResourceClass(interfaze,
+ path,
+ requestMediaType,
+ responseMediaType);
+ ProxyFactory proxyFactory = ExtensibleProxyFactory.getInstance(extensionPoints);
+ Object proxy = proxyFactory.createProxy(interfaze, endpoint);
+ RootResourceClassGenerator.injectProxy(cls, proxy);
+ return cls;
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ public void destroy() {
+ resourceClass = null;
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceListenerServlet.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceListenerServlet.java
new file mode 100644
index 0000000000..c8b0bbf595
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceListenerServlet.java
@@ -0,0 +1,122 @@
+/*
+ * 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.rest.provider;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.common.http.HTTPCacheContext;
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.common.http.HTTPHeader;
+import org.apache.tuscany.sca.common.http.cors.CORSHeaderProcessor;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+
+/**
+ * Servlet responsible for dispatching HTTP service requests to the
+ * target component implementation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class RESTServiceListenerServlet extends HttpServlet implements Servlet {
+
+ private static final long serialVersionUID = -5543706958107836637L;
+
+ transient private RESTBinding binding;
+ transient private ServletConfig config;
+ transient private MessageFactory messageFactory;
+ transient private Invoker serviceInvoker;
+
+ /**
+ * Constructs a new HTTPServiceListenerServlet.
+ */
+ public RESTServiceListenerServlet(Binding binding, Invoker serviceInvoker, MessageFactory messageFactory) {
+ this.binding = (RESTBinding) binding;
+ this.serviceInvoker = serviceInvoker;
+ this.messageFactory = messageFactory;
+ }
+
+ public ServletConfig getServletConfig() {
+ return config;
+ }
+
+ public String getServletInfo() {
+ return "";
+ }
+
+ public void init(ServletConfig config) throws ServletException {
+ this.config = config;
+ }
+
+ public void destroy() {
+
+ }
+
+ @Override
+ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (binding.isCORS()) {
+ CORSHeaderProcessor.processCORS(binding.getCORSConfiguration(), request, response);
+ }
+ HTTPContext bindingContext = new HTTPContext();
+ bindingContext.setHttpRequest(request);
+ bindingContext.setHttpResponse(response);
+
+ // Dispatch the service interaction to the service invoker
+ Message requestMessage = messageFactory.createMessage();
+ requestMessage.setBindingContext(bindingContext);
+ requestMessage.setBody(new Object[]{request, response});
+ Message responseMessage = serviceInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ // Turn a fault into an exception
+ //throw new ServletException((Throwable)responseMessage.getBody());
+ Throwable e = (Throwable)responseMessage.getBody();
+ ((HttpServletResponse)response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+ } else {
+ //handles declarative headers configured on the composite
+ for(HTTPHeader header : binding.getHttpHeaders()) {
+ //treat special headers that need to be calculated
+ if(header.getName().equalsIgnoreCase("Expires")) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(new Date());
+
+ calendar.add(Calendar.HOUR, Integer.parseInt(header.getValue()));
+
+ response.setHeader("Expires", HTTPCacheContext.RFC822DateFormat.format( calendar.getTime() ));
+ } else {
+ //default behaviour to pass the header value to HTTP response
+ response.setHeader(header.getName(), header.getValue());
+ }
+
+ }
+ }
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/TuscanyRESTServlet.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/TuscanyRESTServlet.java
new file mode 100644
index 0000000000..762e4378e0
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/TuscanyRESTServlet.java
@@ -0,0 +1,258 @@
+/*
+ * 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.rest.provider;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.common.http.HTTPCacheContext;
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.common.http.HTTPHeader;
+import org.apache.tuscany.sca.common.http.ThreadHTTPContext;
+import org.apache.tuscany.sca.common.http.cors.CORSHeaderProcessor;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.extensibility.ClassLoaderContext;
+import org.apache.wink.common.internal.registry.ProvidersRegistry;
+import org.apache.wink.common.model.wadl.WADLGenerator;
+import org.apache.wink.server.handlers.HandlersChain;
+import org.apache.wink.server.handlers.MessageContext;
+import org.apache.wink.server.handlers.ResponseHandler;
+import org.apache.wink.server.internal.DeploymentConfiguration;
+import org.apache.wink.server.internal.servlet.RestServlet;
+
+/**
+ *
+ */
+public class TuscanyRESTServlet extends RestServlet {
+ private static final long serialVersionUID = 89997233133964915L;
+
+ private static final Logger logger = Logger.getLogger(TuscanyRESTServlet.class.getName());
+
+ private static final Annotation[] annotations = new Annotation[0];
+
+
+ private ExtensionPointRegistry registry;
+ private RESTBinding binding;
+ private Class<?> resourceClass;
+
+ public TuscanyRESTServlet(ExtensionPointRegistry registry, Binding binding, Class<?> resourceClass) {
+ super();
+ this.registry = registry;
+ this.binding = (RESTBinding) binding;
+ this.resourceClass = resourceClass;
+ }
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ if (binding.isCORS()) {
+ /*
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
+ if (request.getMethod().equals("OPTIONS")) {
+ response.setHeader("Access-Control-Allow-Methods", "DELETE, GET, OPTIONS, POST, PUT");
+ response.setHeader("Access-Control-Max-Age", "1728000");
+ return;
+ }
+ */
+
+ CORSHeaderProcessor.processCORS(binding.getCORSConfiguration(), request, response);
+ }
+
+ //create context
+ HTTPContext bindingContext = new HTTPContext();
+ bindingContext.setHttpRequest(request);
+ bindingContext.setHttpResponse(response);
+
+
+ try {
+ //store in thread local
+ ThreadHTTPContext.setHTTPContext(bindingContext);
+
+ // handle special ?wadl request
+ String query = request.getQueryString();
+ if(query != null && query.indexOf("wadl") >= 0) {
+ handleWadlRequest(request, response);
+ } else {
+ super.service(request, response);
+ }
+ } finally {
+ //remove
+ ThreadHTTPContext.removeHTTPContext();
+ }
+ }
+
+
+ public void init() throws ServletException {
+ ClassLoader cl =
+ ClassLoaderContext.setContextClassLoader(Thread.currentThread().getContextClassLoader(),
+ registry.getServiceDiscovery(),
+ "/META-INF/server/wink-providers",
+ "javax.ws.rs.ext.RuntimeDelegate");
+ try {
+ super.init();
+ } finally {
+ if (cl != null) {
+ // return previous classLoader
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Override
+ public DeploymentConfiguration getDeploymentConfiguration() throws ClassNotFoundException, InstantiationException,
+ IllegalAccessException, IOException {
+
+
+ // setup proper classLoader to work on OSGi environment
+ ClassLoader cl =
+ ClassLoaderContext.setContextClassLoader(Thread.currentThread().getContextClassLoader(),
+ registry.getServiceDiscovery(),
+ "javax.ws.rs.ext.RuntimeDelegate",
+ "/META-INF/wink-alternate-shortcuts.properties",
+ "/META-INF/server/wink-providers");
+
+ DeploymentConfiguration config = null;
+ try {
+ config = super.getDeploymentConfiguration();
+ } finally {
+ if (cl != null) {
+ // return previous classLoader
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+ }
+
+ // [rfeng] FIXME: This is a hack to fool Apache wink to not remove the servlet path
+ config.setFilterConfig(new FilterConfig() {
+
+ public ServletContext getServletContext() {
+ return getServletContext();
+ }
+
+ public Enumeration getInitParameterNames() {
+ return getInitParameterNames();
+ }
+
+ public String getInitParameter(String arg0) {
+ return getInitParameter(arg0);
+ }
+
+ public String getFilterName() {
+ return getServletName();
+ }
+ });
+
+ ProvidersRegistry providers = config.getProvidersRegistry();
+ providers.addProvider(new DataBindingJAXRSReader(registry), 0.2, true);
+ providers.addProvider(new DataBindingJAXRSWriter(registry), 0.2, true);
+
+ config.getResponseUserHandlers().add(new TuscanyResponseHandler());
+
+ return config;
+ }
+
+ private void handleWadlRequest(HttpServletRequest request, HttpServletResponse response) {
+ try {
+ org.apache.wink.common.model.wadl.Application wadlDocument = null;
+ WADLGenerator generator = new WADLGenerator();
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ classes.add(resourceClass);
+ wadlDocument = generator.generate(binding.getURI(), classes);
+
+ MessageBodyWriter<org.apache.wink.common.model.wadl.Application> writer =
+ this.getDeploymentConfiguration().getProvidersRegistry().
+ getMessageBodyWriter(org.apache.wink.common.model.wadl.Application.class,
+ org.apache.wink.common.model.wadl.Application.class,
+ annotations,
+ MediaType.APPLICATION_XML_TYPE,
+ null);
+
+ writer.writeTo(wadlDocument,
+ org.apache.wink.common.model.wadl.Application.class,
+ org.apache.wink.common.model.wadl.Application.class,
+ annotations,
+ MediaType.APPLICATION_XML_TYPE,
+ null, response.getOutputStream());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * TuscanyResponseHandler
+ *
+ * Required to support declarative HTTP Headers
+ */
+ class TuscanyResponseHandler implements ResponseHandler {
+ public void handleResponse(MessageContext context, HandlersChain chain) throws Throwable {
+
+ // assert response is not committed
+ final HttpServletResponse httpResponse = context.getAttribute(HttpServletResponse.class);
+ if (httpResponse.isCommitted()) {
+ logger.log(Level.FINE, "The response is already committed. Nothing to do.");
+ return;
+ }
+
+ //process declarative headers
+ for(HTTPHeader header : binding.getHttpHeaders()) {
+ //treat special headers that need to be calculated
+ if(header.getName().equalsIgnoreCase("Expires")) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(new Date());
+
+ calendar.add(Calendar.HOUR, Integer.parseInt(header.getValue()));
+
+ httpResponse.setHeader("Expires", HTTPCacheContext.RFC822DateFormat.format( calendar.getTime() ));
+ } else {
+ //default behaviour to pass the header value to HTTP response
+ httpResponse.setHeader(header.getName(), header.getValue());
+ }
+ }
+
+ chain.doChain(context);
+ }
+
+ public void init(Properties props) {
+
+ }
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatInterceptor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatInterceptor.java
new file mode 100644
index 0000000000..705564ebd3
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatInterceptor.java
@@ -0,0 +1,159 @@
+/*
+ * 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.rest.wireformat.json.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.binding.rest.wireformat.json.JSONWireFormat;
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+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.apache.wink.json4j.JSONObject;
+
+/**
+ * JSON wire format Interceptor.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JSONWireFormatInterceptor implements Interceptor {
+ private Invoker next;
+ private RESTBinding binding;
+
+ public JSONWireFormatInterceptor(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.binding = (RESTBinding) endpoint.getBinding();
+ }
+
+ public Invoker getNext() {
+ return next;
+ }
+
+ public void setNext(Invoker next) {
+ this.next = next;
+ }
+
+ public Message invoke(Message msg) {
+ HTTPContext bindingContext = (HTTPContext) msg.getBindingContext();
+ if (bindingContext == null) {
+ return getNext().invoke(msg);
+ }
+
+
+ if (binding.getRequestWireFormat() instanceof JSONWireFormat) {
+ if( isPayloadSupported(bindingContext.getHttpRequest().getMethod()) && msg.getBody() != null) {
+ msg = invokeRequest(bindingContext, msg);
+ }
+ }
+
+ msg = getNext().invoke(msg);
+
+ //if it's oneway return back
+ Operation operation = msg.getOperation();
+ if (operation != null && operation.isNonBlocking()) {
+ return msg;
+ }
+
+ if (binding.getResponseWireFormat() instanceof JSONWireFormat) {
+ msg = invokeResponse(bindingContext, msg);
+ }
+
+ return msg;
+ }
+
+ /**
+ * Handle any wire format specific transformations required for request data
+ * @param bindingContext the binding context (e.g. HTTP Request, Response objects)
+ * @param msg the invocation message
+ * @return processed request message
+ */
+ private Message invokeRequest(HTTPContext bindingContext, Message msg) {
+
+ // Decode using the charset in the request if it exists otherwise
+ // use UTF-8 as this is what all browser implementations use.
+ String charset = bindingContext.getHttpRequest().getCharacterEncoding();
+ if (charset == null) {
+ charset = "UTF-8";
+ }
+
+ try {
+ Object[] args = msg.getBody();
+ InputStream in = (InputStream) args[0];
+ String data = read(in, charset);
+ JSONObject jsonPayload = new JSONObject(data);
+ msg.setBody(new Object[]{jsonPayload});
+ } catch(Exception e) {
+ throw new RuntimeException("Unable to parse json paylod: " + msg.getBody().toString());
+ }
+
+ return msg;
+ }
+
+ /**
+ * Handle any wire format specific transformation required for the response data
+ * @param bindingContext the binding context (e.g. HTTP Request, Response objects)
+ * @param msg the response message
+ * @return processed response message
+ */
+ private Message invokeResponse(HTTPContext bindingContext, Message msg) {
+ return msg;
+ }
+
+
+ /**
+ * Check if HTTP Operation should support payload
+ * @param operation
+ * @return
+ */
+ private static boolean isPayloadSupported(String operation) {
+ boolean isGet = "get".equalsIgnoreCase(operation);
+ boolean isDelete = "delete".equalsIgnoreCase(operation);
+
+ return isGet == false && isDelete == false;
+ }
+
+ /**
+ * Read JSON payload from HTTP Request Body
+ * @param in
+ * @param charset
+ * @return
+ * @throws IOException
+ */
+ private static String read(InputStream in, String charset) throws IOException {
+ StringWriter sw = new StringWriter();
+ InputStreamReader reader = new InputStreamReader(in, "UTF-8");
+ char[] buf = new char[8192];
+ while (true) {
+ int size = reader.read(buf);
+ if (size < 0) {
+ break;
+ }
+ sw.write(buf, 0, size);
+ }
+ return sw.toString();
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatProviderFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatProviderFactory.java
new file mode 100644
index 0000000000..6b1bb6cca7
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rest.wireformat.json.provider;
+
+import org.apache.tuscany.sca.binding.rest.wireformat.json.JSONWireFormat;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+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;
+
+/**
+ * JSON wire format Provider Factory.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JSONWireFormatProviderFactory implements WireFormatProviderFactory<JSONWireFormat>{
+ private ExtensionPointRegistry extensionPoints;
+
+ public JSONWireFormatProviderFactory(ExtensionPointRegistry extensionPoints) {
+ this.extensionPoints = extensionPoints;
+ }
+ public WireFormatProvider createReferenceWireFormatProvider(RuntimeEndpointReference endpointReference) {
+ return new JSONWireFormatReferenceProvider(extensionPoints, endpointReference);
+ }
+
+ public WireFormatProvider createServiceWireFormatProvider(RuntimeEndpoint endpoint) {
+ return new JSONWireFormatServiceProvider(extensionPoints, endpoint);
+ }
+
+ public Class<JSONWireFormat> getModelType() {
+ return JSONWireFormat.class;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatReferenceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatReferenceProvider.java
new file mode 100644
index 0000000000..830b02a3e8
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatReferenceProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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.rest.wireformat.json.provider;
+
+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.runtime.RuntimeEndpointReference;
+
+/**
+ * JSON wire format Reference Provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JSONWireFormatReferenceProvider implements WireFormatProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpointReference endpointReference;
+
+ public JSONWireFormatReferenceProvider(ExtensionPointRegistry extensionPoints,RuntimeEndpointReference endpointReference ) {
+ this.extensionPoints = extensionPoints;
+ this.endpointReference = endpointReference;
+ }
+ public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) {
+ return null;
+ }
+
+ public Interceptor createInterceptor() {
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.REFERENCE_BINDING_WIREFORMAT;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatServiceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatServiceProvider.java
new file mode 100644
index 0000000000..754fdfc73e
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/json/provider/JSONWireFormatServiceProvider.java
@@ -0,0 +1,138 @@
+/*
+ * 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.rest.wireformat.json.provider;
+
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.provider.JAXRSHelper;
+import org.apache.tuscany.sca.binding.rest.wireformat.json.JSONWireFormat;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.javabeans.SimpleJavaDataBinding;
+import org.apache.tuscany.sca.databinding.json.JSONDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+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.runtime.RuntimeEndpoint;
+
+/**
+ * JSON wire format service provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class JSONWireFormatServiceProvider implements WireFormatProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpoint endpoint;
+
+ private InterfaceContract serviceContract;
+ private Binding binding;
+ private boolean jaxrs;
+
+ public JSONWireFormatServiceProvider(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.extensionPoints = extensionPoints;
+ this.endpoint = endpoint;
+ this.binding = endpoint.getBinding();
+ this.jaxrs = isJAXRSResource();
+ }
+
+ private boolean isJAXRSResource() {
+ Interface interfaze = endpoint.getComponentServiceInterfaceContract().getInterface();
+ if (interfaze instanceof JavaInterface) {
+ if (JAXRSHelper.isJAXRSResource(((JavaInterface)interfaze).getJavaClass())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) {
+ serviceContract = interfaceContract;
+
+ if (!jaxrs) {
+ boolean configureInput = binding.getRequestWireFormat() != null;
+ boolean configureOutput = binding.getRequestWireFormat() != null || binding.getResponseWireFormat() != null;
+
+ //set JSON databinding
+ setDataBinding(serviceContract.getInterface(), configureInput, configureOutput);
+ }
+
+ return serviceContract;
+ }
+
+ public Interceptor createInterceptor() {
+ if (jaxrs) {
+ return null;
+ }
+ if( (binding.getRequestWireFormat() != null && binding.getRequestWireFormat() instanceof JSONWireFormat) ||
+ (binding.getResponseWireFormat() != null && binding.getResponseWireFormat() instanceof JSONWireFormat) ){
+ return new JSONWireFormatInterceptor(extensionPoints, endpoint);
+ }
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.SERVICE_BINDING_WIREFORMAT;
+ }
+
+
+ /**
+ * Utility method to reset data binding for the interface contract.
+ * We need to handle special case where :
+ * - global wire format for binding
+ * - wire format configured only for response
+ * @param interfaze
+ */
+ @SuppressWarnings({"deprecation", "unchecked"})
+ private void setDataBinding(Interface interfaze, boolean configureInput, boolean configureOutput) {
+ List<Operation> operations = interfaze.getOperations();
+ for (Operation operation : operations) {
+ // handle input types
+ if (configureInput) {
+ operation.setDataBinding(JSONDataBinding.NAME);
+ DataType<List<DataType>> inputType = operation.getInputType();
+ if (inputType != null) {
+ List<DataType> logical = inputType.getLogical();
+ for (DataType inArg : logical) {
+ if (!SimpleJavaDataBinding.NAME.equals(inArg.getDataBinding())) {
+ inArg.setDataBinding(JSONDataBinding.NAME);
+ }
+ }
+ }
+ }
+
+ // handle output types
+ if (configureOutput) {
+ List<DataType> outputTypes = operation.getOutputType().getLogical();
+ for ( DataType outputType : outputTypes) {
+ if (outputType != null) {
+ if (!SimpleJavaDataBinding.NAME.equals(outputType.getDataBinding())) {
+ outputType.setDataBinding(JSONDataBinding.NAME);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatInterceptor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatInterceptor.java
new file mode 100644
index 0000000000..d5055b6701
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatInterceptor.java
@@ -0,0 +1,143 @@
+/*
+ * 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.rest.wireformat.xml.provider;
+
+import java.io.InputStream;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.binding.rest.wireformat.json.JSONWireFormat;
+import org.apache.tuscany.sca.binding.rest.wireformat.xml.XMLWireFormat;
+import org.apache.tuscany.sca.common.http.HTTPContext;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+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;
+
+/**
+ * JSON wire format Interceptor.
+ *
+ * @version $Rev$ $Date$
+*/
+public class XMLWireFormatInterceptor implements Interceptor {
+ private XMLInputFactory inputFactory;
+
+ private Invoker next;
+ private RESTBinding binding;
+
+ public XMLWireFormatInterceptor(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ FactoryExtensionPoint factories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class);
+ inputFactory = factories.getFactory(XMLInputFactory.class);
+
+ this.binding = (RESTBinding) endpoint.getBinding();
+ }
+
+ public Invoker getNext() {
+ return next;
+ }
+
+ public void setNext(Invoker next) {
+ this.next = next;
+ }
+
+ public Message invoke(Message msg) {
+ HTTPContext bindingContext = (HTTPContext) msg.getBindingContext();
+ if (bindingContext == null) {
+ return getNext().invoke(msg);
+ }
+
+
+ if (binding.getRequestWireFormat() instanceof XMLWireFormat) {
+ if( isPayloadSupported(bindingContext.getHttpRequest().getMethod()) && msg.getBody() != null) {
+ msg = invokeRequest(bindingContext, msg);
+ }
+ }
+
+ msg = getNext().invoke(msg);
+
+ //if it's oneway return back
+ Operation operation = msg.getOperation();
+ if (operation != null && operation.isNonBlocking()) {
+ return msg;
+ }
+
+ if (binding.getResponseWireFormat() instanceof XMLWireFormat) {
+ msg = invokeResponse(bindingContext, msg);
+ }
+
+ return msg;
+ }
+
+ /**
+ * Handle any wire format specific transformations required for request data
+ * @param bindingContext the binding context (e.g. HTTP Request, Response objects)
+ * @param msg the invocation message
+ * @return processed request message
+ */
+ private Message invokeRequest(HTTPContext bindingContext, Message msg) {
+ // Decode using the charset in the request if it exists otherwise
+ // use UTF-8 as this is what all browser implementations use.
+ String charset = bindingContext.getHttpRequest().getCharacterEncoding();
+ if (charset == null) {
+ charset = "UTF-8";
+ }
+
+ try {
+ if(msg.getBody() != null) {
+ Object[] args = msg.getBody();
+ InputStream data = (InputStream) args[0];
+ XMLStreamReader xmlPayload = inputFactory.createXMLStreamReader(data, charset);
+ msg.setBody(new Object[]{xmlPayload});
+ }
+ } catch(Exception e) {
+ throw new RuntimeException("Unable to process xml paylod: " + msg.getBody().toString());
+ }
+
+ return msg;
+ }
+
+
+ /**
+ * Handle any wire format specific transformation required for the response data
+ * @param bindingContext the binding context (e.g. HTTP Request, Response objects)
+ * @param msg the response message
+ * @return processed response message
+ */
+ private Message invokeResponse(HTTPContext bindingContext, Message msg) {
+ return msg;
+ }
+
+ /**
+ * Check if HTTP Operation should support payload
+ * @param operation
+ * @return
+ */
+ private static boolean isPayloadSupported(String operation) {
+ boolean isGet = "get".equalsIgnoreCase(operation);
+ boolean isDelete = "delete".equalsIgnoreCase(operation);
+
+ return isGet == false && isDelete == false;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatProviderFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatProviderFactory.java
new file mode 100644
index 0000000000..33900b3de9
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rest.wireformat.xml.provider;
+
+import org.apache.tuscany.sca.binding.rest.wireformat.xml.XMLWireFormat;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+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;
+
+/**
+ * XML wire format Provider Factory.
+ *
+ * @version $Rev$ $Date$
+*/
+public class XMLWireFormatProviderFactory implements WireFormatProviderFactory<XMLWireFormat>{
+ private ExtensionPointRegistry extensionPoints;
+
+ public XMLWireFormatProviderFactory(ExtensionPointRegistry extensionPoints) {
+ this.extensionPoints = extensionPoints;
+ }
+ public WireFormatProvider createReferenceWireFormatProvider(RuntimeEndpointReference endpointReference) {
+ return new XMLWireFormatReferenceProvider(extensionPoints, endpointReference);
+ }
+
+ public WireFormatProvider createServiceWireFormatProvider(RuntimeEndpoint endpoint) {
+ return new XMLWireFormatServiceProvider(extensionPoints, endpoint);
+ }
+
+ public Class<XMLWireFormat> getModelType() {
+ return XMLWireFormat.class;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatReferenceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatReferenceProvider.java
new file mode 100644
index 0000000000..c9e0ac4578
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatReferenceProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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.rest.wireformat.xml.provider;
+
+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.runtime.RuntimeEndpointReference;
+
+/**
+ * XML wire format Reference Provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class XMLWireFormatReferenceProvider implements WireFormatProvider {
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpointReference endpointReference;
+
+ public XMLWireFormatReferenceProvider(ExtensionPointRegistry extensionPoints,RuntimeEndpointReference endpointReference ) {
+ this.extensionPoints = extensionPoints;
+ this.endpointReference = endpointReference;
+ }
+ public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) {
+ return null;
+ }
+
+ public Interceptor createInterceptor() {
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.REFERENCE_BINDING_WIREFORMAT;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatServiceProvider.java b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatServiceProvider.java
new file mode 100644
index 0000000000..01b439961c
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/wireformat/xml/provider/XMLWireFormatServiceProvider.java
@@ -0,0 +1,139 @@
+/*
+ * 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.rest.wireformat.xml.provider;
+
+import java.util.List;
+
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.binding.rest.provider.JAXRSHelper;
+import org.apache.tuscany.sca.binding.rest.wireformat.xml.XMLWireFormat;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.javabeans.SimpleJavaDataBinding;
+import org.apache.tuscany.sca.databinding.xml.XMLStringDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+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.runtime.RuntimeEndpoint;
+
+/**
+ * XML wire format service provider.
+ *
+ * @version $Rev$ $Date$
+*/
+public class XMLWireFormatServiceProvider implements WireFormatProvider {
+ private static final String DATABABINDING = XMLStreamReader.class.getName();
+
+ private ExtensionPointRegistry extensionPoints;
+ private RuntimeEndpoint endpoint;
+
+ private InterfaceContract serviceContract;
+ private Binding binding;
+
+ private boolean jaxrs;
+
+ public XMLWireFormatServiceProvider(ExtensionPointRegistry extensionPoints, RuntimeEndpoint endpoint) {
+ this.extensionPoints = extensionPoints;
+ this.endpoint = endpoint;
+ this.binding = endpoint.getBinding();
+ this.jaxrs = isJAXRSResource();
+ }
+
+ private boolean isJAXRSResource() {
+ Interface interfaze = endpoint.getComponentServiceInterfaceContract().getInterface();
+ if (interfaze instanceof JavaInterface) {
+ if (JAXRSHelper.isJAXRSResource(((JavaInterface)interfaze).getJavaClass())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public InterfaceContract configureWireFormatInterfaceContract(InterfaceContract interfaceContract) {
+ serviceContract = interfaceContract;
+
+ if (!jaxrs) {
+ boolean configureInput = binding.getRequestWireFormat() != null;
+ boolean configureOutput = binding.getRequestWireFormat() != null || binding.getResponseWireFormat() != null;
+
+ //set XML databinding
+ setDataBinding(serviceContract.getInterface(), configureInput, configureOutput);
+ }
+
+ return serviceContract;
+ }
+
+ public Interceptor createInterceptor() {
+ if (jaxrs) {
+ return null;
+ }
+
+ if( (binding.getRequestWireFormat() != null && binding.getRequestWireFormat() instanceof XMLWireFormat) ||
+ (binding.getResponseWireFormat() != null && binding.getResponseWireFormat() instanceof XMLWireFormat) ){
+ return new XMLWireFormatInterceptor(extensionPoints, endpoint);
+ }
+ return null;
+ }
+
+ public String getPhase() {
+ return Phase.SERVICE_BINDING_WIREFORMAT;
+ }
+
+
+ /**
+ * Utility method to reset data binding for the interface contract
+ * @param interfaze
+ */
+ @SuppressWarnings({"deprecation", "unchecked"})
+ private void setDataBinding(Interface interfaze, boolean configureInput, boolean configureOutput) {
+ List<Operation> operations = interfaze.getOperations();
+ for (Operation operation : operations) {
+ // handle input types
+ if (configureInput) {
+ operation.setDataBinding(DATABABINDING);
+ DataType<List<DataType>> inputType = operation.getInputType();
+ if (inputType != null) {
+ List<DataType> logical = inputType.getLogical();
+ for (DataType inArg : logical) {
+ if (!SimpleJavaDataBinding.NAME.equals(inArg.getDataBinding())) {
+ inArg.setDataBinding(DATABABINDING);
+ }
+ }
+ }
+ }
+
+ // handle output types
+ if (configureOutput) {
+ List<DataType> outputTypes = operation.getOutputType().getLogical();
+ for ( DataType outputType : outputTypes ) {
+ if (outputType != null) {
+ outputType.setDataBinding(XMLStringDataBinding.NAME);
+ }
+ }
+ }
+ }
+ }
+}