You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-user@axis.apache.org by Tony Schoenbachler <ts...@eoncc.com> on 2003/05/13 22:18:17 UTC

Axis Architecture guru needed to answer implementation question.. .

I have a question for a Senior Axis Architect who fully understands the Axis
implementation, specifically how the AxisServer's invoke(MessageContext
msgCtx) method is supposed to be utilized.   

I was getting the following error when trying to serialize a JavaBean:  At
the point this exception was thrown, I had already executed the
AxisEngine.invoke() method and had successfully passed the pivot point and
had a reference to the JavaBean that was being requested from the clients
get method.  The server method was successfully executed and had reference
to the correct response. 

java.io.IOException: No serializer found for class com.eon.beans.Agent in
registry org.apache.axis.encoding.SerializationContextImpl@7f11fb
	at
org.apache.axis.encoding.SerializationContextImpl.serializeActual(Unknown
Source)
	at
org.apache.axis.encoding.SerializationContextImpl.serialize(Unknown Source)
	at org.apache.axis.message.RPCParam.serialize(Unknown Source)
	at org.apache.axis.message.RPCElement.outputImpl(Unknown Source)
	at org.apache.axis.message.MessageElement.output(Unknown Source)
	at org.apache.axis.message.SOAPEnvelope.outputImpl(Unknown Source)
	at org.apache.axis.message.MessageElement.output(Unknown Source)
	at org.apache.axis.message.MessageElement.getAsString(Unknown
Source)
	at org.apache.axis.message.MessageElement.getAsDocument(Unknown
Source)
	at
com.eon.axis.jmstransport.JMSListener.onMessage(JMSListener.java:137)
	at org.jboss.mq.SpyMessageConsumer.run(SpyMessageConsumer.java:552)
	at java.lang.Thread.run(Thread.java:536)

It was crashing on the following line of code:

            AxisServer engine = (AxisServer)getAxisEngine();
            msgContext = new MessageContext(engine);
            org.apache.axis.Message soapMessage =  new
org.apache.axis.Message(jmsMsg.getText());
            msgContext.setRequestMessage(soapMessage);

            engine.invoke(msgContext);

            responseMsg = msgContext.getResponseMessage();
            SOAPEnvelope envelope = responseMsg.getSOAPEnvelope();
            Document document = envelope.getAsDocument(); <<== CRASHED HERE
!!!
            String strSOAPBody = XMLUtils.DocumentToString(document);

            TextMessage jmsResponseMsg = session.createTextMessage();
            jmsResponseMsg.setText(strSOAPBody);

            sender.send(jmsResponseMsg);

So, I downloaded the Axis source, compiled in debug mode and started
stepping thru the AxisEngine.invoke() method with the debugger.  Here's the
code...

    /**
     * Main routine of the AXIS server.  In short we locate the appropriate
     * handler for the desired service and invoke() it.
     */
    public void invoke(MessageContext msgContext) throws AxisFault {
        long t0=0, t1=0, t2=0, t3=0, t4=0, t5=0;
        if( tlog.isDebugEnabled() ) {
            t0=System.currentTimeMillis();
        }
        
        if (log.isDebugEnabled()) {
            log.debug("Enter: AxisServer::invoke");
        }

        if (!isRunning()) {
            throw new AxisFault("Server.disabled",
                                Messages.getMessage("serverDisabled00"),
                                null, null);
        }

        String  hName = null ;
        Handler h     = null ;

        // save previous context
        MessageContext previousContext = getCurrentMessageContext(); <<== IS
NULL AT THIS POINT IN MY IMPLEMENTATION

        try {
            // set active context
            setCurrentMessageContext(msgContext);

            hName = msgContext.getStrProp( MessageContext.ENGINE_HANDLER );
            if ( hName != null ) {
                if ( (h = getHandler(hName)) == null ) {
                    ClassLoader cl = msgContext.getClassLoader();
                    try {
                        log.debug( Messages.getMessage("tryingLoad00",
hName) );
                        Class cls = ClassUtils.forName(hName, true, cl);
                        h = (Handler) cls.newInstance();
                    }
                    catch( Exception e ) {
                        h = null ;
                    }
                }
                if( tlog.isDebugEnabled() ) {
                    t1=System.currentTimeMillis();
                }
                if ( h != null )
                    h.invoke(msgContext);
                else
                    throw new AxisFault( "Server.error",
                                         Messages.getMessage("noHandler00",
hName),
                                         null, null );
                if( tlog.isDebugEnabled() ) {
                    t2=System.currentTimeMillis();
                    tlog.debug( "AxisServer.invoke " + hName + " invoke=" +
                                ( t2-t1 ) + " pre=" + (t1-t0 ));
                }
                
            }
            else {
                // This really should be in a handler - but we need to
discuss it
                // first - to make sure that's what we want.
                /* Now we do the 'real' work.  The flow is basically:
*/
                /*   Transport Specific Request Handler/Chain
*/
                /*   Global Request Handler/Chain
*/
                /*   Protocol Specific-Handler(ie. SOAP, XP)
*/
                /*     ie. For SOAP Handler:
*/
                /*           - Service Specific Request Handler/Chain
*/
                /*           - SOAP Semantic Checks
*/
                /*           - Service Specific Response Handler/Chain
*/
                /*   Global Response Handler/Chain
*/
                /*   Transport Specific Response Handler/Chain
*/
 
/**************************************************************/

                // When do we call init/cleanup??
                if (log.isDebugEnabled()) {
                    log.debug(Messages.getMessage("defaultLogic00") );
                }

                /*  This is what the entirety of this logic might evolve to:

                hName = msgContext.getStrProp(MessageContext.TRANSPORT);
                if ( hName != null ) {
                if ((h = hr.find( hName )) != null ) {
                h.invoke(msgContext);
                } else {
                log.error(Messages.getMessage("noTransport02", hName));
                }
                } else {
                // No transport set, so use the default (probably just
                // calls the global->service handlers)
                defaultTransport.invoke(msgContext);
                }

                */

                /* Process the Transport Specific Request Chain */
                /**********************************************/
                hName = msgContext.getTransportName();
                SimpleTargetedChain transportChain = null;

                if (log.isDebugEnabled())
                    log.debug(Messages.getMessage("transport01",
"AxisServer.invoke", hName));

                if( tlog.isDebugEnabled() ) {
                    t1=System.currentTimeMillis();
                }
                if ( hName != null && (h = getTransport( hName )) != null )
{
                    if (h instanceof SimpleTargetedChain) {
                        transportChain = (SimpleTargetedChain)h;
                        h = transportChain.getRequestHandler();
                        if (h != null)
                            h.invoke(msgContext);
                    }
                }

                if( tlog.isDebugEnabled() ) {
                    t2=System.currentTimeMillis();
                }
                /* Process the Global Request Chain */
                /**********************************/
                if ((h = getGlobalRequest()) != null ) {
                    h.invoke(msgContext);
                }

                /**
                 * At this point, the service should have been set by
someone
                 * (either the originator of the MessageContext, or one of
the
                 * transport or global Handlers).  If it hasn't been set, we
                 * fault.
                 */
                h = msgContext.getService();
                if (h == null) {
                    // It's possible that we haven't yet parsed the
                    // message at this point.  This is a kludge to
                    // make sure we have.  There probably wants to be
                    // some kind of declarative "parse point" on the handler
                    // chain instead....
                    Message rm = msgContext.getRequestMessage();
                    rm.getSOAPEnvelope().getFirstBody();
                    
                    h = msgContext.getService();
                    if (h == null)
                        throw new AxisFault("Server.NoService",
 
Messages.getMessage("noService05",
                                                                 "" +
msgContext.getTargetService()),
                                            null, null );
                }
                if( tlog.isDebugEnabled() ) {
                    t3=System.currentTimeMillis();
                }

                // Ensure that if we get SOAP1.2, then reply using SOAP1.2 
 
if(msgContext.getRequestMessage().getSOAPEnvelope().getSOAPConstants() !=
null) {
                    SOAPConstants soapConstants =
msgContext.getRequestMessage().getSOAPEnvelope().getSOAPConstants();
                    msgContext.setSOAPConstants(soapConstants);
                }
                    
                h.invoke(msgContext);

                if( tlog.isDebugEnabled() ) {
                    t4=System.currentTimeMillis();
                }

                /* Process the Global Response Chain */
                /***********************************/
                if ((h = getGlobalResponse()) != null)
                    h.invoke(msgContext);

                /* Process the Transport Specific Response Chain */
                /***********************************************/
                if (transportChain != null) {
                    h = transportChain.getResponseHandler();
                    if (h != null)
                        h.invoke(msgContext);
                }
                
                if( tlog.isDebugEnabled() ) {
                    t5=System.currentTimeMillis();
                    tlog.debug( "AxisServer.invoke2 " +
                                " preTr=" +
                                ( t1-t0 ) + " tr=" + (t2-t1 ) +
                                " preInvoke=" + ( t3-t2 ) +
                                " invoke=" + ( t4-t3 ) +
                                " postInvoke=" + ( t5-t4 ) +
                                " " + msgContext.getTargetService() + "." +
     
                            ((msgContext.getOperation( ) == null) ?
                                 "" : msgContext.getOperation().getName())
);
                }

            }
        } catch (AxisFault e) {
            throw e;
        } catch (Exception e) {
            // Should we even bother catching it ?
            throw AxisFault.makeFault(e);

        } finally {
            // restore previous state
            setCurrentMessageContext(previousContext); <<== SET BACK TO NULL
        }
        
        if (log.isDebugEnabled()) {
            log.debug("Exit: AxisServer::invoke");
        }
    }

In my case, when entering the invoke method the getCurrentMessageContext()
method returns null. This method then sets the current message context to
the MessageContext passed in on the methods parameter list. The function is
executed as normal and then THE CURRENT MESSAGE CONTEXT IS SET BACK TO THE
PREVIOUS MESSAGE CONTEXT which happens to be null, in the finally block.
Now, this is all fine and dandy until I try to serialize the result of the
method call.  The Message context contains the serializer/deserializer
definitions that map the BeanSerializer to my Java bean.  Since it is null
after the call to invoke, I get the no serializer error message listed
above.  

Now, to repair this problem I wrote the following code: 

/**
 * @(#)JMSAxisServer.java
 *
 * Copyright 2002 eOn Communications, Inc. All rights reserved. 
 *
 * @author  tschoenbachler
 * @version $Revision$
 *
 * Creation Date: May 12, 2003
 * Creation Time: 11:22:43 AM
 *
 * Modification(s):
 *
 *  Listed at the end of this source file.
 *
 */
package com.eon.axis.jmstransport;

import org.apache.axis.server.AxisServer;
import org.apache.axis.MessageContext;
import org.apache.axis.AxisEngine;
import org.apache.axis.EngineConfiguration;

public class JMSAxisServer extends AxisServer {

    private static final String id = "$Header: $";

    public JMSAxisServer(EngineConfiguration engineConfiguration) {
         super(engineConfiguration);
     }

    public static void setCurrentMessageContext(MessageContext
messageContext) {
        AxisEngine.setCurrentMessageContext(messageContext);
    }

}

/**
 * Modification(s):
 *   
 *   $Log$  
 *
 */

This code allows me to reset the currentMessageContext after the call to
invoke on the AxisServer.  Now the bean will serialize correctly.  This
solves my problem but as you can see this is a hack and probably not how the
code was meant to be used.  Can anyone shed some light on this issue.  How
can I set the currentMessageContext without overridding the AxisServer
class. I would like to implement this in another way if possible. 

Thanks for any comments in advance. 

Tony Schoenbachler
eOn Communications
tschoenbachler@eoncc.com


Re: Axis Architecture guru needed to answer implementation question.. .

Posted by Jess Sightler <js...@eximtechnologies.com>.
I'm definitely not a "Senior Axis Architext", but I would love to hear a
description of the logic behind this as well.

I've dealt with this problem when trying to support other Transports
with the Axis codebase, and have always had to use hacks like the one
below to set the context, in order for Bean serialization to work.

Is there a better way?

Thanks,
Jess


On Tue, 2003-05-13 at 16:18, Tony Schoenbachler wrote:
> I have a question for a Senior Axis Architect who fully understands the Axis
> implementation, specifically how the AxisServer's invoke(MessageContext
> msgCtx) method is supposed to be utilized.   
> 
> I was getting the following error when trying to serialize a JavaBean:  At
> the point this exception was thrown, I had already executed the
> AxisEngine.invoke() method and had successfully passed the pivot point and
> had a reference to the JavaBean that was being requested from the clients
> get method.  The server method was successfully executed and had reference
> to the correct response. 
> 
> java.io.IOException: No serializer found for class com.eon.beans.Agent in
> registry org.apache.axis.encoding.SerializationContextImpl@7f11fb
> 	at
> org.apache.axis.encoding.SerializationContextImpl.serializeActual(Unknown
> Source)
> 	at
> org.apache.axis.encoding.SerializationContextImpl.serialize(Unknown Source)
> 	at org.apache.axis.message.RPCParam.serialize(Unknown Source)
> 	at org.apache.axis.message.RPCElement.outputImpl(Unknown Source)
> 	at org.apache.axis.message.MessageElement.output(Unknown Source)
> 	at org.apache.axis.message.SOAPEnvelope.outputImpl(Unknown Source)
> 	at org.apache.axis.message.MessageElement.output(Unknown Source)
> 	at org.apache.axis.message.MessageElement.getAsString(Unknown
> Source)
> 	at org.apache.axis.message.MessageElement.getAsDocument(Unknown
> Source)
> 	at
> com.eon.axis.jmstransport.JMSListener.onMessage(JMSListener.java:137)
> 	at org.jboss.mq.SpyMessageConsumer.run(SpyMessageConsumer.java:552)
> 	at java.lang.Thread.run(Thread.java:536)
> 
> It was crashing on the following line of code:
> 
>             AxisServer engine = (AxisServer)getAxisEngine();
>             msgContext = new MessageContext(engine);
>             org.apache.axis.Message soapMessage =  new
> org.apache.axis.Message(jmsMsg.getText());
>             msgContext.setRequestMessage(soapMessage);
> 
>             engine.invoke(msgContext);
> 
>             responseMsg = msgContext.getResponseMessage();
>             SOAPEnvelope envelope = responseMsg.getSOAPEnvelope();
>             Document document = envelope.getAsDocument(); <<== CRASHED HERE
> !!!
>             String strSOAPBody = XMLUtils.DocumentToString(document);
> 
>             TextMessage jmsResponseMsg = session.createTextMessage();
>             jmsResponseMsg.setText(strSOAPBody);
> 
>             sender.send(jmsResponseMsg);
> 
> So, I downloaded the Axis source, compiled in debug mode and started
> stepping thru the AxisEngine.invoke() method with the debugger.  Here's the
> code...
> 
>     /**
>      * Main routine of the AXIS server.  In short we locate the appropriate
>      * handler for the desired service and invoke() it.
>      */
>     public void invoke(MessageContext msgContext) throws AxisFault {
>         long t0=0, t1=0, t2=0, t3=0, t4=0, t5=0;
>         if( tlog.isDebugEnabled() ) {
>             t0=System.currentTimeMillis();
>         }
>         
>         if (log.isDebugEnabled()) {
>             log.debug("Enter: AxisServer::invoke");
>         }
> 
>         if (!isRunning()) {
>             throw new AxisFault("Server.disabled",
>                                 Messages.getMessage("serverDisabled00"),
>                                 null, null);
>         }
> 
>         String  hName = null ;
>         Handler h     = null ;
> 
>         // save previous context
>         MessageContext previousContext = getCurrentMessageContext(); <<== IS
> NULL AT THIS POINT IN MY IMPLEMENTATION
> 
>         try {
>             // set active context
>             setCurrentMessageContext(msgContext);
> 
>             hName = msgContext.getStrProp( MessageContext.ENGINE_HANDLER );
>             if ( hName != null ) {
>                 if ( (h = getHandler(hName)) == null ) {
>                     ClassLoader cl = msgContext.getClassLoader();
>                     try {
>                         log.debug( Messages.getMessage("tryingLoad00",
> hName) );
>                         Class cls = ClassUtils.forName(hName, true, cl);
>                         h = (Handler) cls.newInstance();
>                     }
>                     catch( Exception e ) {
>                         h = null ;
>                     }
>                 }
>                 if( tlog.isDebugEnabled() ) {
>                     t1=System.currentTimeMillis();
>                 }
>                 if ( h != null )
>                     h.invoke(msgContext);
>                 else
>                     throw new AxisFault( "Server.error",
>                                          Messages.getMessage("noHandler00",
> hName),
>                                          null, null );
>                 if( tlog.isDebugEnabled() ) {
>                     t2=System.currentTimeMillis();
>                     tlog.debug( "AxisServer.invoke " + hName + " invoke=" +
>                                 ( t2-t1 ) + " pre=" + (t1-t0 ));
>                 }
>                 
>             }
>             else {
>                 // This really should be in a handler - but we need to
> discuss it
>                 // first - to make sure that's what we want.
>                 /* Now we do the 'real' work.  The flow is basically:
> */
>                 /*   Transport Specific Request Handler/Chain
> */
>                 /*   Global Request Handler/Chain
> */
>                 /*   Protocol Specific-Handler(ie. SOAP, XP)
> */
>                 /*     ie. For SOAP Handler:
> */
>                 /*           - Service Specific Request Handler/Chain
> */
>                 /*           - SOAP Semantic Checks
> */
>                 /*           - Service Specific Response Handler/Chain
> */
>                 /*   Global Response Handler/Chain
> */
>                 /*   Transport Specific Response Handler/Chain
> */
>  
> /**************************************************************/
> 
>                 // When do we call init/cleanup??
>                 if (log.isDebugEnabled()) {
>                     log.debug(Messages.getMessage("defaultLogic00") );
>                 }
> 
>                 /*  This is what the entirety of this logic might evolve to:
> 
>                 hName = msgContext.getStrProp(MessageContext.TRANSPORT);
>                 if ( hName != null ) {
>                 if ((h = hr.find( hName )) != null ) {
>                 h.invoke(msgContext);
>                 } else {
>                 log.error(Messages.getMessage("noTransport02", hName));
>                 }
>                 } else {
>                 // No transport set, so use the default (probably just
>                 // calls the global->service handlers)
>                 defaultTransport.invoke(msgContext);
>                 }
> 
>                 */
> 
>                 /* Process the Transport Specific Request Chain */
>                 /**********************************************/
>                 hName = msgContext.getTransportName();
>                 SimpleTargetedChain transportChain = null;
> 
>                 if (log.isDebugEnabled())
>                     log.debug(Messages.getMessage("transport01",
> "AxisServer.invoke", hName));
> 
>                 if( tlog.isDebugEnabled() ) {
>                     t1=System.currentTimeMillis();
>                 }
>                 if ( hName != null && (h = getTransport( hName )) != null )
> {
>                     if (h instanceof SimpleTargetedChain) {
>                         transportChain = (SimpleTargetedChain)h;
>                         h = transportChain.getRequestHandler();
>                         if (h != null)
>                             h.invoke(msgContext);
>                     }
>                 }
> 
>                 if( tlog.isDebugEnabled() ) {
>                     t2=System.currentTimeMillis();
>                 }
>                 /* Process the Global Request Chain */
>                 /**********************************/
>                 if ((h = getGlobalRequest()) != null ) {
>                     h.invoke(msgContext);
>                 }
> 
>                 /**
>                  * At this point, the service should have been set by
> someone
>                  * (either the originator of the MessageContext, or one of
> the
>                  * transport or global Handlers).  If it hasn't been set, we
>                  * fault.
>                  */
>                 h = msgContext.getService();
>                 if (h == null) {
>                     // It's possible that we haven't yet parsed the
>                     // message at this point.  This is a kludge to
>                     // make sure we have.  There probably wants to be
>                     // some kind of declarative "parse point" on the handler
>                     // chain instead....
>                     Message rm = msgContext.getRequestMessage();
>                     rm.getSOAPEnvelope().getFirstBody();
>                     
>                     h = msgContext.getService();
>                     if (h == null)
>                         throw new AxisFault("Server.NoService",
>  
> Messages.getMessage("noService05",
>                                                                  "" +
> msgContext.getTargetService()),
>                                             null, null );
>                 }
>                 if( tlog.isDebugEnabled() ) {
>                     t3=System.currentTimeMillis();
>                 }
> 
>                 // Ensure that if we get SOAP1.2, then reply using SOAP1.2 
>  
> if(msgContext.getRequestMessage().getSOAPEnvelope().getSOAPConstants() !=
> null) {
>                     SOAPConstants soapConstants =
> msgContext.getRequestMessage().getSOAPEnvelope().getSOAPConstants();
>                     msgContext.setSOAPConstants(soapConstants);
>                 }
>                     
>                 h.invoke(msgContext);
> 
>                 if( tlog.isDebugEnabled() ) {
>                     t4=System.currentTimeMillis();
>                 }
> 
>                 /* Process the Global Response Chain */
>                 /***********************************/
>                 if ((h = getGlobalResponse()) != null)
>                     h.invoke(msgContext);
> 
>                 /* Process the Transport Specific Response Chain */
>                 /***********************************************/
>                 if (transportChain != null) {
>                     h = transportChain.getResponseHandler();
>                     if (h != null)
>                         h.invoke(msgContext);
>                 }
>                 
>                 if( tlog.isDebugEnabled() ) {
>                     t5=System.currentTimeMillis();
>                     tlog.debug( "AxisServer.invoke2 " +
>                                 " preTr=" +
>                                 ( t1-t0 ) + " tr=" + (t2-t1 ) +
>                                 " preInvoke=" + ( t3-t2 ) +
>                                 " invoke=" + ( t4-t3 ) +
>                                 " postInvoke=" + ( t5-t4 ) +
>                                 " " + msgContext.getTargetService() + "." +
>      
>                             ((msgContext.getOperation( ) == null) ?
>                                  "" : msgContext.getOperation().getName())
> );
>                 }
> 
>             }
>         } catch (AxisFault e) {
>             throw e;
>         } catch (Exception e) {
>             // Should we even bother catching it ?
>             throw AxisFault.makeFault(e);
> 
>         } finally {
>             // restore previous state
>             setCurrentMessageContext(previousContext); <<== SET BACK TO NULL
>         }
>         
>         if (log.isDebugEnabled()) {
>             log.debug("Exit: AxisServer::invoke");
>         }
>     }
> 
> In my case, when entering the invoke method the getCurrentMessageContext()
> method returns null. This method then sets the current message context to
> the MessageContext passed in on the methods parameter list. The function is
> executed as normal and then THE CURRENT MESSAGE CONTEXT IS SET BACK TO THE
> PREVIOUS MESSAGE CONTEXT which happens to be null, in the finally block.
> Now, this is all fine and dandy until I try to serialize the result of the
> method call.  The Message context contains the serializer/deserializer
> definitions that map the BeanSerializer to my Java bean.  Since it is null
> after the call to invoke, I get the no serializer error message listed
> above.  
> 
> Now, to repair this problem I wrote the following code: 
> 
> /**
>  * @(#)JMSAxisServer.java
>  *
>  * Copyright 2002 eOn Communications, Inc. All rights reserved. 
>  *
>  * @author  tschoenbachler
>  * @version $Revision$
>  *
>  * Creation Date: May 12, 2003
>  * Creation Time: 11:22:43 AM
>  *
>  * Modification(s):
>  *
>  *  Listed at the end of this source file.
>  *
>  */
> package com.eon.axis.jmstransport;
> 
> import org.apache.axis.server.AxisServer;
> import org.apache.axis.MessageContext;
> import org.apache.axis.AxisEngine;
> import org.apache.axis.EngineConfiguration;
> 
> public class JMSAxisServer extends AxisServer {
> 
>     private static final String id = "$Header: $";
> 
>     public JMSAxisServer(EngineConfiguration engineConfiguration) {
>          super(engineConfiguration);
>      }
> 
>     public static void setCurrentMessageContext(MessageContext
> messageContext) {
>         AxisEngine.setCurrentMessageContext(messageContext);
>     }
> 
> }
> 
> /**
>  * Modification(s):
>  *   
>  *   $Log$  
>  *
>  */
> 
> This code allows me to reset the currentMessageContext after the call to
> invoke on the AxisServer.  Now the bean will serialize correctly.  This
> solves my problem but as you can see this is a hack and probably not how the
> code was meant to be used.  Can anyone shed some light on this issue.  How
> can I set the currentMessageContext without overridding the AxisServer
> class. I would like to implement this in another way if possible. 
> 
> Thanks for any comments in advance. 
> 
> Tony Schoenbachler
> eOn Communications
tschoenbachler@eoncc.com
-- 
=======================================
Jess Sightler
Senior Developer
Exim Technologies
131 Falls Street
Greenville SC 29601
Phone: 864-679-4651
=======================================