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