blob: 8f8586f84d2010c6740937b7fc4c08f0631d9cc2 [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.axiom.om.impl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import javax.activation.DataHandler;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.axiom.attachments.impl.BufferUtils;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.util.StAXUtils;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* MTOMXMLStreamWriter is an XML + Attachments stream writer.
*
* For the moment this assumes that transport takes the decision of whether to optimize or not by
* looking at whether the MTOM optimize is enabled & also looking at the OM tree whether it has any
* optimizable content.
*/
public class MTOMXMLStreamWriter implements XMLStreamWriter {
private static Log log = LogFactory.getLog(MTOMXMLStreamWriter.class);
private final static int UNSUPPORTED = -1;
private final static int EXCEED_LIMIT = 1;
private XMLStreamWriter xmlWriter;
private OutputStream outStream;
private LinkedList binaryNodeList = new LinkedList();
private ByteArrayOutputStream bufferedXML; // XML for the SOAPPart
private OMOutputFormat format = new OMOutputFormat();
// State variables
private boolean isEndDocument = false; // has endElement been called
private boolean isComplete = false; // have the attachments been written
private int depth = 0; // current eleement depth
public MTOMXMLStreamWriter(XMLStreamWriter xmlWriter) {
this.xmlWriter = xmlWriter;
}
/**
* Creates a new MTOMXMLStreamWriter with specified encoding.
*
* @param outStream
* @param format
* @throws XMLStreamException
* @throws FactoryConfigurationError
* @see OMOutputFormat#DEFAULT_CHAR_SET_ENCODING
*/
public MTOMXMLStreamWriter(OutputStream outStream, OMOutputFormat format)
throws XMLStreamException, FactoryConfigurationError {
this.format = format;
this.outStream = outStream;
if (format.getCharSetEncoding() == null) //Default encoding is UTF-8
format.setCharSetEncoding(OMOutputFormat.DEFAULT_CHAR_SET_ENCODING);
if (format.isOptimized()) {
// REVIEW If the buffered XML gets too big, should it be written out to a file
bufferedXML = new ByteArrayOutputStream();
xmlWriter = StAXUtils.createXMLStreamWriter(bufferedXML,format.getCharSetEncoding());
} else {
xmlWriter = StAXUtils.createXMLStreamWriter(outStream,
format.getCharSetEncoding());
}
}
public void writeStartElement(String string) throws XMLStreamException {
xmlWriter.writeStartElement(string);
depth++;
}
public void writeStartElement(String string, String string1) throws XMLStreamException {
xmlWriter.writeStartElement(string, string1);
depth++;
}
public void writeStartElement(String string, String string1, String string2)
throws XMLStreamException {
xmlWriter.writeStartElement(string, string1, string2);
depth++;
}
public void writeEmptyElement(String string, String string1) throws XMLStreamException {
xmlWriter.writeStartElement(string, string1);
}
public void writeEmptyElement(String string, String string1, String string2)
throws XMLStreamException {
xmlWriter.writeStartElement(string, string1, string2);
}
public void writeEmptyElement(String string) throws XMLStreamException {
xmlWriter.writeStartElement(string);
}
public void writeEndElement() throws XMLStreamException {
xmlWriter.writeEndElement();
depth--;
}
public void writeEndDocument() throws XMLStreamException {
xmlWriter.writeEndDocument();
isEndDocument = true;
}
public void close() throws XMLStreamException {
xmlWriter.close();
}
/**
* Flush is overridden to trigger the attachment serialization
*/
public void flush() throws XMLStreamException {
xmlWriter.flush();
String SOAPContentType;
// flush() triggers the optimized attachment writing.
// If the optimized attachments are specified, and the xml
// document is completed, then write out the attachments.
if (format.isOptimized() && !isComplete & (isEndDocument || depth == 0)) {
isComplete = true;
if (format.isSOAP11()) {
SOAPContentType = SOAP11Constants.SOAP_11_CONTENT_TYPE;
} else {
SOAPContentType = SOAP12Constants.SOAP_12_CONTENT_TYPE;
}
try {
MIMEOutputUtils.complete(outStream,
bufferedXML.toByteArray(),
binaryNodeList,
format.getMimeBoundary(),
format.getRootContentId(),
format.getCharSetEncoding(),
SOAPContentType);
bufferedXML.close();
bufferedXML = null;
} catch (UnsupportedEncodingException e) {
throw new OMException(e);
} catch (IOException e) {
throw new OMException(e);
}
}
}
public void writeAttribute(String string, String string1) throws XMLStreamException {
xmlWriter.writeAttribute(string, string1);
}
public void writeAttribute(String string, String string1, String string2, String string3)
throws XMLStreamException {
xmlWriter.writeAttribute(string, string1, string2, string3);
}
public void writeAttribute(String string, String string1, String string2)
throws XMLStreamException {
xmlWriter.writeAttribute(string, string1, string2);
}
public void writeNamespace(String string, String string1) throws XMLStreamException {
xmlWriter.writeNamespace(string, string1);
}
public void writeDefaultNamespace(String string) throws XMLStreamException {
xmlWriter.writeDefaultNamespace(string);
}
public void writeComment(String string) throws XMLStreamException {
xmlWriter.writeComment(string);
}
public void writeProcessingInstruction(String string) throws XMLStreamException {
xmlWriter.writeProcessingInstruction(string);
}
public void writeProcessingInstruction(String string, String string1)
throws XMLStreamException {
xmlWriter.writeProcessingInstruction(string, string1);
}
public void writeCData(String string) throws XMLStreamException {
xmlWriter.writeCData(string);
}
public void writeDTD(String string) throws XMLStreamException {
xmlWriter.writeDTD(string);
}
public void writeEntityRef(String string) throws XMLStreamException {
xmlWriter.writeEntityRef(string);
}
public void writeStartDocument() throws XMLStreamException {
xmlWriter.writeStartDocument();
}
public void writeStartDocument(String string) throws XMLStreamException {
xmlWriter.writeStartDocument(string);
}
public void writeStartDocument(String string, String string1) throws XMLStreamException {
xmlWriter.writeStartDocument(string, string1);
}
public void writeCharacters(String string) throws XMLStreamException {
xmlWriter.writeCharacters(string);
}
public void writeCharacters(char[] chars, int i, int i1) throws XMLStreamException {
xmlWriter.writeCharacters(chars, i, i1);
}
public String getPrefix(String string) throws XMLStreamException {
return xmlWriter.getPrefix(string);
}
public void setPrefix(String string, String string1) throws XMLStreamException {
xmlWriter.setPrefix(string, string1);
}
public void setDefaultNamespace(String string) throws XMLStreamException {
xmlWriter.setDefaultNamespace(string);
}
public void setNamespaceContext(NamespaceContext namespaceContext) throws XMLStreamException {
xmlWriter.setNamespaceContext(namespaceContext);
}
public NamespaceContext getNamespaceContext() {
return xmlWriter.getNamespaceContext();
}
public Object getProperty(String string) throws IllegalArgumentException {
return xmlWriter.getProperty(string);
}
public boolean isOptimized() {
return format.isOptimized();
}
public String getContentType() {
return format.getContentType();
}
public void writeOptimized(OMText node) {
if(log.isDebugEnabled()){
log.debug("Start MTOMXMLStreamWriter.writeOptimized()");
}
binaryNodeList.add(node);
if(log.isDebugEnabled()){
log.debug("Exit MTOMXMLStreamWriter.writeOptimized()");
}
}
/*
* This method check if size of dataHandler exceeds the optimization Threshold
* set on OMOutputFormat.
* return true is size exceeds the threshold limit.
* return false otherwise.
*/
public boolean isOptimizedThreshold(OMText node){
if(log.isDebugEnabled()){
log.debug("Start MTOMXMLStreamWriter.isOptimizedThreshold()");
}
DataHandler dh = (DataHandler)node.getDataHandler();
int optimized = UNSUPPORTED;
if(dh!=null){
if(log.isDebugEnabled()){
log.debug("DataHandler fetched, starting optimized Threshold processing");
}
optimized= BufferUtils.doesDataHandlerExceedLimit(dh, format.getOptimizedThreshold());
}
if(optimized == UNSUPPORTED || optimized == EXCEED_LIMIT){
if(log.isDebugEnabled()){
log.debug("node should be added to binart NodeList for optimization");
}
return true;
}
return false;
}
public void setXmlStreamWriter(XMLStreamWriter xmlWriter) {
this.xmlWriter = xmlWriter;
}
public XMLStreamWriter getXmlStreamWriter() {
return xmlWriter;
}
public String getMimeBoundary() {
return format.getMimeBoundary();
}
public String getRootContentId() {
return format.getRootContentId();
}
public String getNextContentId() {
return format.getNextContentId();
}
/**
* Returns the character set encoding scheme. If the value of the charSetEncoding is not set
* then the default will be returned.
*
* @return Returns encoding.
*/
public String getCharSetEncoding() {
return format.getCharSetEncoding();
}
public void setCharSetEncoding(String charSetEncoding) {
format.setCharSetEncoding(charSetEncoding);
}
public String getXmlVersion() {
return format.getXmlVersion();
}
public void setXmlVersion(String xmlVersion) {
format.setXmlVersion(xmlVersion);
}
public void setSoap11(boolean b) {
format.setSOAP11(b);
}
public boolean isIgnoreXMLDeclaration() {
return format.isIgnoreXMLDeclaration();
}
public void setIgnoreXMLDeclaration(boolean ignoreXMLDeclaration) {
format.setIgnoreXMLDeclaration(ignoreXMLDeclaration);
}
public void setDoOptimize(boolean b) {
format.setDoOptimize(b);
}
public void setOutputFormat(OMOutputFormat format) {
this.format = format;
}
/**
* If this XMLStreamWriter is connected to an OutputStream
* then the OutputStream is returned. This allows a node
* (perhaps an OMSourcedElement) to write its content
* directly to the OutputStream.
* @return OutputStream or null
*/
public OutputStream getOutputStream() throws XMLStreamException {
OutputStream os = null;
if (bufferedXML != null) {
os = bufferedXML;
} else {
os = outStream;
}
if (os != null) {
// Flush the state of the writer..Many times the
// write defers the writing of tag characters (>)
// until the next write. Flush out this character
this.writeCharacters("");
this.flush();
}
return os;
}
/**
* Writes the relevant output.
*
* @param writer
* @throws XMLStreamException
*/
private void writeOutput(OMText textNode) throws XMLStreamException {
int type = textNode.getType();
if (type == OMNode.TEXT_NODE || type == OMNode.SPACE_NODE) {
writeCharacters(textNode.getText());
} else if (type == OMNode.CDATA_SECTION_NODE) {
writeCData(textNode.getText());
} else if (type == OMNode.ENTITY_REFERENCE_NODE) {
writeEntityRef(textNode.getText());
}
}
}