From e5b7380c874745c989d1816b8f552504f038e1bc Mon Sep 17 00:00:00 2001 From: lresende Date: Thu, 26 Sep 2013 20:33:20 +0000 Subject: 2.0 branch for possible maintenance release git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1526672 13f79535-47bb-0310-9956-ffa450edef68 --- .../interfacedef/java/impl/JavaInterfaceImpl.java | 383 +++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 sca-java-2.x/branches/2.0/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java (limited to 'sca-java-2.x/branches/2.0/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java') diff --git a/sca-java-2.x/branches/2.0/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java b/sca-java-2.x/branches/2.0/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java new file mode 100644 index 0000000000..9adeb26451 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java @@ -0,0 +1,383 @@ +/* + * 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.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.contribution.Contribution; +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 static org.apache.tuscany.sca.interfacedef.Operation.IDL_INPUT; +import static org.apache.tuscany.sca.interfacedef.Operation.IDL_OUTPUT; + +import org.oasisopen.sca.ResponseDispatch; + +/** + * Represents a Java interface. + * + * @version $Rev$ $Date$ + */ +public class JavaInterfaceImpl extends InterfaceImpl implements JavaInterface { + + private String className; + private WeakReference> javaClass; + private Class callbackClass; + private QName qname; + private String jaxwsWSDLLocation; + private String jaxwsJavaInterfaceName; + private Contribution contributionContainingClass; + + 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() { + if (isUnresolved()) { + return className; + } else if (javaClass != null) { + return javaClass.get().getName(); + } else { + return null; + } + } + + public void setName(String className) { + if (!isUnresolved()) { + throw new IllegalStateException(); + } + this.className = className; + } + + public QName getQName() { + return qname; + } + + public void setQName(QName interfacename) { + qname = interfacename; + } + + public Class getJavaClass() { + if (javaClass != null){ + return javaClass.get(); + } else { + return null; + } + } + + public void setJavaClass(Class javaClass) { + this.javaClass = new WeakReference>(javaClass); + if (javaClass != null) { + this.className = javaClass.getName(); + } + } + + public Class getCallbackClass() { + return callbackClass; + } + + public void setCallbackClass(Class callbackClass) { + this.callbackClass = callbackClass; + } + + @Override + public String toString() { + return getName(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((className == null) ? 0 : className.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + JavaInterfaceImpl other = (JavaInterfaceImpl)obj; + if (isUnresolved() || other.isUnresolved()) { + if (className == null) { + if (other.className != null) + return false; + } else if (!className.equals(other.className)) + return false; + } else { + if (javaClass == null) { + if (other.javaClass != null) + return false; + } else if (!javaClass.get().equals(other.javaClass.get())) + return false; + if (callbackClass == null) { + if (other.callbackClass != null) + return false; + } else if (!callbackClass.equals(other.callbackClass)) + return false; + } + + return true; + } + + public List getOperations() { + if( !isUnresolved() && isAsyncServer() ) { + return equivalentSyncOperations(); + } else { + return super.getOperations(); + } + } // end method getOperations + + + private List syncOperations = null; + private List equivalentSyncOperations() { + if( syncOperations != null ) return syncOperations; + List allOperations = super.getOperations(); + syncOperations = new ArrayList(); + 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 ) + * - 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 ); + String opName = operation.getName(); + + // 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> requestParams = operation.getInputType(); + +// DataType> inputType = prepareSyncInputParams( requestParams ); +// DataType> returnDataType = prepareSyncReturnParam( requestParams ); + List faultDataTypes = prepareSyncFaults( operation ); + + syncOperation.setName(opName); + syncOperation.setAsyncServer(true); + syncOperation.setInputWrapper(operation.getInputWrapper()); + syncOperation.setOutputWrapper(operation.getOutputWrapper()); + syncOperation.setInputWrapperStyle(operation.isInputWrapperStyle()); + syncOperation.setOutputWrapperStyle(operation.isOutputWrapperStyle()); + syncOperation.setHasArrayWrappedOutput(operation.hasArrayWrappedOutput()); + syncOperation.setNotSubjectToWrapping(operation.isNotSubjectToWrapping()); +// syncOperation.setInputType(inputType); +// syncOperation.setOutputType(returnDataType); + syncOperation.setInputType(operation.getInputType()); + syncOperation.setOutputType(operation.getOutputType()); + 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> prepareSyncInputParams( DataType> requestParams ) { + List requestLogical = requestParams.getLogical(); + int paramCount = requestLogical.size(); + + // Copy the list of async parameters, removing the final DispatchResponse + List asyncParams = new ArrayList( paramCount - 1); + for( int i = 0 ; i < (paramCount - 1) ; i++ ) { + asyncParams.add( requestLogical.get(i) ); + } // end for + + DataType> inputType = + new DataTypeImpl>(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 + */ + @SuppressWarnings("rawtypes") + private DataType> prepareSyncReturnParam( DataType> requestParams ) { + List 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 returnDataType = + returnType == void.class ? null : new DataTypeImpl(UNKNOWN_DATABINDING, returnType, xmlReturnType); + + ArrayList returnTypes = new ArrayList(); + returnTypes.add(returnDataType); + + DataType> outputType = + new DataTypeImpl>(IDL_OUTPUT, requestParams.getPhysical(), returnTypes); + + return outputType; + } // end method prepareSyncReturnParam + + /** + * Prepare the set of equivalent sync faults for a given async operation + * @return - the list of faults + */ + private List 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 ) + * @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 ) { + + if (operation.isAsyncServer()) { + return true; + } + // Async form operations have: + // 1) void return type (equivalent to an output logical List of size '0') + // 2) name ending in "Async" + // 3) final parameter which is of ResponseDispatch type + int size = operation.getOutputType().getLogical().size(); + if (size != 0) { + return false; + } + + if ( !operation.getName().endsWith("Async") ) return false; + + 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 intents = getRequiredIntents(); + for( Intent intent: intents ) { + if ( intent.getName().equals(ASYNC_INVOCATION) ) { + return true; + } + } // end for + return false; + } // end method isAsyncServer + + public String getJAXWSWSDLLocation() { + return jaxwsWSDLLocation; + } + + public void setJAXWSWSDLLocation(String wsdlLocation) { + this.jaxwsWSDLLocation = wsdlLocation; + } + + public String getJAXWSJavaInterfaceName() { + return jaxwsJavaInterfaceName; + } + + public void setJAXWSJavaInterfaceName(String javaInterfaceName) { + this.jaxwsJavaInterfaceName = javaInterfaceName; + } + + /** + * A Java class may reference a WSDL file via a JAXWS annotation. We need to resolve + * the WSDL file location in the context of the same contribution that holds the + * Java file. In order to do this we need to remember the actual contribution that + * was used to resolve a Java class. + * + * @return + */ + public Contribution getContributionContainingClass() { + return contributionContainingClass; + } + + public void setContributionContainingClass(Contribution contributionContainingClass) { + this.contributionContainingClass = contributionContainingClass; + } +} -- cgit v1.2.3