All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceImpl Maven / Gradle / Ivy

/*
 * 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: 1213702 $ $Date: 2011-12-13 06:12:38 -0800 (Tue, 13 Dec 2011) $
 */
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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy