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

org.fabric3.introspection.impl.contract.DefaultContractProcessor Maven / Gradle / Ivy

There is a newer version: 1.1
Show newest version
/*
 * 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.fabric3.introspection.impl.contract;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;

import org.osoa.sca.Constants;
import org.osoa.sca.annotations.Callback;
import org.osoa.sca.annotations.Conversational;
import org.osoa.sca.annotations.EndsConversation;
import org.osoa.sca.annotations.OneWay;
import org.osoa.sca.annotations.Remotable;
import org.osoa.sca.annotations.Reference;

import org.fabric3.introspection.contract.ContractProcessor;
import org.fabric3.introspection.contract.InvalidServiceContractException;
import org.fabric3.introspection.IntrospectionHelper;
import org.fabric3.introspection.TypeMapping;
import org.fabric3.scdl.DataType;
import org.fabric3.scdl.Operation;
import static org.fabric3.scdl.Operation.CONVERSATION_END;
import static org.fabric3.scdl.Operation.NO_CONVERSATION;

/**
 * Default implementation of a ContractProcessor for Java interfaces.
 *
 * @version $Rev: 3105 $ $Date: 2008-03-15 16:47:31 +0000 (Sat, 15 Mar 2008) $
 */
public class DefaultContractProcessor implements ContractProcessor {
    public static final String IDL_INPUT = "idl:input";
    public static final QName ONEWAY_INTENT = new QName(Constants.SCA_NS, "oneWay");

    private final IntrospectionHelper helper;

    public DefaultContractProcessor(@Reference IntrospectionHelper helper) {
        this.helper = helper;
    }

    public JavaServiceContract introspect(TypeMapping typeMapping, Type type) throws InvalidServiceContractException {
        if (type instanceof Class) {
            return introspect(typeMapping, (Class) type);
        } else {
            throw new UnsupportedOperationException("Interface introspection is only supported for classes");
        }
    }

    public JavaServiceContract introspect(TypeMapping typeMapping, Class interfaze) throws InvalidServiceContractException {
        JavaServiceContract contract = introspectInterface(typeMapping, interfaze);
        Callback callback = interfaze.getAnnotation(Callback.class);
        if (callback != null) {
            Class callbackClass = callback.value();
            if (Void.class.equals(callbackClass)) {
                throw new MissingCallbackException(interfaze.getName());
            }
            JavaServiceContract callbackContract = introspectInterface(typeMapping, callbackClass);
            contract.setCallbackContract(callbackContract);
        }
        return contract;
    }

    /**
     * Introspects a class, returning its service contract.
     *
     * @param interfaze the interface to introspect
     * @return the service contract
     * @throws InvalidServiceContractException
     *          if the class is an invalid service inteface or contains invalid service meatadata
     */
    private JavaServiceContract introspectInterface(TypeMapping typeMapping, Class interfaze) throws InvalidServiceContractException {
        JavaServiceContract contract = new JavaServiceContract(interfaze);
        contract.setInterfaceName(interfaze.getSimpleName());

        // TODO this should be refactored to its own processor
        boolean remotable = interfaze.isAnnotationPresent(Remotable.class);
        contract.setRemotable(remotable);

        // TODO this should be refactored to its own processor
        boolean conversational = helper.isAnnotationPresent(interfaze, Conversational.class);
        contract.setConversational(conversational);

        contract.setOperations(getOperations(typeMapping, interfaze, remotable, conversational));

        return contract;
    }

    private  List> getOperations(TypeMapping typeMapping,
                                                    Class type,
                                                    boolean remotable,
                                                    boolean conversational)
            throws InvalidServiceContractException {
        Method[] methods = type.getMethods();
        List> operations = new ArrayList>(methods.length);
        for (Method method : methods) {
            String name = method.getName();
            if (remotable) {
                for (Operation operation : operations) {
                    if (operation.getName().equals(name)) {
                        throw new OverloadedOperationException(method);
                    }
                }
            }

            Class returnType = method.getReturnType();
            Class[] paramTypes = method.getParameterTypes();
            Class[] faultTypes = method.getExceptionTypes();

            int conversationSequence = NO_CONVERSATION;
            if (method.isAnnotationPresent(EndsConversation.class)) {
                if (!conversational) {
                    throw new InvalidConversationalOperationException(
                            "Method is marked as end conversation but contract is not conversational",
                            method.getDeclaringClass().getName(),
                            method);
                }
                conversationSequence = CONVERSATION_END;
            } else if (conversational) {
                conversationSequence = Operation.CONVERSATION_CONTINUE;
            }

            Type actualReturnType = typeMapping.getActualType(returnType);
            DataType returnDataType = new DataType(actualReturnType, actualReturnType);
            List> paramDataTypes = new ArrayList>(paramTypes.length);
            for (Type paramType : paramTypes) {
                Type actualType = typeMapping.getActualType(paramType);
                paramDataTypes.add(new DataType(actualType, actualType));
            }
            List> faultDataTypes = new ArrayList>(faultTypes.length);
            for (Type faultType : faultTypes) {
                Type actualType = typeMapping.getActualType(faultType);
                faultDataTypes.add(new DataType(actualType, actualType));
            }

            DataType>> inputType =
                    new DataType>>(Object[].class, paramDataTypes);
            Operation operation = new Operation(name,
                                                            inputType,
                                                            returnDataType,
                                                            faultDataTypes,
                                                            conversationSequence);

            // TODO this should be refactored to its own processor
            if (method.isAnnotationPresent(OneWay.class)) {
                operation.addIntent(ONEWAY_INTENT);
            }
            operations.add(operation);
        }
        return operations;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy