/* * 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.util; import org.apache.axis2.AxisFault; import org.apache.axis2.Constants; import org.apache.axis2.builder.Builder; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.Parameter; import org.apache.axis2.engine.AxisConfiguration; import org.apache.axis2.transport.MessageFormatter; import org.apache.axis2.transport.http.ApplicationXMLFormatter; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.axis2.transport.http.SOAPMessageFormatter; import org.apache.axis2.transport.http.XFormURLEncodedFormatter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Map; /** * MessageProcessorSelector is utility class which encapsulate MessageBuilder and * MessageFormatter selection logic. * * @since 1.7.0 */ public class MessageProcessorSelector { private static final Log log = LogFactory.getLog(MessageProcessorSelector.class); /** * Initial work for a builder selector which selects the builder for a given message format * based on the the content type of the recieved message. content-type to builder mapping can be * specified through the Axis2.xml. * * @param type content-type * @param msgContext the active MessageContext * @return the builder registered against the given content-type * @throws org.apache.axis2.AxisFault */ public static Builder getMessageBuilder(String type, MessageContext msgContext) throws AxisFault { boolean useFallbackBuilder = false; AxisConfiguration configuration = msgContext.getConfigurationContext().getAxisConfiguration(); Parameter useFallbackParameter = configuration.getParameter(Constants.Configuration.USE_DEFAULT_FALLBACK_BUILDER); if (useFallbackParameter != null) { useFallbackBuilder = JavaUtils.isTrueExplicitly(useFallbackParameter.getValue(), useFallbackBuilder); } String cType = getContentTypeForBuilderSelection(type, msgContext); Builder builder = configuration.getMessageBuilder(cType, useFallbackBuilder); if (builder != null) { // Check whether the request has a Accept header if so use that as the response // message type. // If thats not present, // Setting the received content-type as the messageType to make // sure that we respond using the received message serialization format. Object contentNegotiation = configuration .getParameterValue(Constants.Configuration.ENABLE_HTTP_CONTENT_NEGOTIATION); if (JavaUtils.isTrueExplicitly(contentNegotiation)) { Map transportHeaders = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS); if (transportHeaders != null) { String acceptHeader = (String) transportHeaders.get(HTTPConstants.HEADER_ACCEPT); if (acceptHeader != null) { int index = acceptHeader.indexOf(";"); if (index > 0) { acceptHeader = acceptHeader.substring(0, index); } String[] strings = acceptHeader.split(","); for (String string : strings) { String accept = string.trim(); // We dont want dynamic content negotoatin to work on text.xml as its // ambiguos as to whether the user requests SOAP 1.1 or POX response if (!HTTPConstants.MEDIA_TYPE_TEXT_XML.equals(accept) && configuration.getMessageFormatter(accept) != null) { type = string; break; } } } } } msgContext.setProperty(Constants.Configuration.MESSAGE_TYPE, type); } return builder; } /** * Initial work for a builder selector which selects the builder for a given message format based on the the content type of the recieved message. * content-type to builder mapping can be specified through the Axis2.xml. * * @param msgContext * @return the builder registered against the given content-type * @throws AxisFault */ public static MessageFormatter getMessageFormatter(MessageContext msgContext) throws AxisFault { MessageFormatter messageFormatter = null; String messageFormatString = getMessageFormatterProperty(msgContext); messageFormatString = getContentTypeForFormatterSelection(messageFormatString, msgContext); if (messageFormatString != null) { messageFormatter = msgContext.getConfigurationContext() .getAxisConfiguration().getMessageFormatter(messageFormatString); if (log.isDebugEnabled()) { log.debug("Message format is: " + messageFormatString + "; message formatter returned by AxisConfiguration: " + messageFormatter); } } if (messageFormatter == null) { messageFormatter = (MessageFormatter) msgContext.getProperty(Constants.Configuration.MESSAGE_FORMATTER); if (messageFormatter != null) { return messageFormatter; } } if (messageFormatter == null) { // If we are doing rest better default to Application/xml formatter if (msgContext.isDoingREST()) { String httpMethod = (String) msgContext.getProperty(Constants.Configuration.HTTP_METHOD); if (Constants.Configuration.HTTP_METHOD_GET.equals(httpMethod) || Constants.Configuration.HTTP_METHOD_DELETE.equals(httpMethod)) { return new XFormURLEncodedFormatter(); } return new ApplicationXMLFormatter(); } else { // Lets default to SOAP formatter //TODO need to improve this to use the stateless nature messageFormatter = new SOAPMessageFormatter(); } } return messageFormatter; } private static String getMessageFormatterProperty(MessageContext msgContext) { String messageFormatterProperty = null; Object property = msgContext .getProperty(Constants.Configuration.MESSAGE_TYPE); if (property != null) { messageFormatterProperty = (String) property; } if (messageFormatterProperty == null) { Parameter parameter = msgContext .getParameter(Constants.Configuration.MESSAGE_TYPE); if (parameter != null) { messageFormatterProperty = (String) parameter.getValue(); } } return messageFormatterProperty; } private static String getContentTypeForBuilderSelection(String type, MessageContext msgContext) { /** * Handle special case where content-type : text/xml and SOAPAction = null consider as * POX (REST) message not SOAP 1.1. * * it's required use the Builder associate with "application/xml" here but should not * change content type of current message. * */ String cType = type; if (msgContext.getSoapAction() == null && HTTPConstants.MEDIA_TYPE_TEXT_XML.equals(type) && msgContext.isDoingREST()) { cType = HTTPConstants.MEDIA_TYPE_APPLICATION_XML; } return cType; } private static String getContentTypeForFormatterSelection(String type, MessageContext msgContext) { /** * Handle special case where content-type : text/xml and SOAPAction = null consider as * POX (REST) message not SOAP 1.1. * * 1.) it's required use the Builder associate with "application/xml" here but should not * change content type of current message. */ String cType = type; if (msgContext.isDoingREST() && HTTPConstants.MEDIA_TYPE_TEXT_XML.equals(type)) { cType = HTTPConstants.MEDIA_TYPE_APPLICATION_XML; msgContext.setProperty(Constants.Configuration.CONTENT_TYPE, HTTPConstants.MEDIA_TYPE_TEXT_XML); } return cType; } }