Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.adobe.granite.auth.saml.util;
import com.adobe.granite.auth.saml.model.Assertion;
import com.adobe.granite.auth.saml.model.Attribute;
import com.adobe.granite.auth.saml.model.AuthnStatement;
import com.adobe.granite.auth.saml.model.Issuer;
import com.adobe.granite.auth.saml.model.LogoutRequest;
import com.adobe.granite.auth.saml.model.Message;
import com.adobe.granite.auth.saml.model.NameId;
import com.adobe.granite.auth.saml.model.Response;
import com.adobe.granite.auth.saml.model.Status;
import com.adobe.granite.auth.saml.model.Subject;
import com.adobe.granite.auth.saml.model.xml.SamlXmlConstants;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.encryption.XMLEncryptionException;
import org.apache.xml.security.utils.EncryptionConstants;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.Key;
import java.security.Provider;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
/**
* SamlReader is responsible for reading saml objects from an input stream.
*
*/
public class SamlReader {
private XMLSignatureFactory xmlSignatureFactory;
static {
org.apache.xml.security.Init.init();
}
/**
* default log
*/
private final Logger log = LoggerFactory.getLogger(getClass());
/**
* Creates a new instance of XmlUnmarshaler.
*/
public SamlReader() {
super();
try {
xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(System.getProperty("jsr105Provider", "org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI")).newInstance());
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
log.error("Could not instantiate XML Signature Factory.", e);
}
}
/**
* Reads a response from the xml document contained in the given input stream.
*
* @param inputStream InputStream containing the xml document to unmarshal.
* @param decryptionKey Private key used to decrypt encrypted assertions (dont decrypt if key is null)
* @param verificationKey The public key of the IdP to verify the XML signatures
* @param isSamlRequest Whether we are handling a SamlRequest or a SamlResponse message
* @return Response created from the xml document in the input stream.
* @throws SamlReaderException An error occurred while unmarshaling the Response.
* @throws IOException An error occurred while processing the {@link InputStream}
*/
public Message read(final InputStream inputStream, final Key decryptionKey, final Key verificationKey, boolean isSamlRequest) throws SamlReaderException, IOException {
final DocumentBuilderFactory builderFactory;
final DocumentBuilder builder;
try {
builderFactory = createBuilderFactory();
builder = builderFactory.newDocumentBuilder();
builder.setErrorHandler(new LoggingErrorHandler());
Document doc = builder.parse(inputStream);
Message msg = null;
if (!isSamlRequest) {
// this is a SAML Response message
msg = parse(doc, verificationKey, decryptionKey);
if (msg == null) {
throw new SamlReaderException("Unable to parse document from stream.", new Exception());
}
// store decoded/decrypted message body
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(sw));
msg.setRawMessage(sw.toString());
} else {
// this is a SAML Request message
msg = parseRequest(doc, verificationKey);
if (msg == null) {
throw new SamlReaderException("Unable to parse document from stream.", new Exception());
}
}
return msg;
} catch (ParserConfigurationException e) {
throw new SamlReaderException("Unable to create document builder factory", e);
} catch (SAXException e) {
throw new SamlReaderException("Unable to parse document from stream", e);
} catch (TransformerConfigurationException e) {
throw new SamlReaderException("Unable to parse document from stream", e);
} catch (TransformerException e) {
throw new SamlReaderException("Unable to parse document from stream", e);
}
}
public Message read(final InputStream inputStream, final Key decryptionKey, final Key verificationKey) throws SamlReaderException, IOException {
return read(inputStream, decryptionKey, verificationKey, false);
}
/**
* Create and configure a new document builder factory
*/
private DocumentBuilderFactory createBuilderFactory() throws ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
// do not expand entity reference nodes
dbf.setExpandEntityReferences(false);
// do not include external general entities
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
// do not include external parameter entities or the external DTD subset
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// build the grammar but do not use the default attributes and attribute types information it contains
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
// ignore the external DTD completely
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
return dbf;
}
// -- implementation methods --
/**
* Creates a Response instance by parsing the given document.
*
* @param document Document instance containing an xml response instance.
* @param verificationKey The public key of the IdP to verify the XML signatures
* @param decryptionKey The (optional) private key of the SP to decrypt encrypted assertion elements
* @return Response instance created from the given document.
*/
protected Response parse(final Document document, final Key verificationKey, final Key decryptionKey) {
final Element responseElement = getChildElement(document, SamlXmlConstants.RESPONSE_ELEMENT);
if (responseElement == null) {
log.error("Unable to read Response element from document.");
return null;
}
responseElement.setIdAttribute("ID", true);
final Response response = new Response();
response.setId(responseElement.getAttribute(SamlXmlConstants.ID_ATTR));
response.setVersion(responseElement.getAttribute(SamlXmlConstants.VERSION_ATTR));
response.setIssueInstant(getDateAttr(responseElement, SamlXmlConstants.ISSUE_INSTANT_ATTR));
final Element statusElement = getChildElement(responseElement, SamlXmlConstants.STATUS_ELEMENT);
if (null != statusElement) {
response.setStatus(parseStatus(statusElement));
}
final Element issuerElement = getChildElement(responseElement, SamlXmlConstants.ISSUER_ELEMENT);
if (null != issuerElement) {
response.setIssuer(parseIssuer(issuerElement));
}
response.setInResponseTo(responseElement.getAttribute(SamlXmlConstants.IN_RESPONSE_TO_ATTR));
response.setDestination(responseElement.getAttribute(SamlXmlConstants.DESTINATION_ATTR));
response.setSignatureValid(verifyElementSignature(responseElement, verificationKey));
// potentially decrypt assertions
if (decryptionKey != null) {
this.decryptResponse(document, decryptionKey);
}
final NodeList nodeList = responseElement.getElementsByTagNameNS(SamlXmlConstants.SAML_ASSERTION_NAMESPACE, SamlXmlConstants.ASSERTION_ELEMENT);
for (int i = 0; i < nodeList.getLength(); i++) {
Element assertionElement = (Element) nodeList.item(i);
Assertion assertion = parseAssertion(assertionElement);
final Element subjectElement = getChildElement(assertionElement, SamlXmlConstants.SUBJECT_ELEMENT);
if (null != subjectElement) {
final Element nameIdElement = getChildElement(subjectElement, SamlXmlConstants.NAME_ID_ELEMENT);
if (null != nameIdElement) {
response.setNameId(nameIdElement.getTextContent());
if (nameIdElement.hasAttribute(SamlXmlConstants.FORMAT_ATTR)) {
response.setNameIdFormat(nameIdElement.getAttribute(SamlXmlConstants.FORMAT_ATTR));
}
if (nameIdElement.hasAttribute(SamlXmlConstants.NAME_QUALIFIER_ATTR)) {
response.setNameQualifier(nameIdElement.getAttribute(SamlXmlConstants.NAME_QUALIFIER_ATTR));
}
if (nameIdElement.hasAttribute(SamlXmlConstants.SP_NAME_QUALIFIER_ATTR)) {
response.setSpNameQualifier(nameIdElement.getAttribute(SamlXmlConstants.SP_NAME_QUALIFIER_ATTR));
}
}
}
assertion.setSignatureValid(verifyElementSignature((Element)nodeList.item(i), verificationKey));
if (!assertion.isSignatureValid()) {
// potentially inherit response signature
assertion.setSignatureValid(response.isSignatureValid());
}
response.addAssertion(assertion);
}
return response;
}
protected Response parse(Document document, Key verificationKey) {
return parse(document, verificationKey, null);
}
/**
* Parse a SAML LogoutRequest message
*
* @param document Document instance containing the SAML LogoutRequest message
* @param verificationKey The IdP's public key to verify the signature of the message
* @return LogoutRequest message created from the given message
*/
private LogoutRequest parseRequest(Document document, Key verificationKey) {
final Element requestElement = getChildElement(document, SamlXmlConstants.LOGOUT_REQUEST);
if (requestElement == null) {
log.error("Could not find LogoutRequest element in document");
return null;
}
// read attributes of LogoutRequest
final LogoutRequest logoutRequest = new LogoutRequest();
if (requestElement.hasAttribute(SamlXmlConstants.ID_ATTR)) {
logoutRequest.setId(requestElement.getAttribute(SamlXmlConstants.ID_ATTR));
}
if (requestElement.hasAttribute(SamlXmlConstants.ISSUE_INSTANT_ATTR)) {
logoutRequest.setIssueInstant(getDateAttr(requestElement, SamlXmlConstants.ISSUE_INSTANT_ATTR));
}
if (requestElement.hasAttribute(SamlXmlConstants.DESTINATION_ATTR)) {
logoutRequest.setDestination(requestElement.getAttribute(SamlXmlConstants.DESTINATION_ATTR));
}
// parse child elements
final Element issuerElement = getChildElement(requestElement, SamlXmlConstants.ISSUER_ELEMENT);
if (issuerElement != null) {
logoutRequest.setIssuer(parseIssuer(issuerElement));
}
final Element nameIdElement = getChildElement(requestElement, SamlXmlConstants.NAME_ID_ELEMENT);
if (nameIdElement != null) {
if (nameIdElement.hasAttribute(SamlXmlConstants.NAME_FORMAT_ATTR)) {
logoutRequest.setNameIdFormat(nameIdElement.getAttribute(SamlXmlConstants.NAME_FORMAT_ATTR));
}
logoutRequest.setNameId(nameIdElement.getTextContent());
}
final LinkedList sessionIndexElements = getChildElements(requestElement, SamlXmlConstants.SESSION_INDEX_ELEMENT);
for (Element sessionIndexElement : sessionIndexElements) {
logoutRequest.addSessionIndex(sessionIndexElement.getTextContent());
}
logoutRequest.setSignatureValid(verifyElementSignature(requestElement, verificationKey));
return logoutRequest;
}
/**
* Verify the cryptographic signature of a (decrypted) element.
*
* @param signedElement The element to be verified.
* @param verificationKey The public key of the IDP
* @return True if the element is signed (potentially via signature inheritance) and all signatures are valid,
* False otherwise
*/
private boolean verifyElementSignature(Element signedElement, Key verificationKey) {
// Check verification key
if (verificationKey == null) {
log.debug("Cannot verify signature. Public key of IDP missing.");
return false;
}
// Find enveloped signature nodes
NodeList children = signedElement.getChildNodes();
LinkedList signatureNodes = new LinkedList ();
for (int i = 0; i < children.getLength(); i++) {
if (XMLSignature.XMLNS.equals(children.item(i).getNamespaceURI()) && "Signature".equals(children.item(i).getLocalName())) {
signatureNodes.add(children.item(i));
}
}
if (signatureNodes.size() == 0) {
// no signature node found
// check if this is an assertion element contained within another assertion
if (SamlXmlConstants.ASSERTION_ELEMENT.equals(signedElement.getTagName()) &&
signedElement.getParentNode() != null &&
signedElement.getParentNode().getNodeType() == Element.ELEMENT_NODE) {
Element parentElement = (Element) signedElement.getParentNode();
if (SamlXmlConstants.ASSERTION_ELEMENT.equals(parentElement.getTagName())) {
// recursively verify parent assertion
return verifyElementSignature(parentElement, verificationKey);
}
} else {
log.debug("Signature verification failed. No signature.", signedElement);
return false;
}
}
// Validate all signature nodes
for (Node signatureNode : signatureNodes) {
DOMValidateContext validateContext = new DOMValidateContext(verificationKey, signatureNode);
validateContext.setIdAttributeNS(signedElement, null, SamlXmlConstants.ID_ATTR);
try {
XMLSignature signature = xmlSignatureFactory.unmarshalXMLSignature(validateContext);
// Validate Reference
// MUST contain _single_ ds:reference containing same-document reference to the ID of the root element
List references = signature.getSignedInfo().getReferences();
if (references.size() != 1) {
log.debug("Signature node MUST contain a single ds:reference field.");
return false;
}
String refURI = references.get(0).getURI();
if (refURI == null || refURI.isEmpty() || !refURI.startsWith("#")) {
log.debug("Signature node with empty or invalid reference field.");
return false;
}
if (!refURI.substring(1).equals(signedElement.getAttribute(SamlXmlConstants.ID_ATTR))) {
log.debug("Signature reference MUST point to the enveloping element.");
return false;
}
// Validate Signature
if (!signature.validate(validateContext)) {
return false;
}
} catch (MarshalException e) {
log.error("Unable to unmarshal XML signature.", e);
return false;
} catch (XMLSignatureException e) {
log.error("Unable to validate signature.", e);
return false;
}
}
return true;
}
protected Document decryptResponse(final Document document, final Key decryptionKey) {
final NodeList encryptedAssertions = document.getElementsByTagNameNS(
SamlXmlConstants.SAML_ASSERTION_NAMESPACE,
SamlXmlConstants.ENCRYPTED_ASSERTION_ELEMENT);
if (0 >= encryptedAssertions.getLength()) {
throw new RuntimeException("No EncryptedAssertion element was found");
}
for (int i = 0; i < encryptedAssertions.getLength(); i++) {
this.decryptAssertion((Element) encryptedAssertions.item(i), decryptionKey);
}
return document;
}
/**
* Decrypts data contained in the given encrypted assertion. The EncryptedAssertion element is then replaced
* by the decrypted Assertion element.
*
* @param encryptedAssertion EncrtypedAssertion element to decrypt.
* @param decryptionKey Private key used to decrypt encrypted assertions.
*/
protected void decryptAssertion(final Element encryptedAssertion, final Key decryptionKey) {
XMLCipher xmlCipher;
final DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
final DocumentBuilder builder;
try {
// get encrypted data node (must be the only xenc:EncryptedData element in the saml:EncryptedAssertion node)
Element encryptedDataNode = (Element) encryptedAssertion.getElementsByTagNameNS(EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTEDDATA).item(0);
// get xenc:EncryptionMethod node and read algorithm attribute
Element algorithmNode = (Element) encryptedDataNode.getElementsByTagNameNS(EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONMETHOD).item(0);
String algorithm = algorithmNode.getAttributeNS(null, EncryptionConstants._ATT_ALGORITHM);
builder = builderFactory.newDocumentBuilder();
// initialize xmlcipher with private key from repository as KEK
xmlCipher = XMLCipher.getInstance();
xmlCipher.init(XMLCipher.DECRYPT_MODE, null);
xmlCipher.setKEK(decryptionKey);
// register the retrieval-method encrypted key resolver as an internal key resolver
xmlCipher.registerInternalKeyResolver(new RetrievalMethodEncryptedKeyResolver(algorithm, decryptionKey));
// decrypt xenc:EncryptedData node to byte array
byte[] decryptedAssertion = xmlCipher.decryptToByteArray(encryptedDataNode);
Document doc = builder.parse(new ByteArrayInputStream(decryptedAssertion));
Node decryptedNode = encryptedAssertion.getOwnerDocument().importNode(doc.getDocumentElement(), true);
// replace encrypted assertion element
final Element parentElement = (Element) encryptedAssertion.getParentNode();
parentElement.removeChild(encryptedAssertion);
parentElement.appendChild(decryptedNode);
} catch (final XMLEncryptionException e) {
throw new RuntimeException("Error decrypting response", e);
} catch (ParserConfigurationException e) {
throw new RuntimeException("Error decrypting response", e);
} catch (SAXException e) {
throw new RuntimeException("Error decrypting response", e);
} catch (IOException e) {
throw new RuntimeException("Error decrypting response", e);
}
}
/**
* Creates an Issuer instance from the given issuer element.
*
* @param issuerElement Element containing an xml issuer.
* @return Issuer instance created from the given issuer element.
*/
protected Issuer parseIssuer(final Element issuerElement) {
final String value = issuerElement.getTextContent();
if (null == value) {
return null;
} else {
return new Issuer(value.trim());
}
}
/**
* Creates an Assertion instance from the given assertion element.
*
* @param assertionElement Element containing an xml assertion.
* @return Assertion instance created from the given assertion element.
*/
protected Assertion parseAssertion(final Element assertionElement) {
final Assertion assertion = new Assertion();
// parse Subject element
final Element subjectElement = getChildElement(assertionElement, SamlXmlConstants.SUBJECT_ELEMENT);
if (null != subjectElement) {
Subject subject = new Subject();
final Element nameIdElement = getChildElement(subjectElement, SamlXmlConstants.NAME_ID_ELEMENT);
if (nameIdElement != null) {
NameId nameId = new NameId();
nameId.setValue(nameIdElement.getTextContent());
nameId.setFormat(nameIdElement.getAttribute(SamlXmlConstants.FORMAT_ATTR));
subject.setNameId(nameId);
}
assertion.setSubject(subject);
// TODO parse base/encrypted-ids
// TODO parse subject conditions
}
final Element attributeStatement = getChildElement(assertionElement, SamlXmlConstants.ATTRIBUTE_STATEMENT_ELEMENT);
if (null != attributeStatement) {
final NodeList nodeList = attributeStatement.getElementsByTagNameNS(SamlXmlConstants.SAML_ASSERTION_NAMESPACE, SamlXmlConstants.ATTRIBUTE_ELEMENT);
for (int i = 0; i < nodeList.getLength(); i++) {
assertion.addAttribute(parseAttribute((Element) nodeList.item(i)));
}
}
// parse conditions
final Element conditionsElement = getChildElement(assertionElement, SamlXmlConstants.CONDITIONS_ELEMENT);
if (conditionsElement.hasAttribute(SamlXmlConstants.NOT_BEFORE_ATTR)) {
assertion.setNotBefore(getDateAttr(conditionsElement, SamlXmlConstants.NOT_BEFORE_ATTR));
}
if (conditionsElement.hasAttribute(SamlXmlConstants.NOT_ON_OR_AFTER_ATTR)) {
assertion.setNotOnOrAfter(getDateAttr(conditionsElement, SamlXmlConstants.NOT_ON_OR_AFTER_ATTR));
}
// audience restriction attribute is mandatory
final Element audienceRestrictionElement = getChildElement(conditionsElement, SamlXmlConstants.AUDIENCE_RESTRICTION_ELEMENT);
if (null != audienceRestrictionElement) {
final NodeList nodeList = audienceRestrictionElement.getElementsByTagNameNS(SamlXmlConstants.SAML_ASSERTION_NAMESPACE, SamlXmlConstants.AUDIENCE_ELEMENT);
for (int i = 0; i < nodeList.getLength(); i++) {
assertion.addAudienceRestriction(nodeList.item(i).getTextContent());
}
}
// parse authn statement element(s)
final LinkedList authnStatementElements = getChildElements(assertionElement, SamlXmlConstants.AUTHN_STATEMENT_ELEMENT);
for (Element authnStatementElement : authnStatementElements) {
AuthnStatement authnStatement = new AuthnStatement();
if (authnStatementElement.hasAttribute(SamlXmlConstants.AUTHN_INSTANT_ATTR)) {
authnStatement.setAuthnInstant(getDateAttr(authnStatementElement, SamlXmlConstants.AUTHN_INSTANT_ATTR));
}
if (authnStatementElement.hasAttribute(SamlXmlConstants.SESSION_NOT_ON_OR_AFTER_ATTR)) {
authnStatement.setSessionNotOnOrAfter(getDateAttr(authnStatementElement, SamlXmlConstants.SESSION_NOT_ON_OR_AFTER_ATTR));
}
if (authnStatementElement.hasAttribute(SamlXmlConstants.SESSION_INDEX_ATTR)) {
authnStatement.setSessionIndex(authnStatementElement.getAttribute(SamlXmlConstants.SESSION_INDEX_ATTR));
}
assertion.addAuthnStatement(authnStatement);
// TODO parse SubjectLocality & AuthnContext elements
}
return assertion;
}
/**
* Creates an Attribute instance from the given attribute element.
*
* @param attributeElement Xml Element containing attribute data.
* @return Attribute instance created from the given element.
*/
protected Attribute parseAttribute(final Element attributeElement) {
final Attribute attribute = new Attribute();
attribute.setName(attributeElement.getAttribute(SamlXmlConstants.NAME_ATTR));
attribute.setNameFormat(attributeElement.getAttribute(SamlXmlConstants.NAME_FORMAT_ATTR));
final NodeList valueElements = attributeElement.getElementsByTagNameNS(SamlXmlConstants.SAML_ASSERTION_NAMESPACE, SamlXmlConstants.ATTRIBUTE_VALUE_ELEMENT);
for (int i = 0; i < valueElements.getLength(); i++) {
final Element valueElement = (Element) valueElements.item(i);
attribute.addAttributeValue(valueElement.getTextContent().trim());
}
return attribute;
}
/**
* Creates a Status instance from the given status element.
*
* @param statusElement Status instance created from the given element.
* @return Status instance created from the given element.
*/
protected Status parseStatus(final Element statusElement) {
final Status status = new Status();
final Element statusCodeElement = getChildElement(statusElement, SamlXmlConstants.STATUS_CODE_ELEMENT);
if (null != statusCodeElement) {
status.setStatusCode(statusCodeElement.getAttribute(SamlXmlConstants.VALUE_ATTR));
return status;
}
return null;
// TODO JH need to recursively check for status codes...
}
/**
* Retrieve a date value from a specific attribute.
*
* @param element Element containing the attribute.
* @param attrName Name of the attribute containing the date.
* @return Date created from the given attribute, or null if not found.
*/
protected Calendar getDateAttr(final Element element, final String attrName) {
final String value = element.getAttribute(attrName);
if (null != value && !"".equals(value)) {
Calendar calendar = ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.forOffsetHours(0)).parseDateTime(value).toCalendar(Locale.getDefault());
return calendar;
}
return null;
}
/**
* Retrieves the first child element of the provided node which matches the given name.
*
* @param node Parent node to retrieve a child element from.
* @param name String containing the name of the child element to retrieve.
* @return Child Element matching the given name or null if not found.
*/
protected Element getChildElement(final Node node, final String name) {
final NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
final Node child = nodeList.item(i);
if (Node.ELEMENT_NODE == child.getNodeType()) {
if (child.getLocalName().equals(name)) {
return (Element) child;
}
}
}
return null;
}
/**
* Retrieves a list of child elements of the provided node which match the given name
*
* @param node Parent node to retrieve child elements from
* @param name String containing the name of the child elements to retrieve
* @return A linked list containing all child elements matching the give name
*/
protected LinkedList getChildElements(final Node node, final String name) {
final NodeList nodeList = node.getChildNodes();
final LinkedList childElements = new LinkedList();
for (int i = 0; i < nodeList.getLength(); i++) {
final Node child = nodeList.item(i);
if (Node.ELEMENT_NODE == child.getNodeType()) {
if (child.getLocalName().equals(name)) {
childElements.add((Element) child);
}
}
}
return childElements;
}
private class LoggingErrorHandler implements ErrorHandler {
@Override
public void warning(SAXParseException exception) throws SAXException {
log.warn(exception.getMessage());
}
@Override
public void error(SAXParseException exception) throws SAXException {
log.error(exception.getMessage());
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
log.error(exception.getMessage());
}
}
}