blob: 691330a632a3b72fe4ac4929a2c28f08b25016c8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.jaxws.handler;
import org.apache.axiom.soap.RolePlayer;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPConstants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.util.LoggingControl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.soap.SOAPHandler;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/*
* Utility class to perform static utility type of operations on Handlers.
*/
public class HandlerUtils {
private static Log log = LogFactory.getLog(HandlerUtils.class);
/**
* registerHandlerHeaders will invoke getHeaders on SOAPHandlers and return a List of headers
* that are Understood by the handlers.
* @param msgContext
* @param handlers
*/
public static List<QName> registerSOAPHandlerHeaders(MessageContext msgContext, List<Handler> handlers){
List<QName> understood = new ArrayList<QName>();
if(msgContext == null){
return understood;
}
for(Handler handler:handlers){
if(handler instanceof SOAPHandler){
SOAPHandler soapHandler = (SOAPHandler)handler;
//Invoking getHeaders.
if(log.isDebugEnabled()){
log.debug("Invoking getHeader() on SOAPHandler");
}
Set<QName> headers = soapHandler.getHeaders();
if(headers!=null){
for(QName header:headers){
if(!understood.contains(header)){
if(log.isDebugEnabled()){
log.debug("Adding Header QName" + header + " to uderstoodHeaderQName List");
}
//Adding this to understood header list.
understood.add(header);
}
}
}
}
}
return understood;
}
/**
* checkMustUnderstand will validate headers that where delegated by Axis Engine
* to MessageReceiver for mustUnderstand check.
*
* Note that there is other JAX-WS related mustUnderstand checking occuring elsewhere:
* @see org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher
* @see org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker
*
* @param msgContext Contains the SOAPEnvelope and optionally a list of headers not
* understood by the AxisEngine
* @param understood A list of header QNames understood by JAX-WS, for example those understood
* by associated application handlers. Can be null.
* @param additionalRoles An instance of RolePlayer for any addtional roles played by JAX-WS
* for example, roles configured for associated handlers. Can be null.
*
* @throws AxisFault if any headers marked mustUndersand are not understood.
*/
public static void checkMustUnderstand(MessageContext msgContext, List<QName> understood, List<String> additionalRoles) throws AxisFault {
if (msgContext == null || !msgContext.isHeaderPresent()) {
return;
}
SOAPEnvelope envelope = msgContext.getEnvelope();
if (envelope.getHeader() == null) {
return;
}
if(log.isDebugEnabled()){
log.debug("Reading UnprocessedHeaderNames from Message Context properties");
}
List<QName> unprocessed = (List)msgContext.getProperty(Constants.UNPROCESSED_HEADER_QNAMES);
// Add to the unprocessed header list any headers that are unprocssed and mustUnderstand
// for addtional roles, for example those played by associated JAXWS handlers
if (additionalRoles != null) {
if (log.isDebugEnabled()) {
log.debug("Adding any mustUnderstand headers based on additonal SOAP roles: " + additionalRoles);
}
HandlerRolePlayer handlerRolePlayer = new HandlerRolePlayer(additionalRoles);
Iterator headerBlocks = envelope.getHeader().getHeadersToProcess(handlerRolePlayer);
while (headerBlocks.hasNext()) {
SOAPHeaderBlock shb = (SOAPHeaderBlock) headerBlocks.next();
if (unprocessed == null) {
unprocessed = new ArrayList<QName>();
}
if (!shb.isProcessed() && shb.getMustUnderstand()) {
unprocessed.add(shb.getQName());
if (log.isDebugEnabled()) {
log.debug("Added header to unprocessed list: " + shb.getQName());
}
}
}
}
if(unprocessed == null || unprocessed.size() == 0){
if(log.isDebugEnabled()){
log.debug("UNPROCESSED_HEADER_QNAMES not found.");
}
return;
}
//lets go thru each header only if @HandlerChain is present
if(!canUnderstand(msgContext)){
QName[] qNames = unprocessed.toArray(new QName[0]);
String[] headerNames = new String[qNames.length];
for(int i=0; i<qNames.length; i++){
headerNames[i] ="{" + qNames[i].getNamespaceURI()+ "}" + qNames[i].getLocalPart();
}
QName faultQName = envelope.getVersion().getMustUnderstandFaultCode();
throw new AxisFault(Messages.getMessage("mustunderstandfailed2", headerNames), faultQName);
}
checkUnprocessed(envelope, unprocessed, understood, msgContext);
//resetting the FAULTY_HEADER_QNAME to null.
msgContext.setProperty(Constants.UNPROCESSED_HEADER_QNAMES, null);
}
private static void checkUnprocessed(SOAPEnvelope envelope, List<QName> unprocessed, List<QName> understood, MessageContext msgContext) throws AxisFault{
for (QName headerQName : unprocessed) {
if (understood != null && !understood.isEmpty()) {
if (understood.contains(headerQName)) {
if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled()) {
log.debug("MustUnderstand header registered as understood on AxisOperation: " + headerQName);
}
continue;
}
}
if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled()) {
log.debug("MustUnderstand header not processed or registered as understood " + headerQName);
}
// Throw a MustUnderstand fault for the current SOAP version
String prefix = envelope.getNamespace().getPrefix();
if (!msgContext.isSOAP11()) {
if (prefix == null || "".equals(prefix)) {
prefix = SOAPConstants.SOAP_DEFAULT_NAMESPACE_PREFIX;
}
// TODO: should we be using a prefix on the faultcode? What about
// the QName object Constants.FAULT_SOAP12_MUSTUNDERSTAND?
throw new AxisFault(Messages.getMessage("mustunderstandfailed",
prefix,
headerQName.toString()),
SOAP12Constants.FAULT_CODE_MUST_UNDERSTAND);
} else {
// TODO: should we be using a prefix on the faultcode? What about
// the QName object Constants.FAULT_MUSTUNDERSTAND?
throw new AxisFault(Messages.getMessage("mustunderstandfailed",
prefix,
headerQName.toString()),
SOAP11Constants.FAULT_CODE_MUST_UNDERSTAND);
}
}
}
private static boolean canUnderstand(MessageContext msgContext){
//JAXWSMessageReceiver will only commit to handling must understand if @HandlerChain annotation is present on the
//Endpoint. This will indicate to AxisEngine that Faulty Header names are understood however the mustUnderstand
//Check will be performed in HandlerUtils class after Handlers are injected in application.
AxisService axisSvc = msgContext.getAxisService();
if (axisSvc.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER) != null) {
Parameter param = axisSvc.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
EndpointDescription ed = (EndpointDescription)param.getValue();
//Lets check if there is a Handler implementation present using Metadata layer.
//HandlerChain annotation can be present in Service Endpoint or ServiceEndpointInterface.
// ed.getHandlerChain() looks for HandlerAnnotation at both Endpoint and at SEI.
if(log.isDebugEnabled()){
log.debug("Check to see if a jaxws handler is configured.");
}
if(ed.getHandlerChain()!=null){
return true;
}
return false;
}
else{
//If we cannot get to ServiceDescription to check for HandlerChain annotation we will return true;
return true;
}
}
}
class HandlerRolePlayer implements RolePlayer {
List<String> roles = new ArrayList<String>();
HandlerRolePlayer(List<String> additionalRoles) {
roles.addAll(additionalRoles);
}
public List getRoles() {
return roles;
}
public boolean isUltimateDestination() {
return false;
}
}