You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by sc...@apache.org on 2009/10/24 03:46:15 UTC
svn commit: r829296 [2/3] - in /webservices/axis2/trunk/java/modules:
jaxws-integration/ jaxws-integration/test/org/apache/axis2/jaxws/sample/
jaxws-integration/test/org/apache/axis2/jaxws/sample/dlwminArrays/
jaxws/src/org/apache/axis2/datasource/jaxb...
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/DocLitWrappedMinimalMethodMarshaller.java Sat Oct 24 01:46:13 2009
@@ -20,34 +20,62 @@
package org.apache.axis2.jaxws.marshaller.impl.alt;
import org.apache.axis2.jaxws.ExceptionFactory;
+import org.apache.axis2.jaxws.description.AttachmentDescription;
+import org.apache.axis2.jaxws.description.AttachmentType;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
import org.apache.axis2.jaxws.description.OperationDescription;
import org.apache.axis2.jaxws.description.ParameterDescription;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.marshaller.MethodMarshaller;
+import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
+import org.apache.axis2.jaxws.message.OccurrenceArray;
import org.apache.axis2.jaxws.message.Protocol;
+import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
+import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
import org.apache.axis2.jaxws.message.factory.MessageFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription;
+import org.apache.axis2.util.JavaUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import javax.activation.DataHandler;
+import javax.jws.WebService;
+import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding.Style;
+import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceException;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
/**
- * The Doc/Lit Wrapped Minimal Marshaller is used when 1) The web service is Doc/Lit Wrapped, and 2)
- * The wrapper and fault bean objects are missing (hence the term 'Minimal')
+ * The Doc/Lit Wrapped Minimal Marshaller is used when
+ * 1) The web service is Doc/Lit Wrapped, and
+ * 2) The wrapper and fault bean objects are missing (hence the term 'Minimal')
+ *
+ */
+/**
+ * @author scheu
+ *
*/
public class DocLitWrappedMinimalMethodMarshaller implements MethodMarshaller {
private static Log log = LogFactory.getLog(DocLitWrappedMinimalMethodMarshaller.class);
+ private static JAXBBlockFactory factory =
+ (JAXBBlockFactory)FactoryRegistry.getFactory(JAXBBlockFactory.class);
+
public DocLitWrappedMinimalMethodMarshaller() {
super();
}
@@ -55,6 +83,9 @@
public Message marshalRequest(Object[] signatureArguments, OperationDescription operationDesc)
throws WebServiceException {
+ if (log.isDebugEnabled()) {
+ log.debug("enter marshalRequest operationDesc = " + operationDesc.getName());
+ }
EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
EndpointDescription endpointDesc = ed.getEndpointDescription();
Protocol protocol = Protocol.getProtocolForBinding(endpointDesc.getClientBindingID());
@@ -107,12 +138,22 @@
// We want to use "by Java Type" marshalling for
// all objects
- for (PDElement pde : pdeList) {
+ for (int i=0; i<pdeList.size(); i++) {
+
+ PDElement pde = pdeList.get(i);
+
+ // If the actual value is an array or list
+ // this should be modeled as an
+ // occurrence of elements
+ pde = processOccurrence(pde);
+ pdeList.set(i, pde);
+
+ // Set by java type marshaling
ParameterDescription pd = pde.getParam();
Class type = pd.getParameterActualType();
pde.setByJavaTypeClass(type);
}
-
+
// Put values onto the message
MethodMarshallerUtils.toMessage(pdeList, m, packages);
@@ -121,39 +162,47 @@
m.setDoingSWA(true);
}
+ if (log.isDebugEnabled()) {
+ log.debug("exit marshalRequest");
+ }
return m;
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("fail marshalRequest e=" + e);
+ log.debug(" " + JavaUtils.stackToString(e));
+ }
throw ExceptionFactory.makeWebServiceException(e);
}
+
}
public Object[] demarshalRequest(Message message, OperationDescription operationDesc)
throws WebServiceException {
+ if (log.isDebugEnabled()) {
+ log.debug("enter demarshalRequest operationDesc = " + operationDesc.getName());
+ }
EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
EndpointDescription endpointDesc = ed.getEndpointDescription();
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // Sample RPC message
+ // Sample Document message
// ..
// <soapenv:body>
- // <m:op xmlns:m="urn://api">
- // <param xsi:type="data:foo" >...</param>
- // </m:op>
+ // <m:operation>
+ // <param>hello</param>
+ // </m:operation>
// </soapenv:body>
//
// Important points.
- // 1) RPC has an operation element under the body. This is the name of the
- // wsdl operation.
- // 2) The data blocks are located underneath the operation element. (In doc/lit
- // the data elements are underneath the body.
- // 3) The name of the data blocks (param) are defined by the wsdl:part not the
- // schema. Note that it is unqualified per WSI-BP
- // 4) The type of the data block (data:foo) is defined by schema (thus there is
- // JAXB type rendering.
- // 5) We always send an xsi:type, but other vendor's may not.
- // Get the operation information
+ // 1) There is no operation element under the body.
+ // 2) The data blocks are located underneath the body.
+ // 3) The name of the data block (m:operation) is defined by the schema and match the name of the operation.
+ // This is called the wrapper element. The wrapper element has a corresponding JAXB element pojo.
+ // 4) The parameters (m:param) are child elements of the wrapper element.
+ // 5) NOTE: For doc/literal wrapped "minimal", the wrapper JAXB element pojo is missing.
+
ParameterDescription[] pds = operationDesc.getParameterDescriptions();
MarshalServiceRuntimeDescription marshalDesc =
MethodMarshallerUtils.getMarshalDesc(endpointDesc);
@@ -164,21 +213,42 @@
message.setStyle(Style.DOCUMENT);
message.setIndirection(1);
+ // Create an array of indices indicating where each parameter is located in the body
+ // A -1 indicates that the parameter is not in the body
+ int[] firstIndex = new int[pds.length];
+ int[] lastIndex = new int[pds.length];
+ for (int i=0; i<firstIndex.length; i++) {
+ firstIndex[i] = -1;
+ lastIndex[i] = -1;
+ }
+ calculateBodyIndex(firstIndex, lastIndex, pds, message.getBodyBlockQNames());
+
// We want to use "by Java Type" unmarshalling for
// all objects
Class[] javaTypes = new Class[pds.length];
+ Class[] componentJavaTypes = new Class[pds.length];
for (int i = 0; i < pds.length; i++) {
ParameterDescription pd = pds[i];
javaTypes[i] = pd.getParameterActualType();
+ if (javaTypes[i].isArray()) {
+ componentJavaTypes[i] = javaTypes[i].getComponentType();
+ } else if (javaTypes[i].isAssignableFrom(List.class)) {
+ componentJavaTypes[i] = getComponentType(pd, operationDesc, marshalDesc);
+ } else {
+ componentJavaTypes[i]= null;
+ }
}
// Unmarshal the ParamValues from the Message
- List<PDElement> pvList = MethodMarshallerUtils.getPDElementsWithMissingElements(pds,
- message,
- packages,
- true, // input
- false,
- javaTypes); // sigh...unmarshal by type because there is no wrapper
+ List<PDElement> pvList = getPDElementsForDocLitWrappedMinimal(pds,
+ message,
+ packages,
+ true, // input
+ false,
+ javaTypes,
+ componentJavaTypes,
+ firstIndex,
+ lastIndex);
// Build the signature arguments
Object[] sigArguments = MethodMarshallerUtils.createRequestSignatureArgs(pds, pvList);
@@ -188,8 +258,15 @@
// is for rpc/literal marshaling. This code is for document/literal marshaling.
// Nulls are allowed.
+ if (log.isDebugEnabled()) {
+ log.debug("exit demarshalRequest operationDesc");
+ }
return sigArguments;
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("fail demarshalRequest e= " + e);
+ log.debug(" " + JavaUtils.stackToString(e));
+ }
throw ExceptionFactory.makeWebServiceException(e);
}
}
@@ -200,6 +277,10 @@
throws WebServiceException {
+ if (log.isDebugEnabled()) {
+ log.debug("enter marshalResponse operationDesc = " + operationDesc.getName());
+ }
+
EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
EndpointDescription endpointDesc = ed.getEndpointDescription();
// We want to respond with the same protocol as the request,
@@ -210,26 +291,23 @@
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // Sample RPC message
+ // Sample Document message
// ..
// <soapenv:body>
- // <m:opResponse xmlns:m="urn://api">
- // <param xsi:type="data:foo" >...</param>
- // </m:op>
+ // <m:operationResponse ... >
+ // <param>hello</param>
+ // </m:operationResponse>
// </soapenv:body>
//
// Important points.
- // 1) RPC has an operation element under the body. This is the name of the
- // wsdl operation.
- // 2) The data blocks are located underneath the operation element. (In doc/lit
- // the data elements are underneath the body.
- // 3) The name of the data blocks (param) are defined by the wsdl:part not the
- // schema. Note that it is unqualified.
- // 4) The type of the data block (data:foo) is defined by schema (thus there is
- // JAXB type rendering. Since we are using JAXB to marshal the data,
- // we always generate an xsi:type attribute. This is an implemenation detail
- // and is not defined by any spec.
-
+ // 1) There is no operation element in the message
+ // 2) The data blocks are located underneath the body element.
+ // 3) The name of the data block (m:operationResponse) is defined by the schema.
+ // It matches the operation name + "Response", and it has a corresponding JAXB element.
+ // This element is called the wrapper element
+ // 4) The parameters are (param) are child elements of the wrapper element.
+ // 5) For "minimal" the pojo bean representing the OperationResponse is missing.
+
// Get the operation information
ParameterDescription[] pds = operationDesc.getParameterDescriptions();
MarshalServiceRuntimeDescription marshalDesc =
@@ -272,7 +350,14 @@
}
Element returnElement = null;
QName returnQName = new QName(returnNS, returnLocalPart);
- if (marshalDesc.getAnnotationDesc(returnType).hasXmlRootElement()) {
+ if (isListOrArray(returnObject)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Return element isListOrArray");
+ }
+ OccurrenceArray occurrenceArray = new OccurrenceArray(returnObject);
+ JAXBElement jaxb = new JAXBElement(returnQName, returnType, occurrenceArray);
+ returnElement = new Element(jaxb, returnQName);
+ } else if (marshalDesc.getAnnotationDesc(returnType).hasXmlRootElement()) {
returnElement = new Element(returnObject, returnQName);
} else {
returnElement = new Element(returnObject, returnQName, returnType);
@@ -297,7 +382,17 @@
// We want to use "by Java Type" marshalling for
// all objects
- for (PDElement pde : pdeList) {
+ for (int i=0; i<pdeList.size(); i++) {
+
+ PDElement pde = pdeList.get(i);
+
+ // If the actual value is an array or list
+ // this should be modeled as an
+ // occurrence of elements
+ pde = processOccurrence(pde);
+ pdeList.set(i, pde);
+
+ // Set by java type marshaling
ParameterDescription pd = pde.getParam();
Class type = pd.getParameterActualType();
pde.setByJavaTypeClass(type);
@@ -312,41 +407,94 @@
m.setDoingSWA(true);
}
+ if (log.isDebugEnabled()) {
+ log.debug("exit marshalResponse");
+ }
return m;
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("fail marshalResponse e= " + e);
+ log.debug(" " + JavaUtils.stackToString(e));
+ }
throw ExceptionFactory.makeWebServiceException(e);
}
}
+ /**
+ * If the PDElement represents an array or List,
+ * a new PDElement is returned that models the
+ * the array or List as a series of elements.
+ * @param pde
+ * @return new PDElement or same PDElement
+ */
+ private static PDElement processOccurrence(PDElement pde) {
+ // All arrays and lists should be marshaled as
+ // separate (occurrence) elements
+ Element element = pde.getElement();
+ if (element != null) {
+ Object elementValue = element.getElementValue();
+ if (elementValue instanceof JAXBElement) {
+ JAXBElement jaxb = (JAXBElement) elementValue;
+ Object value = jaxb.getValue();
+ if (isListOrArray(value)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Build OccurrentArray");
+ }
+ OccurrenceArray occurrenceArray = new OccurrenceArray(value);
+ JAXBElement newJAXBElement =
+ new JAXBElement(jaxb.getName(),
+ jaxb.getDeclaredType(),
+ occurrenceArray);
+ element = new Element(newJAXBElement, jaxb.getName());
+ pde = new PDElement(pde.getParam(), element, null);
+ }
+ }
+ }
+ return pde;
+ }
+
+ /**
+ * @param value
+ * @return true if List or Array
+ */
+ private static boolean isListOrArray (Object value) {
+ boolean rc =(value instanceof List) ||
+ (value != null && value.getClass().isArray());
+ if (log.isDebugEnabled()) {
+ log.debug("isListOrArray for " + JavaUtils.getObjectIdentity(value) + " " + rc);
+ }
+ return rc;
+ }
public Object demarshalResponse(Message message, Object[] signatureArgs,
OperationDescription operationDesc)
throws WebServiceException {
+ if (log.isDebugEnabled()) {
+ log.debug("enter demarshalResponse operationDesc = " + operationDesc.getName());
+ }
EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
EndpointDescription endpointDesc = ed.getEndpointDescription();
// Note all exceptions are caught and rethrown with a WebServiceException
try {
- // Sample RPC message
+ // Sample Document message
// ..
// <soapenv:body>
- // <m:opResponse xmlns:m="urn://api">
- // <param xsi:type="data:foo" >...</param>
- // </m:op>
+ // <m:operationResponse ... >
+ // <param>hello</param>
+ // </m:operationResponse>
// </soapenv:body>
//
// Important points.
- // 1) RPC has an operation element under the body. This is the name of the
- // wsdl operation.
- // 2) The data blocks are located underneath the operation element. (In doc/lit
- // the data elements are underneath the body.
- // 3) The name of the data blocks (param) are defined by the wsdl:part not the
- // schema. Note that it is unqualified per WSI-BP
- // 4) The type of the data block (data:foo) is defined by schema (thus there is
- // JAXB type rendering.
- // 5) We always send an xsi:type, but other vendor's may not.
- // Get the operation information
+ // 1) There is no operation element in the message
+ // 2) The data blocks are located underneath the body element.
+ // 3) The name of the data block (m:operationResponse) is defined by the schema.
+ // It matches the operation name + "Response", and it has a corresponding JAXB element.
+ // This element is called the wrapper element
+ // 4) The parameters are (param) are child elements of the wrapper element.
+ // 5) For "minimal" the pojo bean representing the OperationResponse is missing
+
ParameterDescription[] pds = operationDesc.getParameterDescriptions();
MarshalServiceRuntimeDescription marshalDesc =
MethodMarshallerUtils.getMarshalDesc(endpointDesc);
@@ -356,33 +504,66 @@
message.setStyle(Style.DOCUMENT);
message.setIndirection(1);
+ // Create an array of indices indicating where each parameter is located in the body
+ // A -1 indicates that the parameter is not in the body
+ int[] firstIndex = new int[pds.length];
+ int[] lastIndex = new int[pds.length];
+ for (int i=0; i<firstIndex.length; i++) {
+ firstIndex[i] = -1;
+ lastIndex[i] = -1;
+ }
+ calculateBodyIndex(firstIndex, lastIndex, pds, message.getBodyBlockQNames());
+
+ int firstBodyParamIndex = -1;
+
+ for (int i=0; i < pds.length; i++) {
+ if (pds[i].getMode() == Mode.OUT || pds[i].getMode() == Mode.INOUT) {
+ if (firstIndex[i] >= 0 && firstBodyParamIndex == -1) {
+ firstBodyParamIndex = firstIndex[i];
+ }
+ }
+ }
+
+
// Get the return value.
Class returnType = operationDesc.getResultActualType();
+ Class returnComponentType = null;
+ if (returnType.isArray()) {
+ returnComponentType = returnType.getComponentType();
+ } else if (returnType.isAssignableFrom(List.class)) {
+ returnComponentType = getComponentType(null, operationDesc, marshalDesc);
+ } else {
+ returnComponentType= null;
+ }
Object returnValue = null;
boolean hasReturnInBody = false;
if (returnType != void.class) {
// If the webresult is in the header, we need the name of the header so that we can find it.
Element returnElement = null;
if (operationDesc.isResultHeader()) {
- returnElement = MethodMarshallerUtils.getReturnElement(packages,
+ returnElement = getReturnElementForDocLitWrappedMinimal(packages,
message,
returnType,
+ returnComponentType,
operationDesc.isListType(),
true, // is a header
operationDesc.getResultTargetNamespace(),
// header ns
operationDesc.getResultPartName(), // header local part
- MethodMarshallerUtils.numOutputBodyParams(pds) > 0);
+ MethodMarshallerUtils.numOutputBodyParams(pds) > 0,
+ firstBodyParamIndex);
} else {
- returnElement = MethodMarshallerUtils.getReturnElement(packages,
+ returnElement = getReturnElementForDocLitWrappedMinimal(packages,
message,
returnType,
+ returnComponentType,
operationDesc.isListType(),
false,
null,
null,
- MethodMarshallerUtils.numOutputBodyParams(pds) > 0);
+ MethodMarshallerUtils.numOutputBodyParams(pds) > 0,
+ firstBodyParamIndex);
hasReturnInBody = true;
}
@@ -400,26 +581,45 @@
// We want to use "by Java Type" unmarshalling for
// all objects
Class[] javaTypes = new Class[pds.length];
+ Class[] componentJavaTypes = new Class[pds.length];
for (int i = 0; i < pds.length; i++) {
ParameterDescription pd = pds[i];
Class type = pd.getParameterActualType();
+
+ if (type.isArray()) {
+ componentJavaTypes[i] = type.getComponentType();
+ } else if (type.isAssignableFrom(List.class)) {
+ componentJavaTypes[i] = getComponentType(pd, operationDesc, marshalDesc);
+ } else {
+ componentJavaTypes[i]= null;
+ }
javaTypes[i] = type;
}
// Unmarshall the ParamValues from the Message
- List<PDElement> pvList = MethodMarshallerUtils.getPDElements(pds,
- message,
- packages,
- false, // output
- hasReturnInBody,
- javaTypes); // unmarshal by type
+ List<PDElement> pvList = getPDElementsForDocLitWrappedMinimal(pds,
+ message,
+ packages,
+ false, // output
+ hasReturnInBody,
+ javaTypes,
+ componentJavaTypes,
+ firstIndex,
+ lastIndex);
// Populate the response Holders
MethodMarshallerUtils.updateResponseSignatureArgs(pds, pvList, signatureArgs);
+ if (log.isDebugEnabled()) {
+ log.debug("exit demarshalResponse");
+ }
return returnValue;
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("fail demarshalResponse e=" + e);
+ log.debug(" " + JavaUtils.stackToString(e));
+ }
throw ExceptionFactory.makeWebServiceException(e);
}
}
@@ -428,6 +628,9 @@
OperationDescription operationDesc, Protocol protocol)
throws WebServiceException {
+ if (log.isDebugEnabled()) {
+ log.debug("marshalFaultResponse operationDesc = " + operationDesc);
+ }
EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
EndpointDescription endpointDesc = ed.getEndpointDescription();
MarshalServiceRuntimeDescription marshalDesc =
@@ -451,8 +654,15 @@
marshalDesc,
operationDesc,
m);
+ if (log.isDebugEnabled()) {
+ log.debug("exit marshalFaultResponse");
+ }
return m;
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("fail marshalFaultResponse e=" + e);
+ log.debug(" " + JavaUtils.stackToString(e));
+ }
throw ExceptionFactory.makeWebServiceException(e);
}
}
@@ -460,6 +670,9 @@
public Throwable demarshalFaultResponse(Message message, OperationDescription operationDesc)
throws WebServiceException {
+ if (log.isDebugEnabled()) {
+ log.debug("demarshalFaultResponse operationDesc = " + operationDesc);
+ }
EndpointInterfaceDescription ed = operationDesc.getEndpointInterfaceDescription();
EndpointDescription endpointDesc = ed.getEndpointDescription();
MarshalServiceRuntimeDescription marshalDesc =
@@ -469,8 +682,15 @@
try {
Throwable t = MethodMarshallerUtils
.demarshalFaultResponse(operationDesc, marshalDesc, message);
+ if (log.isDebugEnabled()) {
+ log.debug("exit demarshalFaultResponse");
+ }
return t;
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("fail demarshalFaultResponse e=" +e);
+ log.debug(" " + JavaUtils.stackToString(e));
+ }
throw ExceptionFactory.makeWebServiceException(e);
}
}
@@ -508,5 +728,556 @@
qName = new QName(uri, localPart, prefix);
return qName;
}
+
+ /**
+ * Return the list of PDElements that is unmarshalled from the wire.
+ * NOTE: This method is slower as the normal getPDElements method because it
+ * must cache the message in order to do QName matches.
+ * This method is only necessary to support the cases where the incoming message
+ * may have missing data items.
+ * Currently this is limited to the document/literal minimal case.
+ *
+ * @param params ParameterDescription for this operation
+ * @param message Message
+ * @param packages set of packages needed to unmarshal objects for this operation
+ * @param isInput indicates if input or output params (input on server, output on client)
+ * @param hasReturnInBody if isInput=false, then this parameter indicates whether a
+ * return value is expected in the body.
+ * @param javaType
+ * @param javaComponentType
+ * @param firstIndex (array indicating the first block corresponding to the parameter)
+ * @param lastIndex (array indicating the last block corresponding to the parameter)
+ * @see getPDElements
+ * @return ParamValues
+ */
+ static List<PDElement> getPDElementsForDocLitWrappedMinimal(ParameterDescription[] params,
+ Message message,
+ TreeSet<String> packages,
+ boolean isInput,
+ boolean hasReturnInBody,
+ Class[] javaType,
+ Class[] javaComponentType,
+ int[] firstIndex,
+ int[] lastIndex
+ ) throws XMLStreamException {
+
+ if (log.isDebugEnabled()) {
+ log.debug("start getPDElementsForDocLitWrappedMinimal");
+ }
+ List<PDElement> pdeList = new ArrayList<PDElement>();
+
+ int totalBodyBlocks = message.getNumBodyBlocks();
+
+
+
+ // TODO What if return is an swa attachment, then this should start
+ // at 1 not 0.
+ int swaIndex = 0;
+
+ for (int i = 0; i < params.length; i++) {
+ ParameterDescription pd = params[i];
+
+ if (log.isDebugEnabled()) {
+ log.debug(" processing Parameter " + pd);
+ }
+
+
+ if (pd.getMode() == Mode.IN && isInput ||
+ pd.getMode() == Mode.INOUT ||
+ pd.getMode() == Mode.OUT && !isInput) {
+
+ // Don't consider async handlers, they are are not represented on the wire,
+ // thus they don't have a PDElement
+ // TODO
+ //if (isAsyncHandler(param)) {
+ // continue;
+ //}
+
+ Block block = null;
+ JAXBBlockContext context = new JAXBBlockContext(packages);
+
+ AttachmentDescription attachmentDesc = pd.getAttachmentDescription();
+ if (attachmentDesc == null) {
+
+ // In most cases the entire java object is unmarshalled.
+ // But in some cases, the java object is a series of
+ // elements.
+ boolean unmarshalComponents = false;
+ if (pd.isListType() || javaComponentType[i] == null) {
+ context.setProcessType(javaType[i]);
+ context.setIsxmlList(pd.isListType());
+ } else {
+ context.setProcessType(javaComponentType[i]);
+ unmarshalComponents = true;
+ }
+
+
+ // Unmarshal the object into a JAXB object or JAXBElement
+ Element element = null;
+ if (pd.isHeader()) {
+
+ if (log.isDebugEnabled()) {
+ log.debug(" get block from the headers");
+ }
+ // Get the Block from the header
+ // NOTE The parameter name is always used to get the header
+ // element
+ String localName = pd.getParameterName();
+ block = message.getHeaderBlock(pd.getTargetNamespace(),
+ localName,
+ context,
+ factory);
+ element = new Element(block.getBusinessObject(true),
+ block.getQName());
+ } else if (firstIndex[i] >= 0) {
+ if (log.isDebugEnabled()) {
+ log.debug(" get block from the " + firstIndex[i] +
+ " to the " + lastIndex[i]);
+ }
+ // You must use this method if there are more than one body block
+ // This method may cause OM expansion
+ if (unmarshalComponents) {
+ Object container = makeContainer(javaType[i],
+ javaComponentType[i],
+ (lastIndex[i] - firstIndex[i]) + 1);
+
+ for (int blockI=firstIndex[i]; blockI<=lastIndex[i]; blockI++) {
+ block = message.getBodyBlock(blockI, context, factory);
+ Object value = block.getBusinessObject(true);
+ if (value instanceof JAXBElement) {
+ value = ((JAXBElement) value).getValue();
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(" get Business Object " + JavaUtils.getObjectIdentity(value) + " from block " + blockI);
+
+ }
+
+ addComponent(container, value, blockI - firstIndex[i]);
+
+ }
+ element = new Element(container,
+ block.getQName());
+
+ } else {
+ block = message.getBodyBlock(firstIndex[i], context, factory);
+ element = new Element(block.getBusinessObject(true),
+ block.getQName());
+ }
+ } else {
+ // Missing parameter
+ if (log.isDebugEnabled()) {
+ log.debug(" there is no block for this parameter.");
+ }
+ QName qName = new QName(pd.getTargetNamespace(), pd.getPartName());
+ if (!unmarshalComponents) {
+ element = new Element(null, qName);
+ } else {
+ Object container = makeContainer(javaType[i],
+ javaComponentType[i], 0);
+ element = new Element(container, qName);
+ }
+ }
+
+
+ PDElement pde =
+ new PDElement(pd, element, javaComponentType[i] == null ? null
+ : javaComponentType[i]);
+ pdeList.add(pde);
+ } else {
+ // Attachment Processing
+ if (attachmentDesc.getAttachmentType() == AttachmentType.SWA) {
+ String partName = pd.getPartName();
+ String cid = null;
+ if (log.isDebugEnabled()) {
+ log.debug("Getting the attachment dataHandler for partName=" + partName);
+ }
+ if (partName != null && partName.length() > 0) {
+ // Compliant WS-I behavior
+ cid = message.getAttachmentID(partName);
+ }
+ if (cid == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Attachment dataHandler was not found. Fallback to use attachment " + swaIndex);
+ }
+ // Toleration mode for non-compliant attachment names
+ cid = message.getAttachmentID(swaIndex);
+ }
+ DataHandler dh = message.getDataHandler(cid);
+ Attachment attachment = new Attachment(dh, cid);
+ PDElement pde = new PDElement(pd, null, null, attachment);
+ pdeList.add(pde);
+ swaIndex++;
+ } else {
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("pdElementErr"));
+ }
+ }
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("end getPDElementsWithMissingElements");
+ }
+ return pdeList;
+ }
+
+ /**
+ * Calculate the index of the first block for the parameter and
+ * the last block (inclusive) for the parameter
+ * @param firstIndex
+ * @param lastIndex
+ * @param params
+ * @param qNames
+ */
+ private static void calculateBodyIndex(int[] firstIndex, int[] lastIndex,
+ ParameterDescription[] params,
+ List<QName> qNames) {
+ if (log.isDebugEnabled()) {
+ log.debug("Start calculateBodyIndex");
+ for (int i=0; i<qNames.size(); i++) {
+ log.debug(" QName " + i + " = " + qNames.get(i));
+ }
+ }
+ for (int pi=0; pi<params.length; pi++) {
+ if (pi >= 0) {
+ ParameterDescription pd = params[pi];
+ if (log.isDebugEnabled()) {
+ log.debug(" ParameterDescription =" + pd.toString());
+ log.debug(" original firstIndex = " + firstIndex[pi]);
+ log.debug(" original lastIndex = " + lastIndex[pi]);
+ }
+ firstIndex[pi] = -1; // Reset index
+ lastIndex[pi] = -1; // Reset index
+ // Found a parameter that is expected in the body
+ // Calculate its index by looking for an exact qname match
+ for (int qi=0; qi<qNames.size(); qi++) {
+ QName qName = qNames.get(qi);
+ if (qName.getLocalPart().equals(pd.getPartName())) {
+ if (qName.getNamespaceURI().equals(pd.getTargetNamespace())) {
+ if (firstIndex[pi] < 0) {
+ if(log.isDebugEnabled()) {
+ log.debug(" set first index to " + qi);
+ }
+ firstIndex[pi] = qi;
+ }
+ lastIndex[pi] = qi;
+ }
+ }
+ }
+ // Fallback to searching for just the part name
+ if (firstIndex[pi] < 0) {
+ for (int qi=0; qi<qNames.size(); qi++) {
+ QName qName = qNames.get(qi);
+ if (qName.getLocalPart().equals(pd.getPartName())) {
+ if (firstIndex[pi] < 0) {
+ if(log.isDebugEnabled()) {
+ log.debug(" fallback: set first index to " + qi);
+ }
+ firstIndex[pi] = qi;
+ }
+ lastIndex[pi] = qi;
+ }
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(" last index = " + lastIndex[pi]);
+ }
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("End calculateBodyIndex");
+ }
+ }
+ /**
+ * Unmarshal the return object from the message
+ *
+ * @param packages
+ * @param message
+ * @param javaTypeClass
+ * @param javaComponentTypeClass
+ * @param isHeader
+ * @param headerNS (only needed if isHeader)
+ * @param headerLocalPart (only needed if isHeader)
+ * @param hasOutputBodyParams (true if the method has out or inout params other
+ * than the return value)
+ * @param ioutputBodyArgIndes (first index of output body argument or -1)
+ *
+ * @return Element
+ * @throws WebService
+ * @throws XMLStreamException
+ */
+ static Element getReturnElementForDocLitWrappedMinimal(TreeSet<String> packages,
+ Message message,
+ Class javaTypeClass,
+ Class javaComponentTypeClass,
+ boolean isList,
+ boolean isHeader,
+ String headerNS,
+ String headerLocalPart,
+ boolean hasOutputBodyParams,
+ int outputBodyArgIndex)
+
+ throws WebServiceException, XMLStreamException {
+
+ // The return object is the first block in the body
+ JAXBBlockContext context = new JAXBBlockContext(packages);
+
+ // In most cases the entire java object is unmarshalled.
+ // But in some cases, the java object is a series of
+ // elements.
+ boolean unmarshalComponents = false;
+ if (isList || javaComponentTypeClass == null) {
+ context.setProcessType(javaTypeClass);
+ context.setIsxmlList(isList);
+ } else {
+ context.setProcessType(javaComponentTypeClass);
+ unmarshalComponents = true;
+ }
+
+ Element returnElement = null;
+ if (isHeader) {
+
+ // In header
+ Block block = message.getHeaderBlock(headerNS, headerLocalPart, context, factory);
+ // Get the business object. We want to return the object that represents the type.
+ returnElement = new Element(block.getBusinessObject(true), block.getQName());
+ }
+ else {
+ // In Body
+
+ // Determine how many return elements are present
+ int numBodyBlocks = message.getNumBodyBlocks();
+ if (outputBodyArgIndex >= 0) {
+ numBodyBlocks = outputBodyArgIndex;
+ }
+ if (!unmarshalComponents) {
+ if (numBodyBlocks == 1) {
+ if (log.isDebugEnabled()) {
+ log.debug("Case A: Not unmarshalling components, and only 1 block");
+ }
+ // Normal case: Only one body block
+ // We can use the get body block method
+ // that streams the whole block content.
+ Block block = message.getBodyBlock(context, factory);
+ //We look for body block only when the return type associated with operation is not void.
+ //If a null body block is returned in response on a operation that is not void, its a user error.
+ returnElement = new Element(block.getBusinessObject(true), block.getQName());
+ } else if (numBodyBlocks > 1) {
+ if (log.isDebugEnabled()) {
+ log.debug("Case B: Not unmarshalling components, and multiple blocks");
+ }
+ // There is only one return element
+ Block block = message.getBodyBlock(0, context, factory);
+ returnElement = new Element(block.getBusinessObject(true), block.getQName());
+
+ }
+ } else {
+ if (numBodyBlocks > 0) {
+ if (log.isDebugEnabled()) {
+ log.debug("Case C: unmarshalling components. Number of blocks=" + numBodyBlocks);
+ }
+ // Assume that all the qnames matching the first QName are for the return
+ List<QName> qNames = message.getBodyBlockQNames();
+ int firstIndex = 0;
+ int lastIndex = 0;
+ QName returnQName = qNames.get(0);
+ if (log.isDebugEnabled()) {
+ log.debug(" returnQName =" + returnQName);
+ }
+ do {
+ lastIndex++;
+ } while (lastIndex < qNames.size() &&
+ returnQName.equals(qNames.get(lastIndex)));
+
+ // Multiple Elements for QName
+ int numElements = lastIndex - firstIndex;
+ if (log.isDebugEnabled()) {
+ log.debug(" number of return blocks=" + numElements);
+ }
+ Object container = makeContainer(javaTypeClass,
+ javaComponentTypeClass,
+ numElements);
+
+ for (int blockI=firstIndex; blockI<lastIndex; blockI++) {
+ Block block = message.getBodyBlock(blockI, context, factory);
+ Object value = block.getBusinessObject(true);
+ if (value instanceof JAXBElement) {
+ value = ((JAXBElement) value).getValue();
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(" get return Business object (" + JavaUtils.getObjectIdentity(value) +
+ ") for block " + blockI);
+
+ }
+
+ addComponent(container, value, blockI);
+
+
+ }
+ returnElement = new Element(container, returnQName);
+
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Case D: unmarshalling components, but there are no blocks");
+ }
+ Object container = makeContainer(javaTypeClass,
+ javaComponentTypeClass,
+ 0);
+ QName qName = new QName("", "return");
+ returnElement = new Element(container, qName);
+ }
+ }
+
+ //We look for body block only when the return type associated with operation is not void.
+ //If a null body block is returned in response on a operation that has non void return type, its a user error.
+ if (returnElement == null){
+ if(log.isDebugEnabled()){
+ log.debug("Empty Body Block Found in response Message for wsdl Operation defintion that expects an Output");
+ log.debug("Return type associated with SEI operation is not void, Body Block cannot be null");
+ }
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("MethodMarshallerUtilErr1"));
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("getReturnElementForDocLitWrappedMinimal " + JavaUtils.getObjectIdentity(returnElement));
+
+ }
+
+ return returnElement;
+ }
+
+ /**
+ * Make a container array or List
+ * @param type
+ * @param componentType
+ * @param numComponents
+ * @return container array or list
+ */
+ private static Object makeContainer(Class type,
+ Class componentType,
+ int numComponents) {
+ Object container = null;
+ if (type.isArray()) {
+ container = Array.newInstance(componentType,
+ numComponents);
+ } else {
+ try {
+ container = type.newInstance();
+ } catch (Exception e) {
+ container = new ArrayList();
+ }
+ }
+ return container;
+ }
+
+ /**
+ * Add component to the container object
+ * @param container array or List
+ * @param component
+ * @param index
+ * @param container
+ */
+ private static void addComponent(Object container, Object component, int index) {
+ if (container.getClass().isArray()) {
+ if (component != null) {
+ Array.set(container, index, component);
+ }
+ } else {
+ ((List) container).add(component);
+ }
+ }
+
+ /**
+ * Return ComponentType, might need to look at the GenericType
+ * @param pd ParameterDesc or null if return
+ * @param operationDesc OperationDescription
+ * @param msrd MarshalServiceRuntimeDescription
+ * @return
+ */
+ private static Class getComponentType(ParameterDescription pd,
+ OperationDescription operationDesc,
+ MarshalServiceRuntimeDescription msrd) {
+ Class componentType = null;
+ if (log.isDebugEnabled()) {
+ log.debug("start getComponentType");
+ log.debug(" ParameterDescription=" + pd);
+ }
+
+ // Determine if array, list, or other
+ Class cls = null;
+ if (pd == null) {
+ cls = operationDesc.getResultActualType();
+ } else {
+ cls = pd.getParameterActualType();
+ }
+
+ if (cls != null) {
+ if (cls.isArray()) {
+ componentType = cls.getComponentType();
+ } else if (List.class.isAssignableFrom(cls)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Parameter is a List: " + cls);
+ }
+ Method method = msrd.getMethod(operationDesc);
+ if (log.isDebugEnabled()) {
+ log.debug("Method is: " + method);
+ }
+ Type genericType = null;
+ if (pd == null) {
+ genericType =method.getGenericReturnType();
+ } else {
+ ParameterDescription[] pds = operationDesc.getParameterDescriptions();
+ for (int i=0; i< pds.length; i++) {
+ if (pds[i] == pd) {
+ genericType = method.getGenericParameterTypes()[i];
+ }
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("genericType is: " + genericType.getClass() + " "+ genericType);
+ }
+ if (genericType instanceof Class) {
+ if (log.isDebugEnabled()) {
+ log.debug(" genericType instanceof Class");
+ }
+ componentType = String.class;
+ } else if (genericType instanceof ParameterizedType) {
+ if (log.isDebugEnabled()) {
+ log.debug(" genericType instanceof ParameterizedType");
+ }
+ ParameterizedType pt = (ParameterizedType) genericType;
+ if (pt.getRawType() == Holder.class) {
+ if (log.isDebugEnabled()) {
+ log.debug(" strip off holder");
+ }
+ genericType = pt.getActualTypeArguments()[0];
+ if (genericType instanceof Class) {
+ componentType = String.class;
+ } else if (genericType instanceof ParameterizedType) {
+ pt = (ParameterizedType) genericType;
+ }
+ }
+ if (componentType == null) {
+ Type comp = pt.getActualTypeArguments()[0];
+ if (log.isDebugEnabled()) {
+ log.debug(" comp =" + comp.getClass() + " " + comp);
+ }
+ if (comp instanceof Class) {
+ componentType = (Class) comp;
+ } else if (comp instanceof ParameterizedType) {
+ componentType = (Class) ((ParameterizedType) comp).getRawType();
+ }
+ }
+ }
+
+ }
+ }
+
+
+ if (log.isDebugEnabled()) {
+ log.debug("end getComponentType=" + componentType);
+ }
+ return componentType;
+ }
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/marshaller/impl/alt/MethodMarshallerUtils.java Sat Oct 24 01:46:13 2009
@@ -372,245 +372,9 @@
return pdeList;
}
- /**
- * Return the list of PDElements that is unmarshalled from the wire.
- * NOTE: This method is slower as the normal getPDElements method because it
- * must cache the message in order to do QName matches.
- * This method is only necessary to support the cases where the incoming message
- * may have missing data items.
- * Currently this is limited to the document/literal minimal case.
- *
- * @param params ParameterDescription for this operation
- * @param message Message
- * @param packages set of packages needed to unmarshal objects for this operation
- * @param isInput indicates if input or output params (input on server, output on client)
- * @param hasReturnInBody if isInput=false, then this parameter indicates whether a
- * return value is expected in the body.
- * @param unmarshalByJavaType in most scenarios this is null.
- * Only use this in the scenarios that require unmarshalling by java type
- * @see getPDElements
- * @return ParamValues
- */
- static List<PDElement> getPDElementsWithMissingElements(ParameterDescription[] params,
- Message message,
- TreeSet<String> packages,
- boolean isInput,
- boolean hasReturnInBody,
- Class[] unmarshalByJavaType) throws XMLStreamException {
-
- if (log.isDebugEnabled()) {
- log.debug("start getPDElementsWithMissingElements");
- }
- List<PDElement> pdeList = new ArrayList<PDElement>();
-
- // Create an array of indices indicating where each parameter is located in the body
- // A -1 indicates that the parameter is not in the body
- int[] bodyIndex = new int[params.length];
- for (int i=0; i<bodyIndex.length; i++) {
- bodyIndex[i] = -1;
- }
-
- // Calculate the array indices based on the parameter location
- int bi = (!isInput && hasReturnInBody) ? 1 : 0; // If there is a return in the body, the output parameters start at index 1
- for (int i = 0; i < params.length; i++) {
- ParameterDescription pd = params[i];
-
- if (pd.getMode() == Mode.IN && isInput ||
- pd.getMode() == Mode.INOUT ||
- pd.getMode() == Mode.OUT && !isInput) {
- if (!pd.isHeader() && !isSWAAttachment(pd)) {
- bodyIndex[i] = bi;
- bi++;
- }
- }
- }
- int totalBodyBlocks = bi;
-
- // Now recalculate the bodyIndex array if the number of expected body parameters
- // does not match the incoming message.
- if (message.getNumBodyBlocks() != totalBodyBlocks) {
- calculateBodyIndex(bodyIndex, params, message.getBodyBlockQNames());
- }
-
- // TODO What if return is an swa attachment, then this should start
- // at 1 not 0.
- int swaIndex = 0;
-
- for (int i = 0; i < params.length; i++) {
- ParameterDescription pd = params[i];
-
- if (log.isDebugEnabled()) {
- log.debug(" processing Parameter " + pd);
- }
-
-
- if (pd.getMode() == Mode.IN && isInput ||
- pd.getMode() == Mode.INOUT ||
- pd.getMode() == Mode.OUT && !isInput) {
-
- // Don't consider async handlers, they are are not represented on the wire,
- // thus they don't have a PDElement
- // TODO
- //if (isAsyncHandler(param)) {
- // continue;
- //}
-
- Block block = null;
- JAXBBlockContext context = new JAXBBlockContext(packages);
-
- AttachmentDescription attachmentDesc = pd.getAttachmentDescription();
- if (attachmentDesc == null) {
-
- // Normal Processing: Not an Attachment
- // Trigger unmarshal by java type if necessary
- if (unmarshalByJavaType != null && unmarshalByJavaType[i] != null) {
- context.setProcessType(unmarshalByJavaType[i]);
- context.setIsxmlList(pd.isListType());
- }
-
- // Unmarshal the object into a JAXB object or JAXBElement
- Element element = null;
- if (pd.isHeader()) {
-
- if (log.isDebugEnabled()) {
- log.debug(" get block from the headers");
- }
- // Get the Block from the header
- // NOTE The parameter name is always used to get the header
- // element
- String localName = pd.getParameterName();
- block = message.getHeaderBlock(pd.getTargetNamespace(),
- localName,
- context,
- factory);
- element = new Element(block.getBusinessObject(true),
- block.getQName());
- } else if (bodyIndex[i] >= 0) {
- if (totalBodyBlocks > 1) {
- if (log.isDebugEnabled()) {
- log.debug(" get block from the " + bodyIndex[i] +
- " element in the body block");
- }
- // You must use this method if there are more than one body block
- // This method may cause OM expansion
- block = message.getBodyBlock(bodyIndex[i], context, factory);
- } else {
- if (log.isDebugEnabled()) {
- log.debug(" this is the only block in the body block");
- }
- // Use this method if you know there is only one body block.
- // This method prevents OM expansion.
- block = message.getBodyBlock(context, factory);
- }
- element = new Element(block.getBusinessObject(true),
- block.getQName());
- } else {
- // Missing parameter
- if (log.isDebugEnabled()) {
- log.debug(" there is no block for this parameter.");
- }
- QName qName = new QName(pd.getTargetNamespace(), pd.getPartName());
- element = new Element(null, qName);
- }
-
-
- PDElement pde =
- new PDElement(pd, element, unmarshalByJavaType == null ? null
- : unmarshalByJavaType[i]);
- pdeList.add(pde);
- } else {
- // Attachment Processing
- if (attachmentDesc.getAttachmentType() == AttachmentType.SWA) {
- String partName = pd.getPartName();
- String cid = null;
- if (log.isDebugEnabled()) {
- log.debug("Getting the attachment dataHandler for partName=" + partName);
- }
- if (partName != null && partName.length() > 0) {
- // Compliant WS-I behavior
- cid = message.getAttachmentID(partName);
- }
- if (cid == null) {
- if (log.isDebugEnabled()) {
- log.debug("Attachment dataHandler was not found. Fallback to use attachment " + swaIndex);
- }
- // Toleration mode for non-compliant attachment names
- cid = message.getAttachmentID(swaIndex);
- }
- DataHandler dh = message.getDataHandler(cid);
- Attachment attachment = new Attachment(dh, cid);
- PDElement pde = new PDElement(pd, null, null, attachment);
- pdeList.add(pde);
- swaIndex++;
- } else {
- throw ExceptionFactory.makeWebServiceException(Messages.getMessage("pdElementErr"));
- }
- }
- }
- }
-
- if (log.isDebugEnabled()) {
- log.debug("end getPDElementsWithMissingElements");
- }
- return pdeList;
- }
- /**
- * @param bodyIndex
- * @param params
- * @param qNames
- */
- private static void calculateBodyIndex(int[] bodyIndex,
- ParameterDescription[] params,
- List<QName> qNames) {
- if (log.isDebugEnabled()) {
- log.debug("Start calculateBodyIndex");
- for (int i=0; i<qNames.size(); i++) {
- log.debug(" QName " + i + " = " + qNames.get(i));
- }
- }
- for (int pi=0; pi<params.length; pi++) {
- if (pi >= 0) {
- ParameterDescription pd = params[pi];
- if (log.isDebugEnabled()) {
- log.debug(" ParameterDescription =" + pd.toString());
- log.debug(" original bodyIndex = " + bodyIndex[pi]);
- }
- bodyIndex[pi] = -1; // Reset index
- // Found a parameter that is expected in the body
- // Calculate its index by looking for an exact qname match
- for (int qi=0; qi<qNames.size(); qi++) {
- QName qName = qNames.get(qi);
- if (qName.getLocalPart().equals(pd.getPartName())) {
- if (qName.getNamespaceURI().equals(pd.getTargetNamespace())) {
- if(log.isDebugEnabled()) {
- log.debug(" found exact match with " + qName);
- }
- bodyIndex[pi] = qi;
- }
- }
- }
- // Fallback to searching for just the part name
- if (bodyIndex[pi] < 0) {
- for (int qi=0; qi<qNames.size(); qi++) {
- QName qName = qNames.get(qi);
- if (qName.getLocalPart().equals(pd.getPartName())) {
- if(log.isDebugEnabled()) {
- log.debug(" found fallback match with " + qName);
- }
- bodyIndex[pi] = qi;
- }
- }
- }
- if (log.isDebugEnabled()) {
- log.debug(" final bodyIndex = " + bodyIndex[pi]);
- }
- }
- }
- if (log.isDebugEnabled()) {
- log.debug("End calculateBodyIndex");
- }
- }
+
+
/**
* Creates the request signature arguments (server) from a list
Added: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java?rev=829296&view=auto
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java (added)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/OccurrenceArray.java Sat Oct 24 01:46:13 2009
@@ -0,0 +1,75 @@
+/*
+ * 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.axis2.jaxws.message;
+
+import java.lang.reflect.Array;
+import java.util.List;
+
+import org.apache.axis2.util.JavaUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Used by the marshaling engine to wrap an array or List
+ * to indicate that the components should be marshaled
+ * as a series of elements (occurrence elements).
+ *
+ * The DocLitMinimalMethodMarshaller will create
+ * a JAXBElement whose name is the name of the elements
+ * and whose value is a OccurrenceArray that
+ * holds a List or array
+ *
+ * @See DocLitWrappedMinimalMethodMarshaler
+ * @See JAXBDSContext
+ */
+public class OccurrenceArray {
+
+ private static Log log = LogFactory.getLog(OccurrenceArray.class);
+
+ // The held value will be a List or Array
+ Object value = null;
+ public OccurrenceArray(Object value) {
+ if (log.isDebugEnabled()) {
+ log.debug("Creating OccurrenceArray for " + JavaUtils.getObjectIdentity(value));
+ }
+ this.value = value;
+ }
+
+ /**
+ * Get the List or array as a Object[]
+ * @return Object[]
+ */
+ public Object[] getAsArray() {
+ Object[] objects = null;
+ if (value instanceof List) {
+ List l = (List) value;
+ objects = new Object[l.size()];
+ for (int i=0; i<l.size(); i++) {
+ objects[i] = l.get(i);
+ }
+ } else {
+
+ objects = new Object[Array.getLength(value)];
+ for (int i=0; i<objects.length; i++) {
+ objects[i] = Array.get(value, i);
+ }
+ }
+ return objects;
+ }
+}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/JAXBUtils.java Sat Oct 24 01:46:13 2009
@@ -44,6 +44,7 @@
import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
import java.net.URL;
import java.net.URLDecoder;
import java.security.PrivilegedActionException;
@@ -97,7 +98,10 @@
// Construction Type
public enum CONSTRUCTION_TYPE {
- BY_CLASS_ARRAY, BY_CONTEXT_PATH, UNKNOWN}
+ BY_CLASS_ARRAY, // New Instance with Class[]
+ BY_CONTEXT_PATH, // New Instance with context path string (preferred)
+ BY_CLASS_ARRAY_PLUS_ARRAYS, // New Instance with Class[] plus arrays of each class are added
+ UNKNOWN}
;
@@ -164,11 +168,38 @@
* @throws JAXBException
*/
public static JAXBContext getJAXBContext(TreeSet<String> contextPackages,
- Holder<CONSTRUCTION_TYPE> constructionType,
+ Holder<CONSTRUCTION_TYPE> constructionType,
String key,
ClassLoader cacheKey,
Map<String, ?> properties)
throws JAXBException {
+ return getJAXBContext(contextPackages,
+ constructionType,
+ false,
+ key,
+ cacheKey,
+ properties);
+ }
+ /**
+ * Get a JAXBContext for the class
+ *
+ * Note: The contextPackage object is used by multiple threads. It should be considered immutable
+ * and not altered by this method.
+ *
+ * @param contextPackage Set<Package>
+ * @param contructionType (output value that indicates how the context was constructed)
+ * @param forceArrays (forces the returned JAXBContext to include the array types)
+ * @param cacheKey ClassLoader
+ * @return JAXBContext
+ * @throws JAXBException
+ */
+ public static JAXBContext getJAXBContext(TreeSet<String> contextPackages,
+ Holder<CONSTRUCTION_TYPE> constructionType,
+ boolean forceArrays,
+ String key,
+ ClassLoader cacheKey,
+ Map<String, ?> properties)
+ throws JAXBException {
// JAXBContexts for the same class can be reused and are supposed to be thread-safe
if (log.isDebugEnabled()) {
log.debug("Following packages are in this batch of getJAXBContext() :");
@@ -220,7 +251,18 @@
contextValue = innerMap.get(cl);
}
-
+ // If the context value is found, but the caller requested that the JAXBContext
+ // contain arrays, then rebuild the JAXBContext value
+ if (forceArrays &&
+ contextValue != null &&
+ contextValue.constructionType != JAXBUtils.CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS) {
+ if(log.isDebugEnabled()) {
+ log.debug("Found a JAXBContextValue with constructionType=" +
+ contextValue.constructionType + " but the caller requested a JAXBContext " +
+ " that includes arrays. A new JAXBContext will be built");
+ }
+ contextValue = null;
+ }
if (contextPackages == null) {
contextPackages = new TreeSet<String>();
@@ -231,6 +273,11 @@
ClassLoader clKey = (cacheKey != null) ? cacheKey:cl;
contextValue = innerMap.get(clKey);
adjustPoolSize(innerMap);
+ if (forceArrays &&
+ contextValue != null &&
+ contextValue.constructionType != JAXBUtils.CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS) {
+ contextValue = null;
+ }
if (contextValue==null) {
// Create a copy of the contextPackages. This new TreeSet will
// contain only the valid contextPackages.
@@ -240,13 +287,14 @@
TreeSet<String> validContextPackages = new TreeSet<String>(contextPackages);
ClassLoader tryCl = cl;
- contextValue = createJAXBContextValue(validContextPackages, cl, properties);
+ contextValue = createJAXBContextValue(validContextPackages, cl, forceArrays, properties);
// If we don't get all the classes, try the cached classloader
if (cacheKey != null && validContextPackages.size() != contextPackages.size()) {
tryCl = cacheKey;
validContextPackages = new TreeSet<String>(contextPackages);
- contextValue = createJAXBContextValue(validContextPackages, cacheKey, properties);
+ contextValue = createJAXBContextValue(validContextPackages, cacheKey,
+ forceArrays, properties);
}
synchronized (jaxbMap) {
// Add the context value with the original package set
@@ -254,7 +302,7 @@
SoftReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>
softRef1 = jaxbMap.get(key);
if (softRef1 != null) {
- map1 = softRef.get();
+ map1 = softRef1.get();
}
if (map1 == null) {
map1 = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
@@ -271,13 +319,13 @@
SoftReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>
softRef2 = jaxbMap.get(validPackagesKey);
if (softRef2 != null) {
- map2 = softRef.get();
+ map2 = softRef2.get();
}
if (map2 == null) {
map2 = new ConcurrentHashMap<ClassLoader, JAXBContextValue>();
softRef2 =
new SoftReference<ConcurrentHashMap<ClassLoader, JAXBContextValue>>(map2);
- jaxbMap.put(key, softRef2);
+ jaxbMap.put(validPackagesKey, softRef2);
}
map2.put(clKey, contextValue);
@@ -293,6 +341,11 @@
log.debug("JAXBContext [from pool] for " + key);
}
}
+ if (log.isDebugEnabled()) {
+ log.debug("JAXBContext constructionType= " + contextValue.constructionType);
+ log.debug("JAXBContextValue = " + JavaUtils.getObjectIdentity(contextValue));
+ log.debug("JAXBContext = " + JavaUtils.getObjectIdentity(contextValue.jaxbContext));
+ }
constructionType.value = contextValue.constructionType;
return contextValue.jaxbContext;
}
@@ -302,11 +355,14 @@
*
* @param contextPackages Set<String>
* @param cl ClassLoader
+ * @param forceArrays boolean (true if JAXBContext must include all arrays)
+ * @param properties Map of properties for the JAXBContext.newInstance creation method
* @return JAXBContextValue (JAXBContext + constructionType)
* @throws JAXBException
*/
private static JAXBContextValue createJAXBContextValue(TreeSet<String> contextPackages,
ClassLoader cl,
+ boolean forceArrays,
Map<String, ?> properties) throws JAXBException {
JAXBContextValue contextValue = null;
@@ -374,7 +430,7 @@
// The packages are examined to see if they have ObjectFactory/package-info classes.
// Invalid packages are removed from the list
it = contextPackages.iterator();
- boolean contextConstruction = true;
+ boolean contextConstruction = (!forceArrays);
boolean isJAXBFound = false;
while (it.hasNext()) {
String p = it.next();
@@ -413,7 +469,7 @@
if (!isJAXBFound) {
if (log.isDebugEnabled()) {
- log.debug("Both ObjectFactory & package-info not found in package hierachy");
+ log.debug("ObjectFactory & package-info are not found in package hierachy");
}
}
@@ -428,6 +484,17 @@
if (innerMap != null) {
contextValue = innerMap.get(cl);
+ if (forceArrays &&
+ contextValue != null &&
+ contextValue.constructionType != JAXBUtils.CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS) {
+ if(log.isDebugEnabled()) {
+ log.debug("Found a JAXBContextValue with constructionType=" +
+ contextValue.constructionType + " but the caller requested a JAXBContext " +
+ " that includes arrays. A new JAXBContext will be built");
+ }
+ contextValue = null;
+ }
+
if (contextValue != null) {
if (log.isDebugEnabled()) {
log.debug("Successfully found JAXBContext with updated context list:" +
@@ -458,7 +525,11 @@
Class[] classArray = fullList.toArray(new Class[0]);
JAXBContext context = JAXBContext_newInstance(classArray, cl, properties);
if (context != null) {
- contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CLASS_ARRAY);
+ if (forceArrays) {
+ contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CLASS_ARRAY_PLUS_ARRAYS);
+ } else {
+ contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CLASS_ARRAY);
+ }
}
}
if (log.isDebugEnabled()) {
@@ -553,6 +624,7 @@
*/
public static Marshaller getJAXBMarshaller(JAXBContext context) throws JAXBException {
Marshaller m = null;
+
if (!ENABLE_MARSHALL_POOLING) {
if (log.isDebugEnabled()) {
log.debug("Marshaller created [no pooling]");
@@ -585,6 +657,8 @@
public static void releaseJAXBMarshaller(JAXBContext context, Marshaller marshaller) {
if (log.isDebugEnabled()) {
log.debug("Marshaller placed back into pool");
+ log.debug(" Marshaller = " + JavaUtils.getObjectIdentity(marshaller));
+ log.debug(" JAXBContext = " + JavaUtils.getObjectIdentity(context));
}
if (ENABLE_MARSHALL_POOLING) {
marshaller.setAttachmentMarshaller(null);
@@ -933,6 +1007,7 @@
"javax.xml.namespace.QName[]" };
private static void addCommonArrayClasses(List<Class> list) {
+
// Add common primitives arrays (necessary for RPC list type support)
ClassLoader cl = getContextClassLoader();
@@ -954,7 +1029,10 @@
}
}
}
+
}
+
+
/** @return ClassLoader */
private static ClassLoader getContextClassLoader() {
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/message/impl/XMLSpineImpl.java Sat Oct 24 01:46:13 2009
@@ -571,6 +571,9 @@
operationQName.getPrefix());
opElement.setLocalName(operationQName.getLocalPart());
opElement.setNamespace(ns);
+
+ // Necessary to avoid duplicate namespaces later.
+ opElement.declareNamespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
}
}
Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java?rev=829296&r1=829295&r2=829296&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/MarshalServiceRuntimeDescription.java Sat Oct 24 01:46:13 2009
@@ -25,6 +25,7 @@
import org.apache.axis2.jaxws.message.factory.MessageFactory;
import org.apache.axis2.jaxws.utility.PropertyDescriptorPlus;
+import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeSet;
@@ -76,6 +77,13 @@
* @return FaultBeanDescriptor that describes the fault bean
*/
public FaultBeanDesc getFaultBeanDesc(FaultDescription faultDesc);
+
+ /**
+ * @param opDesc
+ * @return Method
+ */
+ public Method getMethod(OperationDescription opDesc);
+
/** @return MessageFactory for this Marshaller */
public MessageFactory getMessageFactory();