001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.message.util;
020:
021: import org.apache.axiom.attachments.Attachments;
022: import org.apache.axiom.om.OMAbstractFactory;
023: import org.apache.axiom.om.OMDocument;
024: import org.apache.axiom.om.OMElement;
025: import org.apache.axiom.om.OMFactory;
026: import org.apache.axiom.om.OMText;
027: import org.apache.axiom.om.OMXMLParserWrapper;
028: import org.apache.axiom.om.impl.MTOMConstants;
029: import org.apache.axiom.om.impl.builder.StAXBuilder;
030: import org.apache.axiom.soap.SOAP11Constants;
031: import org.apache.axiom.soap.SOAPBody;
032: import org.apache.axiom.soap.SOAPEnvelope;
033: import org.apache.axiom.soap.SOAPFactory;
034: import org.apache.axis2.AxisFault;
035: import org.apache.axis2.Constants;
036: import org.apache.axis2.Constants.Configuration;
037: import org.apache.axis2.context.MessageContext;
038: import org.apache.axis2.jaxws.ExceptionFactory;
039: import org.apache.axis2.jaxws.handler.AttachmentsAdapter;
040: import org.apache.axis2.jaxws.handler.TransportHeadersAdapter;
041: import org.apache.axis2.jaxws.message.Message;
042: import org.apache.axis2.jaxws.message.Protocol;
043: import org.apache.axis2.jaxws.message.attachments.AttachmentUtils;
044: import org.apache.axis2.jaxws.message.factory.MessageFactory;
045: import org.apache.axis2.jaxws.registry.FactoryRegistry;
046: import org.apache.axis2.jaxws.utility.JavaUtils;
047: import org.apache.axis2.transport.http.HTTPConstants;
048: import org.apache.commons.logging.Log;
049: import org.apache.commons.logging.LogFactory;
050:
051: import javax.activation.DataHandler;
052: import javax.xml.namespace.QName;
053: import javax.xml.soap.AttachmentPart;
054: import javax.xml.soap.MimeHeader;
055: import javax.xml.soap.MimeHeaders;
056: import javax.xml.soap.SOAPMessage;
057: import javax.xml.ws.WebServiceException;
058:
059: import java.util.ArrayList;
060: import java.util.HashMap;
061: import java.util.Iterator;
062: import java.util.Map;
063:
064: /** Miscellaneous Utilities that may be useful inside and outside the Message subcomponent. */
065: public class MessageUtils {
066:
067: private static final Log log = LogFactory
068: .getLog(MessageUtils.class);
069:
070: /**
071: * Get an axiom SOAPFactory for the specified element
072: *
073: * @param e OMElement
074: * @return SOAPFactory
075: */
076: public static SOAPFactory getSOAPFactory(OMElement e) {
077: // Getting a factory from a SOAPEnvelope is not straight-forward.
078: // Please change this code if an easier mechanism is discovered.
079:
080: OMXMLParserWrapper builder = e.getBuilder();
081: if (builder instanceof StAXBuilder) {
082: StAXBuilder staxBuilder = (StAXBuilder) builder;
083: OMDocument document = staxBuilder.getDocument();
084: if (document != null) {
085: OMFactory factory = document.getOMFactory();
086: if (factory instanceof SOAPFactory) {
087: return (SOAPFactory) factory;
088: }
089: }
090: }
091: // Flow to here indicates that the envelope does not have
092: // an accessible factory. Create a new factory based on the
093: // protocol.
094:
095: while (e != null && !(e instanceof SOAPEnvelope)) {
096: e = (OMElement) e.getParent();
097: }
098: if (e instanceof SOAPEnvelope) {
099: if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(e
100: .getNamespace().getNamespaceURI())) {
101: return OMAbstractFactory.getSOAP11Factory();
102: } else {
103: return OMAbstractFactory.getSOAP12Factory();
104: }
105: }
106: return null;
107: }
108:
109: /**
110: * Create an SAAJ AttachmentPart from a JAXWS Attachment
111: * @param cid String content id
112: * @param dh DataHandler
113: * @param message SOAPMessage
114: * @return AttachmentPart
115: */
116: public static AttachmentPart createAttachmentPart(String cid,
117: DataHandler dh, SOAPMessage message) {
118: // Create the Attachment Part
119: AttachmentPart ap = message.createAttachmentPart(dh);
120:
121: // REVIEW
122: // Do we need to copy the content type from the datahandler ?
123:
124: // Preserve the original content id
125: ap.setContentId(cid);
126: return ap;
127: }
128:
129: /**
130: * Create a JAX-WS Message from the information on an Axis 2 Message Context
131: *
132: * @param msgContext
133: * @return Message
134: */
135: public static Message getMessageFromMessageContext(
136: MessageContext msgContext) throws WebServiceException {
137: if (log.isDebugEnabled()) {
138: log.debug("Start getMessageFromMessageContext");
139: }
140:
141: Message message = null;
142: // If the Axis2 MessageContext that was passed in has a SOAPEnvelope
143: // set on it, grab that and create a JAX-WS Message out of it.
144: SOAPEnvelope soapEnv = msgContext.getEnvelope();
145: if (soapEnv != null) {
146: MessageFactory msgFactory = (MessageFactory) FactoryRegistry
147: .getFactory(MessageFactory.class);
148: try {
149: Protocol protocol = msgContext.isDoingREST() ? Protocol.rest
150: : null;
151: message = msgFactory.createFrom(soapEnv, protocol);
152: } catch (Exception e) {
153: throw ExceptionFactory
154: .makeWebServiceException("Could not create new Message");
155: }
156:
157: Object property = msgContext
158: .getProperty(Constants.Configuration.ENABLE_MTOM);
159: if (property != null
160: && JavaUtils.isTrueExplicitly(property)) {
161: message.setMTOMEnabled(true);
162: }
163:
164: // Add all the MimeHeaders from the Axis2 MessageContext
165: Map headerMap = (Map) msgContext
166: .getProperty(MessageContext.TRANSPORT_HEADERS);
167: if (headerMap != null) {
168: message.setMimeHeaders(headerMap);
169: }
170:
171: // TODO: This is a WORKAROUND for missing SOAPFault data. If we do a toString on the
172: // SOAPEnvelope, then all the data will be available to the provider. Otherwise, it
173: // will be missing the <Reason> element corresponding to the <faultstring> element.
174: // The SOAPFaultProviderTests will check for this failure.
175: SOAPBody soapBody = soapEnv.getBody();
176: if (soapBody.hasFault()) {
177: soapEnv.toString();
178: }
179:
180: if (false) {
181: makeXOPIncludeNodes(msgContext, message);
182: }
183: }
184: return message;
185: }
186:
187: /**
188: * Put the JAX-WS Message onto the Axis2 MessageContext
189: *
190: * @param message JAX-WS Message
191: * @param msgContext Axis2MessageContext
192: */
193: public static void putMessageOnMessageContext(Message message,
194: MessageContext msgContext) throws AxisFault,
195: WebServiceException {
196: // Put the XML message on the Axis 2 Message Context
197: SOAPEnvelope envelope = (SOAPEnvelope) message.getAsOMElement();
198: msgContext.setEnvelope(envelope);
199:
200: // Put the Headers onto the MessageContext
201: Map headerMap = message.getMimeHeaders();
202: msgContext.setProperty(MessageContext.TRANSPORT_HEADERS,
203: headerMap);
204:
205: if (message.getProtocol() == Protocol.rest) {
206: msgContext.setDoingREST(true);
207: msgContext.setProperty(
208: Constants.Configuration.CONTENT_TYPE,
209: HTTPConstants.MEDIA_TYPE_APPLICATION_XML);
210: }
211:
212: // Make sure the the JAX-WS AttachmentAdapter is correctly installed
213: // So that any user attachments provide are moved to the Axiom Attachments
214: // Map
215: if (message.getMessageContext() != null) {
216: AttachmentsAdapter.install(message.getMessageContext());
217: TransportHeadersAdapter
218: .install(message.getMessageContext());
219: }
220:
221: if (message.isDoingSWA()) {
222: // Enable SWA on the Axis2 MessageContext
223: msgContext.setDoingSwA(true);
224: msgContext.setProperty(Configuration.ENABLE_SWA, "true");
225: }
226:
227: // Enable MTOM Attachments
228: if (message.isMTOMEnabled()) {
229: // Enable MTOM on the Axis2 MessageContext
230: msgContext.setProperty(Configuration.ENABLE_MTOM, "true");
231: if (false) {
232: makeBinaryNodes(message);
233: }
234: }
235: }
236:
237: /**
238: * Used to expand the tree and create binary nodes
239: * @param msg
240: * @deprecated
241: */
242: private static void makeBinaryNodes(Message msg) {
243: if (log.isDebugEnabled()) {
244: log
245: .debug("MTOM is enabled on the JAX-WS Message...look for XOP Includes");
246: }
247: // If we have MTOM attachments, we need to replace the <xop:include>
248: // elements with OMText binary nodes.
249:
250: // First find all of the <xop:include> elements
251: SOAPEnvelope envelope = (SOAPEnvelope) msg.getAsOMElement();
252: ArrayList<OMElement> xops = AttachmentUtils
253: .findXopElements(envelope);
254:
255: if (xops != null && xops.size() > 0) {
256: if (log.isDebugEnabled()) {
257: log.debug("Found XOP:Include Elements");
258: }
259:
260: QName href = new QName("", "href");
261: Iterator<OMElement> itr = xops.iterator();
262:
263: while (itr.hasNext()) {
264: OMElement xop = itr.next();
265: String cid = xop.getAttributeValue(href);
266:
267: // Find and remove the Attachment from the JAX-WS Message
268: // (It is removed so that it is not considered a SWA Attachment ...see below)
269: DataHandler dh = msg.removeDataHandler(cid);
270: if (log.isDebugEnabled()) {
271: log.debug("Create Binary OMNode for attachment:"
272: + cid);
273: }
274:
275: // Convert the <xop:include> OMElement into an OMText
276: // binary node and replace it in the tree.
277: OMText binaryNode = AttachmentUtils.makeBinaryOMNode(
278: xop, dh);
279: xop.insertSiblingAfter(binaryNode);
280: xop.detach();
281: }
282: }
283: }
284:
285: /**
286: * Expand the tree and create XOP nodes
287: * @param msg
288: * @deprecated
289: */
290: private static void makeXOPIncludeNodes(MessageContext msgContext,
291: Message message) {
292: // This destroys performance by forcing a double pass through the message.
293: //If attachments are found on the MessageContext, then that means
294: //the inbound message has more than just the normal XML payload
295: Attachments as = (Attachments) msgContext
296: .getProperty(MTOMConstants.ATTACHMENTS);
297: if (as != null) {
298: if (log.isDebugEnabled()) {
299: log.debug("Found Axis MTOM Attachments");
300: }
301:
302: //Walk the tree and find all of the optimized binary nodes.
303: ArrayList<OMText> binaryNodes = AttachmentUtils
304: .findBinaryNodes((SOAPEnvelope) message
305: .getAsOMElement());
306: if (binaryNodes != null && binaryNodes.size() > 0) {
307:
308: if (log.isDebugEnabled()) {
309: log.debug("Found " + binaryNodes.size()
310: + "MTOM Binary Nodes");
311: }
312:
313: //Replace each of the nodes with it's corresponding <xop:include>
314: //element, so JAXB can process it correctly.
315: Iterator<OMText> itr = binaryNodes.iterator();
316: while (itr.hasNext()) {
317: OMText node = itr.next();
318: OMElement xop = AttachmentUtils
319: .makeXopElement(node);
320: node.getParent().addChild(xop);
321: node.detach();
322:
323: //We have to add the individual attachments in their raw
324: //binary form, so we can access them later.
325: if (log.isDebugEnabled()) {
326: log.debug("Create MTOM Message Attachment for "
327: + node.getContentID());
328: }
329: message.addDataHandler((DataHandler) node
330: .getDataHandler(), node.getContentID());
331: }
332: }
333: }
334: }
335: }
|