org.apache.axis2.jaxws.server.JAXWSMessageReceiver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of axis2-jaxws Show documentation
Show all versions of axis2-jaxws Show documentation
Axis2 JAXWS Implementation
/*
* 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.server;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.WSDL2Constants;
import org.apache.axis2.engine.AxisEngine;
import org.apache.axis2.engine.MessageReceiver;
import org.apache.axis2.java.security.AccessController;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.core.InvocationContextFactory;
import org.apache.axis2.jaxws.core.MessageContext;
import org.apache.axis2.jaxws.core.util.MessageContextUtils;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.handler.AttachmentsAdapter;
import org.apache.axis2.jaxws.handler.MEPContext;
import org.apache.axis2.jaxws.handler.SOAPHeadersAdapter;
import org.apache.axis2.jaxws.handler.TransportHeadersAdapter;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.message.util.MessageUtils;
import org.apache.axis2.jaxws.registry.InvocationListenerRegistry;
import org.apache.axis2.jaxws.util.Constants;
import org.apache.axis2.transport.RequestResponseTransport;
import org.apache.axis2.util.JavaUtils;
import org.apache.axis2.util.ThreadContextMigratorUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.ws.Binding;
import javax.xml.ws.WebServiceException;
import java.security.PrivilegedAction;
/**
* The JAXWSMessageReceiver is the entry point, from the server's perspective, to the JAX-WS code.
* This will be called by the Axis Engine and is the end of the chain from an Axis2 perspective.
*/
public class JAXWSMessageReceiver implements MessageReceiver {
private static final Log log = LogFactory.getLog(JAXWSMessageReceiver.class);
private static String PARAM_SERVICE_CLASS = "ServiceClass";
public static String PARAM_BINDING = "Binding";
/**
* We should have already determined which AxisService we're targetting at this point. So now,
* just get the service implementation and invoke the appropriate method.
* @param axisRequestMsgCtx
* @throws org.apache.axis2.AxisFault
*/
public void receive(org.apache.axis2.context.MessageContext axisRequestMsgCtx)
throws AxisFault {
AxisFault faultToReturn = null;
if (log.isDebugEnabled()) {
log.debug("new request received");
}
//Get the name of the service impl that was stored as a parameter
// inside of the services.xml.
AxisService service = axisRequestMsgCtx.getAxisService();
// we need to set the deployment class loader as the TCCL. This is because, in JAX-WS
// services, there can be situations where we have to load classes from the deployment
// artifact (JAX-WS jar file) in the message flow. Ex: Handler classes in the service
// artifact. Adding this as a fix for AXIS2-4930.
setContextClassLoader(service.getClassLoader());
org.apache.axis2.description.Parameter svcClassParam =
service.getParameter(PARAM_SERVICE_CLASS);
if (svcClassParam == null) {
throw new RuntimeException(
Messages.getMessage("JAXWSMessageReceiverNoServiceClass"));
}
Parameter endpointDescParam =
service.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
if (endpointDescParam == null) {
throw new RuntimeException(Messages.getMessage("JAXWSMessageReceiverNoServiceClass"));
}
AxisOperation operation = axisRequestMsgCtx.getAxisOperation();
String mep = operation.getMessageExchangePattern();
if (log.isDebugEnabled()) {
log.debug("MEP: " + mep);
}
try {
//This assumes that we are on the ultimate execution thread
ThreadContextMigratorUtil.performMigrationToThread(
Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, axisRequestMsgCtx);
//We'll need an instance of the EndpointController to actually
//drive the invocation.
//TODO: More work needed to determine the lifecycle of this thing
EndpointController endpointCtlr = new EndpointController();
MessageContext requestMsgCtx = new MessageContext(axisRequestMsgCtx);
requestMsgCtx.setServer(true);
requestMsgCtx.setMEPContext(new MEPContext(requestMsgCtx));
ClassLoader loader = getCachedClassLoader(axisRequestMsgCtx);
if (loader != null) {
requestMsgCtx.setProperty(org.apache.axis2.jaxws.spi.Constants.CACHE_CLASSLOADER,
loader);
}
// The adapters need to be installed on the new request Message Context
AttachmentsAdapter.install(requestMsgCtx);
TransportHeadersAdapter.install(requestMsgCtx);
SOAPHeadersAdapter.install(requestMsgCtx);
Binding binding = (Binding)axisRequestMsgCtx.getProperty(PARAM_BINDING);
EndpointInvocationContext eic = InvocationContextFactory.createEndpointInvocationContext(binding);
addInvocationListenerFactories(eic);
eic.setRequestMessageContext(requestMsgCtx);
// WARNING: This should be left disabled for now. This locks the server side
// into a single threaded invocation.
eic.getRequestMessageContext().setProperty(ServerConstants.SERVER_DISABLE_THREAD_SWITCH, true);
if (isMepInOnly(mep)) {
if (log.isDebugEnabled()) {
log.debug("Detected a one way invocation.");
}
eic.setIsOneWay(true);
endpointCtlr.invokeOneWay(eic);
} else if (JavaUtils.isTrueExplicitly(axisRequestMsgCtx.getProperty(
AddressingConstants.IS_ADDR_INFO_ALREADY_PROCESSED))
&& (axisRequestMsgCtx.getReplyTo() != null
&& !axisRequestMsgCtx.getReplyTo().hasAnonymousAddress())) {
if (log.isDebugEnabled()) {
log.debug("Detected an async invocation.");
}
EndpointCallback ecb = new EndpointCallback();
eic.setCallback(ecb);
endpointCtlr.invokeAsync(eic);
} else {
if (log.isDebugEnabled()) {
log.debug("Detected a sync invocation.");
}
eic = endpointCtlr.invoke(eic);
// If this is a two-way exchange, there should already be a
// JAX-WS MessageContext for the response. We need to pull
// the Message data out of there and set it on the Axis2
// MessageContext.
MessageContext responseMsgCtx = eic.getResponseMessageContext();
// Note that responseMsgCtx may be null if the Provider returned null
// and no wsdl was specified.
// In JAX-WS 2.2 for Providers that return null we should send back
// an empty payload, not a SOAPEnvelope.
if (responseMsgCtx == null &&
MessageContextUtils.getJaxwsProviderInterpretNullOneway(requestMsgCtx)) {
if (log.isDebugEnabled()) {
log.debug("Detected a null return from a Provider, sending back an ack instead of a response.");
}
sendAckBack(axisRequestMsgCtx);
} else {
org.apache.axis2.context.MessageContext axisResponseMsgCtx =
responseMsgCtx.getAxisMessageContext();
if (loader != null) {
responseMsgCtx.setProperty(org.apache.axis2.jaxws.spi.Constants.CACHE_CLASSLOADER,
loader);
}
MessageUtils.putMessageOnMessageContext(responseMsgCtx.getMessage(),
axisResponseMsgCtx);
OperationContext opCtx = axisResponseMsgCtx.getOperationContext();
opCtx.addMessageContext(axisResponseMsgCtx);
// If this is a fault message, we want to throw it as an
// exception so that the transport can do the appropriate things
if (responseMsgCtx.getMessage().isFault()) {
//Rather than create a new AxisFault, we should use the AxisFault that was
//created at the causedBy
if (responseMsgCtx.getCausedByException() != null) {
faultToReturn = responseMsgCtx.getCausedByException();
if (log.isDebugEnabled()) {
log.debug("Setting causedByException from response MessageContext");
}
} else if (requestMsgCtx.getCausedByException() != null) {
faultToReturn = requestMsgCtx.getCausedByException();
if (log.isDebugEnabled()) {
log.debug("Setting causedByException from request MessageContext..which indicates an exception occured in the inbound handler processing");
}
} else {
faultToReturn = new AxisFault("An error was detected during JAXWS processing",
axisResponseMsgCtx);
if (log.isDebugEnabled()) {
log.debug("No causedByException detected");
}
}
} else {
//This assumes that we are on the ultimate execution thread
ThreadContextMigratorUtil.performMigrationToContext(
Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, axisResponseMsgCtx);
//Create the AxisEngine for the reponse and send it.
AxisEngine.send(axisResponseMsgCtx);
//This assumes that we are on the ultimate execution thread
ThreadContextMigratorUtil.performContextCleanup(
Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, axisResponseMsgCtx);
}
}
}
} catch (AxisFault af) {
throw af;
} catch (Exception e) {
ThreadContextMigratorUtil.performThreadCleanup(
Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, axisRequestMsgCtx);
//e.printStackTrace();
// TODO. This is throwing a client exception ?
// TODO Why are we preserving the stack information ?
// Make a webservice exception (which will strip out a unnecessary stuff)
WebServiceException wse = ExceptionFactory.makeWebServiceException(e);
// The AxisEngine expects an AxisFault
throw AxisFault.makeFault(wse);
}
//This assumes that we are on the ultimate execution thread
ThreadContextMigratorUtil
.performThreadCleanup(Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, axisRequestMsgCtx);
if (faultToReturn != null) {
throw faultToReturn;
}
}
/**
* Set context class loader of the current thread.
*
* @param cl the context ClassLoader for the Thread
*/
private void setContextClassLoader(final ClassLoader cl) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
Thread.currentThread().setContextClassLoader(cl);
return null;
}
});
}
private void sendAckBack(org.apache.axis2.context.MessageContext axisMsgCtx){
if (log.isDebugEnabled()) {
log.debug("sendAckBack entry");
}
try {
Object requestResponseTransport =
axisMsgCtx.getProperty(RequestResponseTransport.TRANSPORT_CONTROL);
if (requestResponseTransport != null) {
((RequestResponseTransport) requestResponseTransport).acknowledgeMessage(axisMsgCtx);
}
}catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Ignoring exception from acknowledgeMessage.", e);
}
}
if (log.isDebugEnabled()) {
log.debug("sendAckBack exit");
}
}
private boolean isMepInOnly(String mep) {
boolean inOnly = mep.equals(WSDL2Constants.MEP_URI_ROBUST_IN_ONLY) ||
mep.equals(WSDL2Constants.MEP_URI_IN_ONLY) ||
mep.equals(WSDL2Constants.MEP_URI_IN_ONLY) ||
mep.equals(WSDL2Constants.MEP_URI_ROBUST_IN_ONLY) ||
mep.equals(WSDL2Constants.MEP_URI_ROBUST_IN_ONLY) ||
mep.equals(WSDL2Constants.MEP_URI_IN_ONLY);
return inOnly;
}
/**
* Retrieves the registered InvocationListenerFactory instances and sets them
* on the current EndpointInvocationContext.
* @param eic
*/
void addInvocationListenerFactories(EndpointInvocationContext eic) {
eic.setInvocationListenerFactories(InvocationListenerRegistry.getFactories());
}
public ClassLoader getCachedClassLoader(org.apache.axis2.context.MessageContext msgContext) {
return (ClassLoader) msgContext.getAxisService().getParameterValue(org.apache.axis2.jaxws.spi.Constants.CACHE_CLASSLOADER);
}
}