| /* |
| * 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.transport.http; |
| |
| import org.apache.axiom.attachments.Attachments; |
| import org.apache.axiom.om.OMContainer; |
| import org.apache.axiom.om.OMElement; |
| import org.apache.axiom.om.OMOutputFormat; |
| import org.apache.axiom.om.impl.OMMultipartWriter; |
| import org.apache.axiom.soap.SOAPEnvelope; |
| import org.apache.axiom.soap.SOAPFactory; |
| import org.apache.axiom.soap.SOAPMessage; |
| import org.apache.axiom.util.UIDGenerator; |
| import org.apache.axis2.AxisFault; |
| import org.apache.axis2.Constants; |
| import org.apache.axis2.context.MessageContext; |
| import org.apache.axis2.transport.MessageFormatter; |
| import org.apache.axis2.transport.http.util.URLTemplatingUtil; |
| import org.apache.axis2.util.JavaUtils; |
| import org.apache.axis2.util.Utils; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.xml.stream.XMLStreamException; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.net.URL; |
| |
| public class SOAPMessageFormatter implements MessageFormatter { |
| |
| private static final Log log = LogFactory.getLog(SOAPMessageFormatter.class); |
| |
| public void writeTo(MessageContext msgCtxt, OMOutputFormat format, |
| OutputStream out, boolean preserve) throws AxisFault { |
| if (log.isDebugEnabled()) { |
| log.debug("start writeTo()"); |
| log.debug(" preserve=" + preserve); |
| log.debug(" isOptimized=" + format.isOptimized()); |
| log.debug(" isDoingSWA=" + format.isDoingSWA()); |
| } |
| |
| if (msgCtxt.isDoingMTOM()) { |
| int optimizedThreshold = Utils.getMtomThreshold(msgCtxt); |
| if(optimizedThreshold > 0){ |
| if(log.isDebugEnabled()){ |
| log.debug("Setting MTOM optimized Threshold Value on OMOutputFormat"); |
| } |
| format.setOptimizedThreshold(optimizedThreshold); |
| } |
| } |
| try { |
| if (!(format.isOptimized()) && format.isDoingSWA()) { |
| writeSwAMessage(msgCtxt, out, format, preserve); |
| } else { |
| SOAPEnvelope envelope = msgCtxt.getEnvelope(); |
| // Always use a SOAPMessage for serialization so that we produce an XML declaration. |
| // Note that an XML declaration shouldn't be necessary except for weird cases such as |
| // the UDP transport. This is for compatibility with Axis2 1.7.0 and Axiom 1.2.x; |
| // Axiom 1.3.x no longer produces an XML declaration when serializing a SOAPEnvelope. |
| SOAPMessage message; |
| OMContainer parent = envelope.getParent(); |
| if (parent instanceof SOAPMessage) { |
| message = (SOAPMessage)parent; |
| } else { |
| message = ((SOAPFactory)envelope.getOMFactory()).createSOAPMessage(); |
| message.setSOAPEnvelope(envelope); |
| } |
| message.serialize(out, format, preserve); |
| } |
| } catch (IOException e) { |
| throw AxisFault.makeFault(e); |
| } finally { |
| if (log.isDebugEnabled()) { |
| log.debug("end writeTo()"); |
| } |
| } |
| } |
| |
| public String getContentType(MessageContext msgCtxt, OMOutputFormat format, |
| String soapActionString) { |
| String encoding = format.getCharSetEncoding(); |
| String contentType = format.getContentType(); |
| if (log.isDebugEnabled()) { |
| log.debug("contentType from the OMOutputFormat =" + contentType); |
| } |
| if (encoding != null && contentType != null && |
| contentType.indexOf(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED)==-1) { |
| contentType += "; charset=" + encoding; |
| } |
| |
| // action header is not mandated in SOAP 1.2. So putting it, if |
| // available |
| if (!msgCtxt.isSOAP11() && (soapActionString != null) |
| && !"".equals(soapActionString.trim()) |
| && !"\"\"".equals(soapActionString.trim())) { |
| contentType = contentType + "; action=\"" + soapActionString+ "\""; |
| } |
| |
| // This is a quick safety catch. Prior versions of SOAPFormatter |
| // placed a ';' at the end of the content-type. Many vendors ignore this |
| // last ';'. However it is not legal and some vendors report an error. |
| // To increase interoperability, the ';' is stripped off. |
| contentType = contentType.trim(); |
| if (contentType.lastIndexOf(";") == (contentType.length()-1)) { |
| contentType = contentType.substring(0, contentType.length()-1); |
| } |
| |
| if (log.isDebugEnabled()) { |
| log.debug("contentType returned =" + contentType); |
| } |
| return contentType; |
| } |
| |
| public String formatSOAPAction(MessageContext msgCtxt, OMOutputFormat format, |
| String soapActionString) { |
| // if SOAP 1.2 we attach the soap action to the content-type |
| // No need to set it as a header. |
| if (msgCtxt.isSOAP11()) { |
| if ("".equals(soapActionString)) { |
| return "\"\""; |
| } else { |
| if (soapActionString != null |
| && !soapActionString.startsWith("\"")) { |
| // SOAPAction string must be a quoted string |
| soapActionString = "\"" + soapActionString + "\""; |
| } |
| return soapActionString; |
| } |
| } |
| return null; |
| } |
| |
| public URL getTargetAddress(MessageContext msgCtxt, OMOutputFormat format, |
| URL targetURL) throws AxisFault { |
| |
| // Check whether there is a template in the URL, if so we have to replace then with data |
| // values and create a new target URL. |
| targetURL = URLTemplatingUtil.getTemplatedURL(targetURL, msgCtxt, false); |
| return targetURL; |
| } |
| |
| private void writeSwAMessage(MessageContext msgCtxt, OutputStream outputStream, |
| OMOutputFormat format, boolean preserve) throws AxisFault { |
| if (log.isDebugEnabled()) { |
| log.debug("start writeSwAMessage()"); |
| } |
| Object property = msgCtxt |
| .getProperty(Constants.Configuration.MM7_COMPATIBLE); |
| boolean MM7CompatMode = false; |
| if (property != null) { |
| MM7CompatMode = JavaUtils.isTrueExplicitly(property); |
| } |
| |
| try { |
| OMMultipartWriter mpw = new OMMultipartWriter(outputStream, format); |
| |
| OutputStream rootPartOutputStream = mpw.writeRootPart(); |
| OMElement element = msgCtxt.getEnvelope(); |
| if (preserve) { |
| element.serialize(rootPartOutputStream, format); |
| } else { |
| element.serializeAndConsume(rootPartOutputStream, format); |
| } |
| rootPartOutputStream.close(); |
| |
| OMMultipartWriter attachmentsWriter; |
| OutputStream innerOutputStream; |
| if (!MM7CompatMode) { |
| attachmentsWriter = mpw; |
| innerOutputStream = null; |
| } else { |
| String innerBoundary; |
| String partCID; |
| Object innerBoundaryProperty = msgCtxt |
| .getProperty(Constants.Configuration.MM7_INNER_BOUNDARY); |
| if (innerBoundaryProperty != null) { |
| innerBoundary = (String) innerBoundaryProperty; |
| } else { |
| innerBoundary = "innerBoundary" |
| + UIDGenerator.generateMimeBoundary(); |
| } |
| Object partCIDProperty = msgCtxt |
| .getProperty(Constants.Configuration.MM7_PART_CID); |
| if (partCIDProperty != null) { |
| partCID = (String) partCIDProperty; |
| } else { |
| partCID = "innerCID" |
| + UIDGenerator.generateContentId(); |
| } |
| OMOutputFormat innerFormat = new OMOutputFormat(format); |
| innerFormat.setMimeBoundary(innerBoundary); |
| innerOutputStream = mpw.writePart("multipart/related; boundary=\"" + innerBoundary + "\"", partCID); |
| attachmentsWriter = new OMMultipartWriter(innerOutputStream, innerFormat); |
| } |
| |
| Attachments attachments = msgCtxt.getAttachmentMap(); |
| for (String contentID : attachments.getAllContentIDs()) { |
| attachmentsWriter.writePart(attachments.getDataHandler(contentID), contentID); |
| } |
| |
| if (MM7CompatMode) { |
| attachmentsWriter.complete(); |
| innerOutputStream.close(); |
| } |
| |
| mpw.complete(); |
| } catch (IOException ex) { |
| throw AxisFault.makeFault(ex); |
| } catch (XMLStreamException ex) { |
| throw AxisFault.makeFault(ex); |
| } |
| |
| if (log.isDebugEnabled()) { |
| log.debug("end writeSwAMessage()"); |
| } |
| } |
| |
| } |