blob: 0e280443a2214b3b077d6fbb9b7895e7b803d7a2 [file] [log] [blame]
/*
* Copyright 2002-2004 The Apache Software Foundation.
*
* Licensed 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.axis.description;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.constants.Style;
import org.apache.axis.constants.Use;
import org.apache.commons.logging.Log;
import javax.xml.namespace.QName;
import javax.wsdl.OperationType;
import java.io.Serializable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
/**
* An OperationDesc is an abstract description of an operation on a service.
*
* !!! WORK IN PROGRESS
*
* @author Glen Daniels (gdaniels@apache.org)
*/
public class OperationDesc implements Serializable {
// Constants for "message style" operation patterns. If this OperationDesc
// is message style, the Java method will have one of these signatures:
// public SOAPBodyElement [] method(SOAPBodyElement [])
public static final int MSG_METHOD_BODYARRAY = 1;
// public void method(SOAPEnvelope, SOAPEnvelope)
public static final int MSG_METHOD_SOAPENVELOPE = 2;
// public Element [] method(Element [])
public static final int MSG_METHOD_ELEMENTARRAY = 3;
// public Document method(Document)
public static final int MSG_METHOD_DOCUMENT = 4;
public static final int MSG_METHOD_NONCONFORMING = -4;
private static final Map mepStringToOperationType = new HashMap();
private static final Map operationTypeToMepString = new HashMap();
static {
addMep("request-response", OperationType.REQUEST_RESPONSE);
addMep("oneway", OperationType.ONE_WAY);
addMep("solicit-response", OperationType.SOLICIT_RESPONSE);
addMep("notification", OperationType.NOTIFICATION);
}
private static void addMep(String mepString, OperationType operationType) {
mepStringToOperationType.put(mepString, operationType);
operationTypeToMepString.put(operationType, mepString);
}
protected static Log log =
LogFactory.getLog(OperationDesc.class.getName());
/** The service we're a part of */
private ServiceDesc parent;
/** Parameter list */
private ArrayList parameters = new ArrayList();
/** The operation name (String, or QName?) */
private String name;
/** An XML QName which should dispatch to this method */
private QName elementQName;
/** The actual Java method associated with this operation, if known */
private transient Method method;
/** This operation's style/use. If null, we default to our parent's */
private Style style = null;
private Use use = null;
/** The number of "in" params (i.e. IN or INOUT) for this operation */
private int numInParams = 0;
/** The number of "out" params (i.e. OUT or INOUT) for this operation */
private int numOutParams = 0;
/** A unique SOAPAction value for this operation */
private String soapAction = null;
/** Faults for this operation */
private ArrayList faults = null;
private ParameterDesc returnDesc = new ParameterDesc();
/** If we're a message-style operation, what's our signature? */
private int messageOperationStyle = -1;
/** The documentation for the operation */
private String documentation = null;
/** The MEP for this Operation - uses the WSDL4J OperationType for now
* but we might want to have our own extensible enum for WSDL 2.0
*/
private OperationType mep = OperationType.REQUEST_RESPONSE;
/**
* Default constructor.
*/
public OperationDesc() {
returnDesc.setMode(ParameterDesc.OUT);
returnDesc.setIsReturn(true);
}
/**
* "Complete" constructor
*/
public OperationDesc(String name, ParameterDesc [] parameters, QName returnQName) {
this.name = name;
returnDesc.setQName(returnQName);
returnDesc.setMode(ParameterDesc.OUT);
returnDesc.setIsReturn(true);
for (int i = 0; i < parameters.length; i++) {
addParameter(parameters[i]);
}
}
/**
* Return the operation's name
*/
public String getName() {
return name;
}
/**
* Set the operation's name
*/
public void setName(String name) {
this.name = name;
}
/**
* get the documentation for the operation
*/
public String getDocumentation() {
return documentation;
}
/**
* set the documentation for the operation
*/
public void setDocumentation(String documentation) {
this.documentation = documentation;
}
public QName getReturnQName() {
return returnDesc.getQName();
}
public void setReturnQName(QName returnQName) {
returnDesc.setQName(returnQName);
}
public QName getReturnType() {
return returnDesc.getTypeQName();
}
public void setReturnType(QName returnType) {
log.debug("@" + Integer.toHexString(hashCode()) + "setReturnType(" + returnType +")");
returnDesc.setTypeQName(returnType);
}
public Class getReturnClass() {
return returnDesc.getJavaType();
}
public void setReturnClass(Class returnClass) {
returnDesc.setJavaType(returnClass);
}
public QName getElementQName() {
return elementQName;
}
public void setElementQName(QName elementQName) {
this.elementQName = elementQName;
}
public ServiceDesc getParent() {
return parent;
}
public void setParent(ServiceDesc parent) {
this.parent = parent;
}
public String getSoapAction() {
return soapAction;
}
public void setSoapAction(String soapAction) {
this.soapAction = soapAction;
}
public void setStyle(Style style)
{
this.style = style;
}
/**
* Return the style of the operation, defaulting to the parent
* ServiceDesc's style if we don't have one explicitly set.
*/
public Style getStyle()
{
if (style == null) {
if (parent != null) {
return parent.getStyle();
}
return Style.DEFAULT; // Default
}
return style;
}
public void setUse(Use use)
{
this.use = use;
}
/**
* Return the use of the operation, defaulting to the parent
* ServiceDesc's use if we don't have one explicitly set.
*/
public Use getUse()
{
if (use == null) {
if (parent != null) {
return parent.getUse();
}
return Use.DEFAULT; // Default
}
return use;
}
public void addParameter(ParameterDesc param)
{
// Should we enforce adding INs then INOUTs then OUTs?
param.setOrder(getNumParams());
parameters.add(param);
if ((param.getMode() == ParameterDesc.IN) ||
(param.getMode() == ParameterDesc.INOUT)) {
numInParams++;
}
if ((param.getMode() == ParameterDesc.OUT) ||
(param.getMode() == ParameterDesc.INOUT)) {
numOutParams++;
}
log.debug("@" + Integer.toHexString(hashCode()) + " added parameter >" + param + "@" + Integer.toHexString(param.hashCode()) + "<total parameters:" +getNumParams());
}
public void addParameter(QName paramName,
QName xmlType,
Class javaType,
byte parameterMode,
boolean inHeader,
boolean outHeader) {
ParameterDesc param =
new ParameterDesc(paramName, parameterMode, xmlType,
javaType, inHeader, outHeader);
addParameter(param);
}
public ParameterDesc getParameter(int i)
{
if (parameters.size() <= i)
return null;
return (ParameterDesc)parameters.get(i);
}
public ArrayList getParameters() {
return parameters;
}
/**
* Set the parameters wholesale.
*
* @param newParameters an ArrayList of ParameterDescs
*/
public void setParameters(ArrayList newParameters) {
parameters = new ArrayList(); //Keep numInParams correct.
numInParams = 0;
numOutParams = 0;
for( java.util.ListIterator li= newParameters.listIterator();
li.hasNext(); ){
addParameter((ParameterDesc) li.next());
}
}
public int getNumInParams() {
return numInParams;
}
public int getNumOutParams() {
return numOutParams;
}
public int getNumParams() {
return parameters.size();
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
/**
* Is the return value in the header of the response message?
*/
public boolean isReturnHeader() {
return returnDesc.isOutHeader();
}
/**
* Set whether the return value is in the response message.
*/
public void setReturnHeader(boolean value) {
returnDesc.setOutHeader(value);
}
public ParameterDesc getParamByQName(QName qname)
{
for (Iterator i = parameters.iterator(); i.hasNext();) {
ParameterDesc param = (ParameterDesc) i.next();
if (param.getQName().equals(qname))
return param;
}
return null;
}
public ParameterDesc getInputParamByQName(QName qname)
{
ParameterDesc param = null;
param = getParamByQName(qname);
if ((param == null) || (param.getMode() == ParameterDesc.OUT)) {
param = null;
}
return param;
}
public ParameterDesc getOutputParamByQName(QName qname)
{
ParameterDesc param = null;
for (Iterator i = parameters.iterator(); i.hasNext();) {
ParameterDesc pnext = (ParameterDesc)i.next();
if (pnext.getQName().equals(qname) &&
pnext.getMode() != ParameterDesc.IN) {
param = pnext;
break;
}
}
if (param == null) {
if (null == returnDesc.getQName() ){
param= new ParameterDesc( returnDesc); //Create copy
param.setQName(qname);
}
else if ( qname.equals(returnDesc.getQName())) {
param = returnDesc;
}
}
return param;
}
/**
* Return a list of ALL "in" params (including INOUTs)
*
* Note: if we were sure the order went IN-&gt;INOUT-&gt;OUT, we could optimize
* this.
*
* @return
*/
public ArrayList getAllInParams() {
ArrayList result = new ArrayList();
for (Iterator i = parameters.iterator(); i.hasNext();) {
ParameterDesc desc = (ParameterDesc) i.next();
if (desc.getMode() != ParameterDesc.OUT) {
result.add(desc);
}
}
return result;
}
/**
* Return a list of ALL "out" params (including INOUTs)
*
* Note: if we were sure the order went IN-&gt;INOUT-&gt;OUT, we could optimize
* this.
*
* @return
*/
public ArrayList getAllOutParams() {
ArrayList result = new ArrayList();
for (Iterator i = parameters.iterator(); i.hasNext();) {
ParameterDesc desc = (ParameterDesc) i.next();
if (desc.getMode() != ParameterDesc.IN) {
result.add(desc);
}
}
return result;
}
/**
* Returns an ordered list of out params (NOT inouts)
*/
public ArrayList getOutParams() {
ArrayList result = new ArrayList();
for (Iterator i = parameters.iterator(); i.hasNext();) {
ParameterDesc desc = (ParameterDesc) i.next();
if (desc.getMode() == ParameterDesc.OUT) {
result.add(desc);
}
}
return result;
}
public void addFault(FaultDesc fault)
{
if (faults == null)
faults = new ArrayList();
faults.add(fault);
}
public ArrayList getFaults()
{
return faults;
}
/**
* Returns the FaultDesc for the fault class given.
* Returns null if not found.
*/
public FaultDesc getFaultByClass(Class cls) {
if (faults == null || cls == null) {
return null;
}
while (cls != null) {
// Check each class in the inheritance hierarchy, stopping at
// java.* or javax.* classes.
for (Iterator iterator = faults.iterator(); iterator.hasNext();) {
FaultDesc desc = (FaultDesc) iterator.next();
if (cls.getName().equals(desc.getClassName())) {
return desc;
}
}
cls = cls.getSuperclass();
if (cls != null && (cls.getName().startsWith("java.") ||
cls.getName().startsWith("javax."))) {
cls = null;
}
}
return null;
}
/**
* Returns the FaultDesc for the fault class given.
* Returns null if not found.
*/
public FaultDesc getFaultByClass(Class cls, boolean checkParents) {
if (checkParents) {
return getFaultByClass(cls);
}
if (faults == null || cls == null) {
return null;
}
for (Iterator iterator = faults.iterator(); iterator.hasNext();) {
FaultDesc desc = (FaultDesc) iterator.next();
if (cls.getName().equals(desc.getClassName())) {
return desc;
}
}
return null;
}
/**
* Returns the FaultDesc for a QName (which is typically found
* in the details element of a SOAP fault).
* Returns null if not found.
*/
public FaultDesc getFaultByQName(QName qname) {
if (faults != null) {
for (Iterator iterator = faults.iterator(); iterator.hasNext();) {
FaultDesc desc = (FaultDesc) iterator.next();
if (qname.equals(desc.getQName())) {
return desc;
}
}
}
return null;
}
/**
* Returns the FaultDesc for an XMLType.
* Returns null if not found.
*/
public FaultDesc getFaultByXmlType(QName xmlType) {
if (faults != null) {
for (Iterator iterator = faults.iterator(); iterator.hasNext();) {
FaultDesc desc = (FaultDesc) iterator.next();
if (xmlType.equals(desc.getXmlType())) {
return desc;
}
}
}
return null;
}
public ParameterDesc getReturnParamDesc() {
return returnDesc;
}
public String toString() {
return toString("");
}
public String toString(String indent) {
String text ="";
text+=indent+"name: " + getName() + "\n";
text+=indent+"returnQName: " + getReturnQName() + "\n";
text+=indent+"returnType: " + getReturnType() + "\n";
text+=indent+"returnClass: " + getReturnClass() + "\n";
text+=indent+"elementQName:" + getElementQName() + "\n";
text+=indent+"soapAction: " + getSoapAction() + "\n";
text+=indent+"style: " + getStyle().getName() + "\n";
text+=indent+"use: " + getUse().getName() + "\n";
text+=indent+"numInParams: " + getNumInParams() + "\n";
text+=indent+"method:" + getMethod() + "\n";
for (int i=0; i<parameters.size(); i++) {
text+=indent+" ParameterDesc[" + i + "]:\n";
text+=indent+ ((ParameterDesc)parameters.get(i)).toString(" ") + "\n";
}
if (faults != null) {
for (int i=0; i<faults.size(); i++) {
text+=indent+" FaultDesc[" + i + "]:\n";
text+=indent+ ((FaultDesc)faults.get(i)).toString(" ") + "\n";
}
}
return text;
}
public int getMessageOperationStyle() {
return messageOperationStyle;
}
public void setMessageOperationStyle(int messageOperationStyle) {
this.messageOperationStyle = messageOperationStyle;
}
public OperationType getMep() {
return mep;
}
public void setMep(OperationType mep) {
this.mep = mep;
}
/**
* Get the MEP as a string.
*
* @return the string representation of the MEP
*/
public String getMepString() {
return (String)operationTypeToMepString.get(mep);
}
/**
* Set the MEP using a string like "request-response"
* @param mepString
*/
public void setMep(String mepString) {
OperationType newMep = (OperationType)mepStringToOperationType.get(mepString);
if (newMep != null) {
mep = newMep;
}
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
if (method != null){
out.writeObject(method.getDeclaringClass());
out.writeObject(method.getName());
out.writeObject(method.getParameterTypes());
} else {
out.writeObject(null);
}
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
Class clazz = (Class) in.readObject();
if (clazz != null){
String methodName = (String) in.readObject();
Class[] parameterTypes = (Class[]) in.readObject();
try {
method = clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
throw new IOException("Unable to deserialize the operation's method: "+ methodName);
}
}
}
}