summaryrefslogtreecommitdiff
path: root/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils')
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java1243
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java113
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java104
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java142
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java178
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java175
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java319
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java89
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java46
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java205
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java69
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java177
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java85
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java523
14 files changed, 3468 insertions, 0 deletions
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java
new file mode 100644
index 00000000..f28700a1
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java
@@ -0,0 +1,1243 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.xerces.parsers.DOMParser;
+import org.apache.xerces.parsers.SAXParser;
+import org.apache.xerces.parsers.XMLGrammarPreparser;
+import org.apache.xerces.util.SymbolTable;
+import org.apache.xerces.util.XMLGrammarPoolImpl;
+import org.apache.xerces.xni.grammars.XMLGrammarDescription;
+import org.apache.xerces.xni.grammars.XMLGrammarPool;
+import org.apache.xerces.xni.parser.XMLInputSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+
+/**
+ * Various utility functions for handling XML DOM trees.
+ *
+ * The parsing methods in this class make use of some features internal to the
+ * Xerces DOM parser, mainly for performance reasons. As soon as JAXP
+ * (currently at version 1.2) is better at schema handling, it should be used as
+ * the parser interface.
+ *
+ */
+public class DOMUtils {
+ private static final Logger log = LoggerFactory.getLogger(DOMUtils.class);
+
+ /** Feature URI for namespace aware parsing. */
+ private static final String NAMESPACES_FEATURE =
+ "http://xml.org/sax/features/namespaces";
+ /** Feature URI for validating parsing. */
+ private static final String VALIDATION_FEATURE =
+ "http://xml.org/sax/features/validation";
+ /** Feature URI for schema validating parsing. */
+ private static final String SCHEMA_VALIDATION_FEATURE =
+ "http://apache.org/xml/features/validation/schema";
+ /** Feature URI for normalization of element/attribute values. */
+ private static final String NORMALIZED_VALUE_FEATURE =
+ "http://apache.org/xml/features/validation/schema/normalized-value";
+ /** Feature URI for parsing ignorable whitespace. */
+ private static final String INCLUDE_IGNORABLE_WHITESPACE_FEATURE =
+ "http://apache.org/xml/features/dom/include-ignorable-whitespace";
+ /** Feature URI for creating EntityReference nodes in the DOM tree. */
+ private static final String CREATE_ENTITY_REF_NODES_FEATURE =
+ "http://apache.org/xml/features/dom/create-entity-ref-nodes";
+ /** Property URI for providing external schema locations. */
+ private static final String EXTERNAL_SCHEMA_LOCATION_PROPERTY =
+ "http://apache.org/xml/properties/schema/external-schemaLocation";
+ /** Property URI for providing the external schema location for elements
+ * without a namespace. */
+ private static final String EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY =
+ "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
+
+ private static final String EXTERNAL_GENERAL_ENTITIES_FEATURE =
+ "http://xml.org/sax/features/external-general-entities";
+
+ private static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE =
+ "http://xml.org/sax/features/external-parameter-entities";
+
+ public static final String DISALLOW_DOCTYPE_FEATURE =
+ "http://apache.org/xml/features/disallow-doctype-decl";
+
+
+
+ /** Property URI for the Xerces grammar pool. */
+ private static final String GRAMMAR_POOL =
+ org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX
+ + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY;
+ /** A prime number for initializing the symbol table. */
+ private static final int BIG_PRIME = 2039;
+ /** Symbol table for the grammar pool. */
+ private static SymbolTable symbolTable = new SymbolTable(BIG_PRIME);
+ /** Xerces schema grammar pool. */
+ private static XMLGrammarPool grammarPool = new XMLGrammarPoolImpl();
+ /** Set holding the NamespaceURIs of the grammarPool, to prevent multiple
+ * entries of same grammars to the pool */
+ private static Set grammarNamespaces;
+
+ static {
+ grammarPool.lockPool();
+ grammarNamespaces = new HashSet();
+ }
+
+ /**
+ * Preparse a schema and add it to the schema pool.
+ * The method only adds the schema to the pool if a schema having the same
+ * <code>systemId</code> (namespace URI) is not already present in the pool.
+ *
+ * @param inputStream An <code>InputStream</code> providing the contents of
+ * the schema.
+ * @param systemId The systemId (namespace URI) to use for the schema.
+ * @throws IOException An error occurred reading the schema.
+ */
+ public static void addSchemaToPool(InputStream inputStream, String systemId)
+ throws IOException {
+ XMLGrammarPreparser preparser;
+
+ if (!grammarNamespaces.contains(systemId)) {
+
+ grammarNamespaces.add(systemId);
+
+ // unlock the pool so that we can add another grammar
+ grammarPool.unlockPool();
+
+ // prepare the preparser
+ preparser = new XMLGrammarPreparser(symbolTable);
+ preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null);
+ preparser.setProperty(GRAMMAR_POOL, grammarPool);
+ preparser.setFeature(NAMESPACES_FEATURE, true);
+ preparser.setFeature(VALIDATION_FEATURE, true);
+
+ // add the grammar to the pool
+ preparser.preparseGrammar(
+ XMLGrammarDescription.XML_SCHEMA,
+ new XMLInputSource(null, systemId, null, inputStream, null));
+
+ // lock the pool again so that schemas are not added automatically
+ grammarPool.lockPool();
+ }
+ }
+
+ /**
+ * Parse an XML document from an <code>InputStream</code>.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @param entityResolver An <code>EntityResolver</code> to resolve external
+ * entities (schemas and DTDs). If <code>null</code>, it will not be set.
+ * @param errorHandler An <code>ErrorHandler</code> to decide what to do
+ * with parsing errors. If <code>null</code>, it will not be set.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ InputStream inputStream,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation,
+ EntityResolver entityResolver,
+ ErrorHandler errorHandler,
+ Map<String, Object> parserFeatures)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ DOMParser parser;
+
+// class MyEntityResolver implements EntityResolver {
+//
+// public InputSource resolveEntity(String publicId, String systemId)
+// throws SAXException, IOException {
+// return new InputSource(new ByteArrayInputStream(new byte[0]));
+// }
+// }
+
+
+ //if Debug is enabled make a copy of inputStream to enable debug output in case of SAXException
+ byte buffer [] = null;
+ ByteArrayInputStream baStream = null;
+ if(true == log.isDebugEnabled()) {
+ buffer = IOUtils.toByteArray(inputStream);
+ baStream = new ByteArrayInputStream(buffer);
+
+ }
+
+
+
+ // create the DOM parser
+ if (symbolTable != null) {
+ parser = new DOMParser(symbolTable, grammarPool);
+ } else {
+ parser = new DOMParser();
+ }
+
+ // set parser features and properties
+ try {
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, validating);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, validating);
+ parser.setFeature(NORMALIZED_VALUE_FEATURE, false);
+ parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true);
+ parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false);
+ parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false);
+ parser.setFeature(EXTERNAL_PARAMETER_ENTITIES_FEATURE, false);
+
+ //set external added parser features
+ if (parserFeatures != null) {
+ for (Entry<String, Object> el : parserFeatures.entrySet()) {
+ String key = el.getKey();
+ if (StringUtils.isNotEmpty(key)) {
+ Object value = el.getValue();
+ if (value != null && value instanceof Boolean)
+ parser.setFeature(key, (boolean)value);
+
+ else
+ log.warn("This XML parser only allows features with 'boolean' values");
+
+ } else
+ log.warn("Can not set 'null' feature to XML parser");
+ }
+ }
+
+ //fix XXE problem
+ //parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+
+
+ if (validating) {
+ if (externalSchemaLocations != null) {
+ parser.setProperty(
+ EXTERNAL_SCHEMA_LOCATION_PROPERTY,
+ externalSchemaLocations);
+ }
+ if (externalNoNamespaceSchemaLocation != null) {
+ parser.setProperty(
+ EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY,
+ externalNoNamespaceSchemaLocation);
+ }
+ }
+
+ // set entity resolver and error handler
+ if (entityResolver != null) {
+ parser.setEntityResolver(entityResolver);
+ }
+ if (errorHandler != null) {
+ parser.setErrorHandler(errorHandler);
+ }
+
+ // parse the document and return it
+ // if debug is enabled: use copy of strem (baStream) else use orig stream
+ if(null != baStream)
+ parser.parse(new InputSource(baStream));
+ else
+ parser.parse(new InputSource(inputStream));
+ } catch(SAXException e) {
+ if(true == log.isDebugEnabled() && null != buffer) {
+ String xmlContent = new String(buffer);
+ log.debug("SAXException in:\n" + xmlContent);
+ }
+ throw(e);
+ }
+
+ return parser.getDocument();
+ }
+
+ /**
+ * Parse an XML document from an <code>InputStream</code>.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @param entityResolver An <code>EntityResolver</code> to resolve external
+ * entities (schemas and DTDs). If <code>null</code>, it will not be set.
+ * @param errorHandler An <code>ErrorHandler</code> to decide what to do
+ * with parsing errors. If <code>null</code>, it will not be set.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocumentSimple(InputStream inputStream)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ DOMParser parser;
+
+ parser = new DOMParser();
+ // set parser features and properties
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, false);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, false);
+ parser.setFeature(NORMALIZED_VALUE_FEATURE, false);
+ parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true);
+ parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false);
+
+ parser.parse(new InputSource(inputStream));
+
+ return parser.getDocument();
+ }
+
+
+ /**
+ * Parse an XML document from an <code>InputStream</code>.
+ *
+ * It uses a <code>MOAEntityResolver</code> as the <code>EntityResolver</code>
+ * and a <code>MOAErrorHandler</code> as the <code>ErrorHandler</code>.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @param parserFeatures
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ InputStream inputStream,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation, Map<String, Object> parserFeatures)
+ throws SAXException, IOException, ParserConfigurationException {
+
+
+
+ return parseDocument(
+ inputStream,
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation,
+ new EAAFDomEntityResolver(),
+ null,
+ parserFeatures);
+ }
+
+ /**
+ * Parse an XML document from a <code>String</code>.
+ *
+ * It uses a <code>MOAEntityResolver</code> as the <code>EntityResolver</code>
+ * and a <code>MOAErrorHandler</code> as the <code>ErrorHandler</code>.
+ *
+ * @param xmlString The <code>String</code> containing the XML document.
+ * @param encoding The encoding of the XML document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ String xmlString,
+ String encoding,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation,
+ Map<String, Object> parserFeatures)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding));
+ return parseDocument(
+ in,
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation,
+ parserFeatures);
+ }
+
+
+ /**
+ * Parse an XML document from a <code>String</code>.
+ *
+ * It uses a <code>MOAEntityResolver</code> as the <code>EntityResolver</code>
+ * and a <code>MOAErrorHandler</code> as the <code>ErrorHandler</code>.
+ *
+ * @param xmlString The <code>String</code> containing the XML document.
+ * @param encoding The encoding of the XML document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ String xmlString,
+ String encoding,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding));
+ return parseDocument(
+ in,
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation,
+ null);
+ }
+
+ /**
+ * Parse an UTF-8 encoded XML document from a <code>String</code>.
+ *
+ * @param xmlString The <code>String</code> containing the XML document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ String xmlString,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ return parseDocument(
+ xmlString,
+ "UTF-8",
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation);
+ }
+
+ /**
+ * A convenience method to parse an XML document validating.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @return The root element of the parsed XML document.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Element parseXmlValidating(InputStream inputStream)
+ throws ParserConfigurationException, SAXException, IOException {
+ return DOMUtils
+ .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, null)
+ .getDocumentElement();
+ }
+
+ /**
+ * A convenience method to parse an XML document validating.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param parserFeatures Set additional features to XML parser
+ * @return The root element of the parsed XML document.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Element parseXmlValidating(InputStream inputStream, Map<String, Object> parserFeatures)
+ throws ParserConfigurationException, SAXException, IOException {
+ return DOMUtils
+ .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, parserFeatures)
+ .getDocumentElement();
+ }
+
+ /**
+ * A convenience method to parse an XML document non validating.
+ * This method disallow DocType declarations
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @return The root element of the parsed XML document.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Element parseXmlNonValidating(InputStream inputStream)
+ throws ParserConfigurationException, SAXException, IOException {
+ return DOMUtils
+ .parseDocument(inputStream, false, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null,
+ Collections.unmodifiableMap(new HashMap<String, Object>() {
+ private static final long serialVersionUID = 1L;
+ {
+ put(DOMUtils.DISALLOW_DOCTYPE_FEATURE, true);
+
+ }
+ })).getDocumentElement();
+ }
+
+ /**
+ * Schema validate a given DOM element.
+ *
+ * @param element The element to validate.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return <code>true</code>, if the <code>element</code> validates against
+ * the schemas declared in it.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document from its
+ * serialized representation.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * @throws TransformerException An error occurred serializing the element.
+ */
+ public static boolean validateElement(
+ Element element,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation)
+ throws
+ ParserConfigurationException,
+ IOException,
+ SAXException,
+ TransformerException {
+
+ byte[] docBytes;
+ SAXParser parser;
+
+ // create the SAX parser
+ if (symbolTable != null) {
+ parser = new SAXParser(symbolTable, grammarPool);
+ } else {
+ parser = new SAXParser();
+ }
+
+ // serialize the document
+ docBytes = serializeNode(element, "UTF-8");
+
+ // set up parser features and attributes
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, true);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, true);
+ parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false);
+ parser.setFeature(DISALLOW_DOCTYPE_FEATURE, true);
+
+
+ if (externalSchemaLocations != null) {
+ parser.setProperty(
+ EXTERNAL_SCHEMA_LOCATION_PROPERTY,
+ externalSchemaLocations);
+ }
+ if (externalNoNamespaceSchemaLocation != null) {
+ parser.setProperty(
+ EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY,
+ "externalNoNamespaceSchemaLocation");
+ }
+
+ // set up entity resolver and error handler
+ parser.setEntityResolver(new EAAFDomEntityResolver());
+
+ // parse validating
+ parser.parse(new InputSource(new ByteArrayInputStream(docBytes)));
+ return true;
+ }
+
+
+ /**
+ * Schema validate a given DOM element.
+ *
+ * @param element The element to validate.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return <code>true</code>, if the <code>element</code> validates against
+ * the schemas declared in it.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document from its
+ * serialized representation.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * @throws TransformerException An error occurred serializing the element.
+ */
+ public static boolean validateElement(
+ Element element,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation,
+ EntityResolver entityResolver)
+ throws
+ ParserConfigurationException,
+ IOException,
+ SAXException,
+ TransformerException {
+
+ byte[] docBytes;
+ SAXParser parser;
+
+ // create the SAX parser
+ if (symbolTable != null) {
+ parser = new SAXParser(symbolTable, grammarPool);
+ } else {
+ parser = new SAXParser();
+ }
+
+ // serialize the document
+ docBytes = serializeNode(element, "UTF-8");
+
+ // set up parser features and attributes
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, true);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, true);
+
+ if (externalSchemaLocations != null) {
+ parser.setProperty(
+ EXTERNAL_SCHEMA_LOCATION_PROPERTY,
+ externalSchemaLocations);
+ }
+ if (externalNoNamespaceSchemaLocation != null) {
+ parser.setProperty(
+ EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY,
+ "externalNoNamespaceSchemaLocation");
+ }
+
+ // set up entity resolver and error handler
+ parser.setEntityResolver(entityResolver);
+
+ // parse validating
+ parser.parse(new InputSource(new ByteArrayInputStream(docBytes)));
+ return true;
+ }
+
+ /**
+ * Serialize the given DOM node.
+ *
+ * The node will be serialized using the UTF-8 encoding.
+ *
+ * @param node The node to serialize.
+ * @return String The <code>String</code> representation of the given DOM
+ * node.
+ * @throws TransformerException An error occurred transforming the
+ * node to a <code>String</code>.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static String serializeNode(Node node)
+ throws TransformerException, IOException {
+ return new String(serializeNode(node, "UTF-8", false), "UTF-8");
+ }
+
+
+ /**
+ * Serialize the given DOM node.
+ *
+ * The node will be serialized using the UTF-8 encoding.
+ *
+ * @param node The node to serialize.
+ * @param omitXmlDeclaration The boolean value for omitting the XML Declaration.
+ * @return String The <code>String</code> representation of the given DOM
+ * node.
+ * @throws TransformerException An error occurred transforming the
+ * node to a <code>String</code>.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static String serializeNode(Node node, boolean omitXmlDeclaration)
+ throws TransformerException, IOException {
+ return new String(serializeNode(node, "UTF-8", omitXmlDeclaration), "UTF-8");
+ }
+
+ /**
+ * Serialize the given DOM node.
+ *
+ * The node will be serialized using the UTF-8 encoding.
+ *
+ * @param node The node to serialize.
+ * @param omitXmlDeclaration The boolean value for omitting the XML Declaration.
+ * @param lineSeperator Sets the line seperator String of the parser
+ * @return String The <code>String</code> representation of the given DOM
+ * node.
+ * @throws TransformerException An error occurred transforming the
+ * node to a <code>String</code>.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static String serializeNode(Node node, boolean omitXmlDeclaration, String lineSeperator)
+ throws TransformerException, IOException {
+ return new String(serializeNode(node, "UTF-8", omitXmlDeclaration, lineSeperator), "UTF-8");
+ }
+
+ /**
+ * Serialize the given DOM node to a byte array.
+ *
+ * @param node The node to serialize.
+ * @param xmlEncoding The XML encoding to use.
+ * @return The serialized node, as a byte array. Using a compatible encoding
+ * this can easily be converted into a <code>String</code>.
+ * @throws TransformerException An error occurred transforming the node to a
+ * byte array.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static byte[] serializeNode(Node node, String xmlEncoding)
+ throws TransformerException, IOException {
+ return serializeNode(node, xmlEncoding, false);
+ }
+
+ /**
+ * Serialize the given DOM node to a byte array.
+ *
+ * @param node The node to serialize.
+ * @param xmlEncoding The XML encoding to use.
+ * @param omitDeclaration The boolean value for omitting the XML Declaration.
+ * @return The serialized node, as a byte array. Using a compatible encoding
+ * this can easily be converted into a <code>String</code>.
+ * @throws TransformerException An error occurred transforming the node to a
+ * byte array.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static byte[] serializeNode(Node node, String xmlEncoding, boolean omitDeclaration)
+ throws TransformerException, IOException {
+ return serializeNode(node, xmlEncoding, omitDeclaration, null);
+ }
+
+
+ /**
+ * Serialize the given DOM node to a byte array.
+ *
+ * @param node The node to serialize.
+ * @param xmlEncoding The XML encoding to use.
+ * @param omitDeclaration The boolean value for omitting the XML Declaration.
+ * @param lineSeperator Sets the line seperator String of the parser
+ * @return The serialized node, as a byte array. Using a compatible encoding
+ * this can easily be converted into a <code>String</code>.
+ * @throws TransformerException An error occurred transforming the node to a
+ * byte array.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static byte[] serializeNode(Node node, String xmlEncoding, boolean omitDeclaration, String lineSeperator)
+ throws TransformerException, IOException {
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(16384);
+
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.ENCODING, xmlEncoding);
+ String omit = omitDeclaration ? "yes" : "no";
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, omit);
+ if (null!=lineSeperator) {
+ transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", lineSeperator);//does not work for xalan <= 2.5.1
+ }
+ transformer.transform(new DOMSource(node), new StreamResult(bos));
+
+ bos.flush();
+ bos.close();
+
+ return bos.toByteArray();
+ }
+
+ /**
+ * Return the text that a node contains.
+ *
+ * This routine:
+ * <ul>
+ * <li>Ignores comments and processing instructions.</li>
+ * <li>Concatenates TEXT nodes, CDATA nodes, and the results recursively
+ * processing EntityRef nodes.</li>
+ * <li>Ignores any element nodes in the sublist. (Other possible options are
+ * to recurse into element sublists or throw an exception.)</li>
+ * </ul>
+ *
+ * @param node A DOM node from which to extract text.
+ * @return A String representing its contents.
+ */
+ public static String getText(Node node) {
+ if (!node.hasChildNodes()) {
+ return "";
+ }
+
+ StringBuffer result = new StringBuffer();
+ NodeList list = node.getChildNodes();
+
+ for (int i = 0; i < list.getLength(); i++) {
+ Node subnode = list.item(i);
+ if (subnode.getNodeType() == Node.TEXT_NODE) {
+ result.append(subnode.getNodeValue());
+ } else if (subnode.getNodeType() == Node.CDATA_SECTION_NODE) {
+ result.append(subnode.getNodeValue());
+ } else if (subnode.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ // Recurse into the subtree for text
+ // (and ignore comments)
+ result.append(getText(subnode));
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Build the namespace prefix to namespace URL mapping in effect for a given
+ * node.
+ *
+ * @param node The context node for which build the map.
+ * @return The namespace prefix to namespace URL mapping (
+ * a <code>String</code> value to <code>String</code> value mapping).
+ */
+ public static Map getNamespaceDeclarations(Node node) {
+ Map nsDecls = new HashMap();
+ int i;
+
+ do {
+ if (node.hasAttributes()) {
+ NamedNodeMap attrs = node.getAttributes();
+
+ for (i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr) attrs.item(i);
+
+ // add prefix mapping if none exists
+ if ("xmlns".equals(attr.getPrefix())
+ || "xmlns".equals(attr.getName())) {
+
+ String nsPrefix =
+ attr.getPrefix() != null ? attr.getLocalName() : "";
+
+ if (nsDecls.get(nsPrefix) == null) {
+ nsDecls.put(nsPrefix, attr.getValue());
+ }
+ }
+ }
+ }
+ } while ((node = node.getParentNode()) != null);
+
+ return nsDecls;
+ }
+
+ /**
+ * Add all namespace declarations declared in the parent(s) of a given
+ * element and used in the subtree of the given element to the given element.
+ *
+ * @param context The element to which to add the namespaces.
+ */
+ public static void localizeNamespaceDeclarations(Element context) {
+ Node parent = context.getParentNode();
+
+ if (parent != null) {
+ Map namespaces = getNamespaceDeclarations(context.getParentNode());
+ Set nsUris = collectNamespaceURIs(context);
+ Iterator iter;
+
+ for (iter = namespaces.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry e = (Map.Entry) iter.next();
+
+ if (nsUris.contains(e.getValue())) {
+ String prefix = (String) e.getKey();
+ String nsUri = (String) e.getValue();
+ String nsAttrName = "".equals(prefix) ? "xmlns" : "xmlns:" + prefix;
+
+ context.setAttributeNS(XMLNamespaceConstants.XMLNS_NS_URI, nsAttrName, nsUri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Collect all the namespace URIs used in the subtree of a given element.
+ *
+ * @param context The element that should be searched for namespace URIs.
+ * @return All namespace URIs used in the subtree of <code>context</code>,
+ * including the ones used in <code>context</code> itself.
+ */
+ public static Set collectNamespaceURIs(Element context) {
+ Set result = new HashSet();
+
+ collectNamespaceURIsImpl(context, result);
+ return result;
+ }
+
+ /**
+ * A recursive method to do the work of <code>collectNamespaceURIs</code>.
+ *
+ * @param context The context element to evaluate.
+ * @param result The result, passed as a parameter to avoid unnecessary
+ * instantiations of <code>Set</code>.
+ */
+ private static void collectNamespaceURIsImpl(Element context, Set result) {
+ NamedNodeMap attrs = context.getAttributes();
+ NodeList childNodes = context.getChildNodes();
+ String nsUri;
+ int i;
+
+ // add the namespace of the context element
+ nsUri = context.getNamespaceURI();
+ if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) {
+ result.add(nsUri);
+ }
+
+ // add all namespace URIs from attributes
+ for (i = 0; i < attrs.getLength(); i++) {
+ nsUri = attrs.item(i).getNamespaceURI();
+ if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) {
+ result.add(nsUri);
+ }
+ }
+
+ // add all namespaces from subelements
+ for (i = 0; i < childNodes.getLength(); i++) {
+ Node node = childNodes.item(i);
+
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ collectNamespaceURIsImpl((Element) node, result);
+ }
+ }
+ }
+
+ /**
+ * Check, that each attribute node in the given <code>NodeList</code> has its
+ * parent in the <code>NodeList</code> as well.
+ *
+ * @param nodes The <code>NodeList</code> to check.
+ * @return <code>true</code>, if each attribute node in <code>nodes</code>
+ * has its parent in <code>nodes</code> as well.
+ */
+ public static boolean checkAttributeParentsInNodeList(NodeList nodes) {
+ Set nodeSet = new HashSet();
+ int i;
+
+ // put the nodes into the nodeSet
+ for (i = 0; i < nodes.getLength(); i++) {
+ nodeSet.add(nodes.item(i));
+ }
+
+ // check that each attribute node's parent is in the node list
+ for (i = 0; i < nodes.getLength(); i++) {
+ Node n = nodes.item(i);
+
+ if (n.getNodeType() == Node.ATTRIBUTE_NODE) {
+ Attr attr = (Attr) n;
+ Element owner = attr.getOwnerElement();
+
+ if (owner == null) {
+ if (!isNamespaceDeclaration(attr)) {
+ return false;
+ }
+ }
+
+ if (!nodeSet.contains(owner) && !isNamespaceDeclaration(attr)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert an unstructured <code>NodeList</code> into a
+ * <code>DocumentFragment</code>.
+ *
+ * @param nodeList Contains the node list to be converted into a DOM
+ * DocumentFragment.
+ * @return the resulting DocumentFragment. The DocumentFragment will be
+ * backed by a new DOM Document, i.e. all noded of the node list will be
+ * cloned.
+ * @throws ParserConfigurationException An error occurred creating the
+ * DocumentFragment.
+ * @precondition The nodes in the node list appear in document order
+ * @precondition for each Attr node in the node list, the owning Element is
+ * in the node list as well.
+ * @precondition each Element or Attr node in the node list is namespace
+ * aware.
+ */
+ public static DocumentFragment nodeList2DocumentFragment(NodeList nodeList)
+ throws ParserConfigurationException {
+
+ DocumentBuilder builder =
+ DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document doc = builder.newDocument();
+ DocumentFragment result = doc.createDocumentFragment();
+
+ if (null == nodeList || nodeList.getLength() == 0) {
+ return result;
+ }
+
+ int currPos = 0;
+ currPos =
+ nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1;
+
+ while (currPos < nodeList.getLength()) {
+ currPos =
+ nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1;
+ }
+ return result;
+ }
+
+ /**
+ * Helper method for the <code>nodeList2DocumentFragment</code>.
+ *
+ * @param nodeList The <code>NodeList</code> to convert.
+ * @param currPos The current position in the <code>nodeList</code>.
+ * @param result The resulting <code>DocumentFragment</code>.
+ * @param currOrgElem The current original element.
+ * @param currClonedElem The current cloned element.
+ * @return The current position.
+ */
+ private static int nodeList2DocumentFragment(
+ NodeList nodeList,
+ int currPos,
+ DocumentFragment result,
+ Element currOrgElem,
+ Element currClonedElem) {
+
+ while (currPos < nodeList.getLength()) {
+ Node currentNode = nodeList.item(currPos);
+ switch (currentNode.getNodeType()) {
+ case Node.COMMENT_NODE :
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ case Node.TEXT_NODE :
+ {
+ // Append current node either to resulting DocumentFragment or to
+ // current cloned Element
+ if (null == currClonedElem) {
+ result.appendChild(
+ result.getOwnerDocument().importNode(currentNode, false));
+ } else {
+ // Stop processing if current Node is not a descendant of
+ // current Element
+ if (!isAncestor(currOrgElem, currentNode)) {
+ return --currPos;
+ }
+
+ currClonedElem.appendChild(
+ result.getOwnerDocument().importNode(currentNode, false));
+ }
+ break;
+ }
+
+ case Node.ELEMENT_NODE :
+ {
+ Element nextCurrOrgElem = (Element) currentNode;
+ Element nextCurrClonedElem =
+ result.getOwnerDocument().createElementNS(
+ nextCurrOrgElem.getNamespaceURI(),
+ nextCurrOrgElem.getNodeName());
+
+ // Append current Node either to resulting DocumentFragment or to
+ // current cloned Element
+ if (null == currClonedElem) {
+ result.appendChild(nextCurrClonedElem);
+ currOrgElem = nextCurrOrgElem;
+ currClonedElem = nextCurrClonedElem;
+ } else {
+ // Stop processing if current Node is not a descendant of
+ // current Element
+ if (!isAncestor(currOrgElem, currentNode)) {
+ return --currPos;
+ }
+
+ currClonedElem.appendChild(nextCurrClonedElem);
+ }
+
+ // Process current Node (of type Element) recursively
+ currPos =
+ nodeList2DocumentFragment(
+ nodeList,
+ ++currPos,
+ result,
+ nextCurrOrgElem,
+ nextCurrClonedElem);
+
+ break;
+ }
+
+ case Node.ATTRIBUTE_NODE :
+ {
+ Attr currAttr = (Attr) currentNode;
+
+ // GK 20030411: Hack to overcome problems with IAIK IXSIL
+ if (currAttr.getOwnerElement() == null)
+ break;
+ if (currClonedElem == null)
+ break;
+
+ // currClonedElem must be the owner Element of currAttr if
+ // preconditions are met
+ currClonedElem.setAttributeNS(
+ currAttr.getNamespaceURI(),
+ currAttr.getNodeName(),
+ currAttr.getValue());
+ break;
+ }
+
+ default :
+ {
+ // All other nodes will be ignored
+ }
+ }
+
+ currPos++;
+ }
+
+ return currPos;
+ }
+
+ /**
+ * Check, if the given attribute is a namespace declaration.
+ *
+ * @param attr The attribute to check.
+ * @return <code>true</code>, if the attribute is a namespace declaration,
+ * <code>false</code> otherwise.
+ */
+ private static boolean isNamespaceDeclaration(Attr attr) {
+ return XMLNamespaceConstants.XMLNS_NS_URI.equals(attr.getNamespaceURI());
+ }
+
+ /**
+ * Check, if a given DOM element is an ancestor of a given node.
+ *
+ * @param candAnc The DOM element to check for being the ancestor.
+ * @param cand The node to check for being the child.
+ * @return <code>true</code>, if <code>candAnc</code> is an (indirect)
+ * ancestor of <code>cand</code>; <code>false</code> otherwise.
+ */
+ public static boolean isAncestor(Element candAnc, Node cand) {
+ Node currPar = cand.getParentNode();
+
+ while (currPar != null) {
+ if (candAnc == currPar)
+ return true;
+ currPar = currPar.getParentNode();
+ }
+ return false;
+ }
+
+ /**
+ * Selects the (first) element from a node list and returns it.
+ *
+ * @param nl The NodeList to get the element from.
+ * @return The (first) element included in the node list or <code>null</code>
+ * if the node list is <code>null</code> or empty or no element is
+ * included in the list.
+ */
+ public static Element getElementFromNodeList (NodeList nl) {
+ if ((nl == null) || (nl.getLength() == 0)) {
+ return null;
+ }
+ for (int i=0; i<nl.getLength(); i++) {
+ Node node = nl.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ return (Element)node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns all child elements of the given element.
+ *
+ * @param parent The element to get the child elements from.
+ *
+ * @return A list including all child elements of the given element.
+ * Maybe empty if the parent element has no child elements.
+ */
+ public static List getChildElements (Element parent) {
+ Vector v = new Vector();
+ NodeList nl = parent.getChildNodes();
+ int length = nl.getLength();
+ for (int i=0; i < length; i++) {
+ Node node = nl.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ v.add((Element)node);
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Returns a byte array from given node.
+ * @param node
+ * @return
+ * @throws TransformerException
+ */
+ public static byte[] nodeToByteArray(Node node) throws TransformerException {
+ Source source = new DOMSource(node);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ //StringWriter stringWriter = new StringWriter();
+ Result result = new StreamResult(out);
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer transformer = factory.newTransformer();
+ transformer.transform(source, result);
+ return out.toByteArray();
+ }
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java
new file mode 100644
index 00000000..de8fda45
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID 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.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID 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.egiz.eaaf.core.impl.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+
+/**
+ * Builds a DataURL parameter meant for the security layer implementation
+ * to respond to.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class DataURLBuilder {
+
+ /**
+ * Constructor for DataURLBuilder.
+ */
+ public DataURLBuilder() {
+ super();
+ }
+
+ /**
+ * Constructs a data URL for <code>VerifyIdentityLink</code> or <code>VerifyAuthenticationBlock</code>,
+ * including the <code>MOASessionID</code> as a parameter.
+ *
+ * @param authBaseURL base URL (context path) of the MOA ID Authentication component,
+ * including a trailing <code>'/'</code>
+ * @param authServletName request part of the data URL
+ * @param pendingReqId sessionID to be included in the dataURL
+ * @return String
+ */
+ public String buildDataURL(String authBaseURL, String authServletName, String pendingReqId) {
+ String dataURL;
+ if (!authBaseURL.endsWith("/"))
+ authBaseURL += "/";
+
+ if (authServletName.startsWith("/"))
+ authServletName = authServletName.substring(1);
+
+ dataURL = authBaseURL + authServletName;
+
+ if (StringUtils.isNotEmpty(pendingReqId))
+ dataURL = addParameter(dataURL, EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReqId);
+
+ return dataURL;
+ }
+
+ /**
+ * Method addParameter.
+ * @param urlString represents the url
+ * @param paramname is the parameter to be added
+ * @param value is the value of that parameter
+ * @return String
+ */
+ private String addParameter(String urlString, String paramname, String value) {
+ String url = urlString;
+ if (paramname != null) {
+ if (url.indexOf("?") < 0)
+ url += "?";
+ else
+ url += "&";
+ url += paramname + "=" + value;
+ }
+ return url;
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java
new file mode 100644
index 00000000..5b39386c
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.InputStream;
+
+import org.apache.xerces.util.URI;
+import org.apache.xerces.util.URI.MalformedURIException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+
+/**
+ * An <code>EntityResolver</code> that looks up entities stored as
+ * local resources.
+ *
+ * <p>The following DTDs are mapped to local resources:
+ * <ul>
+ * <li>The XMLSchema.dtd</li>
+ * <li>The datatypes.dtd</li>
+ * </ul>
+ * </p>
+ * <p>For all other resources, an attempt is made to resolve them as resources,
+ * either absolute or relative to <code>Constants.SCHEMA_ROOT</code>.
+ *
+ */
+public class EAAFDomEntityResolver implements EntityResolver {
+ private static final Logger log = LoggerFactory.getLogger(EAAFDomEntityResolver.class);
+
+ /**
+ * Resolve an entity.
+ *
+ * The <code>systemId</code> parameter is used to perform the lookup of the
+ * entity as a resource, either by interpreting the <code>systemId</code> as
+ * an absolute resource path, or by appending the last path component of
+ * <code>systemId</code> to <code>Constants.SCHEMA_ROOT</code>.
+ *
+ * @param publicId The public ID of the resource.
+ * @param systemId The system ID of the resource.
+ * @return An <code>InputSource</code> from which the entity can be read, or
+ * <code>null</code>, if the entity could not be found.
+ * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
+ */
+ public InputSource resolveEntity(String publicId, String systemId) {
+ InputStream stream;
+ int slashPos;
+
+ if (publicId != null) {
+ // check if we can resolve some standard dtd's
+ if (publicId.equalsIgnoreCase("-//W3C//DTD XMLSchema 200102//EN")) {
+ return new InputSource(
+ getClass().getResourceAsStream(
+ XMLNamespaceConstants.SCHEMA_ROOT + "XMLSchema.dtd"));
+ } else if (publicId.equalsIgnoreCase("datatypes")) {
+ return new InputSource(
+ getClass().getResourceAsStream(
+ XMLNamespaceConstants.SCHEMA_ROOT + "datatypes.dtd"));
+ }
+ } else if (systemId != null) {
+ // get the URI path
+ try {
+ URI uri = new URI(systemId);
+ systemId = uri.getPath();
+
+ if (!"file".equals(uri.getScheme()) || "".equals(systemId.trim())) {
+ return null;
+ }
+
+ } catch (MalformedURIException e) {
+ return null;
+ }
+
+ // try to get the resource from the full path
+ stream = getClass().getResourceAsStream(systemId);
+ if (stream != null) {
+ InputSource source = new InputSource(stream);
+
+ source.setSystemId(systemId);
+ return source;
+ }
+
+ // try to get the resource from the last path component
+ slashPos = systemId.lastIndexOf('/');
+ if (slashPos >= 0 && systemId.length() > slashPos) {
+ systemId = systemId.substring(slashPos + 1, systemId.length());
+ stream =
+ getClass().getResourceAsStream(XMLNamespaceConstants.SCHEMA_ROOT + systemId);
+ if (stream != null) {
+ InputSource source = new InputSource(stream);
+
+ source.setSystemId(systemId);
+ return source;
+ }
+ }
+ }
+
+ return null; // nothing found - let the parser handle the entity
+ }
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java
new file mode 100644
index 00000000..01fb7375
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+/**
+ * Utility for accessing files on the file system, and for reading from input streams.
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class FileUtils {
+
+ /**
+ * Reads a file, given by URL, into a byte array.
+ * @param urlString file URL
+ * @return file content
+ * @throws IOException on any exception thrown
+ */
+ public static byte[] readURL(String urlString) throws IOException {
+ URL url = new URL(urlString);
+ InputStream in = new BufferedInputStream(url.openStream());
+ byte[] content = StreamUtils.readStream(in);
+ in.close();
+ return content;
+ }
+
+ /**
+ * Reads a file from a resource.
+ * @param name resource name
+ * @return file content as a byte array
+ * @throws IOException on any exception thrown
+ */
+ public static byte[] readResource(String name) throws IOException {
+ ClassLoader cl = FileUtils.class.getClassLoader();
+ BufferedInputStream in = new BufferedInputStream(cl.getResourceAsStream(name));
+ byte[] content = StreamUtils.readStream(in);
+ in.close();
+ return content;
+ }
+ /**
+ * Reads a file from a resource.
+ * @param name filename
+ * @param encoding character encoding
+ * @return file content
+ * @throws IOException on any exception thrown
+ */
+ public static String readResource(String name, String encoding) throws IOException {
+ byte[] content = readResource(name);
+ return new String(content, encoding);
+ }
+
+
+ /**
+ * Returns the absolute URL of a given url which is relative to the parameter root
+ * @param url
+ * @param root
+ * @return String
+ * @throws MalformedURLException
+ */
+ public static String makeAbsoluteURL(String url, URI root) throws MalformedURLException {
+ return makeAbsoluteURL(url, root.toURL().toString());
+
+ }
+
+ /**
+ * Returns the absolute URL of a given url which is relative to the parameter root
+ * @param url
+ * @param root
+ * @return String
+ */
+ public static String makeAbsoluteURL(String url, String root) {
+ //if url is relative to rootConfigFileDirName make it absolute
+
+ File keyFile;
+ String newURL = url;
+
+ if(null == url) return null;
+
+ if (url.startsWith("http:/") || url.startsWith("https:/") || url.startsWith("file:/") || url.startsWith("ftp:/")) {
+ return url;
+
+ } else {
+ // check if absolute - if not make it absolute
+ keyFile = new File(url);
+ if (!keyFile.isAbsolute()) {
+ keyFile = new File(root, url);
+
+ if (keyFile.toString().startsWith("file:"))
+ newURL = keyFile.toString();
+
+ else
+ newURL = keyFile.toURI().toString();
+
+ }
+ return newURL;
+ }
+ }
+
+
+ private static void copy( InputStream fis, OutputStream fos )
+ {
+ try
+ {
+ byte[] buffer = new byte[ 0xFFFF ];
+ for ( int len; (len = fis.read(buffer)) != -1; )
+ fos.write( buffer, 0, len );
+ }
+ catch( IOException e ) {
+ System.err.println( e );
+ }
+ finally {
+ if ( fis != null )
+ try { fis.close(); } catch ( IOException e ) { e.printStackTrace(); }
+ if ( fos != null )
+ try { fos.close(); } catch ( IOException e ) { e.printStackTrace(); }
+ }
+ }
+
+ public static void copyFile(File src, File dest)
+ {
+ try
+ {
+ copy( new FileInputStream( src ), new FileOutputStream( dest ) );
+ }
+ catch( IOException e ) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java
new file mode 100644
index 00000000..cf1abaa7
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID 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.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID 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.egiz.eaaf.core.impl.utils;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+
+
+/**
+ *
+ * @author Rudolf Schamberger
+ *
+ */
+public class HTTPUtils {
+
+// /**
+// * Utility used to obtainin correct encoded HTTP content.
+// * Reads a given Content adressed by HTTP-URL into String.
+// * Content encoding is considered by using the Content-Type HTTP header charset value.
+// * @param URL HTTP URL to read from.
+// * @return String representation of content
+// * @throws IOException on data-reading problems
+// */
+// public static String readHttpURL(String URL)
+// throws IOException {
+//
+// URL url = new URL(URL);
+// HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+// conn.setRequestMethod("GET");
+// String contentType = conn.getContentType();
+// RE regExp = null;
+// try {
+// regExp = new RE("(;.*charset=)(\"*)(.*[^\"])");
+// } catch (RESyntaxException e) {
+// //RESyntaxException is not possible = expr. is costant
+// }
+// boolean charsetSupplied = regExp.match(contentType);
+// String encoding = "ISO-8859-1"; //default HTTP encoding
+// if (charsetSupplied) {
+// encoding = regExp.getParen(3);
+// }
+// InputStream instream = new BufferedInputStream(conn.getInputStream());
+// InputStreamReader isr = new InputStreamReader(instream, encoding);
+// Reader in = new BufferedReader(isr);
+// int ch;
+// StringBuffer buffer = new StringBuffer();
+// while ((ch = in.read()) > -1) {
+// buffer.append((char)ch);
+// }
+// in.close();
+// conn.disconnect();
+// return buffer.toString();
+// }
+
+ /**
+ * Helper method to retrieve server URL including context path
+ * @param request HttpServletRequest
+ * @return Server URL including context path (e.g. http://localhost:8443/moa-id-auth
+ */
+ public static String getBaseURL(HttpServletRequest request) {
+ StringBuffer buffer = new StringBuffer(getServerURL(request));
+
+ // add context path if available
+ String contextPath = request.getContextPath();
+ if (!StringUtils.isEmpty(contextPath)) {
+ buffer.append(contextPath);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Helper method to retrieve server URL
+ * @param request HttpServletRequest
+ * @return Server URL (e.g. http://localhost:8443)
+ */
+ public static String getServerURL(HttpServletRequest request) {
+ StringBuffer buffer = new StringBuffer();
+
+ // get protocol
+ String protocol = request.getScheme();
+ buffer.append(protocol).append("://");
+
+ // server name
+ buffer.append(request.getServerName());
+
+ // add port if necessary
+ int port = request.getServerPort();
+ if ((protocol.equals("http") && port != 80) || (protocol.equals("https") && port != 443)) {
+ buffer.append(':');
+ buffer.append(port);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Extract the IDP PublicURLPrefix from authrequest
+ *
+ * @param req HttpServletRequest
+ * @return PublicURLPrefix <String> which ends always without /
+ */
+ public static String extractAuthURLFromRequest(HttpServletRequest req) {
+ String authURL = req.getScheme() + "://" + req.getServerName();
+ if ((req.getScheme().equalsIgnoreCase("https") && req.getServerPort()!=443) || (req.getScheme().equalsIgnoreCase("http") && req.getServerPort()!=80)) {
+ authURL = authURL.concat(":" + req.getServerPort());
+ }
+ authURL = authURL.concat(req.getContextPath());
+ return authURL;
+
+ }
+
+ /**
+ * Extract the IDP requested URL from authrequest
+ *
+ * @param req HttpServletRequest
+ * @return RequestURL <String> which ends always without /
+ */
+ public static String extractAuthServletPathFromRequest(HttpServletRequest req) {
+ return extractAuthURLFromRequest(req).concat(req.getServletPath());
+
+ }
+
+ public static String addURLParameter(String url, String paramname,
+ String paramvalue) {
+ String param = paramname + "=" + paramvalue;
+ if (url.indexOf("?") < 0)
+ return url + "?" + param;
+ else
+ return url + "&" + param;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
new file mode 100644
index 00000000..3583a294
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+
+/**
+ * Utility for creating and loading key stores.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class KeyStoreUtils {
+
+ /**
+ * JAVA KeyStore
+ */
+ private static final String KEYSTORE_TYPE_JKS = "JKS";
+
+ /**
+ * PKCS12 KeyStore
+ */
+ private static final String KEYSTORE_TYPE_PKCS12 = "PKCS12";
+
+
+
+ /**
+ * Loads a key store from file.
+ *
+ * @param keystoreType key store type
+ * @param urlString URL of key store
+ * @param password password protecting the key store
+ * @return key store loaded
+ * @throws IOException thrown while reading the key store from file
+ * @throws GeneralSecurityException thrown while creating the key store
+ */
+ public static KeyStore loadKeyStore(
+ String keystoreType,
+ String urlString,
+ String password)
+ throws IOException, GeneralSecurityException {
+
+ URL keystoreURL = new URL(urlString);
+ InputStream in = keystoreURL.openStream();
+ return loadKeyStore(keystoreType, in, password);
+ }
+ /**
+ * Loads a key store from an <code>InputStream</code>, and
+ * closes the <code>InputStream</code>.
+ *
+ * @param keystoreType key store type
+ * @param in input stream
+ * @param password password protecting the key store
+ * @return key store loaded
+ * @throws IOException thrown while reading the key store from the stream
+ * @throws GeneralSecurityException thrown while creating the key store
+ */
+ public static KeyStore loadKeyStore(
+ String keystoreType,
+ InputStream in,
+ String password)
+ throws IOException, GeneralSecurityException {
+
+ char[] chPassword = null;
+ if (password != null)
+ chPassword = password.toCharArray();
+ KeyStore ks = KeyStore.getInstance(keystoreType);
+ ks.load(in, chPassword);
+ in.close();
+ return ks;
+ }
+ /**
+ * Creates a key store from X509 certificate files, aliasing them with
+ * the index in the <code>String[]</code>, starting with <code>"0"</code>.
+ *
+ * @param keyStoreType key store type
+ * @param certFilenames certificate filenames
+ * @return key store created
+ * @throws IOException thrown while reading the certificates from file
+ * @throws GeneralSecurityException thrown while creating the key store
+ */
+ public static KeyStore createKeyStore(
+ String keyStoreType,
+ String[] certFilenames)
+ throws IOException, GeneralSecurityException {
+
+ KeyStore ks = KeyStore.getInstance(keyStoreType);
+ ks.load(null, null);
+ for (int i = 0; i < certFilenames.length; i++) {
+ Certificate cert = loadCertificate(certFilenames[i]);
+ ks.setCertificateEntry("" + i, cert);
+ }
+ return ks;
+ }
+
+ /**
+ * Loads an X509 certificate from file.
+ * @param certFilename filename
+ * @return the certificate loaded
+ * @throws IOException thrown while reading the certificate from file
+ * @throws GeneralSecurityException thrown while creating the certificate
+ */
+ private static Certificate loadCertificate(String certFilename)
+ throws IOException, GeneralSecurityException {
+
+ FileInputStream in = new FileInputStream(certFilename);
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ Certificate cert = certFactory.generateCertificate(in);
+ in.close();
+ return cert;
+ }
+
+
+ /**
+ * Loads a keyStore without knowing the keyStore type
+ * @param keyStorePath URL to the keyStore
+ * @param password Password protecting the keyStore
+ * @return keyStore loaded
+ * @throws KeyStoreException thrown if keyStore cannot be loaded
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public static KeyStore loadKeyStore(String keyStorePath, String password) throws KeyStoreException, IOException{
+
+ //InputStream is = new FileInputStream(keyStorePath);
+ URL keystoreURL = new URL(keyStorePath);
+ InputStream in = keystoreURL.openStream();
+ InputStream isBuffered = new BufferedInputStream(in);
+ return loadKeyStore(isBuffered, password);
+
+ }
+
+ /**
+ * Loads a keyStore without knowing the keyStore type
+ * @param in input stream
+ * @param password Password protecting the keyStore
+ * @return keyStore loaded
+ * @throws KeyStoreException thrown if keyStore cannot be loaded
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+public static KeyStore loadKeyStore(InputStream is, String password) throws KeyStoreException, IOException{
+ is.mark(1024*1024);
+ KeyStore ks = null;
+ try {
+ try {
+ ks = loadKeyStore(KEYSTORE_TYPE_PKCS12, is, password);
+ } catch (IOException e2) {
+ is.reset();
+ ks = loadKeyStore(KEYSTORE_TYPE_JKS, is, password);
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+
+ }
+ return ks;
+
+ }
+
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
new file mode 100644
index 00000000..49b957cc
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @author tlenz
+ *
+ */
+public class KeyValueUtils {
+
+ public static final String KEY_DELIMITER = ".";
+ public static final String CSV_DELIMITER = ",";
+
+ /**
+ * Convert Java properties into a Map<String, String>
+ * <br><br>
+ * <b>Important:</b> The key/values from properties must be of type String!
+ *
+ * @param properties
+ * @return
+ */
+ public static Map<String, String> convertPropertiesToMap(Properties properties) {
+ return new HashMap<String, String>((Map) properties);
+
+ //INFO Java8 solution ;)
+// return properties.entrySet().stream().collect(
+// Collectors.toMap(
+// e -> e.getKey().toString(),
+// e -> e.getValue().toString()
+// )
+// );
+
+ }
+
+ /**
+ * Extract the first child of an input key after a the prefix
+ *
+ * @param key Full input key
+ * @param prefix Prefix
+ * @return Child key {String} if it exists or null
+ */
+ public static String getFirstChildAfterPrefix(String key, String prefix) {
+ String idAfterPrefix = removePrefixFromKey(key, prefix);
+ if (idAfterPrefix != null) {
+ int index = idAfterPrefix.indexOf(KEY_DELIMITER);
+ if (index > 0) {
+ String adding = idAfterPrefix.substring(0, index);
+ if (!(adding.isEmpty())) {
+ return adding;
+
+ }
+ } else if (!(idAfterPrefix.isEmpty())) {
+ return idAfterPrefix;
+
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * Extract the prefix from an input key
+ *
+ * @param key Full input key
+ * @param suffix Suffix of this key
+ * @return Prefix {String} of the key or null if input key does not ends with postfix string
+ */
+ public static String getPrefixFromKey(String key, String suffix) {
+ if (key != null && key.endsWith(suffix)) {
+ String idPreforeSuffix = key.substring(0, key.length()-suffix.length());
+ if (idPreforeSuffix.endsWith(KEY_DELIMITER))
+ return idPreforeSuffix.substring(0, idPreforeSuffix.length()-1);
+ else
+ return idPreforeSuffix;
+ }
+ return null;
+
+ }
+
+ /**
+ * Remove a prefix string from a key
+ *
+ * @param key Full input key
+ * @param prefix Prefix, which should be removed
+ * @return The suffix of the input key or null if the input does not starts with the prefix
+ */
+ public static String removePrefixFromKey(String key, String prefix) {
+ if (prefix == null)
+ prefix = new String();
+
+ if (key!=null && key.startsWith(prefix)) {
+ String afterPrefix = key.substring(prefix.length());
+ int index = afterPrefix.indexOf(KEY_DELIMITER);
+
+ if (index == 0) {
+ afterPrefix = afterPrefix.substring(1);
+
+ }
+ return afterPrefix;
+
+ }
+ return null;
+ }
+
+ /**
+ * Remove a prefix string from all keys in {Map<String, String>} of key/value pairs
+ *
+ * @param keys Input data of key/value pairs
+ * @param prefix Prefix which should be removed
+ * @return {Map<String, String>} of key/value pairs without prefix in key, but never null
+ */
+ public static Map<String, String> removePrefixFromKeys(Map<String, String> keys, String prefix) {
+ Map<String, String> result = new HashMap<String, String>();
+ Iterator<Entry<String, String>> interator = keys.entrySet().iterator();
+ while(interator.hasNext()) {
+ Entry<String, String> el = interator.next();
+ String newKey = removePrefixFromKey(el.getKey(), prefix);
+ if (StringUtils.isNotEmpty(newKey)) {
+ result.put(newKey, el.getValue());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Get a subset of key/value pairs which starts with a prefix string
+ * The Prefix is removed from the key
+ *
+ * @param keys Input data of key/value pairs
+ * @param prefix Prefix string
+ * @return {Map<String, String>} of key/value pairs without prefix in key, but never null
+ */
+ public static Map<String, String> getSubSetWithPrefix(Map<String, String> keys, String prefix) {
+ return removePrefixFromKeys(keys, prefix);
+ }
+
+
+ /**
+ * Add a prefix to key/value pairs to make the key absolute according to key namespace convention
+ *
+ * @param input Input key/value pairs which should be updated
+ * @param prefix Key prefix, which should be added if the key is not absolute
+ * @param absolutIdentifier Key identifier, which indicates an absolute key
+ * @return {Map<String, String>} of key/value pairs in which all keys are absolute but never null
+ */
+ public static Map<String, String> makeKeysAbsolut(Map<String, String> input, String prefix, String absolutIdentifier) {
+ Map<String, String> result = new HashMap<String, String>();
+ Iterator<Entry<String, String>> interator = input.entrySet().iterator();
+ while(interator.hasNext()) {
+ Entry<String, String> el = interator.next();
+ if (!el.getKey().startsWith(absolutIdentifier)) {
+ //key is not absolute -> add prefix
+ result.put(prefix
+ + KEY_DELIMITER
+ + el.getKey(),
+ el.getValue());
+
+ } else {
+ //key is absolute
+ result.put(el.getKey(), el.getValue());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the parent key string from an input key
+ *
+ * @param key input key
+ * @return parent key or the empty String if no parent exists
+ */
+ public static String getParentKey(String key) {
+ if (StringUtils.isNotEmpty(key)) {
+ int index = key.lastIndexOf(KEY_DELIMITER);
+ if (index > 0) {
+ return key.substring(0, index);
+
+ }
+ }
+
+ return new String();
+ }
+
+ /**
+ * Find the highest free list counter
+ *
+ * @param input Array of list keys
+ * @param listPrefix {String} prefix of the list
+ * @return {int} highest free list counter
+ */
+ public static int findNextFreeListCounter(String[] input,
+ String listPrefix) {
+ List<Integer> counters = new ArrayList<Integer>();
+ if (input == null || input.length == 0)
+ return 0;
+
+ else {
+ for (String key : input) {
+ String listIndex = getFirstChildAfterPrefix(key, listPrefix);
+ counters.add(Integer.parseInt(listIndex));
+
+ }
+ Collections.sort(counters);
+ return counters.get(counters.size()-1) + 1;
+ }
+ }
+
+ /**
+ * Find the highest free list counter
+ *
+ * @param keySet {Set<String>} of list keys
+ * @param listPrefix {String} prefix of the list
+ * @return {int} highest free list counter
+ */
+ public static int findNextFreeListCounter(Set<String> keySet,
+ String listPrefix) {
+ if (keySet.isEmpty())
+ return 0;
+
+ String[] array = new String[keySet.size()];
+ keySet.toArray(array);
+ return findNextFreeListCounter(array, listPrefix);
+ }
+
+
+ /**
+ * Normalize a CSV encoded list of value of an key/value pair
+ *
+ * This method removes all whitespace at the begin or the
+ * end of CSV values and remove newLine signs at the end of value.
+ * The ',' is used as list delimiter
+ *
+ * @param value CSV encoded input data
+ * @return normalized CSV encoded data or null if {value} is null or empty
+ */
+ public static String normalizeCSVValueString(String value) {
+ String normalizedCodes = null;
+ if (StringUtils.isNotEmpty(value)) {
+ String[] codes = value.split(CSV_DELIMITER);
+ for (String el: codes) {
+ if (normalizedCodes == null)
+ normalizedCodes = StringUtils.chomp(el.trim());
+ else
+ normalizedCodes += "," + StringUtils.chomp(el.trim());
+
+ }
+ }
+ return normalizedCodes;
+ }
+
+
+ /**
+ * Check a String if it is a comma separated list of values
+ *
+ * This method uses the ',' as list delimiter.
+ *
+ * @param value CSV encoded input data
+ * @return true if the input data contains a ',' and has more then 1 list element, otherwise false
+ */
+ public static boolean isCSVValueString(String value) {
+ if (StringUtils.isNotEmpty(value)) {
+ String[] codes = value.split(CSV_DELIMITER);
+ if (codes.length >= 2) {
+ if (StringUtils.isNotEmpty(codes[1].trim()))
+ return true;
+
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Convert a CSV list to a List of CSV values
+ * <br><br>
+ * This method removes all whitespace at the begin or the
+ * end of CSV values and remove newLine signs at the end of value.
+ * The ',' is used as list delimiter
+ *
+ * @param csv CSV encoded input data
+ * @return List of CSV normalized values, but never null
+ */
+ public static List<String> getListOfCSVValues(String csv) {
+ List<String> list = new ArrayList<String>();
+ if (StringUtils.isNotEmpty(csv)) {
+ String[] values = csv.split(CSV_DELIMITER);
+ for (String el: values)
+ list.add(el.trim());
+
+ }
+
+ return list;
+ }
+
+ /**
+ * This method remove all newline delimiter (\n or \r\n) from input data
+ *
+ * @param value Input String
+ * @return Input String without newline characters
+ */
+ public static String removeAllNewlineFromString(String value) {
+ return value.replaceAll("(\\t|\\r?\\n)+", "");
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java
new file mode 100644
index 00000000..c752c91f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.ListIterator;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+/**
+ * A <code>NodeIterator</code> implementation based on a
+ * <code>ListIterator</code>.
+ *
+ * @see java.util.ListIterator
+ * @see org.w3c.dom.traversal.NodeIterator
+ *
+ */
+public class NodeIteratorAdapter implements NodeIterator {
+
+ /** The <code>ListIterator</code> to wrap. */
+ private ListIterator nodeIterator;
+
+ /**
+ * Create a new <code>NodeIteratorAdapter</code>.
+ * @param nodeIterator The <code>ListIterator</code> to iterate over.
+ */
+ public NodeIteratorAdapter(ListIterator nodeIterator) {
+ this.nodeIterator = nodeIterator;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getRoot()
+ */
+ public Node getRoot() {
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow()
+ */
+ public int getWhatToShow() {
+ return NodeFilter.SHOW_ALL;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getFilter()
+ */
+ public NodeFilter getFilter() {
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences()
+ */
+ public boolean getExpandEntityReferences() {
+ return false;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#nextNode()
+ */
+ public Node nextNode() throws DOMException {
+ if (nodeIterator.hasNext()) {
+ return (Node) nodeIterator.next();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#previousNode()
+ */
+ public Node previousNode() throws DOMException {
+ if (nodeIterator.hasPrevious()) {
+ return (Node) nodeIterator.previous();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#detach()
+ */
+ public void detach() {
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java
new file mode 100644
index 00000000..61933907
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.List;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * A <code>NodeList</code> implementation based on a <code>List</code>.
+ *
+ * @see java.util.List
+ * @see org.w3c.dom.NodeList
+ */
+
+public class NodeListAdapter implements NodeList {
+ /** The <code>List</code> to wrap. */
+ private List nodeList;
+
+ /**
+ * Create a new <code>NodeListAdapter</code>.
+ *
+ * @param nodeList The <code>List</code> containing the nodes.
+ */
+ public NodeListAdapter(List nodeList) {
+ this.nodeList = nodeList;
+ }
+
+ /**
+ * @see org.w3c.dom.NodeList#item(int)
+ */
+ public Node item(int index) {
+ return (Node) nodeList.get(index);
+ }
+
+ /**
+ * @see org.w3c.dom.NodeList#getLength()
+ */
+ public int getLength() {
+ return nodeList.size();
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java
new file mode 100644
index 00000000..aad90649
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID 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.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID 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.egiz.eaaf.core.impl.utils;
+
+
+import java.nio.ByteBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Random number generator used to generate ID's
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class Random {
+ private static final Logger log = LoggerFactory.getLogger(Random.class);
+
+ private final static char[] allowedPreFix =
+ {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
+ private static final DateFormat dateFormater = new SimpleDateFormat("yyyyddMM");
+
+ /** random number generator used */
+ private static SecureRandom random;
+ //private static SeedGenerator seedgenerator;
+
+ static {
+ try {
+ random = SecureRandom.getInstance("SHA256PRNG-FIPS186");
+
+ } catch (NoSuchAlgorithmException e) {
+ log.warn("Can NOT initialize SecureRandom with: 'SHA256PRNG-FIPS186'. Use 'StrongSecureRandom' as backup");
+
+ try {
+ random = SecureRandom.getInstanceStrong();
+
+ } catch (NoSuchAlgorithmException e1) {
+ log.error("Can NOT initialize SecureRandom. StartUp process FAILED!");
+ throw new RuntimeException("Can NOT initialize SecureRandom. StartUp process FAILED!", e);
+
+ }
+
+ }
+
+
+ //random = iaik.security.random.SHA256FIPS186Random.getDefault();
+ }
+
+ /**
+ * Generate a unique process reference-value [160bit], which always starts with a letter
+ * <br>
+ * This unique ID consists of single letter, a 64bit date String[yyyyddMM],
+ * and a 88bit random value.
+ *
+ * @return 160bit ID, which is hex encoded
+ */
+ public static String nextProcessReferenceValue() {
+ //pre-process all three parts of a unique reference value
+ String now = dateFormater.format(new Date()); //8 bytes = 64bit
+ byte[] randValue = nextByteRandom(11);
+ char preFix = allowedPreFix[Math.abs(random.nextInt() % allowedPreFix.length)];
+
+ //generate ID
+ String returnValue = preFix + new String(Hex.encodeHex(ArrayUtils.addAll(now.getBytes(), randValue))); // 20 bytes = 160 bits
+ if (returnValue.length() > 40)
+ return returnValue.substring(0, 40);
+ else
+ return returnValue;
+
+ }
+
+
+
+ /**
+ * Creates a new random number [256bit], and encode it as hex value.
+ *
+ * @return random hex encoded value [256bit]
+ */
+ public static String nextHexRandom32() {
+ return new String(Hex.encodeHex(nextByteRandom(32))); // 32 bytes = 256 bits
+
+ }
+
+ /**
+ * Creates a new random number [128bit], and encode it as hex value.
+ *
+ * @return random hex encoded value [128bit]
+ */
+ public static String nextHexRandom16() {
+ return new String(Hex.encodeHex(nextByteRandom(16))); // 16 bytes = 128 bits
+
+ }
+
+ /**
+ * Creates a new random number [64bit], to be used as an ID.
+ *
+ * @return random long as a String [64bit]
+ */
+ public static String nextLongRandom() {
+ return "".concat(String.valueOf(Math.abs(generateLongRandom(32)))); // 32 bytes = 256 bits
+
+ }
+
+ /**
+ * Creates a new random number, to be used as an ID.
+ *
+ * @return random long as a String [64bit]
+ */
+ @Deprecated
+ public static String nextRandom() {
+ long l = ByteBuffer.wrap(nextByteRandom(32)).getLong(); // 32 bytes = 256 bits
+ return "" + Math.abs(l);
+
+ }
+
+/**
+ * Creates a new random byte[]
+ *
+ * @param size Size of random number in byte
+ * @return
+ */
+public static byte[] nextBytes(int size) {
+ return nextByteRandom(size);
+
+}
+
+ public static void seedRandom() {
+ //TODO: implement reflection on IAIK Seed generator
+// seedgenerator = iaik.security.random.AutoSeedGenerator.getDefault();
+// if (seedgenerator.seedAvailable())
+// random.setSeed(seedgenerator.getSeed());
+
+ random.setSeed(System.nanoTime());
+ }
+
+ private static long generateLongRandom(int size) {
+ return ByteBuffer.wrap(nextByteRandom(size)).getLong();
+ }
+
+ /**
+ * Generate a new random number
+ *
+ * @param size Size of random number in byte
+ * @return
+ */
+ private static synchronized byte[] nextByteRandom(int size) {
+ byte[] b = new byte[size];
+ random.nextBytes(b);
+ return b;
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java
new file mode 100644
index 00000000..c19e5ab1
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID 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.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID 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.egiz.eaaf.core.impl.utils;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class ServletUtils {
+
+
+ public static String getBaseUrl( HttpServletRequest request ) {
+ if ( ( request.getServerPort() == 80 ) ||
+ ( request.getServerPort() == 443 ) )
+ return request.getScheme() + "://" +
+ request.getServerName() +
+ request.getContextPath();
+ else
+ return request.getScheme() + "://" +
+ request.getServerName() + ":" + request.getServerPort() +
+ request.getContextPath();
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java
new file mode 100644
index 00000000..3e4143d4
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Utility methods for streams.
+ *
+ * @author Patrick Peck
+ * @version $Id$
+ */
+public class StreamUtils {
+
+ /**
+ * Compare the contents of two <code>InputStream</code>s.
+ *
+ * @param is1 The 1st <code>InputStream</code> to compare.
+ * @param is2 The 2nd <code>InputStream</code> to compare.
+ * @return boolean <code>true</code>, if both streams contain the exactly the
+ * same content, <code>false</code> otherwise.
+ * @throws IOException An error occurred reading one of the streams.
+ */
+ public static boolean compareStreams(InputStream is1, InputStream is2)
+ throws IOException {
+
+ byte[] buf1 = new byte[256];
+ byte[] buf2 = new byte[256];
+ int length1;
+ int length2;
+
+ try {
+ while (true) {
+ length1 = is1.read(buf1);
+ length2 = is2.read(buf2);
+
+ if (length1 != length2) {
+ return false;
+ }
+ if (length1 <= 0) {
+ return true;
+ }
+ if (!compareBytes(buf1, buf2, length1)) {
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ // close both streams
+ try {
+ is1.close();
+ is2.close();
+ } catch (IOException e) {
+ // ignore this
+ }
+ }
+ }
+
+ /**
+ * Compare two byte arrays, up to a given maximum length.
+ *
+ * @param b1 1st byte array to compare.
+ * @param b2 2nd byte array to compare.
+ * @param length The maximum number of bytes to compare.
+ * @return <code>true</code>, if the byte arrays are equal, <code>false</code>
+ * otherwise.
+ */
+ private static boolean compareBytes(byte[] b1, byte[] b2, int length) {
+ if (b1.length != b2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < b1.length && i < length; i++) {
+ if (b1[i] != b2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Reads a byte array from a stream.
+ * @param in The <code>InputStream</code> to read.
+ * @return The bytes contained in the given <code>InputStream</code>.
+ * @throws IOException on any exception thrown
+ */
+ public static byte[] readStream(InputStream in) throws IOException {
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(in, out, null);
+
+ /*
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int b;
+ while ((b = in.read()) >= 0)
+ out.write(b);
+
+ */
+ in.close();
+ return out.toByteArray();
+ }
+
+ /**
+ * Reads a <code>String</code> from a stream, using given encoding.
+ * @param in The <code>InputStream</code> to read.
+ * @param encoding The character encoding to use for converting the bytes
+ * of the <code>InputStream</code> into a <code>String</code>.
+ * @return The content of the given <code>InputStream</code> converted into
+ * a <code>String</code>.
+ * @throws IOException on any exception thrown
+ */
+ public static String readStream(InputStream in, String encoding) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(in, out, null);
+
+ /*
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int b;
+ while ((b = in.read()) >= 0)
+ out.write(b);
+ */
+ in.close();
+ return out.toString(encoding);
+ }
+
+ /**
+ * Reads all data (until EOF is reached) from the given source to the
+ * destination stream. If the destination stream is null, all data is dropped.
+ * It uses the given buffer to read data and forward it. If the buffer is
+ * null, this method allocates a buffer.
+ *
+ * @param source The stream providing the data.
+ * @param destination The stream that takes the data. If this is null, all
+ * data from source will be read and discarded.
+ * @param buffer The buffer to use for forwarding. If it is null, the method
+ * allocates a buffer.
+ * @exception IOException If reading from the source or writing to the
+ * destination fails.
+ */
+ private static void copyStream(InputStream source, OutputStream destination, byte[] buffer) throws IOException {
+ if (source == null) {
+ throw new NullPointerException("Argument \"source\" must not be null.");
+ }
+ if (buffer == null) {
+ buffer = new byte[8192];
+ }
+
+ if (destination != null) {
+ int bytesRead;
+ while ((bytesRead = source.read(buffer)) >= 0) {
+ destination.write(buffer, 0, bytesRead);
+ }
+ } else {
+ while (source.read(buffer) >= 0);
+ }
+ }
+
+ /**
+ * Gets the stack trace of the <code>Throwable</code> passed in as a string.
+ * @param t The <code>Throwable</code>.
+ * @return a String representing the stack trace of the <code>Throwable</code>.
+ */
+ public static String getStackTraceAsString(Throwable t)
+ {
+ ByteArrayOutputStream stackTraceBIS = new ByteArrayOutputStream();
+ t.printStackTrace(new PrintStream(stackTraceBIS));
+ return new String(stackTraceBIS.toByteArray());
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java
new file mode 100644
index 00000000..7df211ef
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.utils;
+
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * @author tlenz
+ *
+ */
+public class TransactionIDUtils {
+
+ //MDC variables for logging
+ public static final String MDC_TRANSACTION_ID = "transactionId";
+ public static final String MDC_SESSION_ID = "sessionId";
+ public static final String MDC_SERVICEPROVIDER_ID = "oaId";
+
+ /**
+ * Set all MDC variables from pending request to this threat context<br>
+ * These includes SessionID, TransactionID, and unique service-provider identifier
+ *
+ * @param pendingRequest
+ */
+ public static void setAllLoggingVariables(IRequest pendingRequest) {
+ setTransactionId(pendingRequest.getUniqueTransactionIdentifier());
+ setSessionId(pendingRequest.getUniqueSessionIdentifier());
+ setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier());
+
+ }
+
+ /**
+ * Remove all MDC variables from this threat context
+ *
+ */
+ public static void removeAllLoggingVariables() {
+ removeSessionId();
+ removeTransactionId();
+ removeServiceProviderId();
+
+ }
+
+
+ public static void setServiceProviderId(String oaUniqueId) {
+ org.apache.log4j.MDC.put(MDC_SERVICEPROVIDER_ID, oaUniqueId);
+ org.slf4j.MDC.put(MDC_SERVICEPROVIDER_ID, oaUniqueId);
+
+ }
+
+ public static void removeServiceProviderId() {
+ org.apache.log4j.MDC.remove(MDC_SERVICEPROVIDER_ID);
+ org.slf4j.MDC.remove(MDC_SERVICEPROVIDER_ID);
+
+ }
+
+ public static void setTransactionId(String pendingRequestID) {
+ org.apache.log4j.MDC.put(MDC_TRANSACTION_ID,
+ "TID-" + pendingRequestID);
+ org.slf4j.MDC.put(MDC_TRANSACTION_ID,
+ "TID-" + pendingRequestID);
+
+ }
+
+ public static void removeTransactionId() {
+ org.apache.log4j.MDC.remove(MDC_TRANSACTION_ID);
+ org.slf4j.MDC.remove(MDC_TRANSACTION_ID);
+
+ }
+
+ public static void setSessionId(String uniqueSessionId) {
+ org.apache.log4j.MDC.put(MDC_SESSION_ID,
+ "SID-" + uniqueSessionId);
+ org.slf4j.MDC.put(MDC_SESSION_ID,
+ "SID-" + uniqueSessionId);
+
+ }
+
+ public static void removeSessionId() {
+ org.apache.log4j.MDC.remove(MDC_SESSION_ID);
+ org.slf4j.MDC.remove(MDC_SESSION_ID);
+
+ }
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java
new file mode 100644
index 00000000..7df242bd
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java
@@ -0,0 +1,523 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jaxen.JaxenException;
+import org.jaxen.NamespaceContext;
+import org.jaxen.Navigator;
+import org.jaxen.SimpleNamespaceContext;
+import org.jaxen.dom.DOMXPath;
+import org.jaxen.dom.DocumentNavigator;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.traversal.NodeIterator;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+import at.gv.egiz.eaaf.core.exceptions.XPathException;
+
+/**
+ * Utility methods to evaluate XPath expressions on DOM nodes.
+ *
+ * @author Patrick Peck
+ * @version $Id$
+ */
+public class XPathUtils {
+
+ /**
+ * The XPath expression selecting all nodes under a given root (including the
+ * root node itself).
+ */
+ public static final String ALL_NODES_XPATH =
+ "(.//. | .//@* | .//namespace::*)";
+
+ /** The <code>DocumentNavigator</code> to use for navigating the document. */
+ private static Navigator documentNavigator =
+ DocumentNavigator.getInstance();
+ /** The default namespace prefix to namespace URI mappings. */
+ private static NamespaceContext NS_CONTEXT;
+
+ static {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+ ctx.addNamespace(XMLNamespaceConstants.MOA_PREFIX, XMLNamespaceConstants.MOA_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MOA_CONFIG_PREFIX, XMLNamespaceConstants.MOA_CONFIG_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MOA_ID_CONFIG_PREFIX, XMLNamespaceConstants.MOA_ID_CONFIG_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.ECDSA_PREFIX, XMLNamespaceConstants.ECDSA_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.PD_PREFIX, XMLNamespaceConstants.PD_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAML_PREFIX, XMLNamespaceConstants.SAML_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAMLP_PREFIX, XMLNamespaceConstants.SAMLP_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.DSIG_PREFIX, XMLNamespaceConstants.DSIG_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XSLT_PREFIX, XMLNamespaceConstants.XSLT_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XSI_PREFIX, XMLNamespaceConstants.XSI_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.DSIG_FILTER2_PREFIX, XMLNamespaceConstants.DSIG_FILTER2_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.DSIG_EC_PREFIX, XMLNamespaceConstants.DSIG_EC_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MD_PREFIX, XMLNamespaceConstants.MD_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MDP_PREFIX, XMLNamespaceConstants.MDP_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MVV_PREFIX, XMLNamespaceConstants.MVV_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.STB_PREFIX, XMLNamespaceConstants.STB_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.WRR_PREFIX, XMLNamespaceConstants.WRR_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.STORK_PREFIX, XMLNamespaceConstants.STORK_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.STORKP_PREFIX, XMLNamespaceConstants.STORKP_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAML2_PREFIX, XMLNamespaceConstants.SAML2_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAML2P_PREFIX, XMLNamespaceConstants.SAML2P_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XENC_PREFIX, XMLNamespaceConstants.XENC_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XADES_1_1_1_NS_PREFIX, XMLNamespaceConstants.XADES_1_1_1_NS_URI);
+ NS_CONTEXT = ctx;
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * All namespace URIs and prefixes declared in the <code>Constants</code>
+ * interface are used for resolving namespaces.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeIterator selectNodeIterator(Node contextNode, String exp)
+ throws XPathException {
+
+ return selectNodeIterator(contextNode, NS_CONTEXT, exp);
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceElement An element from which to build the
+ * namespace mapping for evaluating the XPath expression
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeIterator selectNodeIterator(
+ Node contextNode,
+ Element namespaceElement,
+ String exp)
+ throws XPathException {
+
+ try {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+ ctx.addElementNamespaces(documentNavigator, namespaceElement);
+ return selectNodeIterator(contextNode, ctx, exp);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceMapping A namespace prefix to namespace URI mapping
+ * (<code>String</code> to <code>String</code>) for evaluating the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeIterator selectNodeIterator(
+ Node contextNode,
+ Map namespaceMapping,
+ String exp)
+ throws XPathException {
+
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping);
+
+ return selectNodeIterator(contextNode, ctx, exp);
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param nsContext The <code>NamespaceContext</code> for resolving namespace
+ * prefixes to namespace URIs for evaluating the XPath expression.
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ private static NodeIterator selectNodeIterator(
+ Node contextNode,
+ NamespaceContext nsContext,
+ String exp)
+ throws XPathException {
+
+ try {
+ DOMXPath xpath = new DOMXPath(exp);
+ List nodes;
+
+ xpath.setNamespaceContext(nsContext);
+ nodes = xpath.selectNodes(contextNode);
+ return new NodeIteratorAdapter(nodes.listIterator());
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * All namespace URIs and prefixes declared in the <code>Constants</code>
+ * interface are used for resolving namespaces.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeList selectNodeList(Node contextNode, String exp)
+ throws XPathException {
+
+ return selectNodeList(contextNode, NS_CONTEXT, exp);
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceElement An element from which to build the
+ * namespace mapping for evaluating the XPath expression
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeList selectNodeList(
+ Node contextNode,
+ Element namespaceElement,
+ String exp)
+ throws XPathException {
+
+ try {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+
+ ctx.addElementNamespaces(documentNavigator, namespaceElement);
+ return selectNodeList(contextNode, ctx, exp);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceMapping A namespace prefix to namespace URI mapping
+ * (<code>String</code> to <code>String</code>) for evaluating the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeList selectNodeList(
+ Node contextNode,
+ Map namespaceMapping,
+ String exp)
+ throws XPathException {
+
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping);
+
+ return selectNodeList(contextNode, ctx, exp);
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param nsContext The <code>NamespaceContext</code> for resolving namespace
+ * prefixes to namespace URIs for evaluating the XPath expression.
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ private static NodeList selectNodeList(Node contextNode, NamespaceContext nsContext, String exp) throws XPathException {
+ try {
+ DOMXPath xpath = new DOMXPath(exp);
+ List nodes;
+ xpath.setNamespaceContext(nsContext);
+ nodes = xpath.selectNodes(contextNode);
+ return new NodeListAdapter(nodes);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * All namespace URIs and prefixes declared in the <code>Constants</code>
+ * interface are used for resolving namespaces.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(Node contextNode, String exp)
+ throws XPathException {
+
+ return selectSingleNode(contextNode, NS_CONTEXT, exp);
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceElement An element from which to build the
+ * namespace mapping for evaluating the XPath expression
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(
+ Node contextNode,
+ Element namespaceElement,
+ String exp)
+ throws XPathException {
+
+ try {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+ ctx.addElementNamespaces(documentNavigator, namespaceElement);
+ return selectSingleNode(contextNode, ctx, exp);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceMapping A namespace prefix to namespace URI mapping
+ * (<code>String</code> to <code>String</code>) for evaluating the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(
+ Node contextNode,
+ Map namespaceMapping,
+ String exp)
+ throws XPathException {
+
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping);
+
+ return selectSingleNode(contextNode, ctx, exp);
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param nsContext The <code>NamespaceContext</code> for resolving namespace
+ * prefixes to namespace URIs for evaluating the XPath expression.
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(
+ Node contextNode,
+ NamespaceContext nsContext,
+ String exp)
+ throws XPathException {
+
+ try {
+ DOMXPath xpath = new DOMXPath(exp);
+ xpath.setNamespaceContext(nsContext);
+ return (Node) xpath.selectSingleNode(contextNode);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return the value of a DOM element whose location is given by an XPath
+ * expression.
+ *
+ * @param root The root element from which to evaluate the XPath.
+ * @param xpath The XPath expression pointing to the element whose value
+ * to return.
+ * @param def The default value to return, if no element can be found using
+ * the given <code>xpath</code>.
+ * @return The element value, if it can be located using the
+ * <code>xpath</code>. Otherwise, <code>def</code> is returned.
+ */
+ public static String getElementValue(
+ Element root,
+ String xpath,
+ String def) {
+
+ Element elem = (Element) XPathUtils.selectSingleNode(root, xpath);
+ return elem != null ? DOMUtils.getText(elem) : def;
+ }
+
+ /**
+ * Return the value of a DOM attribute whose location is given by an XPath
+ * expression.
+ *
+ * @param root The root element from which to evaluate the XPath.
+ * @param xpath The XPath expression pointing to the attribute whose value to
+ * return.
+ * @param def The default value to return, if no attribute can be found using
+ * the given <code>xpath</code>.
+ * @return The element value, if it can be located using the
+ * <code>xpath</code>. Otherwise, <code>def</code> is returned.
+ */
+ public static String getAttributeValue(
+ Element root,
+ String xpath,
+ String def) {
+
+ Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath);
+ return attr != null ? attr.getValue() : def;
+ }
+
+ /**
+ * Returns the namespace prefix used within <code>XPathUtils</code> for referring to
+ * the namespace of the specified (Security Layer command) element.
+ *
+ * This namespace prefix can be used in various XPath expression evaluation methods
+ * within <code> XPathUtils</code> without explicitely binding it to the particular
+ * namespace.
+ *
+ * @param contextElement The (Security Layer command) element.
+ *
+ * @return the namespace prefix used within <code>XPathUtils</code> for referring to
+ * the namespace of the specified (Security Layer command) element.
+ *
+ * throws XpathException If the specified element has a namespace other than the ones
+ * known by this implementation as valid Security Layer namespaces (cf.
+ * @link Constants#SL10_NS_URI, @link Constants#SL11_NS_URI, @link Constants#SL12_NS_URI).
+ */
+ public static String getSlPrefix (Element contextElement) throws XPathException
+ {
+ String sLNamespace = contextElement.getNamespaceURI();
+ String sLPrefix = null;
+
+ if (sLNamespace.equals(XMLNamespaceConstants.SL10_NS_URI))
+ sLPrefix = XMLNamespaceConstants.SL10_PREFIX;
+
+ else if (sLNamespace.equals(XMLNamespaceConstants.SL12_NS_URI))
+ sLPrefix = XMLNamespaceConstants.SL12_PREFIX;
+
+ else if (sLNamespace.equals(XMLNamespaceConstants.SL11_NS_URI))
+ sLPrefix = XMLNamespaceConstants.SL11_PREFIX;
+
+ else
+ throw new XPathException("XPath operation FAILED. Reason: ");
+
+ return sLPrefix;
+ }
+
+
+ /**
+ * Return the SecurityLayer namespace prefix of the context element.
+ * If the context element is not the element that lies within the
+ * SecurityLayer namespace. The Securitylayer namespace is derived from
+ * the <code>xmlns:sl10</code>, <code>sl11</code> or <code>sl</code>
+ * attribute of the context element.
+ *
+ * The returned prefix is needed for evaluating XPATH expressions.
+ *
+ * @param contextElement The element to get a prefix for the Securitylayer namespace,
+ * that is used within the corresponding document.
+ *
+ * @return The string <code>sl10</code>, <code>sl11</code> or <code>sl</code>,
+ * depending on the SecurityLayer namespace of the contextElement.
+ *
+ * throws XPathException If no (vlalid) SecurityLayer namespace prefix or namespace
+ * is defined.
+ */
+ public static String getSlPrefixFromNoRoot (Element contextElement) throws XPathException {
+
+ String slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI);
+ if (slPrefix == null)
+ slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI);
+
+ if (slPrefix == null)
+ slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI);
+
+ return slPrefix;
+
+ }
+
+ /**
+ * Checks if the context element has an attribute <code>xmlns:slPrefix</code> and
+ * if the prefix of that attribute corresponds with a valid SecurityLayer namespace.
+ *
+ * @param contextElement The element to be checked.
+ * @param slPrefix The prefix which should be checked. Must be a valid SecurityLayer
+ * namespace prefix.
+ * @param slNameSpace The SecurityLayer namespace that corresponds to the specified prefix.
+ *
+ * @return The valid SecurityLayer prefix or <code>null</code> if this prefix is
+ * not used.
+ * @throws XPathException
+ */
+ private static String checkSLnsDeclaration(Element contextElement, String slPrefix, String slNameSpace)
+ throws XPathException
+ {
+ String nsAtt = "xmlns:" + slPrefix;
+ String nameSpace = contextElement.getAttribute(nsAtt);
+ if (nameSpace == "") {
+ return null;
+
+ } else {
+ // check if namespace is correct
+ if (nameSpace.equals(slNameSpace))
+ return slPrefix;
+ else
+ throw new XPathException("Unknown Namespace declaration");
+
+ }
+ }
+
+}