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();
}
}