diff options
Diffstat (limited to 'branches/sca-java-1.x/modules')
5 files changed, 279 insertions, 15 deletions
diff --git a/branches/sca-java-1.x/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java b/branches/sca-java-1.x/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java index 5814f3d215..ee26d61c42 100644 --- a/branches/sca-java-1.x/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java +++ b/branches/sca-java-1.x/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java @@ -20,7 +20,10 @@ package org.apache.tuscany.sca.core.databinding.wire; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.xml.namespace.QName; @@ -31,6 +34,7 @@ import org.apache.tuscany.sca.interfacedef.DataType; import org.apache.tuscany.sca.interfacedef.FaultExceptionMapper; import org.apache.tuscany.sca.interfacedef.Operation; import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; import org.apache.tuscany.sca.interfacedef.util.FaultException; import org.apache.tuscany.sca.interfacedef.util.XMLType; import org.apache.tuscany.sca.invocation.DataExchangeSemantics; @@ -63,6 +67,21 @@ public class DataTransformationInterceptor implements Interceptor, DataExchangeS super(); this.sourceOperation = sourceOperation; this.targetOperation = targetOperation; + if ( sourceOperation instanceof JavaOperation ) { + JavaOperation javaOp = (JavaOperation) sourceOperation; + Method sourceMethod = javaOp.getJavaMethod(); + } + // Holder pattern. In order to perform data mediation on Holder return types, it is + // necessary to set up a data transformation on the Holder<T> class T. on return. + DataType<DataType> returnTargetType = getFirstHolderType( sourceOperation.getInputType() ); + if ( returnTargetType != null ) { + this.sourceOperation.setOutputType(returnTargetType); + } + returnTargetType = getFirstHolderType( targetOperation.getInputType() ); + if ( returnTargetType != null ) { + this.targetOperation.setOutputType(returnTargetType); + } + this.mediator = mediator; this.wire = wire; this.faultExceptionMapper = faultExceptionMapper; @@ -73,15 +92,17 @@ public class DataTransformationInterceptor implements Interceptor, DataExchangeS } public Message invoke(Message msg) { + // System.out.println( "DataTransformationInterceptor.invoke source input type=" + sourceOperation.getInputType() ); + // System.out.println( "DataTransformationInterceptor.invoke target input type =" + targetOperation.getInputType() ); Object input = transform(msg.getBody(), sourceOperation.getInputType(), targetOperation.getInputType(), false); msg.setBody(input); Message resultMsg = next.invoke(msg); - Object result = resultMsg.getBody(); if (sourceOperation.isNonBlocking()) { // Not to reset the message body return resultMsg; } + Object result = resultMsg.getBody(); // FIXME: Should we fix the Operation model so that getOutputType // returns DataType<DataType<T>>? DataType<DataType> targetType = @@ -164,6 +185,7 @@ public class DataTransformationInterceptor implements Interceptor, DataExchangeS } } else { + // !resultMsg.isFault() assert !(result instanceof Throwable) : "Expected messages that are not throwable " + result; Object newResult = transform(result, targetType, sourceType, true); @@ -261,4 +283,32 @@ public class DataTransformationInterceptor implements Interceptor, DataExchangeS return true; } + /** + * Returns return type for first Holder in input list. + * Returns null if the inputs do not contain a Holder. + */ + protected static DataType<DataType> getFirstHolderType( DataType<List<DataType>> inputTypes ) { + if (inputTypes != null) { + List<DataType> logicalType = inputTypes.getLogical(); + if (logicalType != null) { + for (int i = 0; i < logicalType.size(); i++) { + DataType dataType = logicalType.get(i); + if (isHolder(dataType.getGenericType())) { + // Fix up output from void to returned data type. + // System.out.println("DataTransformationInterceptor.<> source input[" + i + "] is Holder, logicalType=" + dataType); + return dataType; + } + } + } + } + return null; + } + + protected static boolean isHolder( Type type ) { + String typeString = type.toString(); + if ( typeString.startsWith( "javax.xml.ws.Holder" ) ) { + return true; + } + return false; + } } diff --git a/branches/sca-java-1.x/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java b/branches/sca-java-1.x/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java index a23b9af9ad..4216217028 100644 --- a/branches/sca-java-1.x/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java +++ b/branches/sca-java-1.x/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java @@ -23,6 +23,8 @@ import java.io.Serializable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,6 +60,10 @@ import org.osoa.sca.ConversationEndedException; import org.osoa.sca.ServiceReference; import org.osoa.sca.ServiceRuntimeException; +import java.util.Iterator; +import javax.xml.ws.Holder; + + /** * @version $Rev$ $Date$ */ @@ -150,8 +156,24 @@ public class JDKInvocationHandler implements InvocationHandler, Serializable { throw new IllegalArgumentException("No matching operation is found: " + method); } - // send the invocation down the wire - Object result = invoke(chain, args, wire, source); + // Holder pattern. Items stored in a Holder<T> are promoted to T. + // After the invoke, the returned data <T> are placed back in Holder<T>. + Object [] promotedArgs = promoteHolderArgs( args ); + + Object result = invoke(chain, promotedArgs, wire, source); + + // Returned Holder data <T> are placed back in Holder<T>. + Class [] parameters = method.getParameterTypes(); + if ( parameters != null ) { + for ( int i = 0; i < parameters.length; i++ ) { + Class parameterType = parameters[ i ]; + if ( isHolder( parameterType ) ) { + // Pop results and place in holder (demote). + Holder holder = (Holder) args[ i ]; + holder.value = result; + } + } + } return result; } @@ -272,8 +294,9 @@ public class JDKInvocationHandler implements InvocationHandler, Serializable { } Invoker headInvoker = chain.getHeadInvoker(); Operation operation = chain.getTargetOperation(); - msg.setOperation(operation); - msg.setBody(args); + + msg.setOperation(operation); + msg.setBody( args ); Message msgContext = ThreadMessageContext.getMessageContext(); Object currentConversationID = msgContext.getFrom().getReferenceParameters().getConversationID(); @@ -513,4 +536,59 @@ public class JDKInvocationHandler implements InvocationHandler, Serializable { } + + /** + * Creates a copy of arguments. Holder<T> values are promoted to T. + * Note. It is essential that arg Holders not be destroyed here. + * PromotedArgs should not destroy holders. They are used on response return. + * @param args containing Holders and other objects. + * @return Object [] + */ + protected static Object [] promoteHolderArgs( Object [] args ) { + if ( args == null ) + return args; + Object [] promotedArgs = new Object[ args.length ]; + + for ( int i = 0; i < args.length; i++ ) { + Object argument = args[ i ]; + if ( argument != null ) { + if ( isHolder( argument ) ) { + promotedArgs[ i ] = ((Holder)argument).value; + } else { + promotedArgs[ i ] = args[ i ]; + } + + } + } + return promotedArgs; + } + + /** + * Given a Class, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return boolean whether class is Holder type. + */ + protected static boolean isHolder( Class testClass ) { + if ( testClass.getName().startsWith( "javax.xml.ws.Holder" )) { + return true; + } + return false; + } + + + /** + * Given an Object, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return boolean stating whether Object is a Holder type. + * @author DOB + */ + protected static boolean isHolder( Object object ) { + String objectName = object.getClass().getName(); + if ( object instanceof javax.xml.ws.Holder ) { + return true; + } + return false; + } + + } diff --git a/branches/sca-java-1.x/modules/implementation-java-runtime/src/main/java/org/apache/tuscany/sca/implementation/java/invocation/JavaImplementationInvoker.java b/branches/sca-java-1.x/modules/implementation-java-runtime/src/main/java/org/apache/tuscany/sca/implementation/java/invocation/JavaImplementationInvoker.java index 25d538cff4..1ce4643ccd 100644 --- a/branches/sca-java-1.x/modules/implementation-java-runtime/src/main/java/org/apache/tuscany/sca/implementation/java/invocation/JavaImplementationInvoker.java +++ b/branches/sca-java-1.x/modules/implementation-java-runtime/src/main/java/org/apache/tuscany/sca/implementation/java/invocation/JavaImplementationInvoker.java @@ -20,6 +20,10 @@ package org.apache.tuscany.sca.implementation.java.invocation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; +import java.util.Vector; + +import javax.xml.ws.Holder; import org.apache.tuscany.sca.core.context.InstanceWrapper; import org.apache.tuscany.sca.core.scope.Scope; @@ -68,6 +72,7 @@ public class JavaImplementationInvoker implements Invoker, DataExchangeSemantics @SuppressWarnings("unchecked") public Message invoke(Message msg) { + int argumentHolderCount = 0; Operation op = msg.getOperation(); if (op == null) { op = this.operation; @@ -125,6 +130,31 @@ public class JavaImplementationInvoker implements Invoker, DataExchangeSemantics } } + // Holder pattern. Any payload parameters <T> which are should be in holders are placed in Holder<T>. + if ( imethod != null) { + Class<?> [] params = imethod.getParameterTypes(); + if ( params != null ) { + for ( int i = 0; i < params.length; i++ ) { + Class<?> parameter = params[ i ]; + if ( isHolder( parameter )) { + // System.out.println( "JavaImplementationInvoker.invoke parameter " + i + " is Holder. Payload isArray=" + (payload != null ? payload.getClass().isArray() : "null" )); + if (payload != null && !payload.getClass().isArray()) { + // Promote single param from <T> to Holder<T> + payload = new Holder( payload ); + } else { + // Promote array params from [<T>] to [Holder<T>] + Object [] payloadArray = (Object[]) payload; + for ( int j = 0; j < payloadArray.length; j++ ) { + Object item = payloadArray[ j ]; + payloadArray[ j ] = new Holder( item ); + } + } + argumentHolderCount++; + } + } + } + } + Object ret; if (payload != null && !payload.getClass().isArray()) { ret = imethod.invoke(instance, payload); @@ -140,7 +170,52 @@ public class JavaImplementationInvoker implements Invoker, DataExchangeSemantics scopeContainer.remove(contextId); parameters.setConversationID(null); } - msg.setBody(ret); + + if (argumentHolderCount > 0) { + // Holder pattern. Any payload Holder<T> types are returned as the message body. + List returnArgs = new Vector<Object>(); + int foundHolders = 0; + if ( imethod != null) { + Class<?> [] params = imethod.getParameterTypes(); + if ( params != null ) { + for ( int i = 0; i < params.length; i++ ) { + Class<?> parameter = params[ i ]; + // System.out.println( "JavaImplementationInvoker.invoke return parameter " + i + " type=" + parameter.getClass().getName() ); + if ( isHolder( parameter )) { + if (payload != null && !payload.getClass().isArray()) { + // Demote params from Holder<T> to <T>. + Holder<Object> holder = (Holder<Object>) payload; + returnArgs.add( holder.value ); + foundHolders++; + } else { + // Demote array params from Holder<T> to <T>. + Object [] payloadArray = (Object[]) payload; + for ( int j = 0; j < payloadArray.length; j++ ) { + Holder<Object> item = (Holder<Object>) payloadArray[ j ]; + payloadArray[ j ] = item.value; + returnArgs.add( payloadArray[ j ] ); + } + foundHolders++; + } + } + } + } + } + // Although payload items are returned in a list, currently only support 1 return type. + if ( returnArgs.size() == 1 ) { + Object value = returnArgs.get( 0 ); + if (( value != null ) && ( value.getClass().isArray() )) { + Object [] values = (Object []) value; + if (( values != null ) && ( values.length > 0 )) { + msg.setBody( values[ 0 ] ); + } + } else + msg.setBody(value); + } else + msg.setBody(returnArgs.toArray()); + } else { + msg.setBody(ret); + } } catch (InvocationTargetException e) { Throwable cause = e.getTargetException(); boolean isChecked = false; @@ -196,4 +271,16 @@ public class JavaImplementationInvoker implements Invoker, DataExchangeSemantics return allowsPBR; } + /** + * Given a Class, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return + * @author DOB + */ + public static boolean isHolder( Class testClass ) { + if ( testClass.getName().equals( "javax.xml.ws.Holder" )) { + return true; + } + return false; + } } diff --git a/branches/sca-java-1.x/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java b/branches/sca-java-1.x/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java index 126b435989..fe99adccec 100644 --- a/branches/sca-java-1.x/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java +++ b/branches/sca-java-1.x/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java @@ -224,14 +224,26 @@ public class JavaInterfaceIntrospectorImpl { DataType<XMLType> returnDataType = returnType == void.class ? null : new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, method .getGenericReturnType(), xmlReturnType); + + // Input types List<DataType> paramDataTypes = new ArrayList<DataType>(parameterTypes.length); Type[] genericParamTypes = method.getGenericParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { Class paramType = parameterTypes[i]; XMLType xmlParamType = new XMLType(new QName(ns, "arg" + i), null); - paramDataTypes.add(new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, paramType, genericParamTypes[i], - xmlParamType)); + DataTypeImpl<XMLType> xmlDataType = new DataTypeImpl<XMLType>( + UNKNOWN_DATABINDING, paramType, genericParamTypes[i],xmlParamType); + // Holder pattern. Physical types of Holder<T> classes are updated to <T> to aid in transformations. + if ( isHolder( paramType )) { + Type firstActual = getFirstActualType( genericParamTypes[ i ] ); + if ( firstActual != null ) { + xmlDataType.setPhysical( (Class<?>)firstActual ); + } + } + paramDataTypes.add( xmlDataType); } + + // Fault types List<DataType> faultDataTypes = new ArrayList<DataType>(faultTypes.length); Type[] genericFaultTypes = method.getGenericExceptionTypes(); for (int i = 0; i < faultTypes.length; i++) { @@ -263,4 +275,31 @@ public class JavaInterfaceIntrospectorImpl { return operations; } + /** + * Given a Class, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return boolean whether testClass is Holder type. + */ + protected static boolean isHolder( Class testClass ) { + if ( testClass.getName().startsWith( "javax.xml.ws.Holder" )) { + return true; + } + return false; + } + + /** + * Given a Class<T>, returns T, otherwise null. + * @param testClass + * @return + */ + protected static Type getFirstActualType(Type genericType) { + if (genericType instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType)genericType; + Type[] actualTypes = pType.getActualTypeArguments(); + if ((actualTypes != null) && (actualTypes.length > 0)) { + return actualTypes[0]; + } + } + return null; + } } diff --git a/branches/sca-java-1.x/modules/interface/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java b/branches/sca-java-1.x/modules/interface/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java index c1c8400b71..8fa91a8e52 100644 --- a/branches/sca-java-1.x/modules/interface/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java +++ b/branches/sca-java-1.x/modules/interface/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java @@ -149,13 +149,6 @@ public class DataTypeImpl<L> implements DataType<L> { this.dataBinding = dataBinding; } - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(physical).append(" ").append(dataBinding).append(" ").append(logical); - return sb.toString(); - } - @SuppressWarnings("unchecked") @Override public Object clone() throws CloneNotSupportedException { @@ -216,4 +209,21 @@ public class DataTypeImpl<L> implements DataType<L> { } metaDataMap.put(type, metaData); } + + @Override + public String toString() { + // private Class<?> physical; + // private Type genericType; + // private L logical; + // private Map<Class<?>, Object> metaDataMap; + StringBuilder b = new StringBuilder( 256 ); + b.append( "DataType[" ); + b.append( "dataBinding=" + ((dataBinding==null) ? "null" : dataBinding) ); + b.append( ", genericType=" + ((genericType==null) ? "null" : genericType) ); + b.append( ", physical=" + ((physical==null) ? "null" : physical) ); + b.append( ", logical=" + ((logical==null) ? "null" : logical) ); + b.append( ", metaData size=" + ((metaDataMap==null) ? "0" : metaDataMap.size()) ); + b.append( "]" ); + return b.toString(); + } } |