/*=============================================================================*
* Copyright 2004 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.ws.resource.handler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.resource.ResourceContext;
import org.apache.ws.resource.ResourceContextException;
import org.apache.ws.resource.i18n.Keys;
import org.apache.ws.resource.i18n.MessagesImpl;
import org.apache.ws.util.XmlBeanUtils;
import org.apache.ws.util.i18n.Messages;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.xmlsoap.schemas.soap.envelope.Body;
import org.xmlsoap.schemas.soap.envelope.Envelope;
import org.xmlsoap.schemas.soap.envelope.EnvelopeDocument;
import javax.xml.namespace.QName;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.handler.GenericHandler;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.rpc.soap.SOAPFaultException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* LOG-DONE Base class for platform-specific providers; also is a JAX-RPC Handler for more flexibility.
*
* @author Ian P. Springer
* @author Sal Campana
*/
public abstract class ResourceHandler
extends GenericHandler
{
private static final Log LOG = LogFactory.getLog( ResourceHandler.class );
/**
* DOCUMENT_ME
*/
public static final Messages MSG = MessagesImpl.getInstance();
/**
* DOCUMENT_ME
*/
private static final String WSRF_RESPONSE_XMLOBJECT_LIST = "WSRF_RESPONSE_XMLOBJECT_LIST";
/**
* DOCUMENT_ME
*/
public static final String SERVICE_OPT_WSDL_TARGET_NAMESPACE = "wsdlTargetNamespace";
/**
* DOCUMENT_ME
*/
public static final String SERVICE_OPT_SERVICE_CLASS_NAME = "serviceClassName";
/**
* DOCUMENT_ME
*/
public static final String SERVICE_OPT_RESOURCE_KEY_QNAME = "resourceKeyQname";
/**
* DOCUMENT_ME
*/
public static final String SERVICE_OPT_RESOURCE_KEY_CLASS_NAME = "resourceKeyClass";
/**
* DOCUMENT_ME
*/
public static final String SERVICE_OPT_RESOURCE_HOME_CLASS_NAME = "resourceHomeClass";
/**
* DOCUMENT_ME
*/
public static final String SOAP_ENVELOPE_XMLBEAN = "apollo.soapEnvelopeXmlBean";
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public QName[] getHeaders()
{
return new QName[0];
}
/**
* DOCUMENT_ME
*
* @param msgContext DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public boolean handleRequest( MessageContext msgContext )
{
try
{
LOG.debug( MSG.getMessage( Keys.RECEIVED_REQUEST ) );
SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
SOAPEnvelope envelope = soapMsgContext.getMessage().getSOAPPart().getEnvelope();
EnvelopeDocument envelopeDocXmlBean = EnvelopeDocument.Factory.parse( envelope.toString() );
Envelope envelopeXmlBean = envelopeDocXmlBean.getEnvelope();
Body body = envelopeXmlBean.getBody();
ResourceContext resourceContext = createResourceContext( soapMsgContext );
resourceContext.setProperty( SOAP_ENVELOPE_XMLBEAN, envelopeXmlBean );
List responseBodyElems = new ArrayList();
XmlObject[] childElements = XmlBeanUtils.getChildElements( body );
for ( int i = 0; i < childElements.length; i++ )
{
XmlObject requestXBean = childElements[i];
//todo probably need to change method signatures to take types instead of documents to avoid this,
requestXBean = XmlObject.Factory.parse( requestXBean.xmlText( new XmlOptions().setSaveOuter() ) );
if ( requestXBean != null )
{
Class serviceClass = getServiceClassName( resourceContext );
WsrfService service = createService( serviceClass, resourceContext );
Method serviceMethod = getServiceMethod( service, requestXBean );
LOG.debug( MSG.getMessage( Keys.INVOKE_RESOURCE_METHOD,
serviceMethod.getName() ) );
XmlObject responseXBean = null;
try
{
responseXBean = (XmlObject) serviceMethod.invoke( service,
new Object[]
{
requestXBean
} );
}
catch ( InvocationTargetException ite )
{
LOG.error( MSG.getMessage( Keys.ERROR_INVOKING_METHOD_ON_SERVICE,
serviceMethod.getName(),
serviceClass.getName(),
ite ) );
throw ite.getCause();
}
if ( responseXBean != null )
{
responseBodyElems.add( responseXBean );
}
}
}
if ( ! responseBodyElems.isEmpty() )
{
msgContext.setProperty( WSRF_RESPONSE_XMLOBJECT_LIST, responseBodyElems );
}
}
catch ( Throwable t )
{
if ( t instanceof SOAPFaultException )
{
throw (SOAPFaultException) t;
}
else
{
t.printStackTrace();
throw new JAXRPCException( MSG.getMessage( Keys.UNEXPECTED_ERROR_WITH_EXCEPTION, t ) );
}
}
return false;
}
/**
* DOCUMENT_ME
*
* @param messageContext DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public boolean handleResponse( MessageContext messageContext )
{
LOG.debug( MSG.getMessage( Keys.HANDLING_RESPONSE ) );
SOAPEnvelope responseEnvelope = getResponseEnvelope( (SOAPMessageContext) messageContext );
List responseBodyElems = (List) messageContext.getProperty( WSRF_RESPONSE_XMLOBJECT_LIST );
LOG.debug( MSG.getMessage( Keys.FOUND_RESP_ELEMS,
Integer.toString( responseBodyElems.size() ) ) );
if ( responseBodyElems != null )
{
try
{
SOAPBody body = responseEnvelope.getBody();
for ( int i = 0; i < responseBodyElems.size(); i++ )
{
XmlObject responseBodyElem = (XmlObject) responseBodyElems.get( i );
body.addChildElement( createSOAPBodyElement( responseBodyElem ) );
}
}
catch ( Exception e )
{
if ( e instanceof SOAPFaultException )
{
throw (SOAPFaultException) e;
}
else
{
e.printStackTrace();
throw new JAXRPCException( MSG.getMessage( Keys.UNEXPECTED_ERROR_WITH_EXCEPTION, e ) );
}
}
}
return true;
}
/**
* Creates a {@link ResourceContext} for this request.
*
* @param soapMsgContext the JAX-RPC SOAP message context for this request
*
* @return a ResourceContext for this request
*/
protected abstract ResourceContext createResourceContext( SOAPMessageContext soapMsgContext );
/**
* DOCUMENT_ME
*
* @param responseBodyElem DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
protected abstract SOAPBodyElement createSOAPBodyElement( XmlObject responseBodyElem );
/**
* DOCUMENT_ME
*
* @param resourceContext DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
protected Class getServiceClassName( ResourceContext resourceContext )
throws ResourceContextException,
ClassNotFoundException
{
String serviceClassName = resourceContext.getResourceHome().getServiceClassName();
LOG.debug( MSG.getMessage( Keys.RETRIEVED_SERVICE_CLASSNAME, serviceClassName ) );
if ( serviceClassName == null )
{
throw new JAXRPCException( MSG.getMessage( Keys.SERVICE_OPT_UNDEFINED_IN_HOME,
SERVICE_OPT_SERVICE_CLASS_NAME ) );
}
Class serviceClass = Class.forName( serviceClassName );
return serviceClass;
}
/**
* @param resourceContext
* @param key
*
* @return
*/
protected final String getServiceOption( ResourceContext resourceContext,
String key )
{
return (String) resourceContext.getProperty( key );
}
/**
* DOCUMENT_ME
*
* @param soapMsgContext DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
protected SOAPEnvelope getResponseEnvelope( SOAPMessageContext soapMsgContext )
{
return ( getEnvelope( getResponseMessage( soapMsgContext ) ) );
}
/**
* @param soapMsgContext the response's JAX-RPC message context
*
* @return response JAX-RPC SOAP message
*/
protected SOAPMessage getResponseMessage( SOAPMessageContext soapMsgContext )
{
SOAPMessage soapMsg = soapMsgContext.getMessage();
if ( soapMsg == null )
{
soapMsg = createSOAPMessage();
soapMsgContext.setMessage( soapMsg );
}
return ( soapMsg );
}
/**
* @param soap_msg a SAAJ SOAP message
*
* @return
*/
private SOAPEnvelope getEnvelope( SOAPMessage soap_msg )
{
SOAPEnvelope soap_envelope = null;
try
{
SOAPPart soap_part = soap_msg.getSOAPPart();
soap_envelope = soap_part.getEnvelope();
}
catch ( SOAPException soape )
{
}
return ( soap_envelope );
}
private Method getServiceMethod( WsrfService service,
XmlObject requestXBean )
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( MSG.getMessage( Keys.DERIVE_SERVICE_NAME_FROM_REQ,
requestXBean.toString() ) );
}
Method serviceMethod = null;
String serviceMethodName =
service.getMethodNameMap().getMethodName( XmlBeanUtils.getName( requestXBean ) );
Method[] methods = service.getClass().getMethods();
for ( int i = 0; i < methods.length; i++ )
{
Method method = methods[i];
if ( method.getName().equals( serviceMethodName )
&& ( method.getParameterTypes().length == 1 )
&& method.getParameterTypes()[0].isInstance( requestXBean ) )
{
serviceMethod = method;
break;
}
}
if ( serviceMethod == null )
{
throw new JAXRPCException( MSG.getMessage( Keys.UNABLE_TO_FIND_METHOD_IN_SERVICE,
serviceMethodName,
service.getClass().getName() ) );
}
LOG.debug( MSG.getMessage( Keys.FOUND_SERVICE_METHOD,
serviceMethod.getName() ) );
return serviceMethod;
}
private SOAPMessage createSOAPMessage()
{
try
{
return MessageFactory.newInstance().createMessage();
}
catch ( SOAPException soape )
{
throw new JAXRPCException( MSG.getMessage( Keys.FAILED_TO_CREATE_SOAP_MSG ) );
}
}
private WsrfService createService( Class serviceClass,
ResourceContext resourceContext )
throws NoSuchMethodException,
InstantiationException,
IllegalAccessException,
InvocationTargetException
{
LOG.debug( MSG.getMessage( Keys.CREATING_INSTANCE_OF_SERVICE, serviceClass ) );
Constructor serviceCtor = serviceClass.getConstructor( new Class[]
{
ResourceContext.class
} );
WsrfService service = (WsrfService) serviceCtor.newInstance( new Object[]
{
resourceContext
} );
return service;
}
}