0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019: package org.apache.axis2.jaxws.marshaller.impl.alt;
0020:
0021: import org.apache.axis2.java.security.AccessController;
0022: import org.apache.axis2.jaxws.ExceptionFactory;
0023: import org.apache.axis2.jaxws.description.AttachmentDescription;
0024: import org.apache.axis2.jaxws.description.AttachmentType;
0025: import org.apache.axis2.jaxws.description.EndpointDescription;
0026: import org.apache.axis2.jaxws.description.FaultDescription;
0027: import org.apache.axis2.jaxws.description.OperationDescription;
0028: import org.apache.axis2.jaxws.description.ParameterDescription;
0029: import org.apache.axis2.jaxws.description.ServiceDescription;
0030: import org.apache.axis2.jaxws.i18n.Messages;
0031: import org.apache.axis2.jaxws.message.Block;
0032: import org.apache.axis2.jaxws.message.Message;
0033: import org.apache.axis2.jaxws.message.Protocol;
0034: import org.apache.axis2.jaxws.message.XMLFault;
0035: import org.apache.axis2.jaxws.message.XMLFaultReason;
0036: import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
0037: import org.apache.axis2.jaxws.message.databinding.JAXBUtils;
0038: import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
0039: import org.apache.axis2.jaxws.message.util.XMLFaultUtils;
0040: import org.apache.axis2.jaxws.registry.FactoryRegistry;
0041: import org.apache.axis2.jaxws.runtime.description.marshal.AnnotationDesc;
0042: import org.apache.axis2.jaxws.runtime.description.marshal.FaultBeanDesc;
0043: import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription;
0044: import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescriptionFactory;
0045: import org.apache.axis2.jaxws.utility.ClassUtils;
0046: import org.apache.axis2.jaxws.utility.ConvertUtils;
0047: import org.apache.axis2.jaxws.utility.SAAJFactory;
0048: import org.apache.commons.logging.Log;
0049: import org.apache.commons.logging.LogFactory;
0050:
0051: import javax.activation.DataHandler;
0052: import javax.jws.WebService;
0053: import javax.jws.WebParam.Mode;
0054: import javax.xml.bind.JAXBElement;
0055: import javax.xml.namespace.QName;
0056: import javax.xml.soap.SOAPBody;
0057: import javax.xml.soap.SOAPConstants;
0058: import javax.xml.soap.SOAPFault;
0059: import javax.xml.stream.XMLStreamException;
0060: import javax.xml.ws.AsyncHandler;
0061: import javax.xml.ws.Holder;
0062: import javax.xml.ws.ProtocolException;
0063: import javax.xml.ws.WebServiceException;
0064: import javax.xml.ws.soap.SOAPFaultException;
0065:
0066: import java.io.IOException;
0067: import java.lang.reflect.Array;
0068: import java.lang.reflect.Constructor;
0069: import java.lang.reflect.InvocationTargetException;
0070: import java.lang.reflect.Method;
0071: import java.math.BigDecimal;
0072: import java.math.BigInteger;
0073: import java.security.PrivilegedActionException;
0074: import java.security.PrivilegedExceptionAction;
0075: import java.util.ArrayList;
0076: import java.util.Calendar;
0077: import java.util.Date;
0078: import java.util.GregorianCalendar;
0079: import java.util.List;
0080: import java.util.TreeSet;
0081:
0082: /** Static Utilty Classes used by the MethodMarshaller implementations in the alt package. */
0083: public class MethodMarshallerUtils {
0084:
0085: private static Log log = LogFactory
0086: .getLog(MethodMarshallerUtils.class);
0087:
0088: private static JAXBBlockFactory factory = (JAXBBlockFactory) FactoryRegistry
0089: .getFactory(JAXBBlockFactory.class);
0090:
0091: /** Intentionally Private. This is a static utility class */
0092: private MethodMarshallerUtils() {
0093: }
0094:
0095: /**
0096: * Returns the list of PDElements that need to be marshalled onto the wire
0097: *
0098: * @param marshalDesc
0099: * @param params ParameterDescription for this operation
0100: * @param sigArguments arguments
0101: * @param isInput indicates if input or output params(input args on client,
0102: * output args on server)
0103: * @param isDocLitWrapped
0104: * @param isRPC
0105: * @return PDElements
0106: */
0107: static List<PDElement> getPDElements(
0108: MarshalServiceRuntimeDescription marshalDesc,
0109: ParameterDescription[] params, Object[] sigArguments,
0110: boolean isInput, boolean isDocLitWrapped, boolean isRPC) {
0111: List<PDElement> pdeList = new ArrayList<PDElement>();
0112:
0113: int index = 0;
0114: for (int i = 0; i < params.length; i++) {
0115: ParameterDescription pd = params[i];
0116:
0117: if (pd.getMode() == Mode.IN && isInput
0118: || pd.getMode() == Mode.INOUT
0119: || pd.getMode() == Mode.OUT && !isInput) {
0120:
0121: // Get the matching signature argument
0122: Object value = sigArguments[i];
0123:
0124: // Don't consider async handlers, they are are not represented on the wire,
0125: // thus they don't have a PDElement
0126: if (isAsyncHandler(value)) {
0127: continue;
0128: }
0129:
0130: // Convert from Holder into value
0131: if (isHolder(value)) {
0132: value = ((Holder) value).value;
0133: }
0134:
0135: // Get the formal type representing the value
0136: Class formalType = pd.getParameterActualType();
0137:
0138: // The namespace and local name are obtained differently depending on
0139: // the style/use and header
0140: QName qName = null;
0141: if (pd.isHeader()) {
0142: // Headers (even rpc) are marshalled with the name defined by the
0143: // element= attribute on the wsd:part
0144: qName = new QName(pd.getTargetNamespace(), pd
0145: .getParameterName());
0146: } else if (isDocLitWrapped) {
0147: // For doc/lit wrapped, the localName comes from the PartName
0148: qName = new QName(pd.getTargetNamespace(), pd
0149: .getPartName());
0150: } else if (isRPC) {
0151: // Per WSI-BP, the namespace uri is unqualified
0152: qName = new QName(pd.getPartName());
0153: } else {
0154: qName = new QName(pd.getTargetNamespace(), pd
0155: .getParameterName());
0156: }
0157:
0158: // Create an Element rendering
0159: Element element = null;
0160: AttachmentDescription attachmentDesc = pd
0161: .getAttachmentDescription();
0162: if (attachmentDesc != null) {
0163: PDElement pde = createPDElementForAttachment(pd,
0164: qName, value, formalType);
0165: pdeList.add(pde);
0166: } else {
0167: if (!marshalDesc.getAnnotationDesc(formalType)
0168: .hasXmlRootElement()) {
0169: /* when a schema defines a SimpleType with xsd list jaxws tooling
0170: * generates artifacts with array rather than a java.util.List
0171: * However the ObjectFactory definition uses a List and thus
0172: * marshalling fails. Lets convert the Arrays to List and recreate
0173: * the JAXBElements for the same.
0174: */
0175: if (pd.isListType()) {
0176:
0177: List<Object> list = new ArrayList<Object>();
0178: if (formalType.isArray()) {
0179: for (int count = 0; count < Array
0180: .getLength(value); count++) {
0181: Object obj = Array
0182: .get(value, count);
0183: list.add(obj);
0184: }
0185:
0186: }
0187: element = new Element(list, qName,
0188: List.class);
0189: } else {
0190: element = new Element(value, qName,
0191: formalType);
0192: }
0193: } else {
0194: element = new Element(value, qName);
0195: }
0196: // The object is now ready for marshalling
0197: PDElement pde = new PDElement(pd, element, null);
0198: pdeList.add(pde);
0199: }
0200: }
0201: }
0202:
0203: return pdeList;
0204: }
0205:
0206: /**
0207: * @param pd
0208: * @param qName
0209: * @param value
0210: * @param formalType
0211: * @return
0212: */
0213: private static PDElement createPDElementForAttachment(
0214: ParameterDescription pd, QName qName, Object value,
0215: Class formalType) {
0216: PDElement pde;
0217: if (log.isDebugEnabled()) {
0218: log.debug("Creating a PDElement for an attachment value: "
0219: + ((value == null) ? "null" : value.getClass()
0220: .getName()));
0221: log.debug("ParameterDescription = " + pd.toString());
0222: }
0223: AttachmentDescription attachmentDesc = pd
0224: .getAttachmentDescription();
0225:
0226: AttachmentType attachmentType = attachmentDesc
0227: .getAttachmentType();
0228: if (attachmentType == AttachmentType.SWA) {
0229: // Create an Attachment object with the signature value
0230: Attachment attachment = new Attachment(value, formalType,
0231: attachmentDesc);
0232: pde = new PDElement(pd, null, // For SWA Attachments, there is no element reference to the attachment
0233: null, attachment);
0234: } else {
0235: // TODO NLS and clean this up
0236: throw ExceptionFactory
0237: .makeWebServiceException("SWAREF and MTOM attachment parameters are not "
0238: + "supported in this style/use.");
0239: }
0240: return pde;
0241: }
0242:
0243: /**
0244: * Return the list of PDElements that is unmarshalled from the wire
0245: *
0246: * @param params ParameterDescription for this operation
0247: * @param message Message
0248: * @param packages set of packages needed to unmarshal objects for this operation
0249: * @param isInput indicates if input or output params (input on server, output on client)
0250: * @param hasReturnInBody if isInput=false, then this parameter indicates whether a
0251: * return value is expected in the body.
0252: * @param unmarshalByJavaType in most scenarios this is null.
0253: * Only use this in the scenarios that require unmarshalling by java type
0254: * @return ParamValues
0255: */
0256: static List<PDElement> getPDElements(ParameterDescription[] params,
0257: Message message, TreeSet<String> packages, boolean isInput,
0258: boolean hasReturnInBody, Class[] unmarshalByJavaType)
0259: throws XMLStreamException {
0260:
0261: List<PDElement> pdeList = new ArrayList<PDElement>();
0262:
0263: // Count
0264: int totalBodyBlocks = 0;
0265: for (int i = 0; i < params.length; i++) {
0266: ParameterDescription pd = params[i];
0267:
0268: if (pd.getMode() == Mode.IN && isInput
0269: || pd.getMode() == Mode.INOUT
0270: || pd.getMode() == Mode.OUT && !isInput) {
0271: if (!pd.isHeader() && !isSWAAttachment(pd)) {
0272: totalBodyBlocks++;
0273: }
0274: }
0275: }
0276:
0277: if (!isInput && hasReturnInBody) {
0278: totalBodyBlocks++;
0279: }
0280:
0281: int index = (!isInput && hasReturnInBody) ? 1 : 0;
0282: // TODO What if return is an swa attachment, then this should start
0283: // at 1 not 0.
0284: int swaIndex = 0;
0285: for (int i = 0; i < params.length; i++) {
0286: ParameterDescription pd = params[i];
0287:
0288: if (pd.getMode() == Mode.IN && isInput
0289: || pd.getMode() == Mode.INOUT
0290: || pd.getMode() == Mode.OUT && !isInput) {
0291:
0292: // Don't consider async handlers, they are are not represented on the wire,
0293: // thus they don't have a PDElement
0294: // TODO
0295: //if (isAsyncHandler(param)) {
0296: // continue;
0297: //}
0298:
0299: Block block = null;
0300: JAXBBlockContext context = new JAXBBlockContext(
0301: packages);
0302:
0303: AttachmentDescription attachmentDesc = pd
0304: .getAttachmentDescription();
0305: if (attachmentDesc == null) {
0306:
0307: // Normal Processing: Not an Attachment
0308: // Trigger unmarshal by java type if necessary
0309: if (unmarshalByJavaType != null
0310: && unmarshalByJavaType[i] != null) {
0311: context.setProcessType(unmarshalByJavaType[i]);
0312: context.setIsxmlList(pd.isListType());
0313: }
0314:
0315: // Unmarshal the object into a JAXB object or JAXBElement
0316: if (pd.isHeader()) {
0317:
0318: // Get the Block from the header
0319: // NOTE The parameter name is always used to get the header
0320: // element...even if the style is RPC.
0321: String localName = pd.getParameterName();
0322: block = message.getHeaderBlock(pd
0323: .getTargetNamespace(), localName,
0324: context, factory);
0325: } else {
0326: if (totalBodyBlocks > 1) {
0327: // You must use this method if there are more than one body block
0328: // This method may cause OM expansion
0329: block = message.getBodyBlock(index,
0330: context, factory);
0331: } else {
0332: // Use this method if you know there is only one body block.
0333: // This method prevents OM expansion.
0334: block = message.getBodyBlock(context,
0335: factory);
0336: }
0337: index++;
0338: }
0339:
0340: Element element = new Element(block
0341: .getBusinessObject(true), block.getQName());
0342: PDElement pde = new PDElement(pd, element,
0343: unmarshalByJavaType == null ? null
0344: : unmarshalByJavaType[i]);
0345: pdeList.add(pde);
0346: } else {
0347: // Attachment Processing
0348: if (attachmentDesc.getAttachmentType() == AttachmentType.SWA) {
0349: String cid = message.getAttachmentID(swaIndex);
0350: DataHandler dh = message.getDataHandler(cid);
0351: Attachment attachment = new Attachment(dh, cid);
0352: PDElement pde = new PDElement(pd, null, null,
0353: attachment);
0354: pdeList.add(pde);
0355: swaIndex++;
0356: } else {
0357: // TODO NLS and clean this up
0358: throw ExceptionFactory
0359: .makeWebServiceException("SWAREF and MTOM "
0360: + "attachment parameters are not supported "
0361: + "in this style/use.");
0362: }
0363: }
0364: }
0365: }
0366:
0367: return pdeList;
0368: }
0369:
0370: /**
0371: * Creates the request signature arguments (server) from a list
0372: * of element eabled object (PDEements)
0373: * @param pds ParameterDescriptions for this Operation
0374: * @param pvList Element enabled object
0375: * @return Signature Args
0376: * @throws InstantiationException
0377: * @throws IllegalAccessException
0378: * @throws ClassNotFoundException
0379: */
0380: static Object[] createRequestSignatureArgs(
0381: ParameterDescription[] pds, List<PDElement> pdeList)
0382: throws InstantiationException, IOException,
0383: IllegalAccessException, ClassNotFoundException {
0384: Object[] args = new Object[pds.length];
0385: int pdeIndex = 0;
0386: for (int i = 0; i < args.length; i++) {
0387: // Get the paramValue
0388: PDElement pde = (pdeIndex < pdeList.size()) ? pdeList
0389: .get(pdeIndex) : null;
0390: ParameterDescription pd = pds[i];
0391: if (pde == null || pde.getParam() != pd) {
0392: // We have a ParameterDesc but there is not an equivalent PDElement.
0393: // Provide the default
0394: if (pd.isHolderType()) {
0395: args[i] = createHolder(pd.getParameterType(), null);
0396: } else {
0397: args[i] = null;
0398: }
0399: } else {
0400:
0401: // We have a matching paramValue. Get the type object that represents the type
0402: Object value = null;
0403: if (pde.getAttachment() != null) {
0404: value = pde.getAttachment().getDataHandler();
0405: } else {
0406: value = pde.getElement().getTypeValue();
0407: }
0408: pdeIndex++;
0409:
0410: // Now that we have the type, there may be a mismatch
0411: // between the type (as defined by JAXB) and the formal
0412: // parameter (as defined by JAXWS). Frequently this occurs
0413: // with respect to T[] versus List<T>.
0414: // Use the convert utility to silently do any conversions
0415: if (ConvertUtils.isConvertable(value, pd
0416: .getParameterActualType())) {
0417: value = ConvertUtils.convert(value, pd
0418: .getParameterActualType());
0419: } else {
0420: String objectClass = (value == null) ? "null"
0421: : value.getClass().getName();
0422: throw ExceptionFactory
0423: .makeWebServiceException(Messages
0424: .getMessage("convertProblem",
0425: objectClass,
0426: pd.getParameterActualType()
0427: .getName()));
0428: }
0429:
0430: // The signature may want a holder representation
0431: if (pd.isHolderType()) {
0432: args[i] = createHolder(pd.getParameterType(), value);
0433: } else {
0434: args[i] = value;
0435: }
0436: }
0437:
0438: }
0439: return args;
0440: }
0441:
0442: /**
0443: * Update the signature arguments on the client with the unmarshalled element enabled objects
0444: * (pvList)
0445: *
0446: * @param pds ParameterDescriptions
0447: * @param pdeList Element Enabled objects
0448: * @param signatureArgs Signature Arguments (the out/inout holders are updated)
0449: * @throws InstantiationException
0450: * @throws IllegalAccessException
0451: * @throws ClassNotFoundException
0452: */
0453: static void updateResponseSignatureArgs(ParameterDescription[] pds,
0454: List<PDElement> pdeList, Object[] signatureArgs)
0455: throws InstantiationException, IllegalAccessException,
0456: ClassNotFoundException {
0457: int pdeIndex = 0;
0458:
0459: // Each ParameterDescriptor has a correspondinging signatureArg from the
0460: // the initial client call. The pvList contains the response values from the message.
0461: // Walk the ParameterDescriptor/SignatureArg list and populate the holders with
0462: // the match PDElement
0463: for (int i = 0; i < pds.length; i++) {
0464: // Get the param value
0465: PDElement pde = (pdeIndex < pdeList.size()) ? pdeList
0466: .get(pdeIndex) : null;
0467: ParameterDescription pd = pds[i];
0468: if (pde != null && pde.getParam() == pd) {
0469: // We have a matching paramValue. Get the value that represents the type
0470: Object value = null;
0471: if (pde.getAttachment() == null) {
0472: value = pde.getElement().getTypeValue();
0473: } else {
0474: value = pde.getAttachment().getDataHandler();
0475: }
0476: pdeIndex++;
0477:
0478: // Now that we have the type, there may be a mismatch
0479: // between the type (as defined by JAXB) and the formal
0480: // parameter (as defined by JAXWS). Frequently this occurs
0481: // with respect to T[] versus List<T>.
0482: // Use the convert utility to silently do any conversions
0483: if (ConvertUtils.isConvertable(value, pd
0484: .getParameterActualType())) {
0485: value = ConvertUtils.convert(value, pd
0486: .getParameterActualType());
0487: } else {
0488: String objectClass = (value == null) ? "null"
0489: : value.getClass().getName();
0490: throw ExceptionFactory
0491: .makeWebServiceException(Messages
0492: .getMessage("convertProblem",
0493: objectClass,
0494: pd.getParameterActualType()
0495: .getName()));
0496: }
0497:
0498: // TODO Assert that this ParameterDescriptor must represent
0499: // an OUT or INOUT and must have a non-null holder object to
0500: // store the value
0501: if (isHolder(signatureArgs[i])) {
0502: ((Holder) signatureArgs[i]).value = value;
0503: }
0504: }
0505: }
0506: }
0507:
0508: /**
0509: * Marshal the element enabled objects (pvList) to the Message
0510: *
0511: * @param pdeList element enabled objects
0512: * @param message Message
0513: * @param packages Packages needed to do a JAXB Marshal
0514: * @throws MessageException
0515: */
0516: static void toMessage(List<PDElement> pdeList, Message message,
0517: TreeSet<String> packages) throws WebServiceException {
0518:
0519: int totalBodyBlocks = 0;
0520: for (int i = 0; i < pdeList.size(); i++) {
0521: PDElement pde = pdeList.get(i);
0522: if (!pde.getParam().isHeader() && pde.getElement() != null) { // Element is null for SWARef attachment
0523: totalBodyBlocks++;
0524: }
0525: }
0526:
0527: int index = message.getNumBodyBlocks();
0528: for (int i = 0; i < pdeList.size(); i++) {
0529: PDElement pde = pdeList.get(i);
0530:
0531: // Create JAXBContext
0532: JAXBBlockContext context = new JAXBBlockContext(packages);
0533:
0534: Attachment attachment = pde.getAttachment();
0535: if (attachment == null) {
0536: // Normal Flow: Not an attachment
0537:
0538: // Marshal by type only if necessary
0539: if (pde.getByJavaTypeClass() != null) {
0540: context.setProcessType(pde.getByJavaTypeClass());
0541: if (pde.getParam() != null) {
0542: context.setIsxmlList(pde.getParam()
0543: .isListType());
0544: }
0545: }
0546: // Create a JAXBBlock out of the value.
0547: // (Note that the PDElement.getValue always returns an object
0548: // that has an element rendering...ie. it is either a JAXBElement o
0549: // has @XmlRootElement defined
0550: Block block = factory.createFrom(pde.getElement()
0551: .getElementValue(), context, pde.getElement()
0552: .getQName());
0553:
0554: if (pde.getParam().isHeader()) {
0555: // Header block
0556: QName qname = block.getQName();
0557: message.setHeaderBlock(qname.getNamespaceURI(),
0558: qname.getLocalPart(), block);
0559: } else {
0560: // Body block
0561: if (totalBodyBlocks < 1) {
0562: // If there is only one block, use the following "more performant" method
0563: message.setBodyBlock(block);
0564: } else {
0565: message.setBodyBlock(index, block);
0566: }
0567: index++;
0568: }
0569: } else {
0570: // The parameter is an attachment
0571: AttachmentType type = pde.getParam()
0572: .getAttachmentDescription().getAttachmentType();
0573: if (type == AttachmentType.SWA) {
0574: // All we need to do is set the data handler on the message.
0575: // For SWA attachments, the message does not reference the attachment.
0576: message.addDataHandler(attachment.getDataHandler(),
0577: attachment.getContentID());
0578: message.setDoingSWA(true);
0579: } else {
0580: // TODO NLS and cleanup
0581: throw ExceptionFactory
0582: .makeWebServiceException("SWAREF and MTOM attachment parameters "
0583: + "are not supported in this style/use.");
0584: }
0585: }
0586: }
0587: }
0588:
0589: /**
0590: * Marshals the return object to the message (used on server to marshal return object)
0591: *
0592: * @param returnElement element
0593: * @param returnType
0594: * @param marshalDesc
0595: * @param message
0596: * @param marshalByJavaTypeClass..we must do this for RPC...discouraged otherwise
0597: * @param isHeader
0598: * @throws MessageException
0599: */
0600: static void toMessage(Element returnElement, Class returnType,
0601: boolean isList,
0602: MarshalServiceRuntimeDescription marshalDesc,
0603: Message message, Class marshalByJavaTypeClass,
0604: boolean isHeader) throws WebServiceException {
0605:
0606: // Create the JAXBBlockContext
0607: // RPC uses type marshalling, so recored the rpcType
0608: JAXBBlockContext context = new JAXBBlockContext(marshalDesc
0609: .getPackages());
0610: if (marshalByJavaTypeClass != null) {
0611: context.setProcessType(marshalByJavaTypeClass);
0612: context.setIsxmlList(isList);
0613: }
0614:
0615: // Create a JAXBBlock out of the value.
0616: Block block = factory.createFrom(returnElement
0617: .getElementValue(), context, returnElement.getQName());
0618:
0619: if (isHeader) {
0620: message.setHeaderBlock(returnElement.getQName()
0621: .getNamespaceURI(), returnElement.getQName()
0622: .getLocalPart(), block);
0623: } else {
0624: message.setBodyBlock(block);
0625: }
0626: }
0627:
0628: /**
0629: * Unmarshal the return object from the message
0630: *
0631: * @param packages
0632: * @param message
0633: * @param unmarshalByJavaTypeClass Used only to indicate unmarshaling by type...only necessary
0634: * in some scenarios
0635: * @param isHeader
0636: * @param headerNS (only needed if isHeader)
0637: * @param headerLocalPart (only needed if isHeader)
0638: * @param hasOutputBodyParams (true if the method has out or inout params other
0639: * than the return value)
0640: * @return Element
0641: * @throws WebService
0642: * @throws XMLStreamException
0643: */
0644: static Element getReturnElement(TreeSet<String> packages,
0645: Message message,
0646: Class unmarshalByJavaTypeClass, // normally null
0647: boolean isList, boolean isHeader, String headerNS,
0648: String headerLocalPart, boolean hasOutputBodyParams)
0649:
0650: throws WebServiceException, XMLStreamException {
0651:
0652: // The return object is the first block in the body
0653: JAXBBlockContext context = new JAXBBlockContext(packages);
0654: if (unmarshalByJavaTypeClass != null && !isHeader) {
0655: context.setProcessType(unmarshalByJavaTypeClass);
0656: context.setIsxmlList(isList);
0657: }
0658: Block block = null;
0659: if (isHeader) {
0660: block = message.getHeaderBlock(headerNS, headerLocalPart,
0661: context, factory);
0662: } else {
0663: if (hasOutputBodyParams) {
0664: block = message.getBodyBlock(0, context, factory);
0665: } else {
0666: // If there is only 1 block, we can use the get body block method
0667: // that streams the whole block content.
0668: block = message.getBodyBlock(context, factory);
0669: }
0670: }
0671:
0672: // Get the business object. We want to return the object that represents the type.
0673: Element returnElement = new Element(block
0674: .getBusinessObject(true), block.getQName());
0675: return returnElement;
0676: }
0677:
0678: /**
0679: * Marshaling a fault is essentially the same for rpc/lit and doc/lit. This method is used by
0680: * all of the MethodMarshallers
0681: *
0682: * @param throwable Throwable to marshal
0683: * @param operationDesc OperationDescription
0684: * @param packages Packages needed to marshal the object
0685: * @param message Message
0686: */
0687: static void marshalFaultResponse(Throwable throwable,
0688: MarshalServiceRuntimeDescription marshalDesc,
0689: OperationDescription operationDesc, Message message) {
0690: // Get the root cause of the throwable object
0691: Throwable t = ClassUtils.getRootCause(throwable);
0692: if (log.isDebugEnabled()) {
0693: log.debug("Marshal Throwable ="
0694: + throwable.getClass().getName());
0695: log.debug(" rootCause =" + t.getClass().getName());
0696: log.debug(" exception=" + t.toString());
0697: log.debug(" stack=" + stackToString(t));
0698: }
0699:
0700: XMLFault xmlfault = null;
0701:
0702: try {
0703:
0704: // There are 5 different categories of exceptions.
0705: // Each category has a little different marshaling code.
0706: // A) Service Exception that matches the JAX-WS
0707: // specification (chapter 2.5 of the spec)
0708: // B) Service Exception that matches the JAX-WS "legacy"
0709: // exception (chapter 3.7 of the spec)
0710: // C) SOAPFaultException
0711: // D) WebServiceException
0712: // E) Other runtime exceptions (i.e. NullPointerException)
0713:
0714: // Get the FaultDescriptor matching this Exception.
0715: // If FaultDescriptor is found, this is a JAX-B Service Exception.
0716: // If not found, this is a System Exception
0717: FaultDescription fd = operationDesc
0718: .resolveFaultByExceptionName(t.getClass()
0719: .getCanonicalName());
0720:
0721: if (fd != null) {
0722: if (log.isErrorEnabled()) {
0723: log.debug("Marshal as a Service Exception");
0724: }
0725: // Create the JAXB Context
0726: JAXBBlockContext context = new JAXBBlockContext(
0727: marshalDesc.getPackages());
0728:
0729: // The exception is a Service Exception.
0730: // It may be (A) JAX-WS compliant exception or
0731: // (B) JAX-WS legacy exception
0732:
0733: // The faultBeanObject is a JAXB object that represents the data of the exception.
0734: // It is marshalled in the detail section of the soap fault.
0735: // The faultBeanObject is obtained direction from the exception (A) or via
0736: // the legacy exception rules (B).
0737: Object faultBeanObject = null;
0738:
0739: FaultBeanDesc faultBeanDesc = marshalDesc
0740: .getFaultBeanDesc(fd);
0741: String faultInfo = fd.getFaultInfo();
0742: if (faultInfo == null || faultInfo.length() == 0) {
0743: // Legacy Exception case
0744: faultBeanObject = LegacyExceptionUtil
0745: .createFaultBean(t, fd, marshalDesc);
0746: } else {
0747: // Normal case
0748: // Get the fault bean object.
0749: Method getFaultInfo = t.getClass().getMethod(
0750: "getFaultInfo", null);
0751: faultBeanObject = getFaultInfo.invoke(t, null);
0752: }
0753:
0754: if (log.isErrorEnabled()) {
0755: log.debug("The faultBean type is"
0756: + faultBeanObject.getClass().getName());
0757: }
0758:
0759: // Use "by java type" marshalling if necessary
0760: if (faultBeanObject == t
0761: || (context.getConstructionType() != JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH && isNotJAXBRootElement(
0762: faultBeanObject.getClass(), marshalDesc))) {
0763: context.setProcessType(faultBeanObject.getClass());
0764: }
0765:
0766: QName faultBeanQName = new QName(faultBeanDesc
0767: .getFaultBeanNamespace(), faultBeanDesc
0768: .getFaultBeanLocalName());
0769: // Make sure the faultBeanObject can be marshalled as an element
0770: if (!marshalDesc.getAnnotationDesc(
0771: faultBeanObject.getClass()).hasXmlRootElement()) {
0772: faultBeanObject = new JAXBElement(faultBeanQName,
0773: faultBeanObject.getClass(), faultBeanObject);
0774: }
0775:
0776: // Create a detailblock representing the faultBeanObject
0777: Block[] detailBlocks = new Block[1];
0778: detailBlocks[0] = factory.createFrom(faultBeanObject,
0779: context, faultBeanQName);
0780:
0781: if (log.isErrorEnabled()) {
0782: log
0783: .debug("Create the xmlFault for the Service Exception");
0784: }
0785: // Get the fault text using algorithm defined in JAX-WS 10.2.2.3
0786: String text = t.getMessage();
0787: if (text == null || text.length() == 0) {
0788: text = t.toString();
0789: }
0790: // Now make a XMLFault containing the detailblock
0791: xmlfault = new XMLFault(null, new XMLFaultReason(text),
0792: detailBlocks);
0793: } else {
0794: xmlfault = createXMLFaultFromSystemException(t);
0795: }
0796: } catch (Throwable e) {
0797: // If an exception occurs while demarshalling an exception,
0798: // then rinse and repeat with a system exception
0799: if (log.isDebugEnabled()) {
0800: log.debug("An exception (" + e
0801: + ") occurred while marshalling exception ("
0802: + t + ")");
0803: }
0804: WebServiceException wse = ExceptionFactory
0805: .makeWebServiceException(e);
0806: xmlfault = createXMLFaultFromSystemException(wse);
0807: }
0808:
0809: // Add the fault to the message
0810: message.setXMLFault(xmlfault);
0811: }
0812:
0813: /**
0814: * This method is used by WebService Impl and Provider to create an XMLFault (for marshalling)
0815: * from an exception that is a non-service exception
0816: *
0817: * @param t Throwable that represents a Service Exception
0818: * @return XMLFault
0819: */
0820: public static XMLFault createXMLFaultFromSystemException(Throwable t) {
0821:
0822: try {
0823: XMLFault xmlfault = null;
0824: if (t instanceof SOAPFaultException) {
0825: if (log.isErrorEnabled()) {
0826: log.debug("Marshal SOAPFaultException");
0827: }
0828: // Category C: SOAPFaultException
0829: // Construct the xmlFault from the SOAPFaultException's Fault
0830: SOAPFaultException sfe = (SOAPFaultException) t;
0831: SOAPFault soapFault = sfe.getFault();
0832: if (soapFault == null) {
0833: // No fault ? I will treat this like category E
0834: xmlfault = new XMLFault(null, // Use the default XMLFaultCode
0835: new XMLFaultReason(t.toString())); // Assumes text lang of current Locale
0836: } else {
0837: xmlfault = XMLFaultUtils.createXMLFault(soapFault);
0838: }
0839:
0840: } else if (t instanceof WebServiceException) {
0841: if (log.isErrorEnabled()) {
0842: log.debug("Marshal as a WebServiceException");
0843: }
0844: // Category D: WebServiceException
0845: // The reason is constructed with the getMessage of the exception.
0846: // There is no detail
0847: WebServiceException wse = (WebServiceException) t;
0848:
0849: // Get the fault text using algorithm defined in JAX-WS 10.2.2.3
0850: String text = wse.getMessage();
0851: if (text == null || text.length() == 0) {
0852: text = wse.toString();
0853: }
0854: xmlfault = new XMLFault(null, // Use the default XMLFaultCode
0855: new XMLFaultReason(text)); // Assumes text lang of current Locale
0856: } else {
0857: if (log.isErrorEnabled()) {
0858: log
0859: .debug("Marshal as a unchecked System Exception");
0860: }
0861: // Category E: Other System Exception
0862: // The reason is constructed with the toString of the exception.
0863: // This places the class name of the exception in the reason
0864: // There is no detail.
0865: // Get the fault text using algorithm defined in JAX-WS 10.2.2.3
0866: String text = t.getMessage();
0867: if (text == null || text.length() == 0) {
0868: text = t.toString();
0869: }
0870: xmlfault = new XMLFault(null, // Use the default XMLFaultCode
0871: new XMLFaultReason(text)); // Assumes text lang of current Locale
0872: }
0873: return xmlfault;
0874: } catch (Throwable e) {
0875: try {
0876: // If an exception occurs while demarshalling an exception,
0877: // then rinse and repeat with a webservice exception
0878: if (log.isDebugEnabled()) {
0879: log
0880: .debug("An exception ("
0881: + e
0882: + ") occurred while marshalling exception ("
0883: + t + ")");
0884: }
0885: // Get the fault text using algorithm defined in JAX-WS 10.2.2.3
0886: String text = e.getMessage();
0887: if (text == null || text.length() == 0) {
0888: text = e.toString();
0889: }
0890: WebServiceException wse = ExceptionFactory
0891: .makeWebServiceException(e);
0892:
0893: return new XMLFault(null, // Use the default XMLFaultCode
0894: new XMLFaultReason(text)); // Assumes text lang of current Locale
0895: } catch (Exception e2) {
0896: // Exception while creating Exception for Exception
0897: throw ExceptionFactory.makeWebServiceException(e2);
0898: }
0899: }
0900: }
0901:
0902: /**
0903: * Unmarshal the service/system exception from a Message. This is used by all of the
0904: * marshallers
0905: *
0906: * @param operationDesc
0907: * @param marshalDesc
0908: * @param message
0909: * @return Throwable
0910: * @throws WebServiceException
0911: * @throws ClassNotFoundException
0912: * @throws IllegalAccessException
0913: * @throws InstantiationException
0914: * @throws XMLStreamException
0915: * @throws InvocationTargetException
0916: * @throws NoSuchMethodException
0917: */
0918: static Throwable demarshalFaultResponse(
0919: OperationDescription operationDesc,
0920: MarshalServiceRuntimeDescription marshalDesc,
0921: Message message) throws WebServiceException,
0922: ClassNotFoundException, IllegalAccessException,
0923: InstantiationException, XMLStreamException,
0924: InvocationTargetException, NoSuchMethodException {
0925:
0926: Throwable exception = null;
0927: // Get the fault from the message and get the detail blocks (probably one)
0928: XMLFault xmlfault = message.getXMLFault();
0929: Block[] detailBlocks = xmlfault.getDetailBlocks();
0930:
0931: // If there is only one block, get the element name of that block.
0932: QName elementQName = null;
0933: if (detailBlocks != null && detailBlocks.length == 1) {
0934: elementQName = detailBlocks[0].getQName();
0935: }
0936:
0937: // Use the element name to find the matching FaultDescriptor
0938: FaultDescription faultDesc = null;
0939: if (elementQName != null) {
0940: for (int i = 0; i < operationDesc.getFaultDescriptions().length
0941: && faultDesc == null; i++) {
0942: FaultDescription fd = operationDesc
0943: .getFaultDescriptions()[i];
0944: FaultBeanDesc faultBeanDesc = marshalDesc
0945: .getFaultBeanDesc(fd);
0946: QName tryQName = new QName(faultBeanDesc
0947: .getFaultBeanNamespace(), faultBeanDesc
0948: .getFaultBeanLocalName());
0949: if (log.isErrorEnabled()) {
0950: log.debug(" FaultDescription qname is ("
0951: + tryQName
0952: + ") and detail element qname is ("
0953: + elementQName + ")");
0954: }
0955: if (elementQName.equals(tryQName)) {
0956: faultDesc = fd;
0957: }
0958: }
0959: }
0960:
0961: if (faultDesc == null && elementQName != null) {
0962: // If not found, retry the search using just the local name
0963: for (int i = 0; i < operationDesc.getFaultDescriptions().length
0964: && faultDesc == null; i++) {
0965: FaultDescription fd = operationDesc
0966: .getFaultDescriptions()[i];
0967: FaultBeanDesc faultBeanDesc = marshalDesc
0968: .getFaultBeanDesc(fd);
0969: String tryName = faultBeanDesc.getFaultBeanLocalName();
0970: if (elementQName.getLocalPart().equals(tryName)) {
0971: faultDesc = fd;
0972: }
0973: }
0974: }
0975:
0976: if (faultDesc == null) {
0977: // This is a system exception if the method does not throw a checked exception or if
0978: // the detail block is missing or contains multiple items.
0979: exception = createSystemException(xmlfault, message);
0980: } else {
0981: if (log.isErrorEnabled()) {
0982: log
0983: .debug("Ready to demarshal service exception. The detail entry name is "
0984: + elementQName);
0985: }
0986: FaultBeanDesc faultBeanDesc = marshalDesc
0987: .getFaultBeanDesc(faultDesc);
0988: boolean isLegacy = (faultDesc.getFaultInfo() == null || faultDesc
0989: .getFaultInfo().length() == 0);
0990:
0991: // Get the JAXB object from the block
0992: JAXBBlockContext blockContext = new JAXBBlockContext(
0993: marshalDesc.getPackages());
0994:
0995: // Note that faultBean may not be a bean, it could be a primitive
0996: Class faultBeanFormalClass = loadClass(faultBeanDesc
0997: .getFaultBeanClassName());
0998:
0999: // Use "by java type" marshalling if necessary
1000: if (blockContext.getConstructionType() != JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH
1001: && isNotJAXBRootElement(faultBeanFormalClass,
1002: marshalDesc)) {
1003: blockContext.setProcessType(faultBeanFormalClass);
1004: }
1005:
1006: // Get the jaxb block and business object
1007: Block jaxbBlock = factory.createFrom(detailBlocks[0],
1008: blockContext);
1009: Object faultBeanObject = jaxbBlock.getBusinessObject(true);
1010:
1011: // At this point, faultBeanObject is an object that can be rendered as an
1012: // element. We want the object that represents the type.
1013: if (faultBeanObject instanceof JAXBElement) {
1014: faultBeanObject = ((JAXBElement) faultBeanObject)
1015: .getValue();
1016: }
1017:
1018: if (log.isErrorEnabled()) {
1019: log
1020: .debug("Unmarshalled the detail element into a JAXB object");
1021: }
1022:
1023: // Construct the JAX-WS generated exception that holds the faultBeanObject
1024: Class exceptionClass = loadClass(faultDesc
1025: .getExceptionClassName());
1026: if (log.isErrorEnabled()) {
1027: log
1028: .debug("Found FaultDescription. The exception name is "
1029: + exceptionClass.getName());
1030: }
1031: exception = createServiceException(xmlfault.getReason()
1032: .getText(), exceptionClass, faultBeanObject,
1033: faultBeanFormalClass, marshalDesc, isLegacy);
1034: }
1035: return exception;
1036: }
1037:
1038: /**
1039: * @param pds
1040: * @return Number of inout or out parameters
1041: */
1042: static int numOutputBodyParams(ParameterDescription[] pds) {
1043: int count = 0;
1044: for (int i = 0; i < pds.length; i++) {
1045: // TODO Need to change this to also detect not attachment
1046: if (!pds[i].isHeader()) {
1047: if (pds[i].getMode() == Mode.INOUT
1048: || pds[i].getMode() == Mode.OUT) {
1049: count++;
1050: }
1051: }
1052: }
1053: return count;
1054: }
1055:
1056: /**
1057: * @param value
1058: * @return if async handler
1059: */
1060: static boolean isAsyncHandler(Object value) {
1061: return (value instanceof AsyncHandler);
1062: }
1063:
1064: /**
1065: * @param value
1066: * @return true if value is holder
1067: */
1068: static boolean isHolder(Object value) {
1069: return value != null
1070: && Holder.class.isAssignableFrom(value.getClass());
1071: }
1072:
1073: /**
1074: * Crate a Holder
1075: *
1076: * @param <T>
1077: * @param paramType
1078: * @param value
1079: * @return
1080: * @throws IllegalAccessException
1081: * @throws InstantiationException
1082: * @throws ClassNotFoundException
1083: */
1084: static <T> Holder<T> createHolder(Class paramType, T value)
1085: throws IllegalAccessException, InstantiationException,
1086: ClassNotFoundException {
1087: if (Holder.class.isAssignableFrom(paramType)) {
1088: Holder holder = (Holder) paramType.newInstance();
1089: holder.value = value;
1090: return holder;
1091: }
1092: return null;
1093: }
1094:
1095: /**
1096: * Load the class
1097: *
1098: * @param className
1099: * @return loaded class
1100: * @throws ClassNotFoundException
1101: */
1102: static Class loadClass(String className)
1103: throws ClassNotFoundException {
1104: // Don't make this public, its a security exposure
1105: Class cls = ClassUtils.getPrimitiveClass(className);
1106: if (cls == null) {
1107: cls = forName(className, true, getContextClassLoader());
1108: }
1109: return cls;
1110: }
1111:
1112: /**
1113: * Return the class for this name
1114: *
1115: * @return Class
1116: */
1117: private static Class forName(final String className,
1118: final boolean initialize, final ClassLoader classLoader) {
1119: // NOTE: This method must remain private because it uses AccessController
1120: Class cl = null;
1121: try {
1122: cl = (Class) AccessController
1123: .doPrivileged(new PrivilegedExceptionAction() {
1124: public Object run()
1125: throws ClassNotFoundException {
1126: // Class.forName does not support primitives
1127: Class cls = ClassUtils
1128: .getPrimitiveClass(className);
1129: if (cls == null) {
1130: cls = Class.forName(className,
1131: initialize, classLoader);
1132: }
1133: return cls;
1134: }
1135: });
1136: } catch (PrivilegedActionException e) {
1137: if (log.isDebugEnabled()) {
1138: log.debug("Exception thrown from AccessController: "
1139: + e);
1140: }
1141: throw ExceptionFactory.makeWebServiceException(e
1142: .getException());
1143: }
1144:
1145: return cl;
1146: }
1147:
1148: /** @return ClassLoader */
1149: private static ClassLoader getContextClassLoader() {
1150: // NOTE: This method must remain private because it uses AccessController
1151: ClassLoader cl = null;
1152: try {
1153: cl = (ClassLoader) AccessController
1154: .doPrivileged(new PrivilegedExceptionAction() {
1155: public Object run()
1156: throws ClassNotFoundException {
1157: return Thread.currentThread()
1158: .getContextClassLoader();
1159: }
1160: });
1161: } catch (PrivilegedActionException e) {
1162: if (log.isDebugEnabled()) {
1163: log.debug("Exception thrown from AccessController: "
1164: + e);
1165: }
1166: throw ExceptionFactory.makeWebServiceException(e
1167: .getException());
1168: }
1169:
1170: return cl;
1171: }
1172:
1173: /**
1174: * Create a JAX-WS Service Exception (Generated Exception)
1175: *
1176: * @param message
1177: * @param exceptionclass
1178: * @param bean
1179: * @param beanFormalType
1180: * @return
1181: * @throws InvocationTargetException
1182: * @throws IllegalAccessException
1183: * @throws InstantiationException
1184: * @throws NoSuchMethodException
1185: * @parma marshalDesc is used to get cached information about the exception class and bean
1186: */
1187: private static Exception createServiceException(String message,
1188: Class exceptionclass, Object bean, Class beanFormalType,
1189: MarshalServiceRuntimeDescription marshalDesc,
1190: boolean isLegacyException)
1191: throws InvocationTargetException, IllegalAccessException,
1192: InstantiationException, NoSuchMethodException {
1193:
1194: if (log.isDebugEnabled()) {
1195: log
1196: .debug("Constructing JAX-WS Exception:"
1197: + exceptionclass);
1198: }
1199: Exception exception = null;
1200: if (isLegacyException) {
1201: // Legacy Exception
1202: exception = LegacyExceptionUtil.createFaultException(
1203: exceptionclass, bean, marshalDesc);
1204: } else {
1205: // Normal case, use the contstructor to create the exception
1206: Constructor constructor = exceptionclass
1207: .getConstructor(new Class[] { String.class,
1208: beanFormalType });
1209: exception = (Exception) constructor
1210: .newInstance(new Object[] { message, bean });
1211: }
1212:
1213: return exception;
1214:
1215: }
1216:
1217: /**
1218: * Create a system exception
1219: *
1220: * @param message
1221: * @return
1222: */
1223: public static ProtocolException createSystemException(
1224: XMLFault xmlFault, Message message) {
1225: ProtocolException e = null;
1226: Protocol protocol = message.getProtocol();
1227: String text = xmlFault.getReason().getText();
1228:
1229: if (protocol == Protocol.soap11 || protocol == Protocol.soap12) {
1230: // Throw a SOAPFaultException
1231: if (log.isDebugEnabled()) {
1232: log
1233: .debug("Constructing SOAPFaultException for "
1234: + text);
1235: }
1236: String protocolNS = (protocol == Protocol.soap11) ? SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE
1237: : SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE;
1238: try {
1239: // The following set of instructions is used to avoid
1240: // some unimplemented methods in the Axis2 SAAJ implementation
1241: javax.xml.soap.MessageFactory mf = SAAJFactory
1242: .createMessageFactory(protocolNS);
1243: SOAPBody body = mf.createMessage().getSOAPBody();
1244: SOAPFault soapFault = XMLFaultUtils.createSAAJFault(
1245: xmlFault, body);
1246: e = new SOAPFaultException(soapFault);
1247: } catch (Exception ex) {
1248: // Exception occurred during exception processing.
1249: // TODO Probably should do something better here
1250: if (log.isDebugEnabled()) {
1251: log
1252: .debug(
1253: "Exception occurred during fault processing:",
1254: ex);
1255: }
1256: e = ExceptionFactory.makeProtocolException(text, null);
1257: }
1258: } else if (protocol == Protocol.rest) {
1259: if (log.isDebugEnabled()) {
1260: log.debug("Constructing ProtocolException for " + text);
1261: }
1262: // TODO Is there an explicit exception for REST
1263: e = ExceptionFactory.makeProtocolException(text, null);
1264: } else if (protocol == Protocol.unknown) {
1265: // REVIEW What should happen if there is no protocol
1266: if (log.isDebugEnabled()) {
1267: log.debug("Constructing ProtocolException for " + text);
1268: }
1269: e = ExceptionFactory.makeProtocolException(text, null);
1270: }
1271: return e;
1272: }
1273:
1274: /**
1275: * @param ed
1276: * @return
1277: */
1278: static MarshalServiceRuntimeDescription getMarshalDesc(
1279: EndpointDescription ed) {
1280: ServiceDescription sd = ed.getServiceDescription();
1281: return MarshalServiceRuntimeDescriptionFactory.get(sd);
1282: }
1283:
1284: /**
1285: * This probably should be available from the ParameterDescription
1286: *
1287: * @param cls
1288: * @param marshalDesc
1289: * @return true if primitive, wrapper, java.lang.String. Calendar (or GregorianCalendar),
1290: * BigInteger etc or anything other java type that is mapped by the basic schema types
1291: */
1292: static boolean isNotJAXBRootElement(Class cls,
1293: MarshalServiceRuntimeDescription marshalDesc) {
1294: if (cls == String.class || cls.isPrimitive()
1295: || cls == Calendar.class || cls == byte[].class
1296: || cls == GregorianCalendar.class || cls == Date.class
1297: || cls == BigInteger.class || cls == BigDecimal.class) {
1298:
1299: return true;
1300: }
1301: AnnotationDesc aDesc = marshalDesc.getAnnotationDesc(cls);
1302: if (aDesc != null) {
1303: // XmlRootElementName returns null if @XmlRootElement is not specified
1304: return (aDesc.getXmlRootElementName() == null);
1305: }
1306: return true;
1307: }
1308:
1309: /**
1310: * Get a string containing the stack of the specified exception
1311: * @param e
1312: * @return
1313: */
1314: public static String stackToString(Throwable e) {
1315: java.io.StringWriter sw = new java.io.StringWriter();
1316: java.io.BufferedWriter bw = new java.io.BufferedWriter(sw);
1317: java.io.PrintWriter pw = new java.io.PrintWriter(bw);
1318: e.printStackTrace(pw);
1319: pw.close();
1320: return sw.getBuffer().toString();
1321: }
1322:
1323: static boolean isSWAAttachment(ParameterDescription pd) {
1324: return pd.getAttachmentDescription() != null
1325: && pd.getAttachmentDescription().getAttachmentType() == AttachmentType.SWA;
1326: }
1327: }
|