From 1725e763b9a7fdd4c862167accca060180c9dde1 Mon Sep 17 00:00:00 2001 From: rfeng Date: Fri, 16 Jul 2010 17:49:20 +0000 Subject: Align the JAX-RS resource class/method checks with the spec Allow the binding.rest client to issue RPC over GET calls git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@964880 13f79535-47bb-0310-9956-ffa450edef68 --- .../rest/provider/DataBindingJAXRSReader.java | 5 +- .../rest/provider/DataBindingJAXRSWriter.java | 5 +- .../sca/binding/rest/provider/JAXRSHelper.java | 80 ++++++++++++++++++++++ .../binding/rest/provider/RESTBindingInvoker.java | 39 +++++++---- .../rest/provider/RESTServiceBindingProvider.java | 41 ++++------- 5 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/JAXRSHelper.java (limited to 'sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider') diff --git a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java index d6df778feb..d38881eb28 100644 --- a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java +++ b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSReader.java @@ -66,7 +66,10 @@ public class DataBindingJAXRSReader extends DataBindingJAXRSProvider implemen // 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 (MediaType.APPLICATION_XML_TYPE.equals(mediaType) || MediaType.TEXT_XML_TYPE.equals(mediaType)) { + } 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(); diff --git a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java index 740b685b22..be2a9555d7 100644 --- a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java +++ b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/DataBindingJAXRSWriter.java @@ -69,7 +69,10 @@ public class DataBindingJAXRSWriter extends DataBindingJAXRSProvider implemen 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 { + } else if ("application/x-protobuf".equals(mediaType.toString())) { + dataBinding = mediaType.toString() + "#" + OutputStream.class.getName(); + } + else { dataBinding = dataType.getDataBinding(); write(entityStream, t, type); return; diff --git a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/JAXRSHelper.java b/sca-java-2.x/trunk/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/trunk/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/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java index c8089904ae..1673f3aefa 100644 --- a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java @@ -43,6 +43,7 @@ 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; @@ -107,9 +108,9 @@ public class RESTBindingInvoker implements Invoker { private RestClient createRestClient() { ClientConfig config = new ClientConfig(); - + // configureBasicAuth(config, userName, password); - + config.applications(new Application() { @Override @@ -127,6 +128,9 @@ public class RESTBindingInvoker implements Invoker { }); RestClient client = new RestClient(config); + + // Default to GET for RPC + httpMethod = HttpMethod.GET; for (Map.Entry, String> e : mapping.entrySet()) { if (operation.getAttributes().get(e.getKey()) != null) { @@ -154,12 +158,21 @@ public class RESTBindingInvoker implements Invoker { Object entity = null; Object[] args = msg.getBody(); - + URI uri = URI.create(binding.getURI()); UriBuilder uriBuilder = UriBuilder.fromUri(uri); Method method = ((JavaOperation)operation).getJavaMethod(); - uriBuilder.path(method); + + 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 pathParams = new HashMap(); Map matrixParams = new HashMap(); @@ -168,8 +181,8 @@ public class RESTBindingInvoker implements Invoker { Map formParams = new HashMap(); Map cookieParams = new HashMap(); - boolean isEntity = true; 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) { @@ -201,7 +214,7 @@ public class RESTBindingInvoker implements Invoker { isEntity = false; cookieParams.put(cookieParam.value(), args[i]); } - if(isEntity) { + if (isEntity) { entity = args[i]; } } @@ -212,10 +225,10 @@ public class RESTBindingInvoker implements Invoker { for (Map.Entry p : matrixParams.entrySet()) { uriBuilder.replaceMatrixParam(p.getKey(), p.getValue()); } - + uri = uriBuilder.buildFromMap(pathParams); Resource resource = restClient.resource(uri); - + for (Map.Entry p : headerParams.entrySet()) { resource.header(p.getKey(), String.valueOf(p.getValue())); } @@ -226,18 +239,18 @@ public class RESTBindingInvoker implements Invoker { } resource.contentType(getContentType()); - resource.accept(getAccepts()); - + resource.accept(getAccepts()); + //handles declarative headers configured on the composite - for(HTTPHeader header : binding.getHttpHeaders()) { + for (HTTPHeader header : binding.getHttpHeaders()) { //treat special headers that need to be calculated - if(header.getName().equalsIgnoreCase("Expires")) { + 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() )); + 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()); diff --git a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java index a12c28715a..9a9e5a108e 100644 --- a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java +++ b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTServiceBindingProvider.java @@ -19,8 +19,6 @@ 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.HashMap; import java.util.HashSet; @@ -114,7 +112,8 @@ public class RESTServiceBindingProvider implements EndpointProvider { if (binding.getOperationSelector() != null) { // Configure the interceptors for operation selection OperationSelectorProviderFactory osProviderFactory = - (OperationSelectorProviderFactory)providerFactories.getProviderFactory(binding.getOperationSelector().getClass()); + (OperationSelectorProviderFactory)providerFactories.getProviderFactory(binding.getOperationSelector() + .getClass()); if (osProviderFactory != null) { this.osProvider = osProviderFactory.createServiceOperationSelectorProvider(endpoint); } @@ -123,16 +122,18 @@ public class RESTServiceBindingProvider implements EndpointProvider { if (binding.getRequestWireFormat() != null) { // Configure the interceptors for wire format WireFormatProviderFactory wfProviderFactory = - (WireFormatProviderFactory)providerFactories.getProviderFactory(binding.getRequestWireFormat().getClass()); + (WireFormatProviderFactory)providerFactories.getProviderFactory(binding.getRequestWireFormat() + .getClass()); if (wfProviderFactory != null) { this.wfProvider = wfProviderFactory.createServiceWireFormatProvider(endpoint); } } - if (binding.getResponseWireFormat() != null ) { + if (binding.getResponseWireFormat() != null) { // Configure the interceptors for wire format WireFormatProviderFactory wfProviderFactory = - (WireFormatProviderFactory)providerFactories.getProviderFactory(binding.getResponseWireFormat().getClass()); + (WireFormatProviderFactory)providerFactories.getProviderFactory(binding.getResponseWireFormat() + .getClass()); if (wfProviderFactory != null) { this.wfResponseProvider = wfProviderFactory.createServiceWireFormatProvider(endpoint); } @@ -143,11 +144,11 @@ public class RESTServiceBindingProvider implements EndpointProvider { this.serviceContract = (InterfaceContract)service.getInterfaceContract().clone(); // configure data binding - if (wfProvider != null ) { + if (wfProvider != null) { wfProvider.configureWireFormatInterfaceContract(serviceContract); } - if(wfResponseProvider != null) { + if (wfResponseProvider != null) { wfResponseProvider.configureWireFormatInterfaceContract(serviceContract); } } catch (CloneNotSupportedException e) { @@ -239,7 +240,6 @@ public class RESTServiceBindingProvider implements EndpointProvider { return false; } - /** * Register a Tuscany REST Servlet to handle JAX-RS Resources on a binding endpoint * @return @@ -251,7 +251,8 @@ public class RESTServiceBindingProvider implements EndpointProvider { JavaInterface javaInterface = (JavaInterface)endpoint.getComponentServiceInterfaceContract().getInterface(); Class interfaze = javaInterface.getJavaClass(); - boolean isJAXRS = isJAXRSResource(interfaze); + // The @Path annotation can be from the binding uri + boolean isJAXRS = JAXRSHelper.isJAXRSResource(interfaze); if (isJAXRS) { application = new SimpleApplication(interfaze); @@ -314,7 +315,7 @@ public class RESTServiceBindingProvider implements EndpointProvider { 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())) { + if (path.startsWith(servletHost.getContextPath())) { path = path.substring(servletHost.getContextPath().length()); } Class cls = @@ -336,24 +337,6 @@ public class RESTServiceBindingProvider implements EndpointProvider { } } - public static boolean isJAXRSResource(Class cls) { - for (Annotation a : cls.getAnnotations()) { - if (a.annotationType().getName().startsWith("javax.ws.rs.")) { - return true; - } - } - for (Method method : cls.getMethods()) { - for (Annotation a : method.getAnnotations()) { - if (a.annotationType().getName().startsWith("javax.ws.rs.")) { - return true; - } - } - } - return false; - } - - - /** * Add specific rest interceptor to invocation chain */ -- cgit v1.2.3