/*
* Copyright 2003 Federal Chancellery Austria
* MOA-SPSS 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.egovernment.moa.spss.server.iaik.xml;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.TransformException;
import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import at.gv.egovernment.moa.spss.util.NodeListToNodeSetDataAdapter;
import at.gv.egovernment.moaspss.util.NodeListAdapter;
import at.gv.egovernment.moaspss.util.StreamUtils;
import at.gv.egovernment.moaspss.util.XPathException;
import at.gv.egovernment.moaspss.util.XPathUtils;
import iaik.server.modules.xml.MOAXSecProvider;
import iaik.server.modules.xml.XSLTTransformation;
import iaik.xml.crypto.dsig.XMLSignatureFactory;
import iaik.xml.filter.impl.dsig.CanonInputStream;
import iaik.xml.filter.impl.dsig.Canonicalizer;
import iaik.xml.filter.impl.dsig.Traverser;
/**
* 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 (IOException e) {
return 0;
} catch (NoSuchAlgorithmException e) {
return 0;
} catch (InvalidAlgorithmParameterException e) {
return 0;
} catch (TransformException 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 (IOException e) {
return false;
} catch (NoSuchAlgorithmException e) {
return false;
} catch (InvalidAlgorithmParameterException e) {
return false;
} catch (TransformException e) {
return false;
}
}
/**
* Canonicalize a DOM element.
*
* @param element The element to canonicalize.
* @return InputStream A stream with the canonicalized data.
* @throws InvalidAlgorithmParameterException
* @throws IOException
* @throws TransformException
* @throws AlgorithmException An error occurred canonicalizing the element.
*/
private static InputStream canonicalize(Element element)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException, TransformException {
// CanonicalizationMethod canonicalizationMethod =
// MOAXSecProvider.getXMLSignatureFactory().newCanonicalizationMethod(
// CanonicalizationMethod.EXCLUSIVE, new ExcC14NParameterSpec());
//CanonicalizationAlgorithm c14n =
// new CanonicalizationAlgorithmImplExclusiveCanonicalXML();
//Traverser traverser = new Traverser(element, true, true);
//Canonicalizer canonicalizer = new Canonicalizer(traverser, false, true, null);
//return new CanonInputStream(canonicalizer);
CanonicalizationMethod canonicalizationMethod =
MOAXSecProvider.getXMLSignatureFactory().newCanonicalizationMethod(
CanonicalizationMethod.EXCLUSIVE, new ExcC14NParameterSpec());
//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);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
canonicalizationMethod.transform(new
NodeListToNodeSetDataAdapter(nodeList), null, baos);
baos.close();
return new ByteArrayInputStream(baos.toByteArray());
/*
NodeList nodeList;
try {
nodeList = XPathUtils.selectNodeList(element, XPathUtils.ALL_NODES_XPATH);
} catch (XPathException e) {
nodeList = new NodeListAdapter(Collections.EMPTY_LIST);
}
//c14n.setInput(nodeList);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
canonicalizationMethod.transform(new NodeListToNodeSetDataAdapter(nodeList), null, baos);
baos.close();
return new ByteArrayInputStream(baos.toByteArray());*/
}
}