All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.util.DigestGenerator Maven / Gradle / Ivy

There is a newer version: 3.1
Show newest version
/*
 * Nuiton Utils %%Ignore-License
 *
 *
 * $HeadURL$
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
* Modified by Landais Gabriel, Code Lutin 2008
*
* Works with standard org.w3c.dom XML classes
*
*/

package org.nuiton.util;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Helper class to provide the functionality of the digest value generation. This is an implementation of the DHASH
 * algorithm on .
 *
 * TODO tchemit 2010-08-25 : This class is a nightmare ? we talk about digest mixed with dom nodes ?
 * TODO  tchemit 2010-08-25 : Should have more to explain the purpose (javadoc, author, since...)  or (rename | split) this class.
 */
public class DigestGenerator {
    public static final String UNICODE_BIG_UNMARKED = "UnicodeBigUnmarked";

    /**
     * This method is an overloaded method for the digest generation for Document
     *
     * @param document FIXME
     * @param digestAlgorithm FIXME
     * @return Returns a byte array representing the calculated digest
     * @throws Exception FIXME
     */
    public byte[] getDigest(Document document, String digestAlgorithm)
            throws Exception {
        byte[] digest;
        try {
            MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt(9);
            Collection childNodes = getValidElements(document);
            dos.writeInt(childNodes.size());
            for (Object childNode : childNodes) {
                Node node = (Node) childNode;
                if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
                    dos.write(getDigest((ProcessingInstruction) node,
                                        digestAlgorithm));
                } else if (node.getNodeType() == Node.ELEMENT_NODE) {
                    dos.write(getDigest((Element) node, digestAlgorithm));
                }
            }
            dos.close();
            md.update(baos.toByteArray());
            digest = md.digest();
        } catch (NoSuchAlgorithmException e) {
            throw new Exception(e);
        } catch (IOException e) {
            throw new Exception(e);
        }
        return digest;
    }

    /**
     * This method is an overloaded method for the digest generation for Node
     *
     * @param node FIXME
     * @param digestAlgorithm FIXME
     * @return Returns a byte array representing the calculated digest value
     * @throws Exception FIXME
     */
    public byte[] getDigest(Node node, String digestAlgorithm) throws Exception {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            return getDigest((Element) node, digestAlgorithm);
        }
        if (node.getNodeType() == Node.TEXT_NODE) {
            return getDigest((Text) node, digestAlgorithm);
        }
        if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
            return getDigest((ProcessingInstruction) node, digestAlgorithm);
        }
        return new byte[0];
    }

    /**
     * This method is an overloaded method for the digest generation for Element
     *
     * @param element FIXME
     * @param digestAlgorithm FIXME
     * @return Returns a byte array representing the calculated digest value
     * @throws Exception FIXME
     */
    public byte[] getDigest(Element element, String digestAlgorithm)
            throws Exception {
        byte[] digest;
        try {
            MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt(1);
            dos.write(getExpandedName(element).getBytes(UNICODE_BIG_UNMARKED));
            dos.write((byte) 0);
            dos.write((byte) 0);
            Collection attrs = getAttributesWithoutNS(element);
            dos.writeInt(attrs.size());
            for (Object attr : attrs) {
                dos.write(getDigest((Attr) attr, digestAlgorithm));
            }
            Node node = element.getFirstChild();
            // adjoining Texts are merged,
            // there is no 0-length Text, and
            // comment nodes are removed.
            int length = element.getChildNodes().getLength();
            dos.writeInt(length);
            while (node != null) {
                dos.write(getDigest(node, digestAlgorithm));
                node = node.getNextSibling();
            }
            dos.close();
            md.update(baos.toByteArray());
            digest = md.digest();
        } catch (NoSuchAlgorithmException e) {
            throw new Exception(e);
        } catch (IOException e) {
            throw new Exception(e);
        }
        return digest;
    }

    /**
     * This method is an overloaded method for the digest generation for ProcessingInstruction
     *
     * @param pi FIXME
     * @param digestAlgorithm FIXME
     * @return Returns a byte array representing the calculated digest value
     * @throws Exception FIXME
     */
    public byte[] getDigest(ProcessingInstruction pi, String digestAlgorithm)
            throws Exception {
        byte[] digest;
        try {
            MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
            md.update((byte) 0);
            md.update((byte) 0);
            md.update((byte) 0);
            md.update((byte) 7);
            md.update(pi.getTarget().getBytes(UNICODE_BIG_UNMARKED));
            md.update((byte) 0);
            md.update((byte) 0);
            md.update(pi.getNodeValue().getBytes(UNICODE_BIG_UNMARKED));
            digest = md.digest();
        } catch (NoSuchAlgorithmException e) {
            throw new Exception(e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception(e);
        }
        return digest;
    }

    /**
     * This method is an overloaded method for the digest generation for Attr
     *
     * @param attribute FIXME
     * @param digestAlgorithm FIXME
     * @return Returns a byte array representing the calculated digest value
     * @throws Exception FIXME
     */
    public byte[] getDigest(Attr attribute, String digestAlgorithm)
            throws Exception {
        byte[] digest = new byte[0];
        if (!(attribute.getLocalName().equals("xmlns") || attribute
                .getLocalName().startsWith("xmlns:"))) {
            try {
                MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
                md.update((byte) 0);
                md.update((byte) 0);
                md.update((byte) 0);
                md.update((byte) 2);
                md.update(getExpandedName(attribute).getBytes(
                        UNICODE_BIG_UNMARKED));
                md.update((byte) 0);
                md.update((byte) 0);
                md.update(attribute.getValue().getBytes(UNICODE_BIG_UNMARKED));
                digest = md.digest();
            } catch (NoSuchAlgorithmException e) {
                throw new Exception(e);
            } catch (UnsupportedEncodingException e) {
                throw new Exception(e);
            }
        }
        return digest;
    }

    /**
     * This method is an overloaded method for the digest generation for Text
     *
     * @param text FIXME
     * @param digestAlgorithm FIXME
     * @return Returns a byte array representing the calculated digest value
     * @throws Exception FIXME
     */
    public byte[] getDigest(Text text, String digestAlgorithm) throws Exception {
        byte[] digest;
        try {
            MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
            md.update((byte) 0);
            md.update((byte) 0);
            md.update((byte) 0);
            md.update((byte) 3);
            md.update(text.getTextContent().getBytes(UNICODE_BIG_UNMARKED));
            digest = md.digest();
        } catch (NoSuchAlgorithmException e) {
            throw new Exception(e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception(e);
        }
        return digest;
    }

    /**
     * This method is an overloaded method for getting the expanded name namespaceURI followed by the local name for
     * Element
     *
     * @param element FIXME
     * @return Returns the expanded name of Element
     */
    public String getExpandedName(Element element) {
        return element.getNamespaceURI() + ":" + element.getLocalName();
    }

    /**
     * This method is an overloaded method for getting the expanded name namespaceURI followed by the local name for
     * Attr
     *
     * @param attribute FIXME
     * @return Returns the expanded name of the Attr
     */
    public String getExpandedName(Attr attribute) {
        return attribute.getNamespaceURI() + ":" + attribute.getLocalName();
    }

    /**
     * Gets the collection of attributes which are none namespace declarations for an Element
     *
     * @param element FIXME
     * @return Returns the collection of attributes which are none namespace declarations
     */
    public Collection getAttributesWithoutNS(Element element) {
        SortedMap map = new TreeMap();
        for (int i = 0; i < element.getAttributes().getLength(); i++) {
            Attr attribute = (Attr) element.getAttributes().item(i);
            if (!(attribute.getLocalName().equals("xmlns") || attribute
                    .getLocalName().startsWith("xmlns:"))) {
                map.put(getExpandedName(attribute), attribute);
            }
        }
        return map.values();
    }

    /**
     * Gets the valid element collection of an Document. Element and ProcessingInstruction only
     *
     * @param document FIXME
     * @return Returns a collection of ProcessingInstructions and Elements
     */
    public Collection getValidElements(Document document) {
        ArrayList list = new ArrayList();
        NodeList childNodes = document.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node node = childNodes.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE
                || node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
                list.add(node);
            }
        }
        return list;
    }

    /**
     * Gets the String representation of the byte array
     *
     * @param array FIXME
     * @return Returns the String of the byte
     */
    public String getStringRepresentation(byte[] array) {
        String str = "";
        for (byte anArray : array) {
            str += anArray;
        }
        return str;
    }

    /**
     * Compares two Nodes for the XML equality
     *
     * @param node FIXME
     * @param comparingNode FIXME
     * @param digestAlgorithm FIXME
     * @return Returns true if the Node XML contents are equal
     * @throws Exception FIXME
     */
    public boolean compareNode(Node node, Node comparingNode,
                               String digestAlgorithm) throws Exception {
        return Arrays.equals(getDigest(node, digestAlgorithm), getDigest(
                comparingNode, digestAlgorithm));
    }

    /**
     * Compares two Documents for the XML equality
     *
     * @param document FIXME
     * @param comparingDocument FIXME
     * @param digestAlgorithm FIXME
     * @return Returns true if the Document XML content are equal
     * @throws Exception FIXME
     */
    public boolean compareDocument(Document document,
                                   Document comparingDocument, String digestAlgorithm)
            throws Exception {
        return Arrays.equals(getDigest(document, digestAlgorithm), getDigest(
                comparingDocument, digestAlgorithm));
    }

    /**
     * Compares two Attributes for the XML equality
     *
     * @param attribute FIXME
     * @param comparingAttribute FIXME
     * @param digestAlgorithm FIXME
     * @return Returns true if the Document XML content are equal
     * @throws Exception FIXME
     */
    public boolean compareAttribute(Attr attribute, Attr comparingAttribute,
                                    String digestAlgorithm) throws Exception {
        return Arrays.equals(getDigest(attribute, digestAlgorithm), getDigest(
                comparingAttribute, digestAlgorithm));
    }

    /** String representing the MD5 digest algorithm */
    public static final String md5DigestAlgorithm = "MD5";

    /** String representing the SHA digest algorithm */
    public static final String shaDigestAlgorithm = "SHA";

    /** String representing the SHA1 digest algorithm */
    public static final String sha1DigestAlgorithm = "SHA1";
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy