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

org.jibx.ws.server.Operation Maven / Gradle / Ivy

The newest version!
/*
 * 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 Service corresponds to a method of that Java class.
 * 

* The static {@link #newInstance(Class, OperationDefinition)} method constructs the Operation 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 serviceClass that * matches the specified {@link OperationDefinition}. *

* The operation is linked to the method in the service class where: *

    *
  • the method name is the same as {@link OperationDefinition#getMethodName()}, and
  • *
  • if {@link OperationDefinition#getInputClassName()} is non-null, the type of the first * parameter of the method must match this value, and
  • *
  • if {@link OperationDefinition#getOutputClassName()} is non-null, the return type of the * method must match this value.
  • *
  • The method may have an additional parameter of type {@link InContext}, or
  • *
  • The method may have 2 additional parameters of type {@link InContext} and {@link OutContext}.
  • *
* * @param serviceClass the class that contains the method to be associated with the Operation * @param opdef the definition of the Operation * @return a new Operation * @throws WsConfigurationException if no method in the serviceClass matches the opdef */ 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 null. For non-static methods, the parameter must be non-null. * @param payload the object to pass as an input parameter, or null if the method does not have an * input parameter. * @param processor the current processor. Must be non-null if the method definition includes * {@link InContext} or {@link OutContext} parameters. * @return the return value from the method, or null 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 InContext or * OutContext 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 null if there is no input parameter. * The payload 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 null if it has a void * 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 non-null, 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 non-null, or to the class name of the input // * parameter otherwise (omitting the package name). If there is no input parameter, this method will return // * null. // * // * @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 non-null, or to the class name of the // * method's return value otherwise (omitting the package name). If the method has a void return type, // * this method will return null. // * // * @return output message name // */ // public String getOutputName() { // return m_outputMessageName; // } /** * Returns whether the associated method is static. * * @return true if the method is static, false 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; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy