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, 2014, Oracle and/or its affiliates. All rights reserved. 25 */ 26/* 27 * $Id: DOMXMLObject.java 1333415 2012-05-03 12:03:51Z coheigea $ 28 */ 29package org.jcp.xml.dsig.internal.dom; 30 31import javax.xml.crypto.*; 32import javax.xml.crypto.dom.DOMCryptoContext; 33import javax.xml.crypto.dsig.*; 34 35import java.security.Provider; 36import java.util.*; 37 38import org.w3c.dom.Attr; 39import org.w3c.dom.Document; 40import org.w3c.dom.Element; 41import org.w3c.dom.Node; 42import org.w3c.dom.NodeList; 43 44/** 45 * DOM-based implementation of XMLObject. 46 * 47 * @author Sean Mullan 48 */ 49public final class DOMXMLObject extends DOMStructure implements XMLObject { 50 51 private final String id; 52 private final String mimeType; 53 private final String encoding; 54 private final List<XMLStructure> content; 55 private Element objectElem; 56 57 /** 58 * Creates an <code>XMLObject</code> from the specified parameters. 59 * 60 * @param content a list of {@link XMLStructure}s. The list 61 * is defensively copied to protect against subsequent modification. 62 * May be <code>null</code> or empty. 63 * @param id the Id (may be <code>null</code>) 64 * @param mimeType the mime type (may be <code>null</code>) 65 * @param encoding the encoding (may be <code>null</code>) 66 * @throws ClassCastException if <code>content</code> contains any 67 * entries that are not of type {@link XMLStructure} 68 */ 69 public DOMXMLObject(List<? extends XMLStructure> content, String id, 70 String mimeType, String encoding) 71 { 72 List<XMLStructure> tempList = 73 Collections.checkedList(new ArrayList<XMLStructure>(), 74 XMLStructure.class); 75 if (content != null) { 76 tempList.addAll(content); 77 } 78 this.content = Collections.unmodifiableList(tempList); 79 this.id = id; 80 this.mimeType = mimeType; 81 this.encoding = encoding; 82 } 83 84 /** 85 * Creates an <code>XMLObject</code> from an element. 86 * 87 * @param objElem an Object element 88 * @throws MarshalException if there is an error when unmarshalling 89 */ 90 public DOMXMLObject(Element objElem, XMLCryptoContext context, 91 Provider provider) 92 throws MarshalException 93 { 94 // unmarshal attributes 95 this.encoding = DOMUtils.getAttributeValue(objElem, "Encoding"); 96 97 Attr attr = objElem.getAttributeNodeNS(null, "Id"); 98 if (attr != null) { 99 this.id = attr.getValue(); 100 objElem.setIdAttributeNode(attr, true); 101 } else { 102 this.id = null; 103 } 104 this.mimeType = DOMUtils.getAttributeValue(objElem, "MimeType"); 105 106 NodeList nodes = objElem.getChildNodes(); 107 int length = nodes.getLength(); 108 List<XMLStructure> content = new ArrayList<XMLStructure>(length); 109 for (int i = 0; i < length; i++) { 110 Node child = nodes.item(i); 111 if (child.getNodeType() == Node.ELEMENT_NODE) { 112 Element childElem = (Element)child; 113 String tag = childElem.getLocalName(); 114 if (tag.equals("Manifest")) { 115 content.add(new DOMManifest(childElem, context, provider)); 116 continue; 117 } else if (tag.equals("SignatureProperties")) { 118 content.add(new DOMSignatureProperties(childElem, context)); 119 continue; 120 } else if (tag.equals("X509Data")) { 121 content.add(new DOMX509Data(childElem)); 122 continue; 123 } 124 //@@@FIXME: check for other dsig structures 125 } 126 content.add(new javax.xml.crypto.dom.DOMStructure(child)); 127 } 128 if (content.isEmpty()) { 129 this.content = Collections.emptyList(); 130 } else { 131 this.content = Collections.unmodifiableList(content); 132 } 133 this.objectElem = objElem; 134 } 135 136 public List<XMLStructure> getContent() { 137 return content; 138 } 139 140 public String getId() { 141 return id; 142 } 143 144 public String getMimeType() { 145 return mimeType; 146 } 147 148 public String getEncoding() { 149 return encoding; 150 } 151 152 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context) 153 throws MarshalException { 154 Document ownerDoc = DOMUtils.getOwnerDocument(parent); 155 156 Element objElem = objectElem != null ? objectElem : null; 157 if (objElem == null) { 158 objElem = DOMUtils.createElement(ownerDoc, "Object", 159 XMLSignature.XMLNS, dsPrefix); 160 161 // set attributes 162 DOMUtils.setAttributeID(objElem, "Id", id); 163 DOMUtils.setAttribute(objElem, "MimeType", mimeType); 164 DOMUtils.setAttribute(objElem, "Encoding", encoding); 165 166 // create and append any elements and mixed content, if necessary 167 for (XMLStructure object : content) { 168 if (object instanceof DOMStructure) { 169 ((DOMStructure)object).marshal(objElem, dsPrefix, context); 170 } else { 171 javax.xml.crypto.dom.DOMStructure domObject = 172 (javax.xml.crypto.dom.DOMStructure)object; 173 DOMUtils.appendChild(objElem, domObject.getNode()); 174 } 175 } 176 } 177 178 parent.appendChild(objElem); 179 } 180 181 @Override 182 public boolean equals(Object o) { 183 if (this == o) { 184 return true; 185 } 186 187 if (!(o instanceof XMLObject)) { 188 return false; 189 } 190 XMLObject oxo = (XMLObject)o; 191 192 boolean idsEqual = (id == null ? oxo.getId() == null 193 : id.equals(oxo.getId())); 194 boolean encodingsEqual = 195 (encoding == null ? oxo.getEncoding() == null 196 : encoding.equals(oxo.getEncoding())); 197 boolean mimeTypesEqual = 198 (mimeType == null ? oxo.getMimeType() == null 199 : mimeType.equals(oxo.getMimeType())); 200 201 List<XMLStructure> oxoContent = oxo.getContent(); 202 return (idsEqual && encodingsEqual && mimeTypesEqual && 203 equalsContent(oxoContent)); 204 } 205 206 @Override 207 public int hashCode() { 208 int result = 17; 209 if (id != null) { 210 result = 31 * result + id.hashCode(); 211 } 212 if (encoding != null) { 213 result = 31 * result + encoding.hashCode(); 214 } 215 if (mimeType != null) { 216 result = 31 * result + mimeType.hashCode(); 217 } 218 result = 31 * result + content.hashCode(); 219 220 return result; 221 } 222 223 private boolean equalsContent(List<XMLStructure> otherContent) { 224 if (content.size() != otherContent.size()) { 225 return false; 226 } 227 for (int i = 0, osize = otherContent.size(); i < osize; i++) { 228 XMLStructure oxs = otherContent.get(i); 229 XMLStructure xs = content.get(i); 230 if (oxs instanceof javax.xml.crypto.dom.DOMStructure) { 231 if (!(xs instanceof javax.xml.crypto.dom.DOMStructure)) { 232 return false; 233 } 234 Node onode = ((javax.xml.crypto.dom.DOMStructure)oxs).getNode(); 235 Node node = ((javax.xml.crypto.dom.DOMStructure)xs).getNode(); 236 if (!DOMUtils.nodesEqual(node, onode)) { 237 return false; 238 } 239 } else { 240 if (!(xs.equals(oxs))) { 241 return false; 242 } 243 } 244 } 245 246 return true; 247 } 248} 249