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  * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
  25  */
  26 /*
  27  * $Id: DOMSignatureProperties.java 1333415 2012-05-03 12:03:51Z coheigea $
  28  */
  29 package org.jcp.xml.dsig.internal.dom;
  30 
  31 import javax.xml.crypto.*;
  32 import javax.xml.crypto.dom.DOMCryptoContext;
  33 import javax.xml.crypto.dsig.*;
  34 
  35 import java.util.*;
  36 
  37 import org.w3c.dom.Attr;
  38 import org.w3c.dom.Document;
  39 import org.w3c.dom.Element;
  40 import org.w3c.dom.Node;
  41 import org.w3c.dom.NodeList;
  42 
  43 /**
  44  * DOM-based implementation of SignatureProperties.
  45  *
  46  * @author Sean Mullan
  47  */
  48 public final class DOMSignatureProperties extends DOMStructure 
  49     implements SignatureProperties {
  50  
  51     private final String id;
  52     private final List<SignatureProperty> properties;
  53 
  54     /**
  55      * Creates a <code>DOMSignatureProperties</code> from the specified 
  56      * parameters.
  57      *
  58      * @param properties a list of one or more {@link SignatureProperty}s. The 
  59      *    list is defensively copied to protect against subsequent modification.
  60      * @param id the Id (may be <code>null</code>)
  61      * @return a <code>DOMSignatureProperties</code>
  62      * @throws ClassCastException if <code>properties</code> contains any
  63      *    entries that are not of type {@link SignatureProperty}
  64      * @throws IllegalArgumentException if <code>properties</code> is empty
  65      * @throws NullPointerException if <code>properties</code>
  66      */
  67     public DOMSignatureProperties(List<? extends SignatureProperty> properties,
  68                                   String id)
  69     {
  70         if (properties == null) {
  71             throw new NullPointerException("properties cannot be null");
  72         } else if (properties.isEmpty()) {
  73             throw new IllegalArgumentException("properties cannot be empty");
  74         } else {
  75             this.properties = Collections.unmodifiableList(
  76                 new ArrayList<SignatureProperty>(properties));
  77             for (int i = 0, size = this.properties.size(); i < size; i++) {
  78                 if (!(this.properties.get(i) instanceof SignatureProperty)) {
  79                     throw new ClassCastException
  80                         ("properties["+i+"] is not a valid type");
  81                 }
  82             }
  83         }
  84         this.id = id;
  85     }
  86 
  87     /**
  88      * Creates a <code>DOMSignatureProperties</code> from an element.
  89      *
  90      * @param propsElem a SignatureProperties element
  91      * @throws MarshalException if a marshalling error occurs
  92      */
  93     public DOMSignatureProperties(Element propsElem, XMLCryptoContext context)
  94         throws MarshalException
  95     {
  96         // unmarshal attributes
  97         Attr attr = propsElem.getAttributeNodeNS(null, "Id");
  98         if (attr != null) {
  99             id = attr.getValue();
 100             propsElem.setIdAttributeNode(attr, true);
 101         } else {
 102             id = null;
 103         }
 104 
 105         NodeList nodes = propsElem.getChildNodes();
 106         int length = nodes.getLength();
 107         List<SignatureProperty> properties =
 108             new ArrayList<SignatureProperty>(length);
 109         for (int i = 0; i < length; i++) {
 110             Node child = nodes.item(i);
 111             if (child.getNodeType() == Node.ELEMENT_NODE) {
 112                 properties.add(new DOMSignatureProperty((Element)child,
 113                                                         context));
 114             }
 115         }
 116         if (properties.isEmpty()) {
 117             throw new MarshalException("properties cannot be empty");
 118         } else {
 119             this.properties = Collections.unmodifiableList(properties);
 120         }
 121     }
 122 
 123     public List getProperties() {
 124         return properties;
 125     }
 126 
 127     public String getId() {
 128         return id;
 129     }
 130 
 131     public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
 132         throws MarshalException
 133     {
 134         Document ownerDoc = DOMUtils.getOwnerDocument(parent);
 135         Element propsElem = DOMUtils.createElement(ownerDoc,
 136                                                    "SignatureProperties",
 137                                                    XMLSignature.XMLNS,
 138                                                    dsPrefix);
 139 
 140         // set attributes
 141         DOMUtils.setAttributeID(propsElem, "Id", id);
 142 
 143         // create and append any properties
 144         for (SignatureProperty property : properties) {
 145             ((DOMSignatureProperty)property).marshal(propsElem, dsPrefix,
 146                                                      context);
 147         }
 148             
 149         parent.appendChild(propsElem);
 150     }
 151 
 152     @Override
 153     public boolean equals(Object o) {
 154         if (this == o) {
 155             return true;
 156         }
 157 
 158         if (!(o instanceof SignatureProperties)) {
 159             return false;
 160         }
 161         SignatureProperties osp = (SignatureProperties)o;
 162 
 163         boolean idsEqual = (id == null ? osp.getId() == null
 164                                        : id.equals(osp.getId()));
 165 
 166         return (properties.equals(osp.getProperties()) && idsEqual);
 167     }
 168     
 169     @Override
 170     public int hashCode() {
 171         int result = 17;
 172         if (id != null) {
 173             result = 31 * result + id.hashCode();
 174         }
 175         result = 31 * result + properties.hashCode();
 176         
 177         return result;
 178     }
 179 }