/* * Copyright 2003 Federal Chancellery Austria * MOA-SPSS has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egovernment.moa.spss.server.invoke; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.crypto.Data; import javax.xml.crypto.NodeSetData; import javax.xml.crypto.OctetStreamData; import javax.xml.crypto.URIReference; import javax.xml.parsers.ParserConfigurationException; import org.apache.xerces.dom.CoreDocumentImpl; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.SAXException; import at.gv.egovernment.moa.spss.MOAApplicationException; import at.gv.egovernment.moa.spss.MOASystemException; import at.gv.egovernment.moa.spss.api.common.Content; import at.gv.egovernment.moa.spss.api.common.ContentBinary; import at.gv.egovernment.moa.spss.api.common.ContentLocRef; import at.gv.egovernment.moa.spss.api.common.ContentXML; import at.gv.egovernment.moa.spss.api.common.MetaInfo; import at.gv.egovernment.moa.spss.api.common.XMLDataObjectAssociation; import at.gv.egovernment.moa.spss.api.xmlverify.TransformParameter; import at.gv.egovernment.moa.spss.api.xmlverify.TransformParameterBinary; import at.gv.egovernment.moa.spss.server.iaik.xml.ByteArrayDataObjectImpl; import at.gv.egovernment.moa.spss.server.iaik.xml.ByteStreamDataObjectImpl; import at.gv.egovernment.moa.spss.server.iaik.xml.DataObjectImpl; import at.gv.egovernment.moa.spss.server.iaik.xml.XMLDataObjectImpl; import at.gv.egovernment.moa.spss.server.iaik.xml.XMLNodeListDataObjectImpl; import at.gv.egovernment.moa.spss.server.transaction.TransactionContext; import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager; import at.gv.egovernment.moa.spss.util.MOASPSSEntityResolver; import at.gv.egovernment.moa.spss.util.MessageProvider; import at.gv.egovernment.moaspss.logging.LogMsg; import at.gv.egovernment.moaspss.logging.Logger; import at.gv.egovernment.moaspss.util.Constants; import at.gv.egovernment.moaspss.util.DOMUtils; import at.gv.egovernment.moaspss.util.EntityResolverChain; import at.gv.egovernment.moaspss.util.MOAErrorHandler; import at.gv.egovernment.moaspss.util.StreamEntityResolver; import at.gv.egovernment.moaspss.util.StreamUtils; import at.gv.egovernment.moaspss.util.XPathUtils; import iaik.server.modules.xml.DataObject; import iaik.server.modules.xml.NodeListImplementation; import iaik.server.modules.xml.URIReferenceImpl; import iaik.server.modules.xml.XMLDataObject; import iaik.xml.crypto.utils.URIDereferencerImpl; /** * A class to create DataObjects contained in different * locations of the MOA XML request format. * * @author Patrick Peck * @author Gregor Karlinger * @version $Id$ */ public class DataObjectFactory { /** * XPATH for registering ID attributes of known schemas if * validating parsing fails. */ private static final String XPATH = "descendant-or-self::node()[" + "namespace-uri()='http://www.w3.org/2000/09/xmldsig#' " + "or namespace-uri()='http://reference.e-government.gv.at/namespace/persondata/20020228#' " + "or starts-with(namespace-uri(), 'http://uri.etsi.org/01903/')" + "]/attribute::Id"; /** The single instance of this class. */ private static DataObjectFactory instance = null; /** * Return the only instance of this class. * * @return The only instance of this class. */ public static synchronized DataObjectFactory getInstance() { if (instance == null) { instance = new DataObjectFactory(); } return instance; } /** * Create a new DataObjectFactory. * * Protected to disallow multiple instances. */ protected DataObjectFactory() { } /** * Return the signature environment, i.e., the root element of the * document, into which the signature will be inserted (if created) or which * contains the signature (if verified). * * @param content The Content object containing the signature * environment. * @param supplements Additional schema or DTD information. * @return The signature environment or null, if no * signature environment exists. * @throws MOASystemException A system error occurred building the signature * environment (see message for details). * @throws MOAApplicationException An error occurred building the signature * environment (see message for details). */ public XMLDataObject createSignatureEnvironment( Content content, List supplements) throws MOASystemException, MOAApplicationException { String reference = content.getReference(); EntityResolver entityResolver; byte[] contentBytes; // check for content and reference not being set at the same time checkAllowContentAndReference(content, false); // build the EntityResolver for validating parsing if ((supplements == null) || supplements.isEmpty()) { entityResolver = new MOASPSSEntityResolver(); } else { EntityResolverChain chain = new EntityResolverChain(); chain.addEntityResolver(buildSupplementEntityResolver(supplements)); chain.addEntityResolver(new MOASPSSEntityResolver()); entityResolver = chain; } // convert the content into a byte array try { switch (content.getContentType()) { case Content.BINARY_CONTENT : { InputStream is = ((ContentBinary) content).getBinaryContent(); contentBytes = StreamUtils.readStream(is); break; } case Content.LOCREF_CONTENT: { String locRefURI = ((ContentLocRef) content).getLocationReferenceURI(); InputStream is = null; try { TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); is = context.ResolveURI(locRefURI); if (is == null) { ExternalURIResolver uriResolver = new ExternalURIResolver(); is = uriResolver.resolve(locRefURI); } contentBytes = StreamUtils.readStream(is); } catch (MOAApplicationException e) { throw new MOAApplicationException("3203", new Object[]{reference, locRefURI}, e); } finally { closeInputStream(is); } break; } case Content.REFERENCE_CONTENT : { ExternalURIResolver uriResolver = new ExternalURIResolver(); InputStream is = null; try { is = uriResolver.resolve(reference); contentBytes = StreamUtils.readStream(is); } catch (Exception e) { throw e; } finally { closeInputStream(is); } break; } case Content.XML_CONTENT : { Element element = checkForSingleElement(((ContentXML) content).getXMLContent()); contentBytes = DOMUtils.serializeNode(element, "UTF-8"); break; } default : { contentBytes = null; // this will not happen } } } catch (MOAApplicationException e) { throw e; } catch (Exception e) { throw new MOAApplicationException("2219", null); } if (Logger.isTraceEnabled()) { // For logging in Debug-Mode: Mask baseid with xxx String logString = new String(contentBytes); // TODO use RegExp String startS = ""; String endS = "urn:publicid:gv.at:baseid"; String logWithMaskedBaseid = logString; int start = logString.indexOf(startS); if (start > -1) { int end = logString.indexOf(endS); if (end > -1) { logWithMaskedBaseid = logString.substring(0, start); logWithMaskedBaseid += startS; logWithMaskedBaseid += "xxxxxxxxxxxxxxxxxxxxxxxx"; logWithMaskedBaseid += logString.substring(end, logString.length()); } } // try to parse validating Logger.trace(">>> parsing the following content: \n" + logWithMaskedBaseid); } try { ByteArrayInputStream is = new ByteArrayInputStream(contentBytes); Document doc = DOMUtils.parseDocument( is, true, Constants.ALL_SCHEMA_LOCATIONS, null, entityResolver, new MOAErrorHandler()); Logger.trace("<<< parsed"); return new XMLDataObjectImpl(doc.getDocumentElement()); } catch (Exception e) { // never mind, we'll try non-validating MessageProvider msg = MessageProvider.getInstance(); Logger.info(new LogMsg(msg.getMessage("invoker.00", null))); Logger.info(new LogMsg(e.getMessage())); } // try to parse non-validating try { ByteArrayInputStream is = new ByteArrayInputStream(contentBytes); Document doc = DOMUtils.parseDocument(is, false, null, null); // Since the parse tree will not contain any post schema validation information, // we need to register any attributes known to be of type xsd:Id manually. NodeList idAttributes = XPathUtils.selectNodeList(doc.getDocumentElement(), XPATH); for (int i = 0; i < idAttributes.getLength(); i++) { Node item = idAttributes.item(i); if (item instanceof Attr) { Attr attr = (Attr) item; Element owner = attr.getOwnerElement(); // Only available in DOM-Level 3 (Java 1.5): // owner.setIdAttributeNode(attr, true); if (doc instanceof CoreDocumentImpl) { ((CoreDocumentImpl) doc).putIdentifier(attr.getValue(), owner); } } } return new XMLDataObjectImpl(doc.getDocumentElement()); } catch (Exception e) { throw new MOAApplicationException("2218", null); } } /** * Create an XMLDataObject from the given signature environment. * * @param signatureEnvironment The signature environment contained in the * result. * @param uri The URI identifying the data. This must be either the empty * URI, an URI starting with "#xpointer", "#xmlns" * or "#element"; or an URI starting with "#" and * followed by an element ID. * @param referenceID The reference ID to set for the data object. * @return A data object containing the signature environment. */ public DataObject createFromSignatureEnvironment( Element signatureEnvironment, String uri, String referenceID) throws MOAApplicationException { DataObjectImpl dataObject = null; if ("".equals(uri)) { dataObject = new XMLDataObjectImpl(signatureEnvironment); } else if ( uri.startsWith("#xpointer") || uri.startsWith("#xmlns") || uri.startsWith("#element")) { try { // CHANGE IXSIL to XSECT // maybe use URIDereferencerImpl or XPath ...?? //XPointerReferenceResolver resolver = new XPointerReferenceResolver(); URIDereferencerImpl uriDereferencer = new URIDereferencerImpl(); URIReference uriReference = new URIReferenceImpl(uri, null, signatureEnvironment); Data returnedData = uriDereferencer.dereference(uriReference, null); if(returnedData instanceof NodeSetData) { NodeSetData nodeSetData = (NodeSetData)returnedData; Iterator nodesIterator = nodeSetData.iterator(); List nodeList = new ArrayList(); while(nodesIterator.hasNext()) { nodeList.add(nodesIterator.next()); } NodeList nodes = new NodeListImplementation(nodeList); dataObject = new XMLNodeListDataObjectImpl(nodes); } else if(returnedData instanceof OctetStreamData) { OctetStreamData streamData = (OctetStreamData)returnedData; dataObject = new ByteStreamDataObjectImpl(streamData.getOctetStream()); } else { throw new MOAApplicationException("2237", new Object[] { uri }); } //URI uriObj = new URI(uri); //NodeList nodes = // resolver.resolveForest( // uriObj, // signatureEnvironment.getOwnerDocument(), // null); } catch (Exception e) { throw new MOAApplicationException("2237", new Object[] { uri }); } } else if (uri.startsWith("#")) { String id = uri.substring(1); Element refElem = signatureEnvironment.getOwnerDocument().getElementById(id); if (refElem == null) { throw new MOAApplicationException("2237", new Object[] { id }); } dataObject = new XMLDataObjectImpl(refElem); } dataObject.setReferenceID(referenceID); dataObject.setURI(uri); return dataObject; } /** * Build a StreamEntityResolver from a List of * supplements. * * @param supplements The supplements, given as * XMLDataObjectAssociations. * @return A StreamEntityResolver mapping the supplements by * their reference URI to an InputStream of their respective * content. */ private static StreamEntityResolver buildSupplementEntityResolver(List supplements) throws MOAApplicationException { Map entities = new HashMap(); Iterator iter; for (iter = supplements.iterator(); iter.hasNext();) { XMLDataObjectAssociation supplement = (XMLDataObjectAssociation) iter.next(); Content content = supplement.getContent(); String reference = content.getReference(); switch (content.getContentType()) { case Content.BINARY_CONTENT : { entities.put(reference, ((ContentBinary) content).getBinaryContent()); break; } case Content.LOCREF_CONTENT: { String locRefURI = ((ContentLocRef) content).getLocationReferenceURI(); TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); if (context.FindResolvedEntity(locRefURI)==null) { ExternalURIResolver uriResolver = new ExternalURIResolver(); InputStream uriStream = null; byte[] contentBytes; String contentType = null; try { uriStream = uriResolver.resolve(locRefURI); contentBytes = StreamUtils.readStream(uriStream); contentType = uriResolver.getContentType(); } catch (Exception e) { throw new MOAApplicationException("3202", new Object[]{reference, locRefURI}, e); } finally { closeInputStream(uriStream); } context.PutResolvedEntity(locRefURI, contentBytes, contentType); } InputStream contentIS = context.ResolveURI(locRefURI); entities.put(reference, contentIS); break; } case Content.XML_CONTENT : { // serialize the first element node that is found in the supplement // and make it available as a stream NodeList nodes = ((ContentXML) content).getXMLContent(); int i = 0; // find the first element node while ((i < nodes.getLength()) && (nodes.item(i).getNodeType() != Node.ELEMENT_NODE)) { i++; } // serialize the node if (i < nodes.getLength()) { try { byte[] serialized = DOMUtils.serializeNode(nodes.item(i), "UTF-8"); entities.put(reference, new ByteArrayInputStream(serialized)); } catch (Exception e) { throw new MOAApplicationException("2281", new Object[]{reference}, e); } } break; } } } return new StreamEntityResolver(entities); } /** * Create a DataObject from a Content object. * * @param content The Content object containing the data. * @param finalDataMetaInfo The meta information corresponding with content. * @param referenceID The reference ID to set in the resulting * DataObject. May be null. * @param allowContentAndReference If true, then * content is allowed to contain both a Reference * attribute and content. Otherwise, either a Reference * attribute or content must be set. * @param binaryAsXml If true, a content child given as * Base64Content must contain XML data. * @param xmlAsNodeList If true, the children of a * XMLContent child element are returned as a * XMLNodeListDataObject. Otherwise, XMLContent may * only contain a single child node, which must be an element and which is * returned as an XMLDataObject. * @param referenceAsXml If true, then content loaded from the * URI given as the Reference attribute must be XML data. * If false, an attempt is made to parse the data as XML and * return an XMLDataObject but if this fails, a * BinaryDataObject is returned containing a byte stream to the * data. * @return A DataObject representing the data in * content. If base64AsXml==true and * xmlAsNodeList==false and referenceAsXml==true, * then the result can safely be cast to an XMLDataObject. * @throws MOASystemException An error indicating an internal problem. See the * wrapped exception for details. * @throws MOAApplicationException An error occurred handling the content * (probably while opening a reference or parsing the data). See the wrapped * exception for details. */ public DataObject createFromContentOptionalRefType( Content content, MetaInfo finalDataMetaInfo, String referenceID, boolean allowContentAndReference, boolean binaryAsXml, boolean xmlAsNodeList, boolean referenceAsXml) throws MOASystemException, MOAApplicationException { String reference = content.getReference(); DataObjectImpl dataObject = null; checkAllowContentAndReference(content, allowContentAndReference); // ok, build the data object; use content first, if available switch (content.getContentType()) { case Content.XML_CONTENT : { ContentXML contentXml = (ContentXML) content; dataObject = createFromXmlContent(contentXml, xmlAsNodeList); break; } case Content.BINARY_CONTENT : { ContentBinary contentBinary = (ContentBinary) content; dataObject = createFromBinaryContent(contentBinary, binaryAsXml, false); break; } case Content.LOCREF_CONTENT : { String locRefURI = ((ContentLocRef) content).getLocationReferenceURI(); try { dataObject = createFromURIImpl(locRefURI, referenceAsXml); } catch (MOAApplicationException e) { throw new MOAApplicationException("3201", new Object[]{reference, locRefURI}, e); } break; } case Content.REFERENCE_CONTENT : { dataObject = createFromURIImpl(reference, referenceAsXml); break; } } // set URI and reference ID dataObject.setURI(reference); dataObject.setReferenceID(referenceID); // set Type gathered from corresponding meta information dataObject.setTypeURI(finalDataMetaInfo.getType()); return dataObject; } /** * Check, if content and reference URIs are allowed in the content an throw * an exception if an illegal combination of the two occurs. * * @param content The Content to check. * @param allowContentAndReference Whether explicit content and a reference * are allowed at the same time. * @throws MOAApplicationException If allowContentAndRefernece * is false and both explicit content and reference are set, * an exception is thrown. */ private static void checkAllowContentAndReference( Content content, boolean allowContentAndReference) throws MOAApplicationException { String reference = content.getReference(); // check for content and reference not being set if ((content.getContentType() == Content.REFERENCE_CONTENT) && (reference == null)) { String errorCode = allowContentAndReference ? "1111" : "1110"; throw new MOAApplicationException(errorCode, null); } // if we only allow either content or reference being set at once, check if (!allowContentAndReference && (content.getContentType() != Content.REFERENCE_CONTENT) && (reference != null)) { throw new MOAApplicationException("1110", null); } } /** * Create a DataObject from a * XMLDataObjectAssociation object. * * @param xmlDataObjAssoc The XMLDataObjectAssociation object. * @param xmlContentAllowed Whether the content contained in the * xmlDataObjAssoc is allowed to be of type * XML_CONTENT. * @param binaryContentRepeatable If binary content must be provided as a * DataObject that can be read multiple times. * @return A DataObject representing the data in * xmlDataObjAssoc. * @throws MOASystemException An error indicating an internal problem. See the * wrapped exception for details. * @throws MOAApplicationException An error occurred handling the content * (probably while parsing the data). See the wrapped exception for details. */ public DataObject createFromXmlDataObjectAssociation( XMLDataObjectAssociation xmlDataObjAssoc, boolean xmlContentAllowed, boolean binaryContentRepeatable) throws MOASystemException, MOAApplicationException { Content content = xmlDataObjAssoc.getContent(); MetaInfo metaInfo = xmlDataObjAssoc.getMetaInfo(); String mimeType = metaInfo != null ? metaInfo.getMimeType() : null; DataObjectImpl dataObject = null; switch (content.getContentType()) { case Content.XML_CONTENT : { if (xmlContentAllowed) { dataObject = createFromXmlContent((ContentXML) content, true); } else { throw new MOAApplicationException("2280", null); } break; } case Content.BINARY_CONTENT : { dataObject = createFromBinaryContent( (ContentBinary) content, false, binaryContentRepeatable); break; } case Content.LOCREF_CONTENT : { String locRefURI = ((ContentLocRef) content).getLocationReferenceURI(); try { dataObject = createFromURIImpl(locRefURI, false); } catch (MOAApplicationException e) { throw new MOAApplicationException("3201", new Object[]{content.getReference(), locRefURI}, e); } break; } } dataObject.setURI(content.getReference()); dataObject.setMimeType(mimeType); return dataObject; } /** * Create a DataObject from a TransformParameter * object. * * @param transformParameter The TransformParameter object * containing the data. * @return A DataObject representing the data in * root. * @throws MOASystemException An error indicating an internal problem. See the * wrapped exception for details. * @throws MOAApplicationException An error occurred handling the content * (probably while opening a reference or parsing the data). See the wrapped * exception for details. */ public DataObject createFromTransformParameter(TransformParameter transformParameter) throws MOASystemException, MOAApplicationException { DataObjectImpl dataObject; switch (transformParameter.getTransformParameterType()) { case TransformParameter.BINARY_TRANSFORMPARAMETER : TransformParameterBinary tpBinary = (TransformParameterBinary) transformParameter; try { //dataObject = new ByteArrayDataObjectImpl(Base64Utils.encode(tpBinary.getBinaryContent())); dataObject = new ByteArrayDataObjectImpl( StreamUtils.readStream(tpBinary.getBinaryContent())); } catch (Exception e) { return null; } //dataObject = new ByteStreamDataObjectImpl(tpBinary.getBinaryContent()); break; default : // resolve uri and build the content ExternalURIResolver resolver = new ExternalURIResolver(); InputStream is = resolver.resolve(transformParameter.getURI()); ByteArrayInputStream bis; try { bis = new ByteArrayInputStream(StreamUtils.readStream(is)); } catch (IOException e) { throw new MOAApplicationException("2238", new Object[] {transformParameter.getURI()}, e); } finally { closeInputStream(is); } String contentType = resolver.getContentType(); dataObject = new ByteStreamDataObjectImpl(bis); dataObject.setMimeType(contentType); break; } dataObject.setURI(transformParameter.getURI()); return dataObject; } /** * Create a DataObject from data located at the given URI. * * @param uri The URI where the data is located. This method uses * an ExternalURIResolver to resolve URIs. * @param asXml If true, a DataObject is only * returned, if the content consists of XML data. If it does not consist of * XML data, an MOAApplicationException will be thrown. If this * parameter is false and the content consists of XML data, this * method will still attempt to parse it. * @return The DataObject contained at the URI. * @throws MOASystemException A system error parsing the XML content. * @throws MOAApplicationException An error occurred on opening, reading or * parsing the data behind the URI. */ public DataObject createFromURI(String uri, boolean asXml) throws MOASystemException, MOAApplicationException { return createFromURIImpl(uri, asXml); } /** * Create a DataObject from data located at the given URI. * * @param uri The URI where the data is located. This method uses * an ExternalURIResolver to resolve URIs. * @param asXml If true, a DataObject is only * returned, if the content consists of XML data. If it does not consist of * XML data, an MOAApplicationException will be thrown. If this * parameter is false and the content type is detected as being * XML data, this method will still attemt to parse it. * @return The DataObject contained at the URI. * @throws MOASystemException A system error parsing the XML content. * @throws MOAApplicationException An error occurred on opening, reading or * parsing the data behind the URI. */ private DataObjectImpl createFromURIImpl(String uri, boolean asXml) throws MOASystemException, MOAApplicationException { Logger.trace(">>> resolving uri \"" + uri + "\""); ExternalURIResolver resolver = new ExternalURIResolver(); TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); InputStream is = context.ResolveURI(uri); String contentType = null; boolean foundURI = false; if (is == null) { is = resolver.resolve(uri); contentType = resolver.getContentType(); } else { foundURI = true; contentType = (String) context.FindResolvedEntity(uri).get(1); Logger.trace("found \"" + uri + "\" InputStream in preread Supplements!, do not read any more. Content=" + contentType); } DataObjectImpl dataObject; // read the content if ((contentType != null) && contentTypeIsXml(contentType)) { Document doc; if (asXml) { try { // try parsing non-validating: this has to succeed or we // bail out by throwing an exception is = resolver.resolve(uri); doc = DOMUtils.parseDocument(is, false, null, null); dataObject = new XMLDataObjectImpl(doc.getDocumentElement()); } catch (ParserConfigurationException e) { throw new MOASystemException("1106", null, e); } catch (SAXException e) { throw new MOAApplicationException("2209", null, e); } catch (IOException e) { throw new MOAApplicationException("2210", null, e); } finally { closeInputStream(is); } } else { try { // try parsing non-validating: need not succeed is = resolver.resolve(uri); doc = DOMUtils.parseDocument(is, false, null, null); closeInputStream(is); dataObject = new XMLDataObjectImpl(doc.getDocumentElement()); } catch (Exception e) { // this is the last chance: return the data as a byte stream Logger.trace(">>> reading stream for \"" + uri + "\""); is = resolver.resolve(uri); ByteArrayInputStream bis; try { bis = new ByteArrayInputStream(StreamUtils.readStream(is)); dataObject = new ByteStreamDataObjectImpl(bis); } catch (IOException e1) { throw new MOAApplicationException("2210", new Object[] { uri }, e1); } finally { closeInputStream(is); } Logger.trace(">>> read stream for \"" + uri + "\""); } } } else if (asXml) { // if we need XML data, we're in the wrong place here closeInputStream(is); throw new MOAApplicationException("2211", new Object[] { uri }); } else { // content is binary: make it available as a binary input stream Logger.trace(">>> getting binary input for \"" + uri + "\""); byte[] contentBytes; ByteArrayInputStream bis; try { contentBytes = StreamUtils.readStream(is); bis = new ByteArrayInputStream(contentBytes); } catch (IOException e) { throw new MOAApplicationException("2210", null, e); } finally { closeInputStream(is); } if (!foundURI) { context.PutResolvedEntity(uri, contentBytes, contentType); } dataObject = new ByteStreamDataObjectImpl(bis); Logger.trace("<<< got binary input for \"" + uri + "\""); } dataObject.setMimeType(contentType); dataObject.setURI(uri); Logger.trace("<<< resolved uri \"" + uri + "\""); return dataObject; } /** * Savely closes the specified input stream. * * @param is The input stream to be closed. */ private static void closeInputStream(InputStream is) { try { if (is != null) { is.close(); } } catch (Throwable t) { // Intentionally do nothing here } } /** * Determine whether the content type is XML. * * Content types recognized as XML start with text/xml and * application/xml. * * @param contentType The content MIME type. * @return boolean If true, the content type is XML, otherwise * not. */ private static boolean contentTypeIsXml(String contentType) { return contentType.startsWith("text/xml") || (contentType.startsWith("application/xml")); } /** * Create a DataObject from a ContentXML object. * * @param xmlContent The ContentXML object from * which the DataObject is to be built. * @param xmlAsNodeList If true, the children of * xmlContent are returned as a * XMLNodeListDataObject. Otherwise, * xmlContent may only contain a single child node, which must be * an element and which is returned as an XMLDataObject. * @return A DataObject representing the XML content in * xmlContent. * @throws MOAApplicationException If xmlAsNodeList is * false and xmlContent does not have a single child * element. */ private DataObjectImpl createFromXmlContent( ContentXML xmlContent, boolean xmlAsNodeList) throws MOAApplicationException { DataObjectImpl dataObject; if (xmlAsNodeList) { dataObject = new XMLNodeListDataObjectImpl(xmlContent.getXMLContent()); } else { NodeList nodes = xmlContent.getXMLContent(); Element element = checkForSingleElement(nodes); // build the XMLDataObject dataObject = new XMLDataObjectImpl(element); } return dataObject; } /** * Check, that the given NodeList contains a single DOM element * node and return it, otherwise throw an exception. * * @param nodes The NodeList to check for a single element. * @return The single element contained in nodes. * @throws MOAApplicationException Thrown, if nodes does not * contain exactly 1 element node. */ private Element checkForSingleElement(NodeList nodes) throws MOAApplicationException { Element element = null; int i; // check for a single element node for (i = 0; i < nodes.getLength(); i++) { if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) { if (element == null) { element = (Element) nodes.item(i); } else { throw new MOAApplicationException("1109", null); } } } // return the element node if (element == null) { throw new MOAApplicationException("1107", null); } else { return element; } } /** * Create a DataObject from a ContentBinary object. * * @param binaryContent The ContentBinary object containing the * data. * @param asXml If true, binaryContent must * contain XML data. Otherwise, a BinaryDataObject will be * returned containing a byte stream to the decoded Base64 data. * @param repeatable If multiple calls to getInputStream() must * repeatedly return the content of the data object. * @return A DataObject representing the content contained in * binaryContent. * @throws MOASystemException An error indicating an internal problem. See the * wrapped exception for details. * @throws MOAApplicationException An error occurred handling the content * (probably while parsing the data). See the wrapped exception for details. */ private DataObjectImpl createFromBinaryContent( ContentBinary binaryContent, boolean asXml, boolean repeatable) throws MOASystemException, MOAApplicationException { InputStream byteStream = binaryContent.getBinaryContent(); DataObjectImpl dataObject; if (asXml) { Document doc; try { doc = DOMUtils.parseDocument(byteStream, false, null, null); dataObject = new XMLDataObjectImpl(doc.getDocumentElement()); } catch (ParserConfigurationException e) { throw new MOASystemException("1106", null, e); } catch (SAXException e) { throw new MOAApplicationException("2209", null, e); } catch (IOException e) { throw new MOAApplicationException("2210", null, e); } } else { if (repeatable) { try { dataObject = new ByteArrayDataObjectImpl(StreamUtils.readStream(byteStream)); } catch (IOException e) { throw new MOAApplicationException("2210", null); } } else { dataObject = new ByteStreamDataObjectImpl(byteStream); } } return dataObject; } }