| /* |
| * Copyright 2004,2005 The Apache Software Foundation. |
| * |
| * Licensed 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.handlers.addressing; |
| |
| import org.apache.axiom.om.OMAttribute; |
| import org.apache.axiom.soap.SOAP12Constants; |
| import org.apache.axiom.soap.SOAPHeader; |
| import org.apache.axiom.soap.SOAPHeaderBlock; |
| import org.apache.axis2.AxisFault; |
| import org.apache.axis2.addressing.AddressingConstants; |
| import org.apache.axis2.addressing.EndpointReference; |
| import org.apache.axis2.addressing.EndpointReferenceHelper; |
| import org.apache.axis2.addressing.AddressingFaultsHelper; |
| import org.apache.axis2.addressing.RelatesTo; |
| import org.apache.axis2.client.Options; |
| import org.apache.axis2.context.MessageContext; |
| import org.apache.axis2.util.JavaUtils; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.xml.namespace.QName; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| |
| public abstract class AddressingInHandler extends AddressingHandler implements AddressingConstants { |
| |
| private static final long serialVersionUID = 3907988439637261572L; |
| |
| private static final Log log = LogFactory.getLog(AddressingInHandler.class); |
| private static final boolean isDebugEnabled = log.isDebugEnabled(); |
| |
| public InvocationResponse invoke(MessageContext msgContext) throws AxisFault { |
| // if another handler has already processed the addressing headers, do not do anything here. |
| if (JavaUtils.isTrueExplicitly(msgContext.getProperty(IS_ADDR_INFO_ALREADY_PROCESSED))) { |
| if(isDebugEnabled) { |
| log.debug("Another handler has processed the addressing headers. Nothing to do here."); |
| } |
| |
| return InvocationResponse.CONTINUE; |
| } |
| |
| // check whether someone has explicitly set which addressing handler should run. |
| String namespace = (String) msgContext.getProperty(WS_ADDRESSING_VERSION); |
| if (namespace == null) { |
| namespace = addressingNamespace; |
| } |
| else if (!namespace.equals(addressingNamespace)) { |
| if(isDebugEnabled) { |
| log.debug("This addressing handler does not match the specified namespace, " + namespace); |
| } |
| |
| return InvocationResponse.CONTINUE; |
| } |
| |
| SOAPHeader header = null; |
| if(msgContext.isHeaderPresent()) { |
| header = msgContext.getEnvelope().getHeader(); |
| } |
| |
| // if there are not headers put a flag to disable addressing temporary |
| if (header == null) { |
| msgContext.setProperty(DISABLE_ADDRESSING_FOR_OUT_MESSAGES, Boolean.TRUE); |
| return InvocationResponse.CONTINUE; |
| } |
| |
| if(isDebugEnabled) { |
| log.debug("Starting " + addressingVersion + " IN handler ..."); |
| } |
| |
| ArrayList addressingHeaders; |
| addressingHeaders = header.getHeaderBlocksWithNSURI(namespace); |
| if (addressingHeaders != null && addressingHeaders.size() > 0) { |
| msgContext.setProperty(WS_ADDRESSING_VERSION, namespace); |
| msgContext.setProperty(DISABLE_ADDRESSING_FOR_OUT_MESSAGES, Boolean.FALSE); |
| |
| if(isDebugEnabled) { |
| log.debug(addressingVersion + " Headers present in the SOAP message. Starting to process ..."); |
| } |
| extractAddressingInformation(header, msgContext, addressingHeaders, namespace); |
| msgContext.setProperty(IS_ADDR_INFO_ALREADY_PROCESSED, Boolean.TRUE); |
| } else { |
| msgContext.setProperty(DISABLE_ADDRESSING_FOR_OUT_MESSAGES, Boolean.TRUE); |
| if(isDebugEnabled) { |
| log.debug("No Headers present corresponding to " + addressingVersion); |
| } |
| } |
| return InvocationResponse.CONTINUE; |
| } |
| |
| protected Options extractAddressingInformation(SOAPHeader header, MessageContext messageContext, |
| ArrayList addressingHeaders, String namespace) throws AxisFault { |
| |
| Options messageContextOptions = messageContext.getOptions(); |
| |
| ArrayList checkedHeaderNames = new ArrayList(7); // Up to 7 header names to be recorded |
| ArrayList duplicateHeaderNames = new ArrayList(1); // Normally will not be used for more than 1 header |
| |
| // Per the SOAP Binding spec "headers with an incorrect cardinality MUST NOT be used" So these variables |
| // are used to keep track of invalid cardinality headers so they are not deserialised. |
| boolean ignoreTo = false, ignoreFrom = false, ignoreReplyTo = false, ignoreFaultTo = false, ignoreMessageID = false, ignoreAction = false; |
| |
| // First pass just check for duplicates |
| Iterator addressingHeadersIt = addressingHeaders.iterator(); |
| while (addressingHeadersIt.hasNext()) { |
| SOAPHeaderBlock soapHeaderBlock = (SOAPHeaderBlock) addressingHeadersIt.next(); |
| if (SOAP12Constants.SOAP_ROLE_NONE.equals(soapHeaderBlock.getRole())) |
| continue; |
| |
| if (WSA_TO.equals(soapHeaderBlock.getLocalName())) { |
| ignoreTo = checkDuplicateHeaders(WSA_TO, checkedHeaderNames, duplicateHeaderNames); |
| } else if (WSA_FROM.equals(soapHeaderBlock.getLocalName())) { |
| ignoreFrom = checkDuplicateHeaders(WSA_FROM, checkedHeaderNames, duplicateHeaderNames); |
| } else if (WSA_REPLY_TO.equals(soapHeaderBlock.getLocalName())) { |
| ignoreReplyTo = checkDuplicateHeaders(WSA_REPLY_TO, checkedHeaderNames, duplicateHeaderNames); |
| } else if (WSA_FAULT_TO.equals(soapHeaderBlock.getLocalName())) { |
| ignoreFaultTo = checkDuplicateHeaders(WSA_FAULT_TO, checkedHeaderNames, duplicateHeaderNames); |
| } else if (WSA_MESSAGE_ID.equals(soapHeaderBlock.getLocalName())) { |
| ignoreMessageID = checkDuplicateHeaders(WSA_MESSAGE_ID, checkedHeaderNames, duplicateHeaderNames); |
| } else if (WSA_ACTION.equals(soapHeaderBlock.getLocalName())) { |
| ignoreAction = checkDuplicateHeaders(WSA_ACTION, checkedHeaderNames, duplicateHeaderNames); |
| } |
| } |
| |
| // Now extract information |
| Iterator addressingHeadersIt2 = addressingHeaders.iterator(); |
| while (addressingHeadersIt2.hasNext()) { |
| SOAPHeaderBlock soapHeaderBlock = (SOAPHeaderBlock) addressingHeadersIt2.next(); |
| if (SOAP12Constants.SOAP_ROLE_NONE.equals(soapHeaderBlock.getRole())) |
| continue; |
| |
| if (WSA_TO.equals(soapHeaderBlock.getLocalName()) && !ignoreTo) { |
| extractToEPRInformation(soapHeaderBlock, messageContextOptions, header, namespace); |
| } else if (WSA_FROM.equals(soapHeaderBlock.getLocalName()) && !ignoreFrom) { |
| extractFromEPRInformation(soapHeaderBlock, namespace, messageContext); |
| } else if (WSA_REPLY_TO.equals(soapHeaderBlock.getLocalName()) && !ignoreReplyTo) { |
| extractReplyToEPRInformation(soapHeaderBlock, namespace, messageContext); |
| } else if (WSA_FAULT_TO.equals(soapHeaderBlock.getLocalName()) && !ignoreFaultTo) { |
| extractFaultToEPRInformation(soapHeaderBlock, namespace, messageContext); |
| } else if (WSA_MESSAGE_ID.equals(soapHeaderBlock.getLocalName()) && !ignoreMessageID) { |
| messageContextOptions.setMessageId(soapHeaderBlock.getText()); |
| soapHeaderBlock.setProcessed(); |
| } else if (WSA_ACTION.equals(soapHeaderBlock.getLocalName()) && !ignoreAction) { |
| extractActionInformation(soapHeaderBlock, namespace, messageContext); |
| } else if (WSA_RELATES_TO.equals(soapHeaderBlock.getLocalName())) { |
| extractRelatesToInformation(soapHeaderBlock, namespace, messageContextOptions); |
| } |
| } |
| |
| // Now that all the valid wsa headers have been read, throw an exception if there was an invalid cardinality |
| // This means that if for example there are multiple MessageIDs and a FaultTo, the FaultTo will be respected. |
| if(!duplicateHeaderNames.isEmpty()){ |
| // Simply choose the first problem header we came across as we can only fault for one of them. |
| AddressingFaultsHelper.triggerInvalidCardinalityFault(messageContext, (String)duplicateHeaderNames.get(0)); |
| } |
| |
| // check for the presence of madatory addressing headers |
| checkForMandatoryHeaders(checkedHeaderNames, messageContext); |
| |
| // provide default values for headers that have not been found. |
| setDefaults(checkedHeaderNames, messageContext); |
| |
| return messageContextOptions; |
| } |
| |
| protected abstract void checkForMandatoryHeaders(ArrayList alreadyFoundAddrHeader, MessageContext messageContext) throws AxisFault; |
| |
| protected abstract void setDefaults(ArrayList alreadyFoundAddrHeader, MessageContext messageContext) throws AxisFault; |
| |
| private boolean checkDuplicateHeaders(String addressingHeaderName, ArrayList checkedHeaderNames, ArrayList duplicateHeaderNames) {//throws AxisFault { |
| // If the header name has been seen before then we should return true and add it to the list |
| // of duplicate header names. Otherwise it is the first time we've seen the header so add it |
| // to the checked liat and return false. |
| boolean shouldIgnore = checkedHeaderNames.contains(addressingHeaderName); |
| if(shouldIgnore){ |
| duplicateHeaderNames.add(addressingHeaderName); |
| }else{ |
| checkedHeaderNames.add(addressingHeaderName); |
| } |
| return shouldIgnore; |
| } |
| |
| protected abstract void extractToEprReferenceParameters(EndpointReference toEPR, SOAPHeader header, String namespace); |
| |
| |
| private void extractRelatesToInformation(SOAPHeaderBlock soapHeaderBlock, String addressingNamespace, Options messageContextOptions) { |
| String address = soapHeaderBlock.getText(); |
| OMAttribute relationshipType = |
| soapHeaderBlock.getAttribute( |
| new QName(AddressingConstants.WSA_RELATES_TO_RELATIONSHIP_TYPE)); |
| String relationshipTypeDefaultValue = |
| Submission.WSA_NAMESPACE.equals(addressingNamespace) |
| ? Submission.WSA_DEFAULT_RELATIONSHIP_TYPE |
| : Final.WSA_DEFAULT_RELATIONSHIP_TYPE; |
| RelatesTo relatesTo = |
| new RelatesTo( |
| address, |
| relationshipType == null |
| ? relationshipTypeDefaultValue |
| : relationshipType.getAttributeValue()); |
| messageContextOptions.addRelatesTo(relatesTo); |
| soapHeaderBlock.setProcessed(); |
| } |
| |
| private void extractFaultToEPRInformation(SOAPHeaderBlock soapHeaderBlock, String addressingNamespace, MessageContext messageContext) throws AxisFault { |
| Options messageContextOptions = messageContext.getOptions(); |
| EndpointReference epr = messageContextOptions.getFaultTo(); |
| if (epr == null) { |
| epr = new EndpointReference(""); |
| messageContextOptions.setFaultTo(epr); |
| } |
| extractEPRInformation(soapHeaderBlock, epr, addressingNamespace, messageContext); |
| soapHeaderBlock.setProcessed(); |
| } |
| |
| private void extractReplyToEPRInformation(SOAPHeaderBlock soapHeaderBlock, String addressingNamespace, MessageContext messageContext) throws AxisFault { |
| Options messageContextOptions = messageContext.getOptions(); |
| EndpointReference epr = messageContextOptions.getReplyTo(); |
| if (epr == null) { |
| epr = new EndpointReference(""); |
| messageContextOptions.setReplyTo(epr); |
| } |
| extractEPRInformation(soapHeaderBlock, epr, addressingNamespace, messageContext); |
| soapHeaderBlock.setProcessed(); |
| } |
| |
| private void extractFromEPRInformation(SOAPHeaderBlock soapHeaderBlock, String addressingNamespace, MessageContext messageContext) throws AxisFault { |
| Options messageContextOptions = messageContext.getOptions(); |
| EndpointReference epr = messageContextOptions.getFrom(); |
| if (epr == null) { |
| epr = new EndpointReference(""); // I don't know the address now. Let me pass the empty string now and fill this |
| // once I process the Elements under this. |
| messageContextOptions.setFrom(epr); |
| } |
| extractEPRInformation(soapHeaderBlock, epr, addressingNamespace, messageContext); |
| soapHeaderBlock.setProcessed(); |
| } |
| |
| private void extractToEPRInformation(SOAPHeaderBlock soapHeaderBlock, Options messageContextOptions, SOAPHeader header, String namespace) { |
| |
| EndpointReference epr; |
| //here the addressing epr overidde what ever already there in the message context |
| epr = new EndpointReference(soapHeaderBlock.getText()); |
| messageContextOptions.setTo(epr); |
| |
| // check for reference parameters |
| extractToEprReferenceParameters(epr, header, namespace); |
| soapHeaderBlock.setProcessed(); |
| |
| } |
| |
| //We assume that any action that already exists in the message context must be the |
| //soapaction. We compare that action to the WS-Addressing action, and if they are |
| //different we throw a fault. |
| private void extractActionInformation(SOAPHeaderBlock soapHeaderBlock, String addressingNamespace, MessageContext messageContext) throws AxisFault { |
| Options messageContextOptions = messageContext.getOptions(); |
| String soapAction = messageContextOptions.getAction(); |
| |
| if (soapAction != null && !"".equals(soapAction)) { |
| if (!soapAction.equals(soapHeaderBlock.getText())) { |
| AddressingFaultsHelper.triggerActionMismatchFault(messageContext); |
| } |
| } |
| else { |
| messageContextOptions.setAction(soapHeaderBlock.getText()); |
| } |
| |
| soapHeaderBlock.setProcessed(); |
| } |
| |
| /** |
| * Given the soap header block, this should extract the information within EPR. |
| * |
| * @param headerBlock |
| * @param epr |
| * @param addressingNamespace |
| */ |
| private void extractEPRInformation(SOAPHeaderBlock headerBlock, EndpointReference epr, String addressingNamespace, MessageContext messageContext) throws AxisFault { |
| try { |
| EndpointReferenceHelper.fromOM(epr, headerBlock, addressingNamespace); |
| } |
| catch (AxisFault af) { |
| AddressingFaultsHelper.triggerMissingAddressInEPRFault(messageContext, headerBlock.getLocalName()); |
| } |
| } |
| } |