package at.gv.egovernment.moa.spss.server.iaik.xml; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import iaik.ixsil.algorithms.CanonicalizationAlgorithm; import iaik.ixsil.algorithms.CanonicalizationAlgorithmImplExclusiveCanonicalXML; import iaik.ixsil.exceptions.AlgorithmException; import iaik.server.modules.xml.XSLTTransformation; import at.gv.egovernment.moa.util.NodeListAdapter; import at.gv.egovernment.moa.util.StreamUtils; import at.gv.egovernment.moa.util.XPathException; import at.gv.egovernment.moa.util.XPathUtils; /** * A Transformation containing an XSLT transformation. * * @author Patrick Peck * @version $Id$ */ public class XSLTTransformationImpl extends TransformationImpl implements XSLTTransformation { /** The XSLT stylesheet. */ private Element styleSheetElement; /** The hash code of the canonicalized stylesheet. If calculated, this value * should be != 0. */ private int hashCode; /** * Create a new XSLTTransformationImpl object. * * @param styleSheetElement The XSLT stylesheet element. */ public XSLTTransformationImpl(Element styleSheetElement) { setAlgorithmURI(XSLTTransformation.XSLT); setStyleSheetElement(styleSheetElement); } /** * Set the XSLT stylesheet element. * * @param styleSheetElement The XSLT stylesheet element to set. */ protected void setStyleSheetElement(Element styleSheetElement) { this.styleSheetElement = styleSheetElement; this.hashCode = 0; } /** * @see iaik.server.modules.xml.XSLTTransformation#getStylesheetElement() */ public Element getStylesheetElement() { return styleSheetElement; } /** * Compare this XSLTTransformation to another. * * @param other The object to compare this * XSLTTransformation to. * @return true, if other is an * XSLTTransformation and if the canonicalized representations of * the stylesheets contained in this and other * match. Otherwise, false is returned. * @see java.lang.Object#equals(Object) */ public boolean equals(Object other) { if (other instanceof XSLTTransformation) { XSLTTransformation xslt = (XSLTTransformation) other; return compareElements( getStylesheetElement(), xslt.getStylesheetElement()); } return false; } /** * @see java.lang.Object#hashCode() */ public int hashCode() { if (hashCode == 0) { hashCode = calculateHashCode(getStylesheetElement()); } return hashCode; } /** * Calculate the hash code for a DOM element by canonicalizing it. * * @param element The DOM element for which the hash code is to be calculated. * @return int The hash code, or 0, if it could not be * calculated. */ private static int calculateHashCode(Element element) { try { InputStream is = canonicalize(element); byte[] buf = new byte[256]; int hashCode = 1; int length; int i; while ((length = is.read(buf)) > 0) { for (i = 0; i < length; i++) { hashCode += buf[i] * 31 + i; } } is.close(); return hashCode; } catch (AlgorithmException e) { return 0; } catch (IOException e) { return 0; } } /** * Compare two DOM elements by canonicalizing their contents and comparing the * resulting byte stream. * * @param elem1 The 1st element to compare. * @param elem2 The 2nd element to compare. * @return boolean true, if the elements are considered equal * after canonicalization. Otherwise false is returned. */ private static boolean compareElements(Element elem1, Element elem2) { try { InputStream is1 = canonicalize(elem1); InputStream is2 = canonicalize(elem2); return StreamUtils.compareStreams(is1, is2); } catch (AlgorithmException e) { return false; } catch (IOException e) { return false; } } /** * Canonicalize a DOM element. * * @param element The element to canonicalize. * @return InputStream A stream with the canonicalized data. * @throws AlgorithmException An error occurred canonicalizing the element. */ private static InputStream canonicalize(Element element) throws AlgorithmException { CanonicalizationAlgorithm c14n = new CanonicalizationAlgorithmImplExclusiveCanonicalXML(); NodeList nodeList; try { nodeList = XPathUtils.selectNodeList(element, XPathUtils.ALL_NODES_XPATH); } catch (XPathException e) { nodeList = new NodeListAdapter(Collections.EMPTY_LIST); } c14n.setInput(nodeList); return c14n.canonicalize(); } }