From ece7d18cf35374bf4e26d041799cda8f791c89f8 Mon Sep 17 00:00:00 2001 From: gregor Date: Mon, 7 Jul 2003 10:58:37 +0000 Subject: Initial commit git-svn-id: https://joinup.ec.europa.eu/svn/moa-idspss/trunk@2 d688527b-c9ab-4aba-bd8d-4036d912da1d --- .../moa/spss/server/invoke/DataObjectFactory.java | 717 +++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100644 spss.server/src/at/gv/egovernment/moa/spss/server/invoke/DataObjectFactory.java (limited to 'spss.server/src/at/gv/egovernment/moa/spss/server/invoke/DataObjectFactory.java') diff --git a/spss.server/src/at/gv/egovernment/moa/spss/server/invoke/DataObjectFactory.java b/spss.server/src/at/gv/egovernment/moa/spss/server/invoke/DataObjectFactory.java new file mode 100644 index 000000000..32c81dc07 --- /dev/null +++ b/spss.server/src/at/gv/egovernment/moa/spss/server/invoke/DataObjectFactory.java @@ -0,0 +1,717 @@ +package at.gv.egovernment.moa.spss.server.invoke; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +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 iaik.ixsil.util.URI; +import iaik.ixsil.util.XPointerReferenceResolver; +import iaik.server.modules.xml.DataObject; +import iaik.server.modules.xml.XMLDataObject; + +import at.gv.egovernment.moa.logging.LogMsg; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.EntityResolverChain; +import at.gv.egovernment.moa.util.MOAEntityResolver; +import at.gv.egovernment.moa.util.MOAErrorHandler; +import at.gv.egovernment.moa.util.StreamEntityResolver; +import at.gv.egovernment.moa.util.StreamUtils; + +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.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.util.MessageProvider; + +/** + * A class to create DataObjects contained in different + * locations of the MOA XML request format. + * + * @author Patrick Peck + * @version $Id$ + */ +public class DataObjectFactory { + + /** 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 MOAEntityResolver(); + } else { + EntityResolverChain chain = new EntityResolverChain(); + + chain.addEntityResolver(buildSupplementEntityResolver(supplements)); + chain.addEntityResolver(new MOAEntityResolver()); + 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.REFERENCE_CONTENT : + { + ExternalURIResolver uriResolver = new ExternalURIResolver(); + InputStream is = uriResolver.resolve(reference); + contentBytes = StreamUtils.readStream(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); + } + + // try to parse validating + try { + ByteArrayInputStream is = new ByteArrayInputStream(contentBytes); + Document doc = + DOMUtils.parseDocument( + is, + true, + Constants.ALL_SCHEMA_LOCATIONS, + null, + entityResolver, + new MOAErrorHandler()); + + 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))); + } + + // try to parse non-validating + try { + ByteArrayInputStream is = new ByteArrayInputStream(contentBytes); + Document doc = DOMUtils.parseDocument(is, false, null, null); + 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 { + XPointerReferenceResolver resolver = new XPointerReferenceResolver(); + URI uriObj = new URI(uri); + NodeList nodes = + resolver.resolveForest( + uriObj, + signatureEnvironment.getOwnerDocument(), + null); + dataObject = new XMLNodeListDataObjectImpl(nodes); + } 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) { + 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.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) { + // serializing the element failed - just don't put it in the map + } + } + + break; + } + } + + return new StreamEntityResolver(entities); + } + + /** + * Create a DataObject from a Content object. + * + * @param content The Content object containing the data. + * @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, + 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.REFERENCE_CONTENT : + dataObject = createFromURIImpl(reference, referenceAsXml); + break; + } + + // set URI and reference ID + dataObject.setURI(content.getReference()); + dataObject.setReferenceID(referenceID); + + 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; + } + + 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()); + String contentType = resolver.getContentType(); + dataObject = new ByteStreamDataObjectImpl(is); + 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 { + + ExternalURIResolver resolver = new ExternalURIResolver(); + InputStream is = resolver.resolve(uri); + String contentType = resolver.getContentType(); + 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); + } + } else { + try { + // try parsing non-validating: need not succeed + is = resolver.resolve(uri); + doc = DOMUtils.parseDocument(is, false, null, null); + dataObject = new XMLDataObjectImpl(doc.getDocumentElement()); + } catch (Exception e) { + // this is the last chance: return the data as a byte stream + is = resolver.resolve(uri); + dataObject = new ByteStreamDataObjectImpl(is); + } + } + } else if (asXml) { + // if we need XML data, we're in the wrong place here + throw new MOAApplicationException("2211", new Object[] { uri }); + } else { + // content is binary: make it available as a binary input stream + dataObject = new ByteStreamDataObjectImpl(is); + } + + dataObject.setMimeType(contentType); + dataObject.setURI(uri); + + return dataObject; + } + + /** + * 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; + } + +} -- cgit v1.2.3