/* * 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.engine; import org.apache.axiom.om.OMElement; import org.apache.axiom.soap.SOAPHeader; import org.apache.axis2.AxisFault; import org.apache.axis2.Constants; import org.apache.axis2.addressing.AddressingHelper; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.MessageContext; import org.apache.axis2.context.OperationContext; import org.apache.axis2.context.ServiceContext; import org.apache.axis2.context.ServiceGroupContext; import org.apache.axis2.context.SessionContext; import org.apache.axis2.description.AxisOperation; import org.apache.axis2.description.AxisService; import org.apache.axis2.description.AxisServiceGroup; import org.apache.axis2.description.Parameter; import org.apache.axis2.description.WSDL2Constants; import org.apache.axis2.i18n.Messages; import org.apache.axis2.transport.RequestResponseTransport; import org.apache.axis2.transport.TransportListener; import org.apache.axis2.transport.http.HTTPConstants; 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; import java.util.List; public class DispatchPhase extends Phase { private static final Log log = LogFactory.getLog(DispatchPhase.class); public DispatchPhase() { } public DispatchPhase(String phaseName) { super(phaseName); } private Boolean getDisableAck(MessageContext msgContext) throws AxisFault { // We should send an early ack to the transport whever possible, but some modules need // to use the backchannel, so we need to check if they have disabled this code. Boolean disableAck = (Boolean) msgContext.getProperty(Constants.Configuration.DISABLE_RESPONSE_ACK); if(disableAck == null) { disableAck = (Boolean) (msgContext.getAxisService() != null ? msgContext.getAxisService().getParameterValue(Constants.Configuration.DISABLE_RESPONSE_ACK) : null); } return disableAck; } public void checkPostConditions(MessageContext msgContext) throws AxisFault { EndpointReference toEPR = msgContext.getTo(); if (msgContext.getAxisService() == null) { AxisFault fault = new AxisFault(Messages.getMessage("servicenotfoundforepr", ((toEPR != null) ? toEPR.getAddress() : ""))); fault.setFaultCode(org.apache.axis2.namespace.Constants.FAULT_CLIENT); throw fault; } AxisService service = msgContext.getAxisService(); AxisOperation operation = msgContext.getAxisOperation(); // If operation is an excluded operation, throw an exception. // This code is needed to enable exclude operations for static WSDL files. // Without this code, if one specifies excludeOperations in services.xml // file and a static WSDL is used that contains the operation, // the operation would succeed. if (operation != null && service.isExcludedOperation(operation.getName().getLocalPart())) { AxisFault fault = new AxisFault(Messages.getMessage("operationnotfoundforepr2", ((toEPR != null) ? toEPR.getAddress() : ""), msgContext.getWSAAction())); fault.setFaultCode(org.apache.axis2.namespace.Constants.FAULT_CLIENT); throw fault; } // If we're configured to do so, check the service for a single op... if (operation == null && JavaUtils.isTrue(service.getParameterValue(AxisService.SUPPORT_SINGLE_OP))) { Iterator<AxisOperation> ops = service.getOperations(); // If there's exactly one, that's the one we want. If there's more, forget it. if (ops.hasNext()) { operation = (AxisOperation)ops.next(); if (ops.hasNext()) { operation = null; } } msgContext.setAxisOperation(operation); } // If we still don't have an operation, fault. if (operation == null) { AxisFault fault = new AxisFault(Messages.getMessage("operationnotfoundforepr2", ((toEPR != null) ? toEPR.getAddress() : ""), msgContext.getWSAAction())); fault.setFaultCode(org.apache.axis2.namespace.Constants.FAULT_CLIENT); throw fault; } validateTransport(msgContext); validateBindings(msgContext); loadContexts(service, msgContext); if (msgContext.getOperationContext() == null) { throw new AxisFault(Messages.getMessage("cannotBeNullOperationContext")); } if (msgContext.getServiceContext() == null) { throw new AxisFault(Messages.getMessage("cannotBeNullServiceContext")); } // TODO - review this if ((msgContext.getAxisOperation() == null) && (msgContext.getOperationContext() != null)) { msgContext.setAxisOperation(msgContext.getOperationContext().getAxisOperation()); } if ((msgContext.getAxisService() == null) && (msgContext.getServiceContext() != null)) { msgContext.setAxisService(msgContext.getServiceContext().getAxisService()); } // We should send an early ack to the transport whever possible, but some modules need // to use the backchannel, so we need to check if they have disabled this code. String mepString = msgContext.getAxisOperation().getMessageExchangePattern(); if (isOneway(mepString)) { Object requestResponseTransport = msgContext.getProperty(RequestResponseTransport.TRANSPORT_CONTROL); if (requestResponseTransport != null) { Boolean disableAck = getDisableAck(msgContext); if (disableAck == null || disableAck.booleanValue() == false) { ((RequestResponseTransport) requestResponseTransport).acknowledgeMessage(msgContext); } } } else if (AddressingHelper.isReplyRedirected(msgContext) && AddressingHelper.isFaultRedirected(msgContext)) { if (mepString.equals(WSDL2Constants.MEP_URI_IN_OUT) || mepString.equals(WSDL2Constants.MEP_URI_IN_OUT) || mepString.equals(WSDL2Constants.MEP_URI_IN_OUT)) { // OR, if 2 way operation but the response is intended to not use the response channel of a 2-way transport // then we don't need to keep the transport waiting. Object requestResponseTransport = msgContext.getProperty(RequestResponseTransport.TRANSPORT_CONTROL); if (requestResponseTransport != null) { // We should send an early ack to the transport whever possible, but some modules need // to use the backchannel, so we need to check if they have disabled this code. Boolean disableAck = getDisableAck(msgContext); if (disableAck == null || disableAck.booleanValue() == false) { ((RequestResponseTransport) requestResponseTransport).acknowledgeMessage(msgContext); } } } } ArrayList operationChain = msgContext.getAxisOperation().getRemainingPhasesInFlow(); msgContext.setExecutionChain((ArrayList) operationChain.clone()); } private void loadContexts(AxisService service, MessageContext msgContext) throws AxisFault { String scope = service == null ? null : service.getScope(); ServiceContext serviceContext = msgContext.getServiceContext(); if ((msgContext.getOperationContext() != null) && (serviceContext != null)) { msgContext.setServiceGroupContextId( ((ServiceGroupContext)serviceContext.getParent()).getId()); return; } if (Constants.SCOPE_TRANSPORT_SESSION.equals(scope)) { fillContextsFromSessionContext(msgContext); } else if (Constants.SCOPE_SOAP_SESSION.equals(scope)) { extractServiceGroupContextId(msgContext); } AxisOperation axisOperation = msgContext.getAxisOperation(); // if (axisOperation == null) { // return; // } OperationContext operationContext = axisOperation.findForExistingOperationContext(msgContext); if (operationContext != null) { // register operation context and message context // axisOperation.registerOperationContext(msgContext, operationContext); axisOperation.registerMessageContext(msgContext, operationContext); serviceContext = (ServiceContext) operationContext.getParent(); ServiceGroupContext serviceGroupContext = (ServiceGroupContext) serviceContext.getParent(); msgContext.setServiceContext(serviceContext); msgContext.setServiceGroupContext(serviceGroupContext); msgContext.setServiceGroupContextId(serviceGroupContext.getId()); } else { // 2. if null, create new opCtxt if (serviceContext == null) { // fill the service group context and service context info msgContext.getConfigurationContext(). fillServiceContextAndServiceGroupContext(msgContext); serviceContext = msgContext.getServiceContext(); } operationContext = serviceContext.createOperationContext(axisOperation); axisOperation.registerMessageContext(msgContext, operationContext); } serviceContext.setMyEPR(msgContext.getTo()); } /** * To check whether the incoming request has come in valid transport , simply the transports * that service author wants to expose * * @param msgctx the current MessageContext * @throws AxisFault in case of error */ private void validateTransport(MessageContext msgctx) throws AxisFault { AxisService service = msgctx.getAxisService(); if (service.isEnableAllTransports()) { return; } else { List trs = service.getExposedTransports(); String incomingTrs = msgctx.getIncomingTransportName(); //local transport is a special case, it need not be exposed. if (Constants.TRANSPORT_LOCAL.equals(incomingTrs)) { return; } if (log.isDebugEnabled()) { log.debug("Incoming transport: " + incomingTrs + "; allowed transports: " + trs); } for (int i = 0; i < trs.size(); i++) { String tr = (String) trs.get(i); if (incomingTrs != null && incomingTrs.equals(tr)) { return; } } } EndpointReference toEPR = msgctx.getTo(); throw new AxisFault(Messages.getMessage("servicenotfoundforepr", ((toEPR != null) ? toEPR.getAddress() : ""))); } /** * To check whether the incoming request has come in valid binding , we check whether service * author has disabled any binding using parameters * <code>org.apache.axis2.Constants.Configuration.DISABLE_SOAP12</code> * <code>org.apache.axis2.Constants.Configuration.DISABLE_SOAP11</code> * <code>org.apache.axis2.Constants.Configuration.DISABLE_REST</code> * @param service msgctx the current MessageContext * @throws AxisFault in case of error */ private void validateBindings(MessageContext msgctx) throws AxisFault { AxisService service = msgctx.getAxisService(); if (msgctx.isDoingREST()) { boolean disableREST = false; Parameter disableRESTParameter = service .getParameter(org.apache.axis2.Constants.Configuration.DISABLE_REST); if (disableRESTParameter != null && JavaUtils.isTrueExplicitly(disableRESTParameter.getValue())) { disableREST = true; } if (disableREST) { throw new AxisFault(Messages.getMessage("bindingDisabled","Http")); } } else if (msgctx.isSOAP11()) { boolean disableSOAP11 = false; Parameter disableSOAP11Parameter = service .getParameter(org.apache.axis2.Constants.Configuration.DISABLE_SOAP11); if (disableSOAP11Parameter != null && JavaUtils.isTrueExplicitly(disableSOAP11Parameter.getValue())) { disableSOAP11 = true; } if (disableSOAP11) { throw new AxisFault(Messages.getMessage("bindingDisabled","SOAP11")); } } else { boolean disableSOAP12 = false; Parameter disableSOAP12Parameter = service .getParameter(org.apache.axis2.Constants.Configuration.DISABLE_SOAP12); if (disableSOAP12Parameter != null && JavaUtils .isTrueExplicitly(disableSOAP12Parameter.getValue())) { disableSOAP12 = true; } if(disableSOAP12) { throw new AxisFault(Messages.getMessage("bindingDisabled","SOAP12")); } } } private void fillContextsFromSessionContext(MessageContext msgContext) throws AxisFault { AxisService service = msgContext.getAxisService(); if (service == null) { throw new AxisFault(Messages.getMessage("unabletofindservice")); } SessionContext sessionContext = msgContext.getSessionContext(); if (sessionContext == null) { TransportListener listener = msgContext.getTransportIn().getReceiver(); sessionContext = listener.getSessionContext(msgContext); if (sessionContext == null) { createAndFillContexts(service, msgContext, sessionContext); return; } } String serviceGroupName = msgContext.getAxisServiceGroup().getServiceGroupName(); ServiceGroupContext serviceGroupContext = sessionContext.getServiceGroupContext(serviceGroupName); if (serviceGroupContext != null) { //setting service group context msgContext.setServiceGroupContext(serviceGroupContext); // setting Service context msgContext.setServiceContext(serviceGroupContext.getServiceContext(service)); } else { createAndFillContexts(service, msgContext, sessionContext); } ServiceContext serviceContext = sessionContext.getServiceContext(service); //found the serviceContext from session context , so adding that into msgContext if (serviceContext != null) { msgContext.setServiceContext(serviceContext); serviceContext.setProperty(HTTPConstants.COOKIE_STRING, sessionContext.getCookieID()); } } private void createAndFillContexts(AxisService service, MessageContext msgContext, SessionContext sessionContext) throws AxisFault { ServiceGroupContext serviceGroupContext; AxisServiceGroup axisServiceGroup = service.getAxisServiceGroup(); ConfigurationContext configCtx = msgContext.getConfigurationContext(); serviceGroupContext = configCtx.createServiceGroupContext(axisServiceGroup); msgContext.setServiceGroupContext(serviceGroupContext); ServiceContext serviceContext = serviceGroupContext.getServiceContext(service); msgContext.setServiceContext(serviceContext); if (sessionContext != null) { sessionContext.addServiceContext(serviceContext); sessionContext.addServiceGroupContext(serviceGroupContext); } } private static final QName SERVICE_GROUP_QNAME = new QName(Constants.AXIS2_NAMESPACE_URI, Constants.SERVICE_GROUP_ID, Constants.AXIS2_NAMESPACE_PREFIX); private void extractServiceGroupContextId(MessageContext msgContext) throws AxisFault { SOAPHeader soapHeader = msgContext.getEnvelope().getHeader(); if (soapHeader != null) { OMElement serviceGroupId = soapHeader.getFirstChildWithName(SERVICE_GROUP_QNAME); if (serviceGroupId != null) { msgContext.setServiceGroupContextId(serviceGroupId.getText()); } } } /** * This method will determine if the MEP indicated by 'mepString' specifies * a oneway MEP. */ @SuppressWarnings("deprecation") boolean isOneway(String mepString) { return (mepString.equals(WSDL2Constants.MEP_URI_IN_ONLY) || mepString.equals(WSDL2Constants.MEP_URI_IN_ONLY) || mepString.equals(WSDL2Constants.MEP_URI_IN_ONLY)); } }