| /* |
| * 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.marshaller.impl.alt; |
| |
| import org.apache.axis2.AxisFault; |
| import org.apache.axis2.description.AxisOperation; |
| import org.apache.axis2.description.AxisService; |
| import org.apache.axis2.description.Parameter; |
| import org.apache.axis2.java.security.AccessController; |
| import org.apache.axis2.jaxws.ExceptionFactory; |
| import org.apache.axis2.jaxws.core.MessageContext; |
| 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.FaultDescription; |
| import org.apache.axis2.jaxws.description.OperationDescription; |
| import org.apache.axis2.jaxws.description.ParameterDescription; |
| import org.apache.axis2.jaxws.description.ServiceDescription; |
| import org.apache.axis2.jaxws.i18n.Messages; |
| import org.apache.axis2.jaxws.message.Block; |
| import org.apache.axis2.jaxws.message.Message; |
| import org.apache.axis2.jaxws.message.Protocol; |
| import org.apache.axis2.jaxws.message.XMLFault; |
| import org.apache.axis2.jaxws.message.XMLFaultReason; |
| import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext; |
| import org.apache.axis2.jaxws.message.databinding.JAXBUtils; |
| import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory; |
| import org.apache.axis2.jaxws.message.util.XMLFaultUtils; |
| import org.apache.axis2.jaxws.registry.FactoryRegistry; |
| import org.apache.axis2.jaxws.runtime.description.marshal.AnnotationDesc; |
| import org.apache.axis2.jaxws.runtime.description.marshal.FaultBeanDesc; |
| import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription; |
| import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescriptionFactory; |
| import org.apache.axis2.jaxws.utility.ClassUtils; |
| import org.apache.axis2.jaxws.utility.ConvertUtils; |
| import org.apache.axis2.jaxws.utility.SAAJFactory; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.activation.DataHandler; |
| import javax.jws.WebParam.Mode; |
| import javax.jws.WebService; |
| import javax.xml.bind.JAXBElement; |
| import javax.xml.namespace.QName; |
| import javax.xml.soap.SOAPBody; |
| import javax.xml.soap.SOAPConstants; |
| import javax.xml.soap.SOAPFault; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.ws.AsyncHandler; |
| import javax.xml.ws.Holder; |
| import javax.xml.ws.ProtocolException; |
| import javax.xml.ws.WebServiceException; |
| import javax.xml.ws.soap.SOAPFaultException; |
| import java.io.IOException; |
| import java.lang.reflect.Array; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| import java.util.List; |
| import java.util.TreeSet; |
| |
| /** Static Utilty Classes used by the MethodMarshaller implementations in the alt package. */ |
| public class MethodMarshallerUtils { |
| |
| private static Log log = LogFactory.getLog(MethodMarshallerUtils.class); |
| |
| private static JAXBBlockFactory factory = |
| (JAXBBlockFactory)FactoryRegistry.getFactory(JAXBBlockFactory.class); |
| |
| /** Intentionally Private. This is a static utility class */ |
| private MethodMarshallerUtils() { |
| } |
| |
| /** |
| * Returns the list of PDElements that need to be marshalled onto the wire |
| * |
| * @param marshalDesc |
| * @param params ParameterDescription for this operation |
| * @param sigArguments arguments |
| * @param isInput indicates if input or output params(input args on client, |
| * output args on server) |
| * @param isDocLitWrapped |
| * @param isRPC |
| * @return PDElements |
| */ |
| static List<PDElement> getPDElements(MarshalServiceRuntimeDescription marshalDesc, |
| ParameterDescription[] params, |
| Object[] sigArguments, |
| boolean isInput, |
| boolean isDocLitWrapped, |
| boolean isRPC) { |
| List<PDElement> pdeList = new ArrayList<PDElement>(); |
| |
| int index = 0; |
| 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) { |
| |
| // Get the matching signature argument |
| Object value = sigArguments[i]; |
| |
| // Don't consider async handlers, they are are not represented on the wire, |
| // thus they don't have a PDElement |
| if (isAsyncHandler(value)) { |
| continue; |
| } |
| |
| // Convert from Holder into value |
| if (isHolder(value)) { |
| value = ((Holder)value).value; |
| } |
| |
| // Get the formal type representing the value |
| Class formalType = pd.getParameterActualType(); |
| |
| // The namespace and local name are obtained differently depending on |
| // the style/use and header |
| QName qName = null; |
| if (pd.isHeader()) { |
| // Headers (even rpc) are marshalled with the name defined by the |
| // element= attribute on the wsd:part |
| qName = new QName(pd.getTargetNamespace(), pd.getParameterName()); |
| } else if (isDocLitWrapped) { |
| // For doc/lit wrapped, the localName comes from the PartName |
| qName = new QName(pd.getTargetNamespace(), pd.getPartName()); |
| } else if (isRPC) { |
| // Per WSI-BP, the namespace uri is unqualified |
| qName = new QName(pd.getPartName()); |
| } else { |
| qName = new QName(pd.getTargetNamespace(), pd.getParameterName()); |
| } |
| |
| // Create an Element rendering |
| Element element = null; |
| AttachmentDescription attachmentDesc = pd.getAttachmentDescription(); |
| if (attachmentDesc != null) { |
| PDElement pde = createPDElementForAttachment(pd, qName, value, formalType); |
| pdeList.add(pde); |
| } else { |
| if (!marshalDesc.getAnnotationDesc(formalType).hasXmlRootElement()) { |
| /* when a schema defines a SimpleType with xsd list jaxws tooling |
| * generates artifacts with array rather than a java.util.List |
| * However the ObjectFactory definition uses a List and thus |
| * marshalling fails. Lets convert the Arrays to List and recreate |
| * the JAXBElements for the same. |
| */ |
| if (pd.isListType()) { |
| |
| List<Object> list = new ArrayList<Object>(); |
| if (formalType.isArray()) { |
| for (int count = 0; count < Array.getLength(value); count++) { |
| Object obj = Array.get(value, count); |
| list.add(obj); |
| } |
| |
| } |
| element = new Element(list, qName, List.class); |
| } else { |
| element = new Element(value, qName, formalType); |
| } |
| } |
| else{ |
| element = new Element(value, qName); |
| } |
| // The object is now ready for marshalling |
| PDElement pde = new PDElement(pd, element, null); |
| pdeList.add(pde); |
| } |
| } |
| } |
| |
| return pdeList; |
| } |
| |
| /** |
| * @param pd |
| * @param qName |
| * @param value |
| * @param formalType |
| * @return |
| */ |
| private static PDElement createPDElementForAttachment(ParameterDescription pd, |
| QName qName, |
| Object value, |
| Class formalType) { |
| PDElement pde; |
| if (log.isDebugEnabled()) { |
| log.debug("Creating a PDElement for an attachment value: " + |
| ((value == null)? "null":value.getClass().getName())); |
| log.debug("ParameterDescription = " + pd.toString()); |
| } |
| AttachmentDescription attachmentDesc = pd.getAttachmentDescription(); |
| |
| AttachmentType attachmentType = attachmentDesc.getAttachmentType(); |
| if (attachmentType == AttachmentType.SWA) { |
| // Create an Attachment object with the signature value |
| Attachment attachment = new Attachment(value, |
| formalType, |
| attachmentDesc, |
| pd.getPartName()); |
| pde = new PDElement(pd, |
| null, // For SWA Attachments, there is no element reference to the attachment |
| null, |
| attachment); |
| } else { |
| throw ExceptionFactory.makeWebServiceException(Messages.getMessage("pdElementErr")); |
| } |
| return pde; |
| } |
| |
| /** |
| * Return the list of PDElements that is unmarshalled from the wire |
| * |
| * @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 |
| * @return ParamValues |
| */ |
| static List<PDElement> getPDElements(ParameterDescription[] params, |
| Message message, |
| TreeSet<String> packages, |
| boolean isInput, |
| boolean hasReturnInBody, |
| Class[] unmarshalByJavaType) throws XMLStreamException { |
| |
| List<PDElement> pdeList = new ArrayList<PDElement>(); |
| |
| // Count |
| int totalBodyBlocks = 0; |
| 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)) { |
| totalBodyBlocks++; |
| } |
| } |
| } |
| |
| if (!isInput && hasReturnInBody) { |
| totalBodyBlocks++; |
| } |
| |
| int index = (!isInput && hasReturnInBody) ? 1 : 0; |
| // 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 (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 |
| if (pd.isHeader()) { |
| |
| // Get the Block from the header |
| // NOTE The parameter name is always used to get the header |
| // element...even if the style is RPC. |
| String localName = pd.getParameterName(); |
| block = message.getHeaderBlock(pd.getTargetNamespace(), |
| localName, |
| context, |
| factory); |
| } else { |
| if (totalBodyBlocks > 1) { |
| // You must use this method if there are more than one body block |
| // This method may cause OM expansion |
| block = message.getBodyBlock(index, context, factory); |
| } else { |
| // Use this method if you know there is only one body block. |
| // This method prevents OM expansion. |
| block = message.getBodyBlock(context, factory); |
| } |
| index++; |
| } |
| |
| Element element = new Element(block.getBusinessObject(true), |
| block.getQName()); |
| 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")); |
| } |
| } |
| } |
| } |
| |
| return pdeList; |
| } |
| |
| /** |
| * Creates the request signature arguments (server) from a list |
| * of element eabled object (PDEements) |
| * @param pds ParameterDescriptions for this Operation |
| * @param pvList Element enabled object |
| * @return Signature Args |
| * @throws InstantiationException |
| * @throws IllegalAccessException |
| * @throws ClassNotFoundException |
| */ |
| static Object[] createRequestSignatureArgs(ParameterDescription[] pds, |
| List<PDElement> pdeList) |
| throws InstantiationException, IOException, |
| IllegalAccessException, |
| ClassNotFoundException { |
| Object[] args = new Object[pds.length]; |
| int pdeIndex = 0; |
| for (int i = 0; i < args.length; i++) { |
| // Get the paramValue |
| PDElement pde = (pdeIndex < pdeList.size()) ? pdeList.get(pdeIndex) : null; |
| ParameterDescription pd = pds[i]; |
| if (pde == null || |
| pde.getParam() != pd) { |
| // We have a ParameterDesc but there is not an equivalent PDElement. |
| // Provide the default |
| if (pd.isHolderType()) { |
| args[i] = createHolder(pd.getParameterType(), null); |
| } else { |
| args[i] = null; |
| } |
| } else { |
| |
| // We have a matching paramValue. Get the type object that represents the type |
| Object value = null; |
| if (pde.getAttachment() != null) { |
| value = pde.getAttachment().getDataHandler(); |
| } else { |
| value = pde.getElement().getTypeValue(); |
| } |
| pdeIndex++; |
| |
| // Now that we have the type, there may be a mismatch |
| // between the type (as defined by JAXB) and the formal |
| // parameter (as defined by JAXWS). Frequently this occurs |
| // with respect to T[] versus List<T>. |
| // Use the convert utility to silently do any conversions |
| if (ConvertUtils.isConvertable(value, pd.getParameterActualType())) { |
| value = ConvertUtils.convert(value, pd.getParameterActualType()); |
| } else { |
| String objectClass = (value == null) ? "null" : value.getClass().getName(); |
| throw ExceptionFactory.makeWebServiceException( |
| Messages.getMessage("convertProblem", objectClass, |
| pd.getParameterActualType().getName())); |
| } |
| |
| // The signature may want a holder representation |
| if (pd.isHolderType()) { |
| args[i] = createHolder(pd.getParameterType(), value); |
| } else { |
| args[i] = value; |
| } |
| } |
| |
| } |
| return args; |
| } |
| |
| /** |
| * Update the signature arguments on the client with the unmarshalled element enabled objects |
| * (pvList) |
| * |
| * @param pds ParameterDescriptions |
| * @param pdeList Element Enabled objects |
| * @param signatureArgs Signature Arguments (the out/inout holders are updated) |
| * @throws InstantiationException |
| * @throws IllegalAccessException |
| * @throws ClassNotFoundException |
| */ |
| static void updateResponseSignatureArgs(ParameterDescription[] pds, List<PDElement> pdeList, |
| Object[] signatureArgs) |
| throws InstantiationException, IllegalAccessException, ClassNotFoundException { |
| int pdeIndex = 0; |
| |
| // Each ParameterDescriptor has a correspondinging signatureArg from the |
| // the initial client call. The pvList contains the response values from the message. |
| // Walk the ParameterDescriptor/SignatureArg list and populate the holders with |
| // the match PDElement |
| for (int i = 0; i < pds.length; i++) { |
| // Get the param value |
| PDElement pde = (pdeIndex < pdeList.size()) ? pdeList.get(pdeIndex) : null; |
| ParameterDescription pd = pds[i]; |
| if (pde != null && pde.getParam() == pd) { |
| // We have a matching paramValue. Get the value that represents the type |
| Object value = null; |
| if (pde.getAttachment() == null) { |
| value = pde.getElement().getTypeValue(); |
| } else { |
| value = pde.getAttachment().getDataHandler(); |
| } |
| pdeIndex++; |
| |
| // Now that we have the type, there may be a mismatch |
| // between the type (as defined by JAXB) and the formal |
| // parameter (as defined by JAXWS). Frequently this occurs |
| // with respect to T[] versus List<T>. |
| // Use the convert utility to silently do any conversions |
| if (ConvertUtils.isConvertable(value, pd.getParameterActualType())) { |
| value = ConvertUtils.convert(value, pd.getParameterActualType()); |
| } else { |
| String objectClass = (value == null) ? "null" : value.getClass().getName(); |
| throw ExceptionFactory.makeWebServiceException( |
| Messages.getMessage("convertProblem", objectClass, |
| pd.getParameterActualType().getName())); |
| } |
| |
| // TODO Assert that this ParameterDescriptor must represent |
| // an OUT or INOUT and must have a non-null holder object to |
| // store the value |
| if (isHolder(signatureArgs[i])) { |
| ((Holder)signatureArgs[i]).value = value; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Marshal the element enabled objects (pvList) to the Message |
| * |
| * @param pdeList element enabled objects |
| * @param message Message |
| * @param packages Packages needed to do a JAXB Marshal |
| * @throws MessageException |
| */ |
| static void toMessage(List<PDElement> pdeList, |
| Message message, |
| TreeSet<String> packages) throws WebServiceException { |
| |
| int totalBodyBlocks = 0; |
| for (int i = 0; i < pdeList.size(); i++) { |
| PDElement pde = pdeList.get(i); |
| if (!pde.getParam().isHeader() && |
| pde.getElement() != null) { // Element is null for SWARef attachment |
| totalBodyBlocks++; |
| } |
| } |
| |
| int index = message.getNumBodyBlocks(); |
| for (int i = 0; i < pdeList.size(); i++) { |
| PDElement pde = pdeList.get(i); |
| |
| // Create JAXBContext |
| JAXBBlockContext context = new JAXBBlockContext(packages); |
| |
| Attachment attachment = pde.getAttachment(); |
| if (attachment == null) { |
| // Normal Flow: Not an attachment |
| |
| |
| // Marshal by type only if necessary |
| if (pde.getByJavaTypeClass() != null) { |
| context.setProcessType(pde.getByJavaTypeClass()); |
| if(pde.getParam()!=null){ |
| context.setIsxmlList(pde.getParam().isListType()); |
| } |
| } |
| // Create a JAXBBlock out of the value. |
| // (Note that the PDElement.getValue always returns an object |
| // that has an element rendering...ie. it is either a JAXBElement o |
| // has @XmlRootElement defined |
| Block block = |
| factory.createFrom(pde.getElement().getElementValue(), |
| context, |
| pde.getElement().getQName()); |
| |
| if (pde.getParam().isHeader()) { |
| // Header block |
| QName qname = block.getQName(); |
| message.setHeaderBlock(qname.getNamespaceURI(), qname.getLocalPart(), block); |
| } else { |
| // Body block |
| if (totalBodyBlocks < 1) { |
| // If there is only one block, use the following "more performant" method |
| message.setBodyBlock(block); |
| } else { |
| message.setBodyBlock(index, block); |
| } |
| index++; |
| } |
| } else { |
| // The parameter is an attachment |
| AttachmentType type = pde.getParam(). |
| getAttachmentDescription().getAttachmentType(); |
| if (type == AttachmentType.SWA) { |
| // All we need to do is set the data handler on the message. |
| // For SWA attachments, the message does not reference the attachment. |
| message.addDataHandler(attachment.getDataHandler(), |
| attachment.getContentID()); |
| message.setDoingSWA(true); |
| } else { |
| throw ExceptionFactory.makeWebServiceException(Messages.getMessage("pdElementErr")); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Marshals the return object to the message (used on server to marshal return object) |
| * |
| * @param returnElement element |
| * @param returnType |
| * @param marshalDesc |
| * @param message |
| * @param marshalByJavaTypeClass..we must do this for RPC...discouraged otherwise |
| * @param isHeader |
| * @throws MessageException |
| */ |
| static void toMessage(Element returnElement, |
| Class returnType, |
| boolean isList, |
| MarshalServiceRuntimeDescription marshalDesc, |
| Message message, |
| Class marshalByJavaTypeClass, |
| boolean isHeader) |
| throws WebServiceException { |
| |
| // Create the JAXBBlockContext |
| // RPC uses type marshalling, so recored the rpcType |
| JAXBBlockContext context = new JAXBBlockContext(marshalDesc.getPackages()); |
| if (marshalByJavaTypeClass != null) { |
| context.setProcessType(marshalByJavaTypeClass); |
| context.setIsxmlList(isList); |
| } |
| |
| // Create a JAXBBlock out of the value. |
| Block block = factory.createFrom(returnElement.getElementValue(), |
| context, |
| returnElement.getQName()); |
| |
| if (isHeader) { |
| message.setHeaderBlock(returnElement.getQName().getNamespaceURI(), |
| returnElement.getQName().getLocalPart(), block); |
| } else { |
| message.setBodyBlock(block); |
| } |
| } |
| |
| /** |
| * Unmarshal the return object from the message |
| * |
| * @param packages |
| * @param message |
| * @param unmarshalByJavaTypeClass Used only to indicate unmarshaling by type...only necessary |
| * in some scenarios |
| * @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) |
| * @return Element |
| * @throws WebService |
| * @throws XMLStreamException |
| */ |
| static Element getReturnElement(TreeSet<String> packages, |
| Message message, |
| Class unmarshalByJavaTypeClass, // normally null |
| boolean isList, |
| boolean isHeader, |
| String headerNS, |
| String headerLocalPart, |
| boolean hasOutputBodyParams) |
| |
| throws WebServiceException, XMLStreamException { |
| |
| // The return object is the first block in the body |
| JAXBBlockContext context = new JAXBBlockContext(packages); |
| if (unmarshalByJavaTypeClass != null && !isHeader) { |
| context.setProcessType(unmarshalByJavaTypeClass); |
| context.setIsxmlList(isList); |
| } |
| Block block = null; |
| boolean isBody = false; |
| if (isHeader) { |
| block = message.getHeaderBlock(headerNS, headerLocalPart, context, factory); |
| } else { |
| if (hasOutputBodyParams) { |
| block = message.getBodyBlock(0, context, factory); |
| isBody = true; |
| } else { |
| // If there is only 1 block, we can use the get body block method |
| // that streams the whole block content. |
| 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. |
| isBody = true; |
| } |
| } |
| //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(isBody && block == 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")); |
| } |
| // Get the business object. We want to return the object that represents the type. |
| Element returnElement = new Element(block.getBusinessObject(true), block.getQName()); |
| return returnElement; |
| } |
| |
| /** |
| * Marshaling a fault is essentially the same for rpc/lit and doc/lit. This method is used by |
| * all of the MethodMarshallers |
| * |
| * @param throwable Throwable to marshal |
| * @param operationDesc OperationDescription |
| * @param packages Packages needed to marshal the object |
| * @param message Message |
| */ |
| static void marshalFaultResponse(Throwable throwable, |
| MarshalServiceRuntimeDescription marshalDesc, |
| OperationDescription operationDesc, |
| Message message) { |
| // Get the root cause of the throwable object |
| Throwable t = ClassUtils.getRootCause(throwable); |
| if (log.isDebugEnabled()) { |
| log.debug("Marshal Throwable =" + throwable.getClass().getName()); |
| log.debug(" rootCause =" + t.getClass().getName()); |
| log.debug(" exception=" + t.toString()); |
| log.debug(" stack=" + stackToString(t)); |
| } |
| |
| XMLFault xmlfault = null; |
| |
| try { |
| |
| // There are 5 different categories of exceptions. |
| // Each category has a little different marshaling code. |
| // A) Service Exception that matches the JAX-WS |
| // specification (chapter 2.5 of the spec) |
| // B) Service Exception that matches the JAX-WS "legacy" |
| // exception (chapter 3.7 of the spec) |
| // C) SOAPFaultException |
| // D) WebServiceException |
| // E) Other runtime exceptions (i.e. NullPointerException) |
| |
| // Get the FaultDescriptor matching this Exception. |
| // If FaultDescriptor is found, this is a JAX-B Service Exception. |
| // If not found, this is a System Exception |
| FaultDescription fd = |
| operationDesc.resolveFaultByExceptionName(t.getClass().getCanonicalName()); |
| |
| if (fd != null) { |
| if (log.isErrorEnabled()) { |
| log.debug("Marshal as a Service Exception"); |
| } |
| // Create the JAXB Context |
| JAXBBlockContext context = new JAXBBlockContext(marshalDesc.getPackages()); |
| |
| // The exception is a Service Exception. |
| // It may be (A) JAX-WS compliant exception or |
| // (B) JAX-WS legacy exception |
| |
| // The faultBeanObject is a JAXB object that represents the data of the exception. |
| // It is marshalled in the detail section of the soap fault. |
| // The faultBeanObject is obtained direction from the exception (A) or via |
| // the legacy exception rules (B). |
| Object faultBeanObject = null; |
| |
| FaultBeanDesc faultBeanDesc = marshalDesc.getFaultBeanDesc(fd); |
| String faultInfo = fd.getFaultInfo(); |
| if (faultInfo == null || faultInfo.length() == 0) { |
| // Legacy Exception case |
| faultBeanObject = LegacyExceptionUtil.createFaultBean(t, fd, marshalDesc); |
| } else { |
| // Normal case |
| // Get the fault bean object. |
| Method getFaultInfo = t.getClass().getMethod("getFaultInfo", null); |
| faultBeanObject = getFaultInfo.invoke(t, null); |
| } |
| |
| if (log.isErrorEnabled()) { |
| log.debug("The faultBean type is" + faultBeanObject.getClass().getName()); |
| } |
| |
| // Use "by java type" marshalling if necessary |
| if (faultBeanObject == t || |
| (context.getConstructionType() != JAXBUtils.CONSTRUCTION_TYPE |
| .BY_CONTEXT_PATH && |
| isNotJAXBRootElement(faultBeanObject.getClass(), marshalDesc))) { |
| context.setProcessType(faultBeanObject.getClass()); |
| } |
| |
| QName faultBeanQName = new QName(faultBeanDesc.getFaultBeanNamespace(), |
| faultBeanDesc.getFaultBeanLocalName()); |
| // Make sure the faultBeanObject can be marshalled as an element |
| if (!marshalDesc.getAnnotationDesc(faultBeanObject.getClass()). |
| hasXmlRootElement()) |
| { |
| faultBeanObject = new JAXBElement(faultBeanQName, faultBeanObject.getClass(), |
| faultBeanObject); |
| } |
| |
| // Create a detailblock representing the faultBeanObject |
| Block[] detailBlocks = new Block[1]; |
| detailBlocks[0] = factory.createFrom(faultBeanObject, context, faultBeanQName); |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Create the xmlFault for the Service Exception"); |
| } |
| // Get the fault text using algorithm defined in JAX-WS 10.2.2.3 |
| String text = t.getMessage(); |
| if (text == null || text.length() == 0) { |
| text = t.toString(); |
| } |
| // Now make a XMLFault containing the detailblock |
| xmlfault = new XMLFault(null, new XMLFaultReason(text), detailBlocks); |
| } else { |
| xmlfault = createXMLFaultFromSystemException(t); |
| } |
| } catch (Throwable e) { |
| // If an exception occurs while demarshalling an exception, |
| // then rinse and repeat with a system exception |
| if (log.isDebugEnabled()) { |
| log.debug("An exception (" + e + ") occurred while marshalling exception (" + t + |
| ")"); |
| } |
| WebServiceException wse = ExceptionFactory.makeWebServiceException(e); |
| xmlfault = createXMLFaultFromSystemException(wse); |
| } |
| |
| // Add the fault to the message |
| message.setXMLFault(xmlfault); |
| } |
| |
| /** |
| * This method is used by WebService Impl and Provider to create an XMLFault (for marshalling) |
| * from an exception that is a non-service exception |
| * |
| * @param t Throwable that represents a Service Exception |
| * @return XMLFault |
| */ |
| public static XMLFault createXMLFaultFromSystemException(Throwable t) { |
| |
| try { |
| XMLFault xmlfault = null; |
| if (t instanceof SOAPFaultException) { |
| if (log.isErrorEnabled()) { |
| log.debug("Marshal SOAPFaultException"); |
| } |
| // Category C: SOAPFaultException |
| // Construct the xmlFault from the SOAPFaultException's Fault |
| SOAPFaultException sfe = (SOAPFaultException)t; |
| SOAPFault soapFault = sfe.getFault(); |
| if (soapFault == null) { |
| // No fault ? I will treat this like category E |
| xmlfault = |
| new XMLFault(null, // Use the default XMLFaultCode |
| new XMLFaultReason( |
| t.toString())); // Assumes text lang of current Locale |
| } else { |
| xmlfault = XMLFaultUtils.createXMLFault(soapFault); |
| } |
| |
| } else if (t instanceof WebServiceException) { |
| if (log.isErrorEnabled()) { |
| log.debug("Marshal as a WebServiceException"); |
| } |
| // Category D: WebServiceException |
| // The reason is constructed with the getMessage of the exception. |
| // There is no detail |
| WebServiceException wse = (WebServiceException)t; |
| |
| // Get the fault text using algorithm defined in JAX-WS 10.2.2.3 |
| String text = wse.getMessage(); |
| if (text == null || text.length() == 0) { |
| text = wse.toString(); |
| } |
| xmlfault = new XMLFault(null, // Use the default XMLFaultCode |
| new XMLFaultReason( |
| text)); // Assumes text lang of current Locale |
| } else { |
| if (log.isErrorEnabled()) { |
| log.debug("Marshal as a unchecked System Exception"); |
| } |
| // Category E: Other System Exception |
| // The reason is constructed with the toString of the exception. |
| // This places the class name of the exception in the reason |
| // There is no detail. |
| // Get the fault text using algorithm defined in JAX-WS 10.2.2.3 |
| String text = t.getMessage(); |
| if (text == null || text.length() == 0) { |
| text = t.toString(); |
| } |
| xmlfault = new XMLFault(null, // Use the default XMLFaultCode |
| new XMLFaultReason( |
| text)); // Assumes text lang of current Locale |
| } |
| return xmlfault; |
| } catch (Throwable e) { |
| try { |
| // If an exception occurs while demarshalling an exception, |
| // then rinse and repeat with a webservice exception |
| if (log.isDebugEnabled()) { |
| log.debug("An exception (" + e + ") occurred while marshalling exception (" + |
| t + ")"); |
| } |
| // Get the fault text using algorithm defined in JAX-WS 10.2.2.3 |
| String text = e.getMessage(); |
| if (text == null || text.length() == 0) { |
| text = e.toString(); |
| } |
| WebServiceException wse = ExceptionFactory.makeWebServiceException(e); |
| |
| return new XMLFault(null, // Use the default XMLFaultCode |
| new XMLFaultReason( |
| text)); // Assumes text lang of current Locale |
| } catch (Exception e2) { |
| // Exception while creating Exception for Exception |
| throw ExceptionFactory.makeWebServiceException(e2); |
| } |
| } |
| } |
| |
| /** |
| * Unmarshal the service/system exception from a Message. This is used by all of the |
| * marshallers |
| * |
| * @param operationDesc |
| * @param marshalDesc |
| * @param message |
| * @return Throwable |
| * @throws WebServiceException |
| * @throws ClassNotFoundException |
| * @throws IllegalAccessException |
| * @throws InstantiationException |
| * @throws XMLStreamException |
| * @throws InvocationTargetException |
| * @throws NoSuchMethodException |
| */ |
| static Throwable demarshalFaultResponse(OperationDescription operationDesc, |
| MarshalServiceRuntimeDescription marshalDesc, |
| Message message) |
| throws WebServiceException, ClassNotFoundException, IllegalAccessException, |
| InstantiationException, XMLStreamException, InvocationTargetException, |
| NoSuchMethodException { |
| |
| Throwable exception = null; |
| |
| // Get the fault from the message and get the detail blocks (probably one) |
| XMLFault xmlfault = message.getXMLFault(); |
| Block[] detailBlocks = xmlfault.getDetailBlocks(); |
| |
| // If there is only one block, get the element name of that block. |
| QName elementQName = null; |
| if (detailBlocks != null && detailBlocks.length == 1) { |
| elementQName = detailBlocks[0].getQName(); |
| } |
| |
| // Use the element name to find the matching FaultDescriptor |
| FaultDescription faultDesc = null; |
| if (elementQName != null) { |
| for (int i = 0; i < operationDesc.getFaultDescriptions().length && faultDesc == null; |
| i++) { |
| FaultDescription fd = operationDesc.getFaultDescriptions()[i]; |
| FaultBeanDesc faultBeanDesc = marshalDesc.getFaultBeanDesc(fd); |
| |
| if (faultBeanDesc != null) { |
| QName tryQName = new QName(faultBeanDesc.getFaultBeanNamespace(), |
| faultBeanDesc.getFaultBeanLocalName()); |
| if (log.isErrorEnabled()) { |
| log.debug(" FaultDescription qname is (" + tryQName + |
| ") and detail element qname is (" + elementQName + ")"); |
| } |
| |
| if (elementQName.equals(tryQName)) { |
| faultDesc = fd; |
| } |
| } |
| } |
| } |
| |
| if (faultDesc == null && elementQName != null) { |
| // If not found, retry the search using just the local name |
| for (int i = 0; i < operationDesc.getFaultDescriptions().length && faultDesc == null; |
| i++) { |
| FaultDescription fd = operationDesc.getFaultDescriptions()[i]; |
| FaultBeanDesc faultBeanDesc = marshalDesc.getFaultBeanDesc(fd); |
| if (faultBeanDesc != null) { |
| String tryName = faultBeanDesc.getFaultBeanLocalName(); |
| if (elementQName.getLocalPart().equals(tryName)) { |
| faultDesc = fd; |
| } |
| } |
| } |
| } |
| |
| |
| if (faultDesc == null) { |
| // This is a system exception if the method does not throw a checked exception or if |
| // the detail block is missing or contains multiple items. |
| exception = createSystemException(xmlfault, message); |
| } else { |
| if (log.isErrorEnabled()) { |
| log.debug("Ready to demarshal service exception. The detail entry name is " + |
| elementQName); |
| } |
| FaultBeanDesc faultBeanDesc = marshalDesc.getFaultBeanDesc(faultDesc); |
| boolean isLegacy = |
| (faultDesc.getFaultInfo() == null || faultDesc.getFaultInfo().length() == 0); |
| |
| // Get the JAXB object from the block |
| JAXBBlockContext blockContext = new JAXBBlockContext(marshalDesc.getPackages()); |
| |
| // Note that faultBean may not be a bean, it could be a primitive |
| Class faultBeanFormalClass; |
| try { |
| faultBeanFormalClass = loadClass(faultBeanDesc.getFaultBeanClassName()); |
| } catch (ClassNotFoundException e){ |
| faultBeanFormalClass = loadClass(faultBeanDesc.getFaultBeanClassName(), operationDesc.getEndpointInterfaceDescription().getEndpointDescription().getAxisService().getClassLoader()); |
| } |
| |
| // Use "by java type" marshalling if necessary |
| if (blockContext.getConstructionType() != |
| JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH && |
| isNotJAXBRootElement(faultBeanFormalClass, marshalDesc)) { |
| blockContext.setProcessType(faultBeanFormalClass); |
| } |
| |
| // Get the jaxb block and business object |
| Block jaxbBlock = factory.createFrom(detailBlocks[0], blockContext); |
| Object faultBeanObject = jaxbBlock.getBusinessObject(true); |
| |
| // At this point, faultBeanObject is an object that can be rendered as an |
| // element. We want the object that represents the type. |
| if (faultBeanObject instanceof JAXBElement) { |
| faultBeanObject = ((JAXBElement)faultBeanObject).getValue(); |
| } |
| |
| if (log.isErrorEnabled()) { |
| log.debug("Unmarshalled the detail element into a JAXB object"); |
| } |
| |
| // Construct the JAX-WS generated exception that holds the faultBeanObject |
| Class exceptionClass; |
| try { |
| exceptionClass = loadClass(faultDesc.getExceptionClassName()); |
| } catch (ClassNotFoundException e){ |
| exceptionClass = loadClass(faultDesc.getExceptionClassName(), operationDesc.getEndpointInterfaceDescription().getEndpointDescription().getAxisService().getClassLoader()); |
| } |
| if (log.isErrorEnabled()) { |
| log.debug("Found FaultDescription. The exception name is " + |
| exceptionClass.getName()); |
| } |
| exception = createServiceException(xmlfault.getReason().getText(), |
| exceptionClass, |
| faultBeanObject, |
| faultBeanFormalClass, |
| marshalDesc, |
| isLegacy); |
| } |
| return exception; |
| } |
| |
| |
| /** |
| * @param pds |
| * @return Number of inout or out parameters |
| */ |
| static int numOutputBodyParams(ParameterDescription[] pds) { |
| int count = 0; |
| for (int i=0; i<pds.length; i++) { |
| // TODO Need to change this to also detect not attachment |
| if (!pds[i].isHeader()) { |
| if (pds[i].getMode() == Mode.INOUT || |
| pds[i].getMode() == Mode.OUT) { |
| count++; |
| } |
| } |
| } |
| return count; |
| } |
| |
| |
| /** |
| * @param value |
| * @return if async handler |
| */ |
| static boolean isAsyncHandler(Object value) { |
| return (value instanceof AsyncHandler); |
| } |
| |
| /** |
| * @param value |
| * @return true if value is holder |
| */ |
| static boolean isHolder(Object value) { |
| return value != null && Holder.class.isAssignableFrom(value.getClass()); |
| } |
| |
| /** |
| * Crate a Holder |
| * |
| * @param <T> |
| * @param paramType |
| * @param value |
| * @return |
| * @throws IllegalAccessException |
| * @throws InstantiationException |
| * @throws ClassNotFoundException |
| */ |
| static <T> Holder<T> createHolder(Class paramType, T value) |
| throws IllegalAccessException, InstantiationException, ClassNotFoundException { |
| if (Holder.class.isAssignableFrom(paramType)) { |
| Holder holder = (Holder) paramType.newInstance(); |
| holder.value = value; |
| return holder; |
| } |
| return null; |
| } |
| |
| /** |
| * Load the class |
| * |
| * @param className |
| * @return loaded class |
| * @throws ClassNotFoundException |
| */ |
| static Class loadClass(String className) throws ClassNotFoundException { |
| // Don't make this public, its a security exposure |
| Class cls = ClassUtils.getPrimitiveClass(className); |
| if (cls == null) { |
| cls = forName(className, true, getContextClassLoader()); |
| } |
| return cls; |
| } |
| |
| /** |
| * Load the class |
| * |
| * @param className |
| * @return loaded class |
| * @throws ClassNotFoundException |
| */ |
| static Class loadClass(String className, ClassLoader cl) throws ClassNotFoundException { |
| // Don't make this public, its a security exposure |
| Class cls = ClassUtils.getPrimitiveClass(className); |
| if (cls == null) { |
| cls = forName(className, true, cl); |
| } |
| return cls; |
| } |
| /** |
| * Return the class for this name |
| * |
| * @return Class |
| */ |
| private static Class forName(final String className, final boolean initialize, |
| final ClassLoader classLoader) throws ClassNotFoundException { |
| // NOTE: This method must remain private because it uses AccessController |
| Class cl = null; |
| try { |
| cl = (Class)AccessController.doPrivileged( |
| new PrivilegedExceptionAction() { |
| public Object run() throws ClassNotFoundException { |
| // Class.forName does not support primitives |
| Class cls = ClassUtils.getPrimitiveClass(className); |
| if (cls == null) { |
| cls = Class.forName(className, initialize, classLoader); |
| } |
| return cls; |
| } |
| } |
| ); |
| } catch (PrivilegedActionException e) { |
| if (log.isDebugEnabled()) { |
| log.debug("Exception thrown from AccessController: " + e); |
| } |
| throw (ClassNotFoundException) e.getException(); |
| } |
| |
| return cl; |
| } |
| |
| /** @return ClassLoader */ |
| private static ClassLoader getContextClassLoader() { |
| // NOTE: This method must remain private because it uses AccessController |
| ClassLoader cl = null; |
| try { |
| cl = (ClassLoader)AccessController.doPrivileged( |
| new PrivilegedExceptionAction() { |
| public Object run() throws ClassNotFoundException { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| } |
| ); |
| } catch (PrivilegedActionException e) { |
| if (log.isDebugEnabled()) { |
| log.debug("Exception thrown from AccessController: " + e); |
| } |
| throw ExceptionFactory.makeWebServiceException(e.getException()); |
| } |
| |
| return cl; |
| } |
| |
| |
| /** |
| * Create a JAX-WS Service Exception (Generated Exception) |
| * |
| * @param message |
| * @param exceptionclass |
| * @param bean |
| * @param beanFormalType |
| * @return |
| * @throws InvocationTargetException |
| * @throws IllegalAccessException |
| * @throws InstantiationException |
| * @throws NoSuchMethodException |
| * @parma marshalDesc is used to get cached information about the exception class and bean |
| */ |
| private static Exception createServiceException(String message, |
| Class exceptionclass, |
| Object bean, |
| Class beanFormalType, |
| MarshalServiceRuntimeDescription marshalDesc, |
| boolean isLegacyException) throws |
| InvocationTargetException, IllegalAccessException, InstantiationException, |
| NoSuchMethodException { |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Constructing JAX-WS Exception:" + exceptionclass); |
| } |
| Exception exception = null; |
| if (isLegacyException) { |
| // Legacy Exception |
| exception = LegacyExceptionUtil.createFaultException(exceptionclass, |
| bean, |
| marshalDesc); |
| } else { |
| // Normal case, use the contstructor to create the exception |
| Constructor constructor = |
| exceptionclass.getConstructor(new Class[] { String.class, beanFormalType }); |
| exception = (Exception)constructor.newInstance(new Object[] { message, bean }); |
| } |
| |
| return exception; |
| |
| } |
| |
| /** |
| * Create a system exception |
| * |
| * @param message |
| * @return |
| */ |
| public static ProtocolException createSystemException(XMLFault xmlFault, Message message) { |
| ProtocolException e = null; |
| Protocol protocol = message.getProtocol(); |
| String text = xmlFault.getReason().getText(); |
| |
| if (protocol == Protocol.soap11 || protocol == Protocol.soap12) { |
| // Throw a SOAPFaultException |
| if (log.isDebugEnabled()) { |
| log.debug("Constructing SOAPFaultException for " + text); |
| } |
| String protocolNS = (protocol == Protocol.soap11) ? |
| SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE : |
| SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE; |
| try { |
| // The following set of instructions is used to avoid |
| // some unimplemented methods in the Axis2 SAAJ implementation |
| javax.xml.soap.MessageFactory mf = SAAJFactory.createMessageFactory(protocolNS); |
| SOAPBody body = mf.createMessage().getSOAPBody(); |
| SOAPFault soapFault = XMLFaultUtils.createSAAJFault(xmlFault, body); |
| e = new SOAPFaultException(soapFault); |
| } catch (Exception ex) { |
| // Exception occurred during exception processing. |
| // TODO Probably should do something better here |
| if (log.isDebugEnabled()) { |
| log.debug("Exception occurred during fault processing:", ex); |
| } |
| e = ExceptionFactory.makeProtocolException(text, null); |
| } |
| } else if (protocol == Protocol.rest) { |
| if (log.isDebugEnabled()) { |
| log.debug("Constructing ProtocolException for " + text); |
| } |
| // TODO Is there an explicit exception for REST |
| e = ExceptionFactory.makeProtocolException(text, null); |
| } else if (protocol == Protocol.unknown) { |
| // REVIEW What should happen if there is no protocol |
| if (log.isDebugEnabled()) { |
| log.debug("Constructing ProtocolException for " + text); |
| } |
| e = ExceptionFactory.makeProtocolException(text, null); |
| } |
| return e; |
| } |
| |
| /** |
| * @param ed |
| * @return |
| */ |
| static MarshalServiceRuntimeDescription getMarshalDesc(EndpointDescription ed) { |
| ServiceDescription sd = ed.getServiceDescription(); |
| return MarshalServiceRuntimeDescriptionFactory.get(sd); |
| } |
| |
| /** |
| * This probably should be available from the ParameterDescription |
| * |
| * @param cls |
| * @param marshalDesc |
| * @return true if primitive, wrapper, java.lang.String. Calendar (or GregorianCalendar), |
| * BigInteger etc or anything other java type that is mapped by the basic schema types |
| */ |
| static boolean isNotJAXBRootElement(Class cls, MarshalServiceRuntimeDescription marshalDesc) { |
| if (cls == String.class || |
| cls.isPrimitive() || |
| cls == Calendar.class || |
| cls == byte[].class || |
| cls == GregorianCalendar.class || |
| cls == Date.class || |
| cls == BigInteger.class || |
| cls == BigDecimal.class) { |
| |
| return true; |
| } |
| AnnotationDesc aDesc = marshalDesc.getAnnotationDesc(cls); |
| if (aDesc != null) { |
| // XmlRootElementName returns null if @XmlRootElement is not specified |
| return (aDesc.getXmlRootElementName() == null); |
| } |
| return true; |
| } |
| |
| /** |
| * Get a string containing the stack of the specified exception |
| * @param e |
| * @return |
| */ |
| public static String stackToString(Throwable e) { |
| java.io.StringWriter sw= new java.io.StringWriter(); |
| java.io.BufferedWriter bw = new java.io.BufferedWriter(sw); |
| java.io.PrintWriter pw= new java.io.PrintWriter(bw); |
| e.printStackTrace(pw); |
| pw.close(); |
| return sw.getBuffer().toString(); |
| } |
| |
| static boolean isSWAAttachment(ParameterDescription pd) { |
| return pd.getAttachmentDescription() != null && |
| pd.getAttachmentDescription().getAttachmentType() == AttachmentType.SWA; |
| } |
| |
| /** |
| * Register the unmarshalling information so that it can |
| * be used to speed up subsequent marshalling events. |
| * @param mc |
| * @param packages |
| * @param packagesKey |
| */ |
| static void registerUnmarshalInfo(MessageContext mc, |
| TreeSet<String> packages, |
| String packagesKey) throws AxisFault { |
| |
| // The information is registered on the AxisOperation. |
| if (mc == null || |
| mc.getAxisMessageContext() == null || |
| mc.getAxisMessageContext().getAxisService() == null || |
| mc.getAxisMessageContext().getAxisOperation() == null) { |
| return; |
| } |
| |
| // This needs to be stored on the AxisOperation as unmarshalling |
| // info will be specific to a method and its parameters |
| AxisOperation axisOp = mc.getAxisMessageContext().getAxisOperation(); |
| |
| // There are two things that need to be saved. |
| // 1) The UnmarshalInfo object containing the packages |
| // (which will be used by the CustomBuilder) |
| // 2) A MessageContextListener which (when triggered) registers |
| // the JAXBCustomBuilder |
| Parameter param = axisOp.getParameter(UnmarshalInfo.KEY); |
| if (param == null) { |
| UnmarshalInfo info = new UnmarshalInfo(packages, packagesKey); |
| axisOp.addParameter(UnmarshalInfo.KEY, info); |
| param = axisOp.getParameter(UnmarshalInfo.KEY); |
| param.setTransient(true); |
| // Add a listener that will set the JAXBCustomBuilder |
| UnmarshalMessageContextListener. |
| create(mc.getAxisMessageContext().getServiceContext()); |
| } |
| } |
| } |