src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/WsaTube.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

     1 /*
     2  * Copyright (c) 1997, 2010, 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  */
    26 package com.sun.xml.internal.ws.addressing;
    28 import com.sun.istack.internal.NotNull;
    29 import com.sun.xml.internal.ws.addressing.model.InvalidAddressingHeaderException;
    30 import com.sun.xml.internal.ws.addressing.model.MissingAddressingHeaderException;
    31 import com.sun.xml.internal.ws.api.SOAPVersion;
    32 import com.sun.xml.internal.ws.api.WSBinding;
    33 import com.sun.xml.internal.ws.api.server.WSEndpoint;
    34 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
    35 import com.sun.xml.internal.ws.api.message.Header;
    36 import com.sun.xml.internal.ws.api.message.Message;
    37 import com.sun.xml.internal.ws.api.message.Messages;
    38 import com.sun.xml.internal.ws.api.message.Packet;
    39 import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
    40 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
    41 import com.sun.xml.internal.ws.api.pipe.NextAction;
    42 import com.sun.xml.internal.ws.api.pipe.Tube;
    43 import com.sun.xml.internal.ws.api.pipe.TubeCloner;
    44 import com.sun.xml.internal.ws.api.pipe.helper.AbstractFilterTubeImpl;
    45 import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature;
    46 import com.sun.xml.internal.ws.developer.WSBindingProvider;
    47 import com.sun.xml.internal.ws.message.FaultDetailHeader;
    48 import com.sun.xml.internal.ws.resources.AddressingMessages;
    49 import com.sun.xml.internal.ws.binding.BindingImpl;
    51 import javax.xml.namespace.QName;
    52 import javax.xml.soap.SOAPFault;
    53 import javax.xml.stream.XMLStreamException;
    54 import javax.xml.ws.WebServiceException;
    55 import javax.xml.ws.Binding;
    56 import javax.xml.ws.soap.AddressingFeature;
    57 import javax.xml.ws.soap.SOAPBinding;
    58 import java.util.Iterator;
    59 import java.util.Set;
    60 import java.util.Arrays;
    61 import java.util.logging.Logger;
    62 import java.util.logging.Level;
    64 /**
    65  * WS-Addressing processing code shared between client and server.
    66  *
    67  * <p>
    68  * This tube is used only when WS-Addressing is enabled.
    69  *
    70  * @author Rama Pulavarthi
    71  * @author Arun Gupta
    72  */
    73 abstract class WsaTube extends AbstractFilterTubeImpl {
    74     /**
    75      * Port that we are processing.
    76      */
    77     protected final @NotNull WSDLPort wsdlPort;
    78     protected final WSBinding binding;
    79     final WsaTubeHelper helper;
    80     protected final @NotNull AddressingVersion addressingVersion;
    81     protected final SOAPVersion soapVersion;
    83     /**
    84      * True if the addressing headers are mandatory.
    85      */
    86     private final boolean addressingRequired;
    88     public WsaTube(WSDLPort wsdlPort, WSBinding binding, Tube next) {
    89         super(next);
    90         this.wsdlPort = wsdlPort;
    91         this.binding = binding;
    92         addKnownHeadersToBinding(binding);
    93         addressingVersion = binding.getAddressingVersion();
    94         soapVersion = binding.getSOAPVersion();
    95         helper = getTubeHelper();
    96         addressingRequired = AddressingVersion.isRequired(binding);
    97     }
    99     public WsaTube(WsaTube that, TubeCloner cloner) {
   100         super(that, cloner);
   101         this.wsdlPort = that.wsdlPort;
   102         this.binding = that.binding;
   103         this.helper = that.helper;
   104         addressingVersion = that.addressingVersion;
   105         soapVersion = that.soapVersion;
   106         addressingRequired = that.addressingRequired;
   107     }
   109     private void addKnownHeadersToBinding(WSBinding binding) {
   110         Set<QName> headerQNames = binding.getKnownHeaders();
   111         for (AddressingVersion addrVersion: AddressingVersion.values()) {
   112           headerQNames.add(addrVersion.actionTag);
   113           headerQNames.add(addrVersion.faultDetailTag);
   114           headerQNames.add(addrVersion.faultToTag);
   115           headerQNames.add(addrVersion.fromTag);
   116           headerQNames.add(addrVersion.messageIDTag);
   117           headerQNames.add(addrVersion.relatesToTag);
   118           headerQNames.add(addrVersion.replyToTag);
   119           headerQNames.add(addrVersion.toTag);
   120         }
   121     }
   123     @Override
   124     public @NotNull NextAction processException(Throwable t) {
   125         return super.processException(t);
   126     }
   128     protected WsaTubeHelper getTubeHelper() {
   129         if(binding.isFeatureEnabled(AddressingFeature.class)) {
   130             return new WsaTubeHelperImpl(wsdlPort, null, binding);
   131         } else if(binding.isFeatureEnabled(MemberSubmissionAddressingFeature.class)) {
   132             //seiModel is null as it is not needed.
   133             return new com.sun.xml.internal.ws.addressing.v200408.WsaTubeHelperImpl(wsdlPort, null, binding);
   134         } else {
   135             // Addressing is not enabled, WsaTube should not be included in the pipeline
   136             throw new WebServiceException(AddressingMessages.ADDRESSING_NOT_ENABLED(this.getClass().getSimpleName()));
   137         }
   138     }
   140     /**
   141      * Validates the inbound message. If an error is found, create
   142      * a fault message and returns that. Otherwise
   143      * it will pass through the parameter 'packet' object to the return value.
   144      */
   145     protected Packet validateInboundHeaders(Packet packet) {
   146         SOAPFault soapFault;
   147         FaultDetailHeader s11FaultDetailHeader;
   149         try {
   150             checkMessageAddressingProperties(packet);
   151             return packet;
   152         } catch (InvalidAddressingHeaderException e) {
   153             LOGGER.log(Level.WARNING,
   154                     addressingVersion.getInvalidMapText()+", Problem header:" + e.getProblemHeader()+ ", Reason: "+ e.getSubsubcode(),e);
   155             soapFault = helper.createInvalidAddressingHeaderFault(e, addressingVersion);
   156             s11FaultDetailHeader = new FaultDetailHeader(addressingVersion, addressingVersion.problemHeaderQNameTag.getLocalPart(), e.getProblemHeader());
   157         } catch (MissingAddressingHeaderException e) {
   158             LOGGER.log(Level.WARNING,addressingVersion.getMapRequiredText()+", Problem header:"+ e.getMissingHeaderQName(),e);
   159             soapFault = helper.newMapRequiredFault(e);
   160             s11FaultDetailHeader = new FaultDetailHeader(addressingVersion, addressingVersion.problemHeaderQNameTag.getLocalPart(), e.getMissingHeaderQName());
   161         }
   163         if (soapFault != null) {
   164             // WS-A fault processing for one-way methods
   165             if ((wsdlPort !=null)  && packet.getMessage().isOneWay(wsdlPort)) {
   166                 return packet.createServerResponse(null, wsdlPort, null, binding);
   167             }
   169             Message m = Messages.create(soapFault);
   170             if (soapVersion == SOAPVersion.SOAP_11) {
   171                 m.getHeaders().add(s11FaultDetailHeader);
   172             }
   174             return packet.createServerResponse(m, wsdlPort, null,  binding);
   175         }
   177         return packet;
   178     }
   180     /**
   181      * This method checks all the WS-Addressing headers are valid and as per the spec definded rules.
   182      * Mainly it checks the cardinality of the WSA headers and checks that mandatory headers exist.
   183      * It also checks if the SOAPAction is equal to wsa:Action value when non-empty.
   184      *
   185      * Override this method if you need to additional checking of headers other than just existence of the headers.
   186      * For ex: On server-side, check Anonymous and Non-Anonymous semantics in addition to checking cardinality.
   187      *
   188      * Override checkMandatoryHeaders(Packet p) to have different validation rules for different versions
   189      *
   190      * @param packet
   191      */
   192     protected void checkMessageAddressingProperties(Packet packet) {
   193         checkCardinality(packet);
   194     }
   196     final boolean isAddressingEngagedOrRequired(Packet packet, WSBinding binding) {
   197         if (AddressingVersion.isRequired(binding))
   198             return true;
   200         if (packet == null)
   201             return false;
   203         if (packet.getMessage() == null)
   204             return false;
   206         if (packet.getMessage().getHeaders() != null)
   207             return false;
   209         String action = packet.getMessage().getHeaders().getAction(addressingVersion, soapVersion);
   210         if (action == null)
   211             return true;
   213         return true;
   214     }
   216     /**
   217      * Checks the cardinality of WS-Addressing headers on an inbound {@link Packet}. This method
   218      * checks for the cardinality if WS-Addressing is engaged (detected by the presence of wsa:Action
   219      * header) or wsdl:required=true.
   220      *
   221      * @param packet The inbound packet.
   222      * @throws WebServiceException if:
   223      * <ul>
   224      * <li>there is an error reading ReplyTo or FaultTo</li>
   225      * <li>WS-Addressing is required and {@link Message} within <code>packet</code> is null</li>
   226      * <li>WS-Addressing is required and no headers are found in the {@link Message}</li>
   227      * <li>an uknown WS-Addressing header is present</li>
   228      * </ul>
   229      */
   230     protected void checkCardinality(Packet packet) {
   231         Message message = packet.getMessage();
   232         if (message == null) {
   233             if (addressingRequired)
   234                 throw new WebServiceException(AddressingMessages.NULL_MESSAGE());
   235             else
   236                 return;
   237         }
   239         Iterator<Header> hIter = message.getHeaders().getHeaders(addressingVersion.nsUri, true);
   241         if (!hIter.hasNext()) {
   242             // no WS-A headers are found
   243             if (addressingRequired)
   244                 // if WS-A is required, then throw an exception looking for wsa:Action header
   245                 throw new MissingAddressingHeaderException(addressingVersion.actionTag,packet);
   246             else
   247                 // else no need to process
   248                 return;
   249         }
   251         boolean foundFrom = false;
   252         boolean foundTo = false;
   253         boolean foundReplyTo = false;
   254         boolean foundFaultTo = false;
   255         boolean foundAction = false;
   256         boolean foundMessageId = false;
   257         boolean foundRelatesTo = false;
   258         QName duplicateHeader = null;
   260         while (hIter.hasNext()) {
   261             Header h = hIter.next();
   263             // check if the Header is in current role
   264             if (!isInCurrentRole(h, binding)) {
   265                 continue;
   266             }
   268             String local = h.getLocalPart();
   269             if (local.equals(addressingVersion.fromTag.getLocalPart())) {
   270                 if (foundFrom) {
   271                     duplicateHeader = addressingVersion.fromTag;
   272                     break;
   273                 }
   274                 foundFrom = true;
   275             } else if (local.equals(addressingVersion.toTag.getLocalPart())) {
   276                 if (foundTo) {
   277                     duplicateHeader = addressingVersion.toTag;
   278                     break;
   279                 }
   280                 foundTo = true;
   281             } else if (local.equals(addressingVersion.replyToTag.getLocalPart())) {
   282                 if (foundReplyTo) {
   283                     duplicateHeader = addressingVersion.replyToTag;
   284                     break;
   285                 }
   286                 foundReplyTo = true;
   287                 try { // verify that the header is in a good shape
   288                     h.readAsEPR(addressingVersion);
   289                 } catch (XMLStreamException e) {
   290                     throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e);
   291                 }
   292             } else if (local.equals(addressingVersion.faultToTag.getLocalPart())) {
   293                 if (foundFaultTo) {
   294                     duplicateHeader = addressingVersion.faultToTag;
   295                     break;
   296                 }
   297                 foundFaultTo = true;
   298                 try { // verify that the header is in a good shape
   299                     h.readAsEPR(addressingVersion);
   300                 } catch (XMLStreamException e) {
   301                     throw new WebServiceException(AddressingMessages.FAULT_TO_CANNOT_PARSE(), e);
   302                 }
   303             } else if (local.equals(addressingVersion.actionTag.getLocalPart())) {
   304                 if (foundAction) {
   305                     duplicateHeader = addressingVersion.actionTag;
   306                     break;
   307                 }
   308                 foundAction = true;
   309             } else if (local.equals(addressingVersion.messageIDTag.getLocalPart())) {
   310                 if (foundMessageId) {
   311                     duplicateHeader = addressingVersion.messageIDTag;
   312                     break;
   313                 }
   314                 foundMessageId = true;
   315             } else if (local.equals(addressingVersion.relatesToTag.getLocalPart())) {
   316                 foundRelatesTo = true;
   317             } else if (local.equals(addressingVersion.faultDetailTag.getLocalPart())) {
   318                 // TODO: should anything be done here ?
   319                 // TODO: fault detail element - only for SOAP 1.1
   320             } else {
   321                 System.err.println(AddressingMessages.UNKNOWN_WSA_HEADER());
   322             }
   323         }
   325         // check for invalid cardinality first before checking for mandatory headers
   326         if (duplicateHeader != null) {
   327             throw new InvalidAddressingHeaderException(duplicateHeader, addressingVersion.invalidCardinalityTag);
   328         }
   330         // WS-A is engaged if wsa:Action header is found
   331         boolean engaged = foundAction;
   333         // check for mandatory set of headers only if:
   334         // 1. WS-A is engaged or
   335         // 2. wsdl:required=true
   336         // Both wsa:Action and wsa:To MUST be present on request (for oneway MEP) and
   337         // response messages (for oneway and request/response MEP only)
   338         if (engaged || addressingRequired) {
   339             // Check for mandatory headers always (even for Protocol messages).
   340             // If it breaks any interop scenarios, Remove the comments.
   341             /*
   342             WSDLBoundOperation wbo = getWSDLBoundOperation(packet);
   343             // no need to check for for non-application messages
   344             if (wbo == null)
   345                 return;
   346             */
   347             checkMandatoryHeaders(packet, foundAction, foundTo, foundReplyTo,
   348                     foundFaultTo, foundMessageId, foundRelatesTo);
   349         }
   350     }
   352     final boolean isInCurrentRole(Header header, WSBinding binding) {
   353         // TODO: binding will be null for protocol messages
   354         // TODO: returning true assumes that protocol messages are
   355         // TODO: always in current role, this may not to be fixed.
   356         if (binding == null)
   357             return true;
   358         return ((SOAPBinding)binding).getRoles().contains(header.getRole(soapVersion));
   360     }
   362     protected final WSDLBoundOperation getWSDLBoundOperation(Packet packet) {
   363         //we can find Req/Response or Oneway only with WSDLModel
   364         if(wsdlPort == null)
   365             return null;
   366         QName opName = packet.getWSDLOperation();
   367         if(opName != null)
   368             return wsdlPort.getBinding().get(opName);
   369         return null;
   370     }
   372     protected void validateSOAPAction(Packet packet) {
   373         String gotA = packet.getMessage().getHeaders().getAction(addressingVersion, soapVersion);
   374         if (gotA == null)
   375             throw new WebServiceException(AddressingMessages.VALIDATION_SERVER_NULL_ACTION());
   376         if(packet.soapAction != null && !packet.soapAction.equals("\"\"") && !packet.soapAction.equals("\""+gotA+"\"")) {
   377             throw new InvalidAddressingHeaderException(addressingVersion.actionTag, addressingVersion.actionMismatchTag);
   378         }
   379     }
   381     protected abstract void validateAction(Packet packet);
   383     /**
   384      * This should be called only when Addressing is engaged.
   385      *
   386      * Checks only for presence of wsa:Action and validates that wsa:Action
   387      * equals SOAPAction header when non-empty
   388      * Should be overridden if other wsa headers need to be checked based on version.
   389      *
   390      * @param packet
   391      * @param foundAction
   392      * @param foundTo
   393      * @param foundReplyTo
   394      * @param foundFaultTo
   395      * @param foundMessageId
   396      * @param foundRelatesTo
   397      */
   398     protected void checkMandatoryHeaders(
   399         Packet packet, boolean foundAction, boolean foundTo, boolean foundReplyTo,
   400             boolean foundFaultTo, boolean foundMessageId, boolean foundRelatesTo) {
   401         // if no wsa:Action header is found
   402         if (!foundAction)
   403             throw new MissingAddressingHeaderException(addressingVersion.actionTag,packet);
   404         validateSOAPAction(packet);
   405     }
   406     private static final Logger LOGGER = Logger.getLogger(WsaTube.class.getName());
   407 }

mercurial