Package org.jibx.ws.server

Source Code of org.jibx.ws.server.Operation

/*
* Copyright (c) 2008, Sosnoski Software Associates Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of
* JiBX nor the names of its contributors may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT Lm_outputClassIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jibx.ws.server;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.jibx.runtime.JiBXException;
import org.jibx.ws.WsConfigurationException;
import org.jibx.ws.WsException;
import org.jibx.ws.context.InContext;
import org.jibx.ws.context.MessageContext;
import org.jibx.ws.context.OutContext;
import org.jibx.ws.process.Processor;

/**
* An operation that can be invoked by a service. Each {@link Service} is associated with a Java class. Each
* {@link Operation} for the <code>Service</code> corresponds to a method of that Java class.
* <p>
* The static {@link #newInstance(Class, OperationDefinition)} method constructs the <code>Operation</code> by
* determining which method within the service class matches the specified {@link OperationDefinition}.
*
* @author Nigel Charman
*/
public final class Operation
{
//    private final String m_operationName;
//    private final String m_inputMessageName;
//    private final String m_outputMessageName;
    private final Method m_method;
    private final Class m_inputClass;
    private final Class m_outputClass;
    private final ParamIndices m_idxs;

    /**
     * Constructs an {@link Operation} that corresponds to the method of the specified <code>serviceClass</code> that
     * matches the specified {@link OperationDefinition}.
     * <p>
     * The operation is linked to the method in the service class where:
     * <ul>
     * <li>the method name is the same as {@link OperationDefinition#getMethodName()}, and</li>
     * <li>if {@link OperationDefinition#getInputClassName()} is <code>non-null</code>, the type of the first
     * parameter of the method must match this value, and</li>
     * <li>if {@link OperationDefinition#getOutputClassName()} is <code>non-null</code>, the return type of the
     * method must match this value.</li>
     * <li>The method may have an additional parameter of type {@link InContext}, or</li>
     * <li>The method may have 2 additional parameters of type {@link InContext} and {@link OutContext}.</li>
     * </ul>
     *
     * @param serviceClass the class that contains the method to be associated with the <code>Operation</code>
     * @param opdef the definition of the <code>Operation</code>
     * @return a new <code>Operation</code>
     * @throws WsConfigurationException if no method in the <code>serviceClass</code> matches the <code>opdef</code>
     */
    public static Operation newInstance(Class serviceClass, OperationDefinition opdef) throws WsConfigurationException {
        String methodName = opdef.getMethodName();
        if (methodName == null) {
            throw new IllegalArgumentException("Method Name must be set on operation definition");
        }

        Method[] methods = serviceClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            if (methodName.equals(methods[i].getName())) {
                Method method = methods[i];
                ParamIndices idxs = matchSignature(method, opdef.getInputClassName(), opdef.getOutputClassName());
                if (idxs != null) {
                    return new Operation(opdef, method, idxs);
                }
            }
        }

        throw new WsConfigurationException("Method " + methodName + " not found in " + serviceClass.getName()
            + " with expected signature");
    }

    /**
     * Construct the Operation.
     *
     * @param opdef the definition of the operation
     * @param method the method to be associated with the Operation
     * @param idxs specifies the indices of the method parameters
     */
    private Operation(OperationDefinition opdef, Method method, ParamIndices idxs) {
        m_method = method;
        m_idxs = idxs;

        Class[] params = method.getParameterTypes();
        m_inputClass = (params.length == 0) ? null : params[0];

        Class result = method.getReturnType();
        m_outputClass = (result == void.class) ? null : result;

//        m_operationName = (opdef.getOperationName() != null) ? opdef.getOperationName() : method.getName();
//
//        if (opdef.getInputMessageName() != null) {
//            m_inputMessageName = opdef.getInputMessageName();
//        } else {
//            if (m_inputClass != null) {
//                m_inputMessageName = splitClassName(m_inputClass.getName());
//            } else {
//                m_inputMessageName = null;
//            }
//        }
//        if (opdef.getOutputMessageName() != null) {
//            m_outputMessageName = opdef.getOutputMessageName();
//        } else {
//            if (m_outputClass != null) {
//                m_outputMessageName = splitClassName(m_outputClass.getName());
//            } else {
//                m_outputMessageName = null;
//            }
//        }
    }

    /**
     * Invokes the method that is associated with this operation, passing the optional payload as a parameter. If the
     * method definition includes {@link InContext} or {@link OutContext} parameters, the current contexts are retrieved
     * from the specified {@link Processor}.
     *
     * @param serviceObj the current Service object, on which to invoke the method. If the method is static, this
     * parameter may be set to <code>null</code>. For non-static methods, the parameter must be <code>non-null</code>.
     * @param payload the object to pass as an input parameter, or <code>null</code> if the method does not have an
     * input parameter.
     * @param processor the current processor. Must be <code>non-null</code> if the method definition includes
     * {@link InContext} or {@link OutContext} parameters.
     * @return the return value from the method, or <code>null</code> for void methods.
     * @throws InvocationTargetException wraps an exception thrown by the method that was invoked
     * @throws WsException if the processor is in an invalid state to provide <code>InContext</code> or
     * <code>OutContext</code> parameters
     */
    public Object invoke(Object serviceObj, Object payload, Processor processor) throws InvocationTargetException,
        WsException {

        Object[] args = null;

        if (m_idxs.m_paramCount > 0) {
            args = new Object[m_idxs.m_paramCount];
            if (m_idxs.m_payloadIndex != -1) {
                args[m_idxs.m_payloadIndex] = payload;
            }
            if (m_idxs.m_inContextIndex != -1) {
                MessageContext currentContext = processor.getCurrentMessageContext();
                if (!(currentContext instanceof InContext)) {
                    throw new WsException(
                        "Error - attempt to invoke operation when current context is not an InContext");
                }
                args[m_idxs.m_inContextIndex] = currentContext;
            }
            if (m_idxs.m_outContextIndex != -1) {
                MessageContext nextContext = processor.getNextMessageContext();
                if (!(nextContext instanceof OutContext)) {
                    throw new WsException(
                        "Error - attempt to invoke 2-way operation when next message context is not an OutContext");
                }
                args[m_idxs.m_outContextIndex] = nextContext;
            }
        }

        try {
            return m_method.invoke(serviceObj, args);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(
                "Operation does not have access to method that was visible on construction - " + e.getMessage());
        }
    }

    /**
     * Check for signature match with method. If the signature matches, this saves the method information.
     *
     * @throws JiBXException on nesting error
     */
    private static ParamIndices matchSignature(Method method, String inputClassName, String outputClassName) {
        ParamIndices idxs = new ParamIndices();
        Class[] params = method.getParameterTypes();
        if (params.length == 0) {
            if (inputClassName != null) {
                return null;
            }
        } else {
            if (inputClassName == null || inputClassName.equals(params[0].getName())) {
                idxs.m_payloadIndex = 0;
            } else {
                return null;
            }
            if (params.length > 1) {
                if (params[1] == InContext.class) {
                    idxs.m_inContextIndex = 1;
                } else {
                    return null;
                }
                if (params.length > 2) {
                    if (params[2] == OutContext.class) {
                        idxs.m_outContextIndex = 2;
                    } else {
                        return null;
                    }
                    if (params.length > 3) {
                        return null;
                    }
                }
            }

        }
        if (outputClassName != null) {
            if (!outputClassName.equals(method.getReturnType().getName())) {
                return null;
            }
        }
        idxs.m_paramCount = params.length;

        return idxs;
    }

//    /**
//     * Get simple class name from fully-qualified class name.
//     *
//     * @param full fully-qualified class name
//     * @return class name without package information
//     */
//    private String splitClassName(String full) {
//        int split = full.lastIndexOf('.');
//        if (split >= 0) {
//            return full.substring(split + 1);
//        } else {
//            return full;
//        }
//    }

    /**
     * Returns the class of the input parameter to the method, or <code>null</code> if there is no input parameter.
     * The <code>payload</code> passed to the {@link #invoke(Object, Object, Processor)} method must be of this class.
     *
     * @return inputClass
     */
    public Class getInputClass() {
        return m_inputClass;
    }

    /**
     * Returns the class of the return value of the method, or <code>null</code> if it has a <code>void</code>
     * return type. The {@link #invoke(Object, Object, Processor)} method will return an object of this type.
     *
     * @return outputClass
     */
    public Class getOutputClass() {
        return m_outputClass;
    }

//    /**
//     * Returns the name of the operation. This will be set to the value from
//     * {@link OperationDefinition#getOperationName()} if <code>non-null</code>, or to the method name otherwise.
//     *
//     * @return operation name
//     */
//    public String getOperationName() {
//        return m_operationName;
//    }
//
//    /**
//     * Returns the name of the input message. This will be set to the value from
//     * {@link OperationDefinition#getInputMessageName()} if <code>non-null</code>, or to the class name of the input
//     * parameter otherwise (omitting the package name). If there is no input parameter, this method will return
//     * <code>null</code>.
//     *
//     * @return input message name
//     */
//    public String getInputName() {
//        return m_inputMessageName;
//    }
//
//    /**
//     * Returns the name of the output message. This will be set to the value from
//     * {@link OperationDefinition#getOutputMessageName()} if <code>non-null</code>, or to the class name of the
//     * method's return value otherwise (omitting the package name). If the method has a <code>void</code> return type,
//     * this method will return <code>null</code>.
//     *
//     * @return output message name
//     */
//    public String getOutputName() {
//        return m_outputMessageName;
//    }

    /**
     * Returns whether the associated method is static.
     *
     * @return <code>true</code> if the method is static, <code>false</code> otherwise.
     */
    public boolean isStaticMethod() {
        int mods = m_method.getModifiers();
        return Modifier.isStatic(mods);
    }

    /** {@inheritDoc} */
    public String toString() {
        return m_method.toString();
    }
   
    /** Stores the indices of the parameters to the method. */
    private static final class ParamIndices
    {
        private ParamIndices() {
        }
       
        /** The number of parameters to the method. */
        private int m_paramCount;
       
        /** The index of the payload (input) parameter, or -1 if there is no payload parameter. */
        private int m_payloadIndex = -1;

        /** The index of the {@link InContext} parameter, or -1 if there is no {@link InContext} parameter. */
        private int m_inContextIndex = -1;

        /** The index of the {@link OutContext} parameter, or -1 if there is no {@link OutContext} parameter. */
        private int m_outContextIndex = -1;
    }
}
TOP

Related Classes of org.jibx.ws.server.Operation

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.