| /* |
| * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.xml.internal.ws.api.message.saaj; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.soap.SOAPException; |
| import javax.xml.soap.SOAPHeader; |
| import javax.xml.soap.SOAPHeaderElement; |
| import javax.xml.soap.SOAPMessage; |
| |
| import com.sun.xml.internal.ws.api.SOAPVersion; |
| import com.sun.xml.internal.ws.api.WSBinding; |
| import com.sun.xml.internal.ws.api.message.Header; |
| import com.sun.xml.internal.ws.api.message.MessageHeaders; |
| import com.sun.xml.internal.ws.binding.SOAPBindingImpl; |
| import com.sun.xml.internal.ws.message.saaj.SAAJHeader; |
| |
| public class SAAJMessageHeaders implements MessageHeaders { |
| SOAPMessage sm; |
| Map<SOAPHeaderElement, Header> nonSAAJHeaders; |
| Map<QName, Integer> notUnderstoodCount; |
| SOAPVersion soapVersion; |
| private Set<QName> understoodHeaders; |
| |
| public SAAJMessageHeaders(SOAPMessage sm, SOAPVersion version) { |
| this.sm = sm; |
| this.soapVersion = version; |
| initHeaderUnderstanding(); |
| } |
| |
| /** Set the initial understood/not understood state of the headers in this |
| * object |
| */ |
| private void initHeaderUnderstanding() { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return; |
| } |
| |
| Iterator allHeaders = soapHeader.examineAllHeaderElements(); |
| while(allHeaders.hasNext()) { |
| SOAPHeaderElement nextHdrElem = (SOAPHeaderElement) allHeaders.next(); |
| if (nextHdrElem == null) { |
| continue; |
| } |
| if (nextHdrElem.getMustUnderstand()) { |
| notUnderstood(nextHdrElem.getElementQName()); |
| } |
| //only headers explicitly marked as understood should be |
| //in the understoodHeaders set, so don't add anything to |
| //that set at the beginning |
| } |
| |
| } |
| |
| @Override |
| public void understood(Header header) { |
| understood(header.getNamespaceURI(), header.getLocalPart()); |
| } |
| |
| @Override |
| public void understood(String nsUri, String localName) { |
| understood(new QName(nsUri, localName)); |
| } |
| |
| @Override |
| public void understood(QName qName) { |
| if (notUnderstoodCount == null) { |
| notUnderstoodCount = new HashMap<QName, Integer>(); |
| } |
| |
| Integer count = notUnderstoodCount.get(qName); |
| if (count != null && count.intValue() > 0) { |
| //found the header in notUnderstood headers - decrement count |
| count = count.intValue() - 1; |
| if (count <= 0) { |
| //if the value is zero or negative, remove that header name |
| //since all headers by that name are understood now |
| notUnderstoodCount.remove(qName); |
| } else { |
| notUnderstoodCount.put(qName, count); |
| } |
| } |
| |
| if (understoodHeaders == null) { |
| understoodHeaders = new HashSet<QName>(); |
| } |
| //also add it to the understood headers list (optimization for getUnderstoodHeaders) |
| understoodHeaders.add(qName); |
| |
| } |
| |
| @Override |
| public boolean isUnderstood(Header header) { |
| return isUnderstood(header.getNamespaceURI(), header.getLocalPart()); |
| } |
| @Override |
| public boolean isUnderstood(String nsUri, String localName) { |
| return isUnderstood(new QName(nsUri, localName)); |
| } |
| |
| @Override |
| public boolean isUnderstood(QName name) { |
| if (understoodHeaders == null) { |
| return false; |
| } |
| return understoodHeaders.contains(name); |
| } |
| |
| public boolean isUnderstood(int index) { |
| // TODO Auto-generated method stub |
| return false; |
| } |
| |
| @Override |
| public Header get(String nsUri, String localName, boolean markAsUnderstood) { |
| SOAPHeaderElement h = find(nsUri, localName); |
| if (h != null) { |
| if (markAsUnderstood) { |
| understood(nsUri, localName); |
| } |
| return new SAAJHeader(h); |
| } |
| return null; |
| } |
| |
| @Override |
| public Header get(QName name, boolean markAsUnderstood) { |
| return get(name.getNamespaceURI(), name.getLocalPart(), markAsUnderstood); |
| } |
| |
| @Override |
| public Iterator<Header> getHeaders(QName headerName, |
| boolean markAsUnderstood) { |
| return getHeaders(headerName.getNamespaceURI(), headerName.getLocalPart(), markAsUnderstood); |
| } |
| |
| @Override |
| public Iterator<Header> getHeaders(final String nsUri, final String localName, |
| final boolean markAsUnderstood) { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return null; |
| } |
| Iterator allHeaders = soapHeader.examineAllHeaderElements(); |
| if (markAsUnderstood) { |
| //mark all the matchingheaders as understood up front |
| //make an iterator while we're doing that |
| List<Header> headers = new ArrayList<Header>(); |
| while (allHeaders.hasNext()) { |
| SOAPHeaderElement nextHdr = (SOAPHeaderElement) allHeaders.next(); |
| if (nextHdr != null && |
| nextHdr.getNamespaceURI().equals(nsUri)) { |
| if (localName == null || |
| nextHdr.getLocalName().equals(localName)) { |
| understood(nextHdr.getNamespaceURI(), nextHdr.getLocalName()); |
| headers.add(new SAAJHeader(nextHdr)); |
| } |
| } |
| } |
| return headers.iterator(); |
| } |
| //if we got here markAsUnderstood is false - return a lazy iterator rather |
| //than traverse the entire list of headers now |
| return new HeaderReadIterator(allHeaders, nsUri, localName); |
| } |
| |
| @Override |
| public Iterator<Header> getHeaders(String nsUri, boolean markAsUnderstood) { |
| return getHeaders(nsUri, null, markAsUnderstood); |
| } |
| @Override |
| public boolean add(Header header) { |
| try { |
| header.writeTo(sm); |
| } catch (SOAPException e) { |
| //TODO log exception |
| return false; |
| } |
| |
| //the newly added header is not understood by default |
| notUnderstood(new QName(header.getNamespaceURI(), header.getLocalPart())); |
| |
| //track non saaj headers so that they can be retrieved later |
| if (isNonSAAJHeader(header)) { |
| //TODO assumes only one header with that name? |
| addNonSAAJHeader(find(header.getNamespaceURI(), header.getLocalPart()), |
| header); |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public Header remove(QName name) { |
| return remove(name.getNamespaceURI(), name.getLocalPart()); |
| } |
| |
| @Override |
| public Header remove(String nsUri, String localName) { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return null; |
| } |
| SOAPHeaderElement headerElem = find(nsUri, localName); |
| if (headerElem == null) { |
| return null; |
| } |
| headerElem = (SOAPHeaderElement) soapHeader.removeChild(headerElem); |
| |
| //it might have been a nonSAAJHeader - remove from that map |
| removeNonSAAJHeader(headerElem); |
| |
| //remove it from understoodHeaders and notUnderstoodHeaders if present |
| QName hdrName = (nsUri == null) ? new QName(localName) : new QName(nsUri, localName); |
| if (understoodHeaders != null) { |
| understoodHeaders.remove(hdrName); |
| } |
| removeNotUnderstood(hdrName); |
| |
| return new SAAJHeader(headerElem); |
| } |
| |
| private void removeNotUnderstood(QName hdrName) { |
| if (notUnderstoodCount == null) { |
| return; |
| } |
| Integer notUnderstood = notUnderstoodCount.get(hdrName); |
| if (notUnderstood != null) { |
| int intNotUnderstood = notUnderstood; |
| intNotUnderstood--; |
| if (intNotUnderstood <= 0) { |
| notUnderstoodCount.remove(hdrName); |
| } |
| } |
| |
| } |
| |
| private SOAPHeaderElement find(QName qName) { |
| return find(qName.getNamespaceURI(), qName.getLocalPart()); |
| } |
| |
| private SOAPHeaderElement find(String nsUri, String localName) { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return null; |
| } |
| Iterator allHeaders = soapHeader.examineAllHeaderElements(); |
| while(allHeaders.hasNext()) { |
| SOAPHeaderElement nextHdrElem = (SOAPHeaderElement) allHeaders.next(); |
| if (nextHdrElem.getNamespaceURI().equals(nsUri) && |
| nextHdrElem.getLocalName().equals(localName)) { |
| return nextHdrElem; |
| } |
| } |
| return null; |
| } |
| |
| private void notUnderstood(QName qName) { |
| if (notUnderstoodCount == null) { |
| notUnderstoodCount = new HashMap<QName, Integer>(); |
| } |
| Integer count = notUnderstoodCount.get(qName); |
| if (count == null) { |
| notUnderstoodCount.put(qName, 1); |
| } else { |
| notUnderstoodCount.put(qName, count + 1); |
| } |
| |
| //if for some strange reason it was previously understood and now is not, |
| //remove it from understoodHeaders if it exists there |
| if (understoodHeaders != null) { |
| understoodHeaders.remove(qName); |
| } |
| } |
| |
| /** |
| * Utility method to get the SOAPHeader from a SOAPMessage, adding one if |
| * one is not present in the original message. |
| */ |
| private SOAPHeader ensureSOAPHeader() { |
| SOAPHeader header; |
| try { |
| header = sm.getSOAPPart().getEnvelope().getHeader(); |
| if (header != null) { |
| return header; |
| } else { |
| return sm.getSOAPPart().getEnvelope().addHeader(); |
| } |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| |
| private boolean isNonSAAJHeader(Header header) { |
| return !(header instanceof SAAJHeader); |
| } |
| |
| private void addNonSAAJHeader(SOAPHeaderElement headerElem, Header header) { |
| if (nonSAAJHeaders == null) { |
| nonSAAJHeaders = new HashMap<SOAPHeaderElement, Header>(); |
| } |
| nonSAAJHeaders.put(headerElem, header); |
| } |
| |
| private void removeNonSAAJHeader(SOAPHeaderElement headerElem) { |
| if (nonSAAJHeaders != null) { |
| nonSAAJHeaders.remove(headerElem); |
| } |
| } |
| |
| @Override |
| public boolean addOrReplace(Header header) { |
| remove(header.getNamespaceURI(), header.getLocalPart()); |
| return add(header); |
| } |
| |
| @Override |
| public void replace(Header old, Header header) { |
| if (remove(old.getNamespaceURI(), old.getLocalPart()) == null) |
| throw new IllegalArgumentException(); |
| add(header); |
| } |
| |
| @Override |
| public Set<QName> getUnderstoodHeaders() { |
| return understoodHeaders; |
| } |
| |
| @Override |
| public Set<QName> getNotUnderstoodHeaders(Set<String> roles, |
| Set<QName> knownHeaders, WSBinding binding) { |
| Set<QName> notUnderstoodHeaderNames = new HashSet<QName>(); |
| if (notUnderstoodCount == null) { |
| return notUnderstoodHeaderNames; |
| } |
| for (QName headerName : notUnderstoodCount.keySet()) { |
| int count = notUnderstoodCount.get(headerName); |
| if (count <= 0) { |
| continue; |
| } |
| SOAPHeaderElement hdrElem = find(headerName); |
| if (!hdrElem.getMustUnderstand()) { |
| continue; |
| } |
| SAAJHeader hdr = new SAAJHeader(hdrElem); |
| //mustUnderstand attribute is true - but there may be |
| //additional criteria |
| boolean understood = false; |
| if (roles != null) { |
| understood = !roles.contains(hdr.getRole(soapVersion)); |
| } |
| if (understood) { |
| continue; |
| } |
| //if it must be understood see if it is understood by the binding |
| //or is in knownheaders |
| if (binding != null && binding instanceof SOAPBindingImpl) { |
| understood = ((SOAPBindingImpl) binding).understandsHeader(headerName); |
| if (!understood) { |
| if (knownHeaders != null && knownHeaders.contains(headerName)) { |
| understood = true; |
| } |
| } |
| } |
| if (!understood) { |
| notUnderstoodHeaderNames.add(headerName); |
| } |
| } |
| return notUnderstoodHeaderNames; |
| } |
| |
| @Override |
| public Iterator<Header> getHeaders() { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return null; |
| } |
| Iterator allHeaders = soapHeader.examineAllHeaderElements(); |
| return new HeaderReadIterator(allHeaders, null, null); |
| } |
| |
| private static class HeaderReadIterator implements Iterator<Header> { |
| SOAPHeaderElement current; |
| Iterator soapHeaders; |
| String myNsUri; |
| String myLocalName; |
| |
| public HeaderReadIterator(Iterator allHeaders, String nsUri, |
| String localName) { |
| this.soapHeaders = allHeaders; |
| this.myNsUri = nsUri; |
| this.myLocalName = localName; |
| } |
| |
| @Override |
| public boolean hasNext() { |
| if (current == null) { |
| advance(); |
| } |
| return (current != null); |
| } |
| |
| @Override |
| public Header next() { |
| if (!hasNext()) { |
| return null; |
| } |
| if (current == null) { |
| return null; |
| } |
| |
| SAAJHeader ret = new SAAJHeader(current); |
| current = null; |
| return ret; |
| } |
| |
| @Override |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| private void advance() { |
| while (soapHeaders.hasNext()) { |
| SOAPHeaderElement nextHdr = (SOAPHeaderElement) soapHeaders.next(); |
| if (nextHdr != null && |
| (myNsUri == null || nextHdr.getNamespaceURI().equals(myNsUri)) && |
| (myLocalName == null || nextHdr.getLocalName().equals(myLocalName))) { |
| current = nextHdr; |
| //found it |
| return; |
| } |
| } |
| //if we got here we didn't find a match |
| current = null; |
| } |
| |
| } |
| |
| @Override |
| public boolean hasHeaders() { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return false; |
| } |
| |
| Iterator allHeaders = soapHeader.examineAllHeaderElements(); |
| return allHeaders.hasNext(); |
| } |
| |
| @Override |
| public List<Header> asList() { |
| SOAPHeader soapHeader = ensureSOAPHeader(); |
| if (soapHeader == null) { |
| return Collections.emptyList(); |
| } |
| |
| Iterator allHeaders = soapHeader.examineAllHeaderElements(); |
| List<Header> headers = new ArrayList<Header>(); |
| while (allHeaders.hasNext()) { |
| SOAPHeaderElement nextHdr = (SOAPHeaderElement) allHeaders.next(); |
| headers.add(new SAAJHeader(nextHdr)); |
| } |
| return headers; |
| } |
| } |