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