summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessor.java276
-rw-r--r--java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessorTestCase.java67
-rw-r--r--java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/StockQuote.java44
3 files changed, 387 insertions, 0 deletions
diff --git a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessor.java b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessor.java
new file mode 100644
index 0000000000..155c89c7f2
--- /dev/null
+++ b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessor.java
@@ -0,0 +1,276 @@
+/*
+ * 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.interfacedef.java.jaxws;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor;
+
+public class JAXWSAsyncInterfaceProcessor implements JavaInterfaceVisitor {
+ private static String ASYNC = "Async";
+
+ public JAXWSAsyncInterfaceProcessor(ExtensionPointRegistry registry) {
+
+ }
+
+ public void visitInterface(JavaInterface javaInterface) throws InvalidInterfaceException {
+ List<Operation> validOperations = new ArrayList<Operation>();
+ List<Operation> asyncOperations = new ArrayList<Operation>();
+
+ validOperations.addAll(javaInterface.getOperations());
+ for(Operation o : javaInterface.getOperations()) {
+ if (! o.getName().endsWith(ASYNC)) {
+ Operation op = o;
+
+ for(Operation asyncOp : getAsyncOperations(javaInterface.getOperations(), o.getName()) ) {
+ if (isJAXWSAsyncPoolingOperation(op, asyncOp) ||
+ isJAXWSAsyncCallbackOperation(op, asyncOp)) {
+ validOperations.remove(asyncOp);
+ asyncOperations.add(asyncOp);
+ }
+ }
+ }
+ }
+
+ javaInterface.getOperations().clear();
+ javaInterface.getOperations().addAll(validOperations);
+
+ javaInterface.getAttributes().put("JAXWS-ASYNC-OPERATIONS", asyncOperations);
+ }
+
+ /**
+ * The additional client-side asynchronous polling and callback methods defined by JAX-WS are recognized in a Java interface as follows:
+ * For each method M in the interface, if another method P in the interface has
+ *
+ * a) a method name that is M's method name with the characters "Async" appended, and
+ * b) the same parameter signature as M, and
+ * c)a return type of Response<R> where R is the return type of M
+ *
+ * @param operation
+ * @param asyncOperation
+ * @return
+ */
+ private static boolean isJAXWSAsyncPoolingOperation(Operation operation, Operation asyncOperation) {
+ //a method name that is M's method name with the characters "Async" appended
+ if (operation.getName().endsWith(ASYNC)) {
+ return false;
+ }
+
+ if (! asyncOperation.getName().endsWith(ASYNC)) {
+ return false;
+ }
+
+ if(! asyncOperation.getName().equals(operation.getName() + ASYNC)) {
+ return false;
+ }
+
+ //the same parameter signature as M
+ List<DataType> operationInputType = operation.getInputType().getLogical();
+ List<DataType> asyncOperationInputType = asyncOperation.getInputType().getLogical();
+ int size = operationInputType.size();
+ for (int i = 0; i < size; i++) {
+ if (!isCompatible(operationInputType.get(i), asyncOperationInputType.get(i))) {
+ return false;
+ }
+ }
+
+ //a return type of Response<R> where R is the return type of M
+ DataType<?> operationOutputType = operation.getOutputType();
+ DataType<?> asyncOperationOutputType = asyncOperation.getOutputType();
+
+ if (operationOutputType != null && asyncOperationOutputType != null) {
+ ParameterizedType asyncReturnType = (ParameterizedType) asyncOperationOutputType.getGenericType();
+ Class<?> asyncReturnTypeClass = (Class<?>)asyncReturnType.getRawType();
+ if(asyncReturnTypeClass.getName().equals("javax.xml.ws.Response")) {
+ //now check the actual type of the Response<R> with R
+ Class<?> returnType = operationOutputType.getPhysical();
+ Class<?> asyncActualReturnTypeClass = (Class<?>) asyncReturnType.getActualTypeArguments()[0];
+
+ if(returnType == asyncActualReturnTypeClass ||
+ returnType.isPrimitive() && primitiveAssignable(returnType,asyncActualReturnTypeClass)) {
+ //valid
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * For each method M in the interface, if another method C in the interface has
+ * a) a method name that is M's method name with the characters "Async" appended, and
+ * b) a parameter signature that is M's parameter signature with an additional
+ * final parameter of type AsyncHandler<R> where R is the return type of M, and
+ * c) a return type of Future<?>
+ *
+ * then C is a JAX-WS callback method that isn't part of the SCA interface contract.
+ *
+ * @param operation
+ * @param asyncOperation
+ * @return
+ */
+ private static boolean isJAXWSAsyncCallbackOperation(Operation operation, Operation asyncOperation) {
+ //a method name that is M's method name with the characters "Async" appended
+ if (operation.getName().endsWith(ASYNC)) {
+ return false;
+ }
+
+ if (! asyncOperation.getName().endsWith(ASYNC)) {
+ return false;
+ }
+
+ if(! asyncOperation.getName().equals(operation.getName() + ASYNC)) {
+ return false;
+ }
+
+ //a parameter signature that is M's parameter signature
+ //with an additional final parameter of type AsyncHandler<R> where R is the return type of M, and
+ List<DataType> operationInputType = operation.getInputType().getLogical();
+ List<DataType> asyncOperationInputType = asyncOperation.getInputType().getLogical();
+ int size = operationInputType.size();
+ for (int i = 0; i < size; i++) {
+ if (!isCompatible(operationInputType.get(i), asyncOperationInputType.get(i))) {
+ return false;
+ }
+ }
+
+ if(asyncOperationInputType.size() == size + 1) {
+ ParameterizedType asyncLastParameterType = (ParameterizedType) asyncOperationInputType.get(size + 1).getGenericType();
+ Class<?> asyncLastParameterTypeClass = (Class<?>)asyncLastParameterType.getRawType();
+ if(asyncLastParameterTypeClass.getName().equals("javax.xml.ws.AsyncHandler")) {
+ //now check the actual type of the AsyncHandler<R> with R
+ Class<?> returnType = operation.getOutputType().getPhysical();
+ Class<?> asyncActualLastParameterTypeClass = (Class<?>) asyncLastParameterType.getActualTypeArguments()[0];
+
+ if(returnType == asyncActualLastParameterTypeClass ||
+ returnType.isPrimitive() && primitiveAssignable(returnType,asyncActualLastParameterTypeClass)) {
+ //valid
+ } else {
+ return false;
+ }
+ }
+ }
+
+ //a return type of Response<R> where R is the return type of M
+ DataType<?> operationOutputType = operation.getOutputType();
+ DataType<?> asyncOperationOutputType = asyncOperation.getOutputType();
+
+ if (operationOutputType != null && asyncOperationOutputType != null) {
+ ParameterizedType asyncReturnType = (ParameterizedType) asyncOperationOutputType.getGenericType();
+ Class<?> asyncReturnTypeClass = (Class<?>)asyncReturnType.getRawType();
+ if(asyncReturnTypeClass.getName().equals("javax.xml.ws.Response")) {
+ //now check the actual type of the Response<R> with R
+ Class<?> returnType = operationOutputType.getPhysical();
+ Class<?> asyncActualReturnTypeClass = (Class<?>) asyncReturnType.getActualTypeArguments()[0];
+
+ if(returnType == asyncActualReturnTypeClass ||
+ returnType.isPrimitive() && primitiveAssignable(returnType,asyncActualReturnTypeClass)) {
+ //valid
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get operation by name
+ *
+ * @param operations
+ * @param operationName
+ * @return
+ */
+ private static List<Operation> getAsyncOperations(List<Operation> operations, String operationName) {
+ List<Operation> returnOperations = new ArrayList<Operation>();
+
+ for(Operation o : operations) {
+ if(o.getName().equals(operationName + ASYNC)) {
+ returnOperations.add(o);
+ }
+ }
+
+ return returnOperations;
+ }
+
+
+ /**
+ * Check if two operation parameters are compatible
+ *
+ * @param source
+ * @param target
+ * @return
+ */
+ private static boolean isCompatible(DataType<?> source, DataType<?> target) {
+ if (source == target) {
+ return true;
+ }
+
+ return target.getPhysical().isAssignableFrom(source.getPhysical());
+ }
+
+ /**
+ * Compares a two types, assuming one is a primitive, to determine if the
+ * other is its object counterpart
+ */
+ private static boolean primitiveAssignable(Class<?> memberType, Class<?> param) {
+ if (memberType == Integer.class) {
+ return param == Integer.TYPE;
+ } else if (memberType == Double.class) {
+ return param == Double.TYPE;
+ } else if (memberType == Float.class) {
+ return param == Float.TYPE;
+ } else if (memberType == Short.class) {
+ return param == Short.TYPE;
+ } else if (memberType == Character.class) {
+ return param == Character.TYPE;
+ } else if (memberType == Boolean.class) {
+ return param == Boolean.TYPE;
+ } else if (memberType == Byte.class) {
+ return param == Byte.TYPE;
+ } else if (param == Integer.class) {
+ return memberType == Integer.TYPE;
+ } else if (param == Double.class) {
+ return memberType == Double.TYPE;
+ } else if (param == Float.class) {
+ return memberType == Float.TYPE;
+ } else if (param == Short.class) {
+ return memberType == Short.TYPE;
+ } else if (param == Character.class) {
+ return memberType == Character.TYPE;
+ } else if (param == Boolean.class) {
+ return memberType == Boolean.TYPE;
+ } else if (param == Byte.class) {
+ return memberType == Byte.TYPE;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessorTestCase.java b/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessorTestCase.java
new file mode 100644
index 0000000000..ec73ad4218
--- /dev/null
+++ b/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSAsyncInterfaceProcessorTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * 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.interfacedef.java.jaxws;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JAXWSAsyncInterfaceProcessorTestCase {
+ private ExtensionPointRegistry registry;
+
+ @Before
+ public void setUp() throws Exception {
+ registry = new DefaultExtensionPointRegistry();
+ }
+
+ /**
+ * Test method for
+ * {@link org.apache.tuscany.sca.interfacedef.java.jaxws.JAXWSAsyncInterfaceProcessor#visitInterface(JavaInterface)}.
+ */
+ @Test
+ public final void testProcessor() throws Exception {
+ DefaultJavaInterfaceFactory iFactory = new DefaultJavaInterfaceFactory(registry);
+ JavaInterface contract = iFactory.createJavaInterface(StockQuote.class);
+
+ assertTrue(contract.isRemotable());
+
+ Assert.assertEquals(1,contract.getOperations().size());
+
+ List<Operation> asyncOperations = (List<Operation>) contract.getAttributes().get("JAXWS-ASYNC-OPERATIONS");
+ Assert.assertEquals(2,asyncOperations.size());
+
+ //list operation
+ System.out.println(">>> Filtered Operations");
+ for(Operation o : contract.getOperations()) {
+ System.out.println(">>>>>>" + o);
+ }
+
+ }
+}
diff --git a/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/StockQuote.java b/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/StockQuote.java
new file mode 100644
index 0000000000..d1259e9120
--- /dev/null
+++ b/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/StockQuote.java
@@ -0,0 +1,44 @@
+/*
+ * 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.interfacedef.java.jaxws;
+
+import java.util.concurrent.Future;
+
+import javax.jws.WebService;
+import javax.xml.ws.AsyncHandler;
+import javax.xml.ws.Response;
+
+/**
+ * JAX-WS Async style interface
+ *
+ * @version $Rev$ $Date$
+ */
+
+@WebService
+public interface StockQuote {
+
+ float getPrice(String ticker);
+
+ Response<Float> getPriceAsync(String ticker);
+
+ Future<?> getPriceAsync(String ticker, AsyncHandler<Float> callback);
+
+
+}