Re: Result handler not being invoked - SOLVED

Michael Guyver <[email protected]> Wed, 7 Feb 2007 13:11:36 +0000 (UTC)
Newsgroups gmane.comp.java.openamf.user
Message-ID <[email protected]>
Michael Guyver <kenevel <at> gmail.com> writes:

Hi there, 

I finally got to the bottom of this and the reason I wasn't seeing a result was
because you need to re-use the RPC envelope from the request. I was not using
the transmitted values to identify my response so I guess the NetConnection was
simply discarding it as something in which it wasn't interested. See in
particular the values below from sniffing the request/response with the Charles
HttpProxy.

I hope this helps people understand how the AMF remoting hangs together. You may
well be asking my I didn't just use the OpenAMF framework in its entirety
anyway; well, I don't want to do RPC, I want to be able to call REST-style URLs
and get a response based on those, not the serialized request. Call me old
fashioned... but I like to understand how things work.

Cheers 

Mike

For completeness, here's my hacked-together code:

------------------------------------------------------------------------------
-------------------------------------------------------------------- Java code
------------------------------------------------------------------------------

package uk.co.mindfruit.flex.amf;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openamf.AMFBody;
import org.openamf.AMFError;
import org.openamf.AMFMessage;
import org.openamf.config.CustomClassMappingConfig;
import org.openamf.config.OpenAMFConfig;
import org.openamf.io.AMFDeserializer;
import org.openamf.io.AMFSerializer;

public class DefaultAmfServlet extends HttpServlet {

    protected void service(HttpServletRequest request, 
                           HttpServletResponse response) 
        throws ServletException, IOException {
        
        // initialise the custom-class mapping as I'm not using the whole gamut 
        // of functions from the OpenAMF project: this realy is intended as a 
        // proof-of-concept to get this working: AMF0, AS3, Flex 2.1 & Java
        if
(OpenAMFConfig.getInstance().getCustomClassName(Person.class.getName()) == null){
            CustomClassMappingConfig customClassMapping = new
CustomClassMappingConfig();
            customClassMapping.setCustomClassName("guyverm.Person");
            customClassMapping.setJavaClassName(Person.class.getName());
           
OpenAMFConfig.getInstance().addCustomClassMappingConfig(customClassMapping);
        }

        DataInputStream inputStream = new DataInputStream(request.getInputStream());
        AMFDeserializer deserializer = new AMFDeserializer(inputStream);
        AMFMessage requestMessage = deserializer.getAMFMessage();

        // check target
        Object serviceResult = new Person("Michael", "Guyver");
        String target = getTarget(requestMessage.getBody(0), serviceResult);
        
        // create response
        AMFMessage responseMessage = new AMFMessage();
        responseMessage.addBody(new AMFBody(target, "null", serviceResult));
        
        // write output
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        AMFSerializer serializer = new AMFSerializer(new DataOutputStream(baos));
        serializer.serializeMessage(responseMessage);
        
        response.setContentType("application/x-amf");
        response.setContentLength(baos.size());
        ServletOutputStream sos = response.getOutputStream();
        baos.writeTo(sos);
        sos.flush();
    }
    
    private String getTarget(AMFBody requestBody, Object serviceResult) {
        String target = "/onResult";
        if (serviceResult instanceof AMFError) {
            target = "/onStatus";
        }
        return requestBody.getResponse() + target;
    }
}

------------------------------------------------------------------------------
--------------------------------- Charles-HttpProxy AMF request representation
------------------------------------------------------------------------------

AMFMessage                             Message    
+---Header                             Array
+---Body                               Array
    +---[0]                            Body Part
        +---Target        String       doRpc()
        +---Response      String       /1
        +---Content       Array

------------------------------------------------------------------------------
-------------------------------- Charles-HttpProxy AMF response representation
------------------------------------------------------------------------------

AMFMessage                             Message    
+---Header                             Array
+---Body                               Array
    +---[0]                            Body Part
        +---Target        String       /1/onResult
        +---Response      String       null
        +---Content       Custom Class guyverm.Person
            +---firstName String       Michael
            +---surname   String       Guyver
        
As you can see, the request.body[0].Response is included in the
response.body[0].Target, to which the /onResult is appended. Add this and
everything starts behaving itself. 


------------------------------------------------------------------------------
---------------------------------------------------------------- Action Script
------------------------------------------------------------------------------

package guyverm {

    import flash.net.NetConnection;
    import flash.net.ObjectEncoding;

    /* 
     * see http://www.adobe.com/devnet/flex/articles/flex2_amfphp_03.html
     */
    public class RemotingConnection extends NetConnection {
        
        public function RemotingConnection(sURL:String) {
            objectEncoding = ObjectEncoding.AMF0;
            if (sURL) {
                connect(sURL);
            }
        }
        
    }
}


package guyverm {
    public class Person {
        
        private var myFirstName:String;
        private var mySurname:String;
        
        public function get firstName():String{
            return myFirstName;
        }
        public function set firstName(name:String) : void {
            myFirstName = name;
        }
        public function get surname():String {
            return mySurname;
        }
        public function set surname(name:String) : void {
            mySurname = name;
        }
        public function toString():String {
            return myFirstName + " " + mySurname;
        }
    }
}

package guyverm {

    import flash.display.DisplayObjectContainer;
    import flash.events.NetStatusEvent;
    import flash.net.Responder;
    import mx.controls.TextArea;
    import mx.core.IMXMLObject;
    
    public class ErsteKlasse implements IMXMLObject {
    
        private var displayObj:DisplayObjectContainer;
        private var traceArea:TextArea;
        private var gateway:RemotingConnection;
        
        
        function ErsteKlasse(){
            super();
        }
        
        /**
         * From interface IMXMLObject.
         */
        public function initialized(document:Object, id:String):void {
            displayObj = (document as DisplayObjectContainer);
        }
        
        private function log(message:String):void {
            if (traceArea != null){
                traceArea.htmlText = traceArea.htmlText + "<br/>" + message;
            }
        }
        
        flash.net.registerClassAlias( "guyverm.Person", guyverm.Person );

        public function makeRemoteConnection():void {
            gateway = new RemotingConnection("http://swf.localhost/flex/butt.amf");
            gateway.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            gateway.call("doRpc()", new Responder(resultHandler, faultHandler));
        }

        public function netStatusHandler(event:NetStatusEvent):void {
            log("in ErsteKlasse.netStatusHandler: event.info.code: " +
event.info.code);
        }
        
        public function resultHandler(result:Object) : void {
            log("in ErsteKlasse.resultHandler: " + result);
        }
        
        public function faultHandler(message:String) : void {
            log("in ErsteKlasse.faultHandler: " + message);
        }
        //------------------------------------------------------- MXML setters
        public function set debugArea(uiComponent:TextArea):void {
            traceArea = uiComponent;
        }
    }
}


------------------------------------------------------------------------------
------------------------------------------------------------------------- MXML
------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>

<mx:Application 
    xmlns="*" 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:guyverm="guyverm.*" 
    paddingTop="2"
    paddingBottom="2"
    paddingLeft="2"
    paddingRight="2">

    <mx:TextArea width="100%" height="100%" id="debugPane"></mx:TextArea>

    <guyverm:ErsteKlasse 
        debugArea="{debugPane}" 
        id="serviceTarget"/>

    <mx:Button label="Flex butt" click="serviceTarget.makeRemoteConnection()" />

</mx:Application>

------------------------------------------------------------------------------
---------------------------------------------------------------------- web.xml
------------------------------------------------------------------------------

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 
    version="2.4">

    <display-name>Flex Remoting Demo</display-name>

    <servlet>
        <servlet-name>amfService</servlet-name>
        <servlet-class>uk.co.mindfruit.flex.amf.DefaultAmfServlet</servlet-class>
    </servlet>
        
    <servlet-mapping>
        <servlet-name>amfService</servlet-name>
        <url-pattern>*.amf</url-pattern>
    </servlet-mapping>  
   
</web-app>





-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642