blob: 866e02e9e716d89a15d250dfb4e2e041bfcfe5cf [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.xml.security.stax.impl.transformer;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.stax.ext.Transformer;
import org.apache.xml.security.stax.ext.XMLSecurityConstants;
import org.apache.xml.security.stax.ext.XMLSecurityUtils;
import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
import org.apache.xml.security.stax.impl.processor.input.XMLEventReaderInputProcessor;
import org.apache.xml.security.utils.UnsyncByteArrayInputStream;
import org.apache.xml.security.utils.UnsyncByteArrayOutputStream;
import javax.xml.stream.*;
import java.io.*;
import java.util.Map;
/**
*/
public class TransformIdentity implements Transformer {
private static XMLOutputFactory xmlOutputFactory;
private static XMLInputFactory xmlInputFactory;
private OutputStream outputStream;
private XMLEventWriter xmlEventWriterForOutputStream;
private Transformer transformer;
private ChildOutputMethod childOutputMethod;
protected static XMLOutputFactory getXmlOutputFactory() {
synchronized(TransformIdentity.class) {
if (xmlOutputFactory == null) {
xmlOutputFactory = XMLOutputFactory.newInstance();
}
}
return xmlOutputFactory;
}
public static XMLInputFactory getXmlInputFactory() {
synchronized(TransformIdentity.class) {
if (xmlInputFactory == null) {
xmlInputFactory = XMLInputFactory.newInstance();
}
}
return xmlInputFactory;
}
@Override
public void setOutputStream(OutputStream outputStream) throws XMLSecurityException {
this.outputStream = outputStream;
}
protected OutputStream getOutputStream() {
return this.outputStream;
}
protected XMLEventWriter getXmlEventWriterForOutputStream() throws XMLStreamException {
if (this.xmlEventWriterForOutputStream != null) {
return this.xmlEventWriterForOutputStream;
}
if (this.outputStream != null) {
return this.xmlEventWriterForOutputStream = getXmlOutputFactory().createXMLEventWriter(new FilterOutputStream(outputStream) {
@Override
public void close() throws IOException {
//do not close the parent output stream!
super.flush();
}
});
}
return null;
}
@Override
public void setTransformer(Transformer transformer) throws XMLSecurityException {
this.transformer = transformer;
}
protected Transformer getTransformer() {
return transformer;
}
@Override
public void setProperties(Map<String, Object> properties) throws XMLSecurityException {
throw new UnsupportedOperationException("no properties supported");
}
@Override
public XMLSecurityConstants.TransformMethod getPreferredTransformMethod(XMLSecurityConstants.TransformMethod forInput) {
switch (forInput) {
case XMLSecEvent:
return XMLSecurityConstants.TransformMethod.XMLSecEvent;
case InputStream:
return XMLSecurityConstants.TransformMethod.InputStream;
default:
throw new IllegalArgumentException("Unsupported class " + forInput.name());
}
}
@Override
public void transform(XMLSecEvent xmlSecEvent) throws XMLStreamException {
if (getXmlEventWriterForOutputStream() != null) {
//we have an output stream
getXmlEventWriterForOutputStream().add(xmlSecEvent);
} else {
//we have a child transformer
if (childOutputMethod == null) {
final XMLSecurityConstants.TransformMethod preferredChildTransformMethod =
getTransformer().getPreferredTransformMethod(XMLSecurityConstants.TransformMethod.XMLSecEvent);
switch (preferredChildTransformMethod) {
case XMLSecEvent: {
childOutputMethod = new ChildOutputMethod() {
@Override
public void transform(Object object) throws XMLStreamException {
getTransformer().transform((XMLSecEvent) object);
}
@Override
public void doFinal() throws XMLStreamException {
getTransformer().doFinal();
}
};
break;
}
case InputStream: {
childOutputMethod = new ChildOutputMethod() {
private UnsyncByteArrayOutputStream baos;
private XMLEventWriter xmlEventWriter;
@Override
public void transform(Object object) throws XMLStreamException {
if (xmlEventWriter == null) {
baos = new UnsyncByteArrayOutputStream();
xmlEventWriter = getXmlOutputFactory().createXMLEventWriter(baos);
}
xmlEventWriter.add((XMLSecEvent) object);
}
@Override
public void doFinal() throws XMLStreamException {
xmlEventWriter.close();
try (InputStream is = new UnsyncByteArrayInputStream(baos.toByteArray())) {
getTransformer().transform(is);
getTransformer().doFinal();
} catch (IOException ex) {
throw new XMLStreamException(ex);
}
}
};
break;
}
}
}
if (childOutputMethod != null) {
childOutputMethod.transform(xmlSecEvent);
}
}
}
@Override
public void transform(final InputStream inputStream) throws XMLStreamException {
if (getOutputStream() != null) {
//we have an output stream
try {
XMLSecurityUtils.copy(inputStream, getOutputStream());
} catch (IOException e) {
throw new XMLStreamException(e);
}
} else {
//we have a child transformer
if (childOutputMethod == null) {
final XMLSecurityConstants.TransformMethod preferredChildTransformMethod =
getTransformer().getPreferredTransformMethod(XMLSecurityConstants.TransformMethod.InputStream);
switch (preferredChildTransformMethod) {
case XMLSecEvent: {
childOutputMethod = new ChildOutputMethod() {
private XMLEventReaderInputProcessor xmlEventReaderInputProcessor;
@Override
public void transform(Object object) throws XMLStreamException {
if (xmlEventReaderInputProcessor == null) {
xmlEventReaderInputProcessor = new XMLEventReaderInputProcessor(
null,
getXmlInputFactory().createXMLStreamReader(inputStream)
);
}
try {
XMLSecEvent xmlSecEvent;
do {
xmlSecEvent = xmlEventReaderInputProcessor.processNextEvent(null);
getTransformer().transform(xmlSecEvent);
} while (xmlSecEvent.getEventType() != XMLStreamConstants.END_DOCUMENT);
} catch (XMLSecurityException e) {
throw new XMLStreamException(e);
}
}
@Override
public void doFinal() throws XMLStreamException {
getTransformer().doFinal();
}
};
break;
}
case InputStream: {
childOutputMethod = new ChildOutputMethod() {
@Override
public void transform(Object object) throws XMLStreamException {
getTransformer().transform(inputStream);
}
@Override
public void doFinal() throws XMLStreamException {
getTransformer().doFinal();
}
};
break;
}
}
}
if (childOutputMethod != null) {
childOutputMethod.transform(inputStream);
}
}
}
@Override
public void doFinal() throws XMLStreamException {
if (xmlEventWriterForOutputStream != null) {
xmlEventWriterForOutputStream.close();
}
if (childOutputMethod != null) {
childOutputMethod.doFinal();
} else if (transformer != null) {
transformer.doFinal();
}
}
interface ChildOutputMethod {
void transform(Object object) throws XMLStreamException;
void doFinal() throws XMLStreamException;
}
}