1 /* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.ws.api.message.saaj; 27 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.HashMap; 31 import java.util.HashSet; 32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Set; 36 37 import javax.xml.namespace.QName; 38 import javax.xml.soap.SOAPException; 39 import javax.xml.soap.SOAPHeader; 40 import javax.xml.soap.SOAPHeaderElement; 41 import javax.xml.soap.SOAPMessage; 42 43 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; 44 import com.sun.xml.internal.messaging.saaj.soap.impl.HeaderImpl; 45 import com.sun.xml.internal.ws.api.SOAPVersion; 46 import com.sun.xml.internal.ws.api.WSBinding; 47 import com.sun.xml.internal.ws.api.message.Header; 48 import com.sun.xml.internal.ws.api.message.MessageHeaders; 49 import com.sun.xml.internal.ws.binding.SOAPBindingImpl; 50 import com.sun.xml.internal.ws.message.saaj.SAAJHeader; 51 52 public class SAAJMessageHeaders implements MessageHeaders { 53 SOAPMessage sm; 54 Map<SOAPHeaderElement, Header> nonSAAJHeaders; 55 Map<QName, Integer> notUnderstoodCount; 56 SOAPVersion soapVersion; 57 private Set<QName> understoodHeaders; 58 59 public SAAJMessageHeaders(SOAPMessage sm, SOAPVersion version) { 60 this.sm = sm; 61 this.soapVersion = version; 62 initHeaderUnderstanding(); 63 } 64 65 /** Set the initial understood/not understood state of the headers in this 66 * object 67 */ 68 private void initHeaderUnderstanding() { 69 SOAPHeader soapHeader = ensureSOAPHeader(); 70 if (soapHeader == null) { 71 return; 72 } 73 74 Iterator allHeaders = soapHeader.examineAllHeaderElements(); 75 while(allHeaders.hasNext()) { 76 SOAPHeaderElement nextHdrElem = (SOAPHeaderElement) allHeaders.next(); 77 if (nextHdrElem == null) { 78 continue; 79 } 80 if (nextHdrElem.getMustUnderstand()) { 81 notUnderstood(nextHdrElem.getElementQName()); 82 } 83 //only headers explicitly marked as understood should be 84 //in the understoodHeaders set, so don't add anything to 85 //that set at the beginning 86 } 87 88 } 89 90 @Override 91 public void understood(Header header) { 92 understood(header.getNamespaceURI(), header.getLocalPart()); 93 } 94 95 @Override 96 public void understood(String nsUri, String localName) { 97 understood(new QName(nsUri, localName)); 98 } 99 100 @Override 101 public void understood(QName qName) { 102 if (notUnderstoodCount == null) { 103 notUnderstoodCount = new HashMap<QName, Integer>(); 104 } 105 106 Integer count = notUnderstoodCount.get(qName); 107 if (count != null && count.intValue() > 0) { 108 //found the header in notUnderstood headers - decrement count 109 count = count.intValue() - 1; 110 if (count <= 0) { 111 //if the value is zero or negative, remove that header name 112 //since all headers by that name are understood now 113 notUnderstoodCount.remove(qName); 114 } else { 115 notUnderstoodCount.put(qName, count); 116 } 117 } 118 119 if (understoodHeaders == null) { 120 understoodHeaders = new HashSet<QName>(); 121 } 122 //also add it to the understood headers list (optimization for getUnderstoodHeaders) 123 understoodHeaders.add(qName); 124 125 } 126 127 @Override 128 public boolean isUnderstood(Header header) { 129 return isUnderstood(header.getNamespaceURI(), header.getLocalPart()); 130 } 131 @Override 132 public boolean isUnderstood(String nsUri, String localName) { 133 return isUnderstood(new QName(nsUri, localName)); 134 } 135 136 @Override 137 public boolean isUnderstood(QName name) { 138 if (understoodHeaders == null) { 139 return false; 140 } 141 return understoodHeaders.contains(name); 142 } 143 144 public boolean isUnderstood(int index) { 145 // TODO Auto-generated method stub 146 return false; 147 } 148 149 @Override 150 public Header get(String nsUri, String localName, boolean markAsUnderstood) { 151 SOAPHeaderElement h = find(nsUri, localName); 152 if (h != null) { 153 if (markAsUnderstood) { 154 understood(nsUri, localName); 155 } 156 return new SAAJHeader(h); 157 } 158 return null; 159 } 160 161 @Override 162 public Header get(QName name, boolean markAsUnderstood) { 163 return get(name.getNamespaceURI(), name.getLocalPart(), markAsUnderstood); 164 } 165 166 @Override 167 public Iterator<Header> getHeaders(QName headerName, 168 boolean markAsUnderstood) { 169 return getHeaders(headerName.getNamespaceURI(), headerName.getLocalPart(), markAsUnderstood); 170 } 171 172 @Override 173 public Iterator<Header> getHeaders(final String nsUri, final String localName, 174 final boolean markAsUnderstood) { 175 SOAPHeader soapHeader = ensureSOAPHeader(); 176 if (soapHeader == null) { 177 return null; 178 } 179 Iterator allHeaders = soapHeader.examineAllHeaderElements(); 180 if (markAsUnderstood) { 181 //mark all the matchingheaders as understood up front 182 //make an iterator while we're doing that 183 List<Header> headers = new ArrayList<Header>(); 184 while (allHeaders.hasNext()) { 185 SOAPHeaderElement nextHdr = (SOAPHeaderElement) allHeaders.next(); 186 if (nextHdr != null && 187 nextHdr.getNamespaceURI().equals(nsUri)) { 188 if (localName == null || 189 nextHdr.getLocalName().equals(localName)) { 190 understood(nextHdr.getNamespaceURI(), nextHdr.getLocalName()); 191 headers.add(new SAAJHeader(nextHdr)); 192 } 193 } 194 } 195 return headers.iterator(); 196 } 197 //if we got here markAsUnderstood is false - return a lazy iterator rather 198 //than traverse the entire list of headers now 199 return new HeaderReadIterator(allHeaders, nsUri, localName); 200 } 201 202 @Override 203 public Iterator<Header> getHeaders(String nsUri, boolean markAsUnderstood) { 204 return getHeaders(nsUri, null, markAsUnderstood); 205 } 206 @Override 207 public boolean add(Header header) { 208 try { 209 header.writeTo(sm); 210 } catch (SOAPException e) { 211 //TODO log exception 212 return false; 213 } 214 215 //the newly added header is not understood by default 216 notUnderstood(new QName(header.getNamespaceURI(), header.getLocalPart())); 217 218 //track non saaj headers so that they can be retrieved later 219 if (isNonSAAJHeader(header)) { 220 //TODO assumes only one header with that name? 221 addNonSAAJHeader(find(header.getNamespaceURI(), header.getLocalPart()), 222 header); 223 } 224 225 return true; 226 } 227 228 @Override 229 public Header remove(QName name) { 230 return remove(name.getNamespaceURI(), name.getLocalPart()); 231 } 232 233 @Override 234 public Header remove(String nsUri, String localName) { 235 SOAPHeader soapHeader = ensureSOAPHeader(); 236 if (soapHeader == null) { 237 return null; 238 } 239 SOAPDocumentImpl soapDocument = ((HeaderImpl)soapHeader).getSoapDocument(); 240 SOAPHeaderElement headerElem = find(nsUri, localName); 241 if (headerElem == null) { 242 return null; 243 } 244 headerElem = (SOAPHeaderElement) soapDocument.find(soapHeader.removeChild(headerElem)); 245 246 //it might have been a nonSAAJHeader - remove from that map 247 removeNonSAAJHeader(headerElem); 248 249 //remove it from understoodHeaders and notUnderstoodHeaders if present 250 QName hdrName = (nsUri == null) ? new QName(localName) : new QName(nsUri, localName); 251 if (understoodHeaders != null) { 252 understoodHeaders.remove(hdrName); 253 } 254 removeNotUnderstood(hdrName); 255 256 return new SAAJHeader(headerElem); 257 } 258 259 private void removeNotUnderstood(QName hdrName) { 260 if (notUnderstoodCount == null) { 261 return; 262 } 263 Integer notUnderstood = notUnderstoodCount.get(hdrName); 264 if (notUnderstood != null) { 265 int intNotUnderstood = notUnderstood; 266 intNotUnderstood--; 267 if (intNotUnderstood <= 0) { 268 notUnderstoodCount.remove(hdrName); 269 } 270 } 271 272 } 273 274 private SOAPHeaderElement find(QName qName) { 275 return find(qName.getNamespaceURI(), qName.getLocalPart()); 276 } 277 278 private SOAPHeaderElement find(String nsUri, String localName) { 279 SOAPHeader soapHeader = ensureSOAPHeader(); 280 if (soapHeader == null) { 281 return null; 282 } 283 Iterator allHeaders = soapHeader.examineAllHeaderElements(); 284 while(allHeaders.hasNext()) { 285 SOAPHeaderElement nextHdrElem = (SOAPHeaderElement) allHeaders.next(); 286 if (nextHdrElem.getNamespaceURI().equals(nsUri) && 287 nextHdrElem.getLocalName().equals(localName)) { 288 return nextHdrElem; 289 } 290 } 291 return null; 292 } 293 294 private void notUnderstood(QName qName) { 295 if (notUnderstoodCount == null) { 296 notUnderstoodCount = new HashMap<QName, Integer>(); 297 } 298 Integer count = notUnderstoodCount.get(qName); 299 if (count == null) { 300 notUnderstoodCount.put(qName, 1); 301 } else { 302 notUnderstoodCount.put(qName, count + 1); 303 } 304 305 //if for some strange reason it was previously understood and now is not, 306 //remove it from understoodHeaders if it exists there 307 if (understoodHeaders != null) { 308 understoodHeaders.remove(qName); 309 } 310 } 311 312 /** 313 * Utility method to get the SOAPHeader from a SOAPMessage, adding one if 314 * one is not present in the original message. 315 */ 316 private SOAPHeader ensureSOAPHeader() { 317 SOAPHeader header; 318 try { 319 header = sm.getSOAPPart().getEnvelope().getHeader(); 320 if (header != null) { 321 return header; 322 } else { 323 return sm.getSOAPPart().getEnvelope().addHeader(); 324 } 325 } catch (Exception e) { 326 return null; 327 } 328 } 329 330 private boolean isNonSAAJHeader(Header header) { 331 return !(header instanceof SAAJHeader); 332 } 333 334 private void addNonSAAJHeader(SOAPHeaderElement headerElem, Header header) { 335 if (nonSAAJHeaders == null) { 336 nonSAAJHeaders = new HashMap<>(); 337 } 338 nonSAAJHeaders.put(headerElem, header); 339 } 340 341 private void removeNonSAAJHeader(SOAPHeaderElement headerElem) { 342 if (nonSAAJHeaders != null) { 343 nonSAAJHeaders.remove(headerElem); 344 } 345 } 346 347 @Override 348 public boolean addOrReplace(Header header) { 349 remove(header.getNamespaceURI(), header.getLocalPart()); 350 return add(header); 351 } 352 353 @Override 354 public void replace(Header old, Header header) { 355 if (remove(old.getNamespaceURI(), old.getLocalPart()) == null) 356 throw new IllegalArgumentException(); 357 add(header); 358 } 359 360 @Override 361 public Set<QName> getUnderstoodHeaders() { 362 return understoodHeaders; 363 } 364 365 @Override 366 public Set<QName> getNotUnderstoodHeaders(Set<String> roles, 367 Set<QName> knownHeaders, WSBinding binding) { 368 Set<QName> notUnderstoodHeaderNames = new HashSet<QName>(); 369 if (notUnderstoodCount == null) { 370 return notUnderstoodHeaderNames; 371 } 372 for (QName headerName : notUnderstoodCount.keySet()) { 373 int count = notUnderstoodCount.get(headerName); 374 if (count <= 0) { 375 continue; 376 } 377 SOAPHeaderElement hdrElem = find(headerName); 378 if (!hdrElem.getMustUnderstand()) { 379 continue; 380 } 381 SAAJHeader hdr = new SAAJHeader(hdrElem); 382 //mustUnderstand attribute is true - but there may be 383 //additional criteria 384 boolean understood = false; 385 if (roles != null) { 386 understood = !roles.contains(hdr.getRole(soapVersion)); 387 } 388 if (understood) { 389 continue; 390 } 391 //if it must be understood see if it is understood by the binding 392 //or is in knownheaders 393 if (binding != null && binding instanceof SOAPBindingImpl) { 394 understood = ((SOAPBindingImpl) binding).understandsHeader(headerName); 395 if (!understood) { 396 if (knownHeaders != null && knownHeaders.contains(headerName)) { 397 understood = true; 398 } 399 } 400 } 401 if (!understood) { 402 notUnderstoodHeaderNames.add(headerName); 403 } 404 } 405 return notUnderstoodHeaderNames; 406 } 407 408 @Override 409 public Iterator<Header> getHeaders() { 410 SOAPHeader soapHeader = ensureSOAPHeader(); 411 if (soapHeader == null) { 412 return null; 413 } 414 Iterator allHeaders = soapHeader.examineAllHeaderElements(); 415 return new HeaderReadIterator(allHeaders, null, null); 416 } 417 418 private static class HeaderReadIterator implements Iterator<Header> { 419 SOAPHeaderElement current; 420 Iterator soapHeaders; 421 String myNsUri; 422 String myLocalName; 423 424 public HeaderReadIterator(Iterator allHeaders, String nsUri, 425 String localName) { 426 this.soapHeaders = allHeaders; 427 this.myNsUri = nsUri; 428 this.myLocalName = localName; 429 } 430 431 @Override 432 public boolean hasNext() { 433 if (current == null) { 434 advance(); 435 } 436 return (current != null); 437 } 438 439 @Override 440 public Header next() { 441 if (!hasNext()) { 442 return null; 443 } 444 if (current == null) { 445 return null; 446 } 447 448 SAAJHeader ret = new SAAJHeader(current); 449 current = null; 450 return ret; 451 } 452 453 @Override 454 public void remove() { 455 throw new UnsupportedOperationException(); 456 } 457 458 private void advance() { 459 while (soapHeaders.hasNext()) { 460 SOAPHeaderElement nextHdr = (SOAPHeaderElement) soapHeaders.next(); 461 if (nextHdr != null && 462 (myNsUri == null || nextHdr.getNamespaceURI().equals(myNsUri)) && 463 (myLocalName == null || nextHdr.getLocalName().equals(myLocalName))) { 464 current = nextHdr; 465 //found it 466 return; 467 } 468 } 469 //if we got here we didn't find a match 470 current = null; 471 } 472 473 } 474 475 @Override 476 public boolean hasHeaders() { 477 SOAPHeader soapHeader = ensureSOAPHeader(); 478 if (soapHeader == null) { 479 return false; 480 } 481 482 Iterator allHeaders = soapHeader.examineAllHeaderElements(); 483 return allHeaders.hasNext(); 484 } 485 486 @Override 487 public List<Header> asList() { 488 SOAPHeader soapHeader = ensureSOAPHeader(); 489 if (soapHeader == null) { 490 return Collections.emptyList(); 491 } 492 493 Iterator allHeaders = soapHeader.examineAllHeaderElements(); 494 List<Header> headers = new ArrayList<Header>(); 495 while (allHeaders.hasNext()) { 496 SOAPHeaderElement nextHdr = (SOAPHeaderElement) allHeaders.next(); 497 headers.add(new SAAJHeader(nextHdr)); 498 } 499 return headers; 500 } 501 }