summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/trunk/modules
diff options
context:
space:
mode:
authoredwardsmj <edwardsmj@13f79535-47bb-0310-9956-ffa450edef68>2010-06-25 10:21:28 +0000
committeredwardsmj <edwardsmj@13f79535-47bb-0310-9956-ffa450edef68>2010-06-25 10:21:28 +0000
commit7d7d7269a21d2e857f7e69ae82b5604af503f3e9 (patch)
tree84abf7e95297b5272eecda9aba7ebd72e44e0efc /sca-java-2.x/trunk/modules
parenteb1a98a7d7b9d279a7591f9bf2942001b5c34e7e (diff)
Introspection of SCA Async Server form on Java interface and Equivalence mapping of Async Server interface to Synchronous Java interface, as described in TUSCANY-3609 and TUSCANY-3610
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@957877 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-java-2.x/trunk/modules')
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/META-INF/MANIFEST.MF1
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java12
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java2
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java186
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java17
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java51
-rw-r--r--sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java17
7 files changed, 285 insertions, 1 deletions
diff --git a/sca-java-2.x/trunk/modules/interface-java/META-INF/MANIFEST.MF b/sca-java-2.x/trunk/modules/interface-java/META-INF/MANIFEST.MF
index e61a52374e..41dd68ed26 100644
--- a/sca-java-2.x/trunk/modules/interface-java/META-INF/MANIFEST.MF
+++ b/sca-java-2.x/trunk/modules/interface-java/META-INF/MANIFEST.MF
@@ -21,6 +21,7 @@ Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-Description: Apache Tuscany SCA Java Interface Model
Import-Package: javax.xml.namespace,
javax.xml.stream,
+ org.oasisopen.sca;version="2.0.0",
org.apache.tuscany.sca.assembly;version="2.0.0",
org.apache.tuscany.sca.assembly.xml;version="2.0.0",
org.apache.tuscany.sca.contribution.processor;version="2.0.0",
diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java
index c44650de9f..e894ac279b 100644
--- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java
+++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java
@@ -54,5 +54,17 @@ public interface JavaOperation extends Operation {
* @param action the action value
*/
void setAction(String action);
+
+ /**
+ * Sets whether this operation has async server style
+ * @param isAsync - "true" marks this operation as async server style
+ */
+ public void setAsyncServer( boolean isAsync );
+
+ /**
+ * Indicates whether this operation is async server style
+ * @return - true if the operation is async server style
+ */
+ public boolean isAsyncServer();
}
diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java
index b443cb988e..dbedf1d55a 100644
--- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java
+++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java
@@ -58,6 +58,8 @@ public abstract class JavaInterfaceFactoryImpl implements JavaInterfaceFactory {
if (javaInterface == null) {
javaInterface = createJavaInterface();
introspector.introspectInterface(javaInterface, interfaceClass);
+ // Now that all introspection is complete we can mark the interface resolved
+ javaInterface.setUnresolved(false);
cache.put(interfaceClass, javaInterface);
}
return javaInterface;
diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java
index 0b418054c5..54946a9413 100644
--- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java
+++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java
@@ -19,10 +19,25 @@
package org.apache.tuscany.sca.interfacedef.java.impl;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.List;
+import java.lang.reflect.ParameterizedType;
import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
import org.apache.tuscany.sca.interfacedef.impl.InterfaceImpl;
import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.apache.tuscany.sca.policy.Intent;
+
+import org.oasisopen.sca.ResponseDispatch;
/**
* Represents a Java interface.
@@ -37,6 +52,10 @@ public class JavaInterfaceImpl extends InterfaceImpl implements JavaInterface {
private QName qname;
protected JavaInterfaceImpl() {
+ super();
+ // Mark the interface as unresolved until all the basic processing is complete
+ // including Intent & Policy introspection
+ this.setUnresolved(true);
}
public String getName() {
@@ -135,5 +154,172 @@ public class JavaInterfaceImpl extends InterfaceImpl implements JavaInterface {
return true;
}
+
+ public List<Operation> getOperations() {
+ if( !isUnresolved() && isAsyncServer() ) {
+ return equivalentSyncOperations();
+ } else {
+ return super.getOperations();
+ }
+ } // end method getOperations
+
+
+ private List<Operation> syncOperations = null;
+ private List<Operation> equivalentSyncOperations() {
+ if( syncOperations != null ) return syncOperations;
+ List<Operation> allOperations = super.getOperations();
+ syncOperations = new ArrayList<Operation>();
+ for( Operation operation: allOperations) {
+ syncOperations.add( getSyncFormOfOperation( (JavaOperation) operation ) );
+ // Store the actual async operations under the attribute "ASYNC-SERVER-OPERATIONS"
+ this.getAttributes().put("ASYNC-SERVER-OPERATIONS", allOperations);
+ } // end for
+
+ return syncOperations;
+ } // end method equivalentSyncOperations
+
+ private static final String UNKNOWN_DATABINDING = null;
+ /**
+ * Prepares the synchronous form of an asynchronous operation
+ * - async form: void someOperationAsync( FooType inputParam, DispatchResponse<BarType> )
+ * - sync form: BarType someOperation( FooType inputParam )
+ * @param operation - the operation to convert
+ * @return - the synchronous form of the operation - for an input operation that is not async server in form, this
+ * method simply returns the original operation unchanged
+ */
+ private Operation getSyncFormOfOperation( JavaOperation operation ) {
+ if( isAsyncServerOperation( operation ) ) {
+ JavaOperation syncOperation = new JavaOperationImpl();
+ String opName = operation.getName().substring(0, operation.getName().length() - 5 );
+
+ // Prepare the list of equivalent input parameters, which simply excludes the (final) DispatchResponse object
+ // and the equivalent return parameter, which is the (generic) type from the DispatchResponse object
+ DataType<List<DataType>> requestParams = operation.getInputType();
+
+ DataType<List<DataType>> inputType = prepareSyncInputParams( requestParams );
+ DataType<XMLType> returnDataType = prepareSyncReturnParam( requestParams );
+ List<DataType> faultDataTypes = prepareSyncFaults( operation );
+
+ syncOperation.setName(opName);
+ syncOperation.setAsyncServer(true);
+ syncOperation.setInputType(inputType);
+ syncOperation.setOutputType(returnDataType);
+ syncOperation.setFaultTypes(faultDataTypes);
+ syncOperation.setNonBlocking(operation.isNonBlocking());
+ syncOperation.setJavaMethod(operation.getJavaMethod());
+ syncOperation.setInterface(this);
+ return syncOperation;
+ } else {
+ // If it's not Async form, then it's a synchronous operation
+ return operation;
+ } // end if
+ } // end getSyncFormOfOperation
+
+ /**
+ * Produce the equivalent sync method input parameters from the input parameters of the async method
+ * @param requestParams - async method input parameters
+ * @return - the equivalent sync method input parameters
+ */
+ private DataType<List<DataType>> prepareSyncInputParams( DataType<List<DataType>> requestParams ) {
+ List<DataType> requestLogical = requestParams.getLogical();
+ int paramCount = requestLogical.size();
+
+ // Copy the list of async parameters, removing the final DispatchResponse
+ List<DataType> asyncParams = new ArrayList<DataType>( paramCount - 1);
+ for( int i = 0 ; i < (paramCount - 1) ; i++ ) {
+ asyncParams.add( requestLogical.get(i) );
+ } // end for
+
+ DataType<List<DataType>> inputType =
+ new DataTypeImpl<List<DataType>>(requestParams.getDataBinding(),
+ requestParams.getPhysical(), asyncParams);
+ return inputType;
+ } // end method prepareSyncInputParams
+
+ /**
+ * Prepare the return data type of the equivalent sync operation, based on the parameterization of the ResponseDispatch object
+ * of the async operation - the return data type is the Generic type of the final DispatchResponse<?>
+ * @param requestParams - - async method input parameters
+ * @return - the sync method return parameter
+ */
+ private DataType<XMLType> prepareSyncReturnParam( DataType<List<DataType>> requestParams ) {
+ List<DataType> requestLogical = requestParams.getLogical();
+ int paramCount = requestLogical.size();
+
+ DataType<?> finalParam = requestLogical.get( paramCount - 1 );
+ ParameterizedType t = (ParameterizedType)finalParam.getGenericType();
+ XMLType returnXMLType = (XMLType)finalParam.getLogical();
+
+ String namespace = null;
+ if( returnXMLType.isElement() ) {
+ namespace = returnXMLType.getElementName().getNamespaceURI();
+ } else {
+ namespace = returnXMLType.getTypeName().getNamespaceURI();
+ }
+
+ Type[] typeArgs = t.getActualTypeArguments();
+ if( typeArgs.length != 1 ) throw new IllegalArgumentException( "ResponseDispatch parameter is not parameterized correctly");
+
+ Class<?> returnType = (Class<?>)typeArgs[0];
+
+ // Set outputType to null for void
+ XMLType xmlReturnType = new XMLType(new QName(namespace, "return"), null);
+ DataType<XMLType> returnDataType =
+ returnType == void.class ? null : new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, xmlReturnType);
+
+ return returnDataType;
+ } // end method prepareSyncReturnParam
+
+ /**
+ * Prepare the set of equivalent sync faults for a given async operation
+ * @return - the list of faults
+ */
+ private List<DataType> prepareSyncFaults( JavaOperation operation ) {
+ //TODO - deal with Faults - for now just copy through whatever is associated with the async operation
+ return operation.getFaultTypes();
+ }
+
+ /**
+ * Determines if an interface operation has the form of an async server operation
+ * - async form: void someOperationAsync( FooType inputParam, ...., DispatchResponse<BarType> )
+ * @param operation - the operation to examine
+ * @return - true if the operation has the form of an async operation, false otherwise
+ */
+ private boolean isAsyncServerOperation( Operation operation ) {
+ // Async form operations have:
+ // 1) void return type
+ // 2) name ending in "Async"
+ // 3) final parameter which is of ResponseDispatch<?> type
+ DataType<?> response = operation.getOutputType();
+ if( response != null ) {
+ if ( response.getPhysical() != void.class ) return false;
+ } // end if
+
+ if ( !operation.getName().endsWith("Async") ) return false;
+
+ DataType<List<DataType>> requestParams = operation.getInputType();
+ int paramCount = requestParams.getLogical().size();
+ if( paramCount < 1 ) return false;
+ DataType<?> finalParam = requestParams.getLogical().get( paramCount - 1 );
+ if ( finalParam.getPhysical() != ResponseDispatch.class ) return false;
+
+ return true;
+ } // end method isAsyncServerOperation
+
+ static QName ASYNC_INVOCATION = new QName(Constants.SCA11_NS, "asyncInvocation");
+ /**
+ * Indicates if this interface is an Async Server interface
+ * @return true if the interface is Async Server, false otherwise
+ */
+ private boolean isAsyncServer() {
+
+ List<Intent> intents = getRequiredIntents();
+ for( Intent intent: intents ) {
+ if ( intent.getName().equals(ASYNC_INVOCATION) ) {
+ return true;
+ }
+ } // end for
+ return false;
+ } // end method isAsyncServer
}
diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java
index d05dc7eba8..0f5962c964 100644
--- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java
+++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java
@@ -51,6 +51,7 @@ import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor;
import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper;
import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.oasisopen.sca.annotation.AsyncFault;
import org.oasisopen.sca.annotation.OneWay;
import org.oasisopen.sca.annotation.Remotable;
@@ -199,6 +200,11 @@ public class JavaInterfaceIntrospectorImpl {
getActualTypes(method.getGenericParameterTypes(), method.getParameterTypes(), typeBindings);
Class<?>[] faultTypes =
getActualTypes(method.getGenericExceptionTypes(), method.getExceptionTypes(), typeBindings);
+
+ // For async server interfaces, faults are described using the @AsyncFaults annotation
+ if( method.isAnnotationPresent(AsyncFault.class) ) {
+ faultTypes = readAsyncFaultTypes( method );
+ } // end if
boolean nonBlocking = method.isAnnotationPresent(OneWay.class);
if (nonBlocking) {
@@ -256,6 +262,17 @@ public class JavaInterfaceIntrospectorImpl {
}
return operations;
}
+
+ /**
+ * Reads the fault types declared in an @AsyncFault annotation on an async server method
+ * @param method - the Method
+ * @return - an array of fault/exception classes
+ */
+ private Class<?>[] readAsyncFaultTypes( Method method ) {
+ AsyncFault theFaults = method.getAnnotation(AsyncFault.class);
+ if ( theFaults == null ) return null;
+ return theFaults.value();
+ } // end method readAsyncFaultTypes
private boolean jaxwsAsyncMethod(Method method) {
if (method.getName().endsWith("Async")) {
diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java
index 61d38dac76..352cffeef2 100644
--- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java
+++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java
@@ -27,6 +27,7 @@ import java.util.List;
import org.apache.tuscany.sca.interfacedef.DataType;
import org.apache.tuscany.sca.interfacedef.Interface;
import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
/**
@@ -54,7 +55,12 @@ public final class JavaInterfaceUtil {
public static Method findMethod(Class<?> implClass, Operation operation) throws NoSuchMethodException {
String name = operation.getName();
if (operation instanceof JavaOperation) {
- name = ((JavaOperation)operation).getJavaMethod().getName();
+ if( ((JavaOperation)operation).isAsyncServer() ) {
+ // In this case, the operation is a mapped async server style method and needs special handling
+ return findAsyncServerMethod( implClass, (JavaOperation)operation );
+ } else {
+ name = ((JavaOperation)operation).getJavaMethod().getName();
+ } // end if
}
Interface interface1 = operation.getInterface();
int numParams = operation.getInputType().getLogical().size();
@@ -85,6 +91,49 @@ public final class JavaInterfaceUtil {
Class<?>[] paramTypes = getPhysicalTypes(operation);
return implClass.getMethod(name, paramTypes);
}
+
+ /**
+ * Return the method on the implementation class that matches the async server version of the operation.
+ *
+ * @param implClass the implementation class or interface
+ * @param operation the operation to match - this is the sync equivalent of an async server operation
+ * @return the method described by the operation
+ * @throws NoSuchMethodException if no such method exists
+ */
+ public static Method findAsyncServerMethod(Class<?> implClass, JavaOperation operation) throws NoSuchMethodException {
+ String name = operation.getJavaMethod().getName();
+ List<Operation> actualOps = (List<Operation>) operation.getInterface().getAttributes().get("ASYNC-SERVER-OPERATIONS");
+ Operation matchingOp = null;
+ for( Operation op: actualOps ) {
+ if( op.getName().equals(name) ) {
+ matchingOp = op;
+ break;
+ }
+ } // end for
+ if( matchingOp == null ) throw new NoSuchMethodException("No matching async method for operation " + operation.getName());
+
+ int numParams = matchingOp.getInputType().getLogical().size();
+
+ List<Method> matchingMethods = new ArrayList<Method>();
+ for (Method m : implClass.getMethods()) {
+ if (m.getName().equals(name) && m.getParameterTypes().length == (numParams) ) {
+ matchingMethods.add(m);
+ }
+ }
+
+ if (matchingMethods.size() == 1) {
+ return matchingMethods.get(0);
+ }
+ if (matchingMethods.size() > 1) {
+ Class<?>[] paramTypes = getPhysicalTypes(matchingOp);
+ return implClass.getMethod(name, paramTypes);
+ }
+
+ // No matching method found
+ throw new NoSuchMethodException("No matching method for operation " + operation.getName()
+ + " is found on " + implClass);
+
+ } // end method findAsyncServerMethod
/**
* @Deprecated
diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java
index 4384213bf5..7169cc164d 100644
--- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java
+++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java
@@ -33,6 +33,7 @@ public class JavaOperationImpl extends OperationImpl implements JavaOperation {
private Method method;
private String action;
+ private boolean isAsyncServer = false;
public Method getJavaMethod() {
return method;
@@ -74,6 +75,22 @@ public class JavaOperationImpl extends OperationImpl implements JavaOperation {
return false;
return true;
}
+
+ /**
+ * Sets whether this operation has async server style
+ * @param isAsync - "true" marks this operation as async server style
+ */
+ public void setAsyncServer( boolean isAsync ) {
+ isAsyncServer = isAsync;
+ }
+
+ /**
+ * Indicates whether this operation is async server style
+ * @return - true if the operation is async server style
+ */
+ public boolean isAsyncServer() {
+ return isAsyncServer;
+ }
@Override
public String toString() {