1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/**
6 * Licensed to the Apache Software Foundation (ASF) under one
7 * or more contributor license agreements. See the NOTICE file
8 * distributed with this work for additional information
9 * regarding copyright ownership. The ASF licenses this file
10 * to you under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance
12 * with the License. You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an
18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 * KIND, either express or implied. See the License for the
20 * specific language governing permissions and limitations
21 * under the License.
22 */
23/*
24 * ===========================================================================
25 *
26 * (C) Copyright IBM Corp. 2003 All Rights Reserved.
27 *
28 * ===========================================================================
29 */
30/*
31 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
32 */
33/*
34 * $Id: DOMXPathFilter2Transform.java 1203789 2011-11-18 18:46:07Z mullan $
35 */
36package org.jcp.xml.dsig.internal.dom;
37
38import javax.xml.crypto.*;
39import javax.xml.crypto.dsig.*;
40import javax.xml.crypto.dsig.spec.TransformParameterSpec;
41import javax.xml.crypto.dsig.spec.XPathType;
42import javax.xml.crypto.dsig.spec.XPathFilter2ParameterSpec;
43import java.security.InvalidAlgorithmParameterException;
44import java.util.ArrayList;
45import java.util.HashMap;
46import java.util.List;
47import java.util.Map;
48import java.util.Set;
49import org.w3c.dom.Attr;
50import org.w3c.dom.Element;
51import org.w3c.dom.NamedNodeMap;
52
53/**
54 * DOM-based implementation of XPath Filter 2.0 Transform.
55 * (Uses Apache XML-Sec Transform implementation)
56 *
57 * @author Joyce Leung
58 */
59public final class DOMXPathFilter2Transform extends ApacheTransform {
60
61    public void init(TransformParameterSpec params)
62        throws InvalidAlgorithmParameterException
63    {
64        if (params == null) {
65            throw new InvalidAlgorithmParameterException("params are required");
66        } else if (!(params instanceof XPathFilter2ParameterSpec)) {
67            throw new InvalidAlgorithmParameterException
68                ("params must be of type XPathFilter2ParameterSpec");
69        }
70        this.params = params;
71    }
72
73    public void init(XMLStructure parent, XMLCryptoContext context)
74        throws InvalidAlgorithmParameterException
75    {
76        super.init(parent, context);
77        try {
78            unmarshalParams(DOMUtils.getFirstChildElement(transformElem));
79        } catch (MarshalException me) {
80            throw new InvalidAlgorithmParameterException(me);
81        }
82    }
83
84    private void unmarshalParams(Element curXPathElem) throws MarshalException
85    {
86        List<XPathType> list = new ArrayList<XPathType>();
87        while (curXPathElem != null) {
88            String xPath = curXPathElem.getFirstChild().getNodeValue();
89            String filterVal = DOMUtils.getAttributeValue(curXPathElem,
90                                                          "Filter");
91            if (filterVal == null) {
92                throw new MarshalException("filter cannot be null");
93            }
94            XPathType.Filter filter = null;
95            if (filterVal.equals("intersect")) {
96                filter = XPathType.Filter.INTERSECT;
97            } else if (filterVal.equals("subtract")) {
98                filter = XPathType.Filter.SUBTRACT;
99            } else if (filterVal.equals("union")) {
100                filter = XPathType.Filter.UNION;
101            } else {
102                throw new MarshalException("Unknown XPathType filter type" +
103                                           filterVal);
104            }
105            NamedNodeMap attributes = curXPathElem.getAttributes();
106            if (attributes != null) {
107                int length = attributes.getLength();
108                Map<String, String> namespaceMap =
109                    new HashMap<String, String>(length);
110                for (int i = 0; i < length; i++) {
111                    Attr attr = (Attr)attributes.item(i);
112                    String prefix = attr.getPrefix();
113                    if (prefix != null && prefix.equals("xmlns")) {
114                        namespaceMap.put(attr.getLocalName(), attr.getValue());
115                    }
116                }
117                list.add(new XPathType(xPath, filter, namespaceMap));
118            } else {
119                list.add(new XPathType(xPath, filter));
120            }
121
122            curXPathElem = DOMUtils.getNextSiblingElement(curXPathElem);
123        }
124        this.params = new XPathFilter2ParameterSpec(list);
125    }
126
127    public void marshalParams(XMLStructure parent, XMLCryptoContext context)
128        throws MarshalException
129    {
130        super.marshalParams(parent, context);
131        XPathFilter2ParameterSpec xp =
132            (XPathFilter2ParameterSpec)getParameterSpec();
133        String prefix = DOMUtils.getNSPrefix(context, Transform.XPATH2);
134        String qname = (prefix == null || prefix.length() == 0)
135                       ? "xmlns" : "xmlns:" + prefix;
136        List<XPathType> xpathList = xp.getXPathList();
137        for (XPathType xpathType : xpathList) {
138            Element elem = DOMUtils.createElement(ownerDoc, "XPath",
139                                                  Transform.XPATH2, prefix);
140            elem.appendChild
141                (ownerDoc.createTextNode(xpathType.getExpression()));
142            DOMUtils.setAttribute(elem, "Filter",
143                                  xpathType.getFilter().toString());
144            elem.setAttributeNS("http://www.w3.org/2000/xmlns/", qname,
145                                Transform.XPATH2);
146
147            // add namespace attributes, if necessary
148            Set<Map.Entry<String, String>> entries =
149                xpathType.getNamespaceMap().entrySet();
150            for (Map.Entry<String, String> entry : entries) {
151                elem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" +
152                                    entry.getKey(),
153                                    entry.getValue());
154            }
155
156            transformElem.appendChild(elem);
157        }
158    }
159}
160