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, 2013, Oracle and/or its affiliates. All rights reserved. 25 */ 26 /* 27 * $Id: DOMSignatureProperty.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 SignatureProperty. 45 * 46 * @author Sean Mullan 47 */ 48 public final class DOMSignatureProperty extends DOMStructure 49 implements SignatureProperty { 50 51 private final String id; 52 private final String target; 53 private final List<XMLStructure> content; 54 55 /** 56 * Creates a <code>SignatureProperty</code> from the specified parameters. 57 * 58 * @param content a list of one or more {@link XMLStructure}s. The list 59 * is defensively copied to protect against subsequent modification. 60 * @param target the target URI 61 * @param id the Id (may be <code>null</code>) 62 * @return a <code>SignatureProperty</code> 63 * @throws ClassCastException if <code>content</code> contains any 64 * entries that are not of type {@link XMLStructure} 65 * @throws IllegalArgumentException if <code>content</code> is empty 66 * @throws NullPointerException if <code>content</code> or 67 * <code>target</code> is <code>null</code> 68 */ 69 public DOMSignatureProperty(List<? extends XMLStructure> content, 70 String target, String id) 71 { 72 if (target == null) { 73 throw new NullPointerException("target cannot be null"); 74 } else if (content == null) { 75 throw new NullPointerException("content cannot be null"); 76 } else if (content.isEmpty()) { 77 throw new IllegalArgumentException("content cannot be empty"); 78 } else { 79 this.content = Collections.unmodifiableList( 80 new ArrayList<XMLStructure>(content)); 81 for (int i = 0, size = this.content.size(); i < size; i++) { 82 if (!(this.content.get(i) instanceof XMLStructure)) { 83 throw new ClassCastException 84 ("content["+i+"] is not a valid type"); 85 } 86 } 87 } 88 this.target = target; 89 this.id = id; 90 } 91 92 /** 93 * Creates a <code>DOMSignatureProperty</code> from an element. 94 * 95 * @param propElem a SignatureProperty element 96 */ 97 public DOMSignatureProperty(Element propElem, XMLCryptoContext context) 98 throws MarshalException 99 { 100 // unmarshal attributes 101 target = DOMUtils.getAttributeValue(propElem, "Target"); 102 if (target == null) { 103 throw new MarshalException("target cannot be null"); 104 } 105 Attr attr = propElem.getAttributeNodeNS(null, "Id"); 106 if (attr != null) { 107 id = attr.getValue(); 108 propElem.setIdAttributeNode(attr, true); 109 } else { 110 id = null; 111 } 112 113 NodeList nodes = propElem.getChildNodes(); 114 int length = nodes.getLength(); 115 List<XMLStructure> content = new ArrayList<XMLStructure>(length); 116 for (int i = 0; i < length; i++) { 117 content.add(new javax.xml.crypto.dom.DOMStructure(nodes.item(i))); 118 } 119 if (content.isEmpty()) { 120 throw new MarshalException("content cannot be empty"); 121 } else { 122 this.content = Collections.unmodifiableList(content); 123 } 124 } 125 126 public List getContent() { 127 return content; 128 } 129 130 public String getId() { 131 return id; 132 } 133 134 public String getTarget() { 135 return target; 136 } 137 138 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context) 139 throws MarshalException 140 { 141 Document ownerDoc = DOMUtils.getOwnerDocument(parent); 142 Element propElem = DOMUtils.createElement(ownerDoc, "SignatureProperty", 143 XMLSignature.XMLNS, dsPrefix); 144 145 // set attributes 146 DOMUtils.setAttributeID(propElem, "Id", id); 147 DOMUtils.setAttribute(propElem, "Target", target); 148 149 // create and append any elements and mixed content 150 for (XMLStructure property : content) { 151 DOMUtils.appendChild(propElem, 152 ((javax.xml.crypto.dom.DOMStructure)property).getNode()); 153 } 154 155 parent.appendChild(propElem); 156 } 157 158 @Override 159 public boolean equals(Object o) { 160 if (this == o) { 161 return true; 162 } 163 164 if (!(o instanceof SignatureProperty)) { 165 return false; 166 } 167 SignatureProperty osp = (SignatureProperty)o; 168 169 boolean idsEqual = (id == null ? osp.getId() == null 170 : id.equals(osp.getId())); 171 172 @SuppressWarnings("unchecked") 173 List<XMLStructure> ospContent = osp.getContent(); 174 return (equalsContent(ospContent) && 175 target.equals(osp.getTarget()) && idsEqual); 176 } 177 178 @Override 179 public int hashCode() { 180 int result = 17; 181 if (id != null) { 182 result = 31 * result + id.hashCode(); 183 } 184 result = 31 * result + target.hashCode(); 185 result = 31 * result + content.hashCode(); 186 187 return result; 188 } 189 190 private boolean equalsContent(List<XMLStructure> otherContent) { 191 int osize = otherContent.size(); 192 if (content.size() != osize) { 193 return false; 194 } 195 for (int i = 0; i < osize; i++) { 196 XMLStructure oxs = otherContent.get(i); 197 XMLStructure xs = content.get(i); 198 if (oxs instanceof javax.xml.crypto.dom.DOMStructure) { 199 if (!(xs instanceof javax.xml.crypto.dom.DOMStructure)) { 200 return false; 201 } 202 Node onode = ((javax.xml.crypto.dom.DOMStructure)oxs).getNode(); 203 Node node = ((javax.xml.crypto.dom.DOMStructure)xs).getNode(); 204 if (!DOMUtils.nodesEqual(node, onode)) { 205 return false; 206 } 207 } else { 208 if (!(xs.equals(oxs))) { 209 return false; 210 } 211 } 212 } 213 214 return true; 215 } 216 }