Package org.apache.tuscany.sca.interfacedef.java.jaxws

Source Code of org.apache.tuscany.sca.interfacedef.java.jaxws.JAXWSAsyncInterfaceProcessor

/*
* 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.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;

import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;

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.JavaOperation;
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)) {
                JavaOperation op = (JavaOperation)o;
                if (op.getJavaMethod().getName().endsWith(ASYNC)) {
                    continue;
                }
                for (Operation asyncOp : getAsyncOperations(javaInterface.getOperations(), op)) {
                    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) {

        if (asyncOperation.getOutputType() == null || Response.class != asyncOperation.getOutputType().getPhysical()) {
            // The return type is not Response<T>
            return false;
        }

        //the same parameter signature as M
        List<DataType> operationInputType = operation.getInputType().getLogical();
        List<DataType> asyncOperationInputType = asyncOperation.getInputType().getLogical();
        int size = operationInputType.size();
        if (asyncOperationInputType.size() != size) {
            return false;
        }
        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) {
            Class<?> asyncReturnTypeClass = (Class<?>)asyncOperationOutputType.getPhysical();
            if (asyncReturnTypeClass == Response.class) {
                //now check the actual type of the Response<R> with R
                Class<?> returnType = operationOutputType.getPhysical();
                Class<?> asyncActualReturnTypeClass = Object.class;
                if (asyncOperationOutputType.getGenericType() instanceof ParameterizedType) {
                    ParameterizedType asyncReturnType = (ParameterizedType)asyncOperationOutputType.getGenericType();
                    asyncActualReturnTypeClass = (Class<?>)asyncReturnType.getActualTypeArguments()[0];
                }

                if (operation.getWrapper() != null) {
                    // The return type could be the wrapper type per JAX-WS spec
                    Class<?> wrapperClass = operation.getWrapper().getOutputWrapperClass();
                    if (wrapperClass == asyncActualReturnTypeClass) {
                        return true;
                    }
                }
                if (returnType == asyncActualReturnTypeClass || returnType.isPrimitive()
                    && primitiveAssignable(returnType, asyncActualReturnTypeClass)) {
                    return true;
                } 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) {

        if (asyncOperation.getOutputType() == null || Future.class != asyncOperation.getOutputType().getPhysical()) {
            // The return type is not Future<?>
            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();
        if (asyncOperationInputType.size() != size + 1) {
            return false;
        }
        for (int i = 0; i < size; i++) {
            if (!isCompatible(operationInputType.get(i), asyncOperationInputType.get(i))) {
                return false;
            }
        }

        Type genericParamType = asyncOperationInputType.get(size).getGenericType();

        Class<?> asyncLastParameterTypeClass = asyncOperationInputType.get(size).getPhysical();
        if (asyncLastParameterTypeClass == AsyncHandler.class) {
            //now check the actual type of the AsyncHandler<R> with R
            Class<?> returnType = operation.getOutputType().getPhysical();
            Class<?> asyncActualLastParameterTypeClass = Object.class;
            if (genericParamType instanceof ParameterizedType) {
                ParameterizedType asyncLastParameterType = (ParameterizedType)genericParamType;
                asyncActualLastParameterTypeClass = (Class<?>)asyncLastParameterType.getActualTypeArguments()[0];
            }

            if (operation.getWrapper() != null) {
                // The return type could be the wrapper type per JAX-WS spec
                Class<?> wrapperClass = operation.getWrapper().getOutputWrapperClass();
                if (wrapperClass == asyncActualLastParameterTypeClass) {
                    return true;
                }
            }

            if (returnType == asyncActualLastParameterTypeClass || returnType.isPrimitive()
                && primitiveAssignable(returnType, asyncActualLastParameterTypeClass)) {
                return true;
            } else {
                return false;
            }
        }

        return true;
    }

    /**
     * Get operation by name
     *
     * @param operations
     * @param operationName
     * @return
     */
    private static List<Operation> getAsyncOperations(List<Operation> operations, JavaOperation op) {
        List<Operation> returnOperations = new ArrayList<Operation>();

        for (Operation o : operations) {
            if (o == op) {
                continue;
            }
            String operationName = op.getName();
            if (o.getName().equals(operationName)) {
                // Async operations have the same name when @WebMethod is present
                /*
                JavaOperation jop = (JavaOperation)o;
                if (op.getJavaMethod().getName().equals(jop.getJavaMethod().getName() + ASYNC)) {
                    returnOperations.add(o);
                }
                */
                returnOperations.add(o);
            } else 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;
        }
    }
}
TOP

Related Classes of org.apache.tuscany.sca.interfacedef.java.jaxws.JAXWSAsyncInterfaceProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.