blob: 8e475430808209e4a44e684d491da859d617f83b [file] [log] [blame]
/*
* 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()");
}
}
}