1 2 Previous Next 22 Replies Latest reply on Jul 18, 2007 2:10 PM by cingram Go to original post
      • 15. Re: Seam and Adobe Flex

        Guys,

        Where can I find some examples of using Seam and Flex with Seam remoting?

        Thanks

        • 16. Re: Seam and Adobe Flex
          patrickmadden

          I have Flex Builder 2.1 where I developed an actionscript 3.0 library. I have successfully - after decent amount of work - have it talking to JBoss Seam application with Jboss Web Services 2.0.0.0.GA. I'm using the Flash 9 player and JRE 1.6 on the client side. If you can guarantee JRE 1.5 on the client side there is not much trouble. Search for posts by me in the seam forum and the JBoss Web Services forum to figure out how to ease the pain.

          I'm not exactly using Seam Remoting at this point but am interested in looking at that in the future.

          On the web application I'm using Ajax4JSF and Rich Faces with Seam 2.0 Beta. I have a tabbed pane where one tab contains the Flex component embedded. I use a rich faces toolbar that talks to my flex application using exposed External Interface api's. Once inside flex, I talk to the backend via the JBoss Web Services. It really integrates nicely once its done.

          If you might have clients connecting via JRE 1.6 plugin, I would download the 4_2 branch of JBoss App server and download the JBoss web services 2.0.0.0 GA - again, look for my posts in the Seam forum to see how to do this and your JBoss Web Services will talk to flex apps without any problems.

          Hope this helps,

          PVM

          • 17. Re: Seam and Adobe Flex

            This is crazy having to have both flash and jre in browser. What are you using jre for? Is there a way to make seam work with flex without requiring jre in brower?
            Thanks

            • 18. Re: Seam and Adobe Flex
              patrickmadden

              Should have been more clear. I'm using jdk 1.6u2 on the server side with JBoss AS 4.2.1.GA (from svn - its not really GA just yet but seams very stable). There are reasons I need to do this as we sometimes run into JRE 1.6 on client side with some Java WebStart applications and applets that are available to start from our seam based web app. There is new code in JDK 1.6 that was not there in 1.5 and it messes with normal operation of JBoss Web Services. Trust me, its true. With JBossWS 2.0.0.0GA, they add some extra jar files to the $Jboss.home/lib/endorsed directory to fix the problem.

              My flex based components had difficulty speaking to the backend web services with the standard install of JBoss 4.2.0.GA and JBoss Web Services 1.2.1.GA and

              Even if you have JDK 1.5 on the backend and for some reason use any remote standalone java application, webstart application or applet that may be using JRE 1.6 on the client (its not always easy to control btw what is on the client) you will run into issues with JBoss Web Services.

              The issue at hand is Flex with Seam and how to talk to the backend, I have it running very nicely right now with EJB3 web services running in Seam.

              But to answer your question, yes I don't believe you need to deal with JRE just to use flash/flex components and seam. Just be careful if you see errors such as xxx needs to overrride setProperty. Because if you do, its issues on the backend with java endorsed dirs.

              Here is a small code example of my ActionScript 3 code that connects to an EJB3 Web Service running with Seam and JBoss.

              package com.clooster.as3.app.service
              {
               import flash.net.URLVariables;
              
               import flash.events.EventDispatcher;
               import flash.events.IEventDispatcher;
               import flash.net.URLRequest;
               import flash.net.URLRequestMethod;
               import flash.events.Event;
               import flash.net.URLLoader;
               import flash.utils.*;
               import flash.utils.describeType;
              
               import mx.controls.Alert;
               import mx.rpc.Fault;
               import mx.rpc.soap.WebService
               import mx.rpc.soap.LoadEvent;
               import mx.rpc.soap.SOAPDecoder;
               import mx.rpc.events.FaultEvent;
               import mx.rpc.events.ResultEvent;
              
               import com.clooster.as3.common.util.logging.Logger;
               import com.clooster.as3.common.events.WebServiceEvent;
               import mx.utils.ObjectUtil;
              
               public class CloosterFlashWebService extends EventDispatcher implements ICloosterFlashWebService
               {
               protected var sessionID:String;
               protected var logger:Logger = new Logger("CloosterFlashWebService");
              
               protected var webService:WebService = new WebService();
               protected var isAvailable:Boolean = false;
              
               public function CloosterFlashWebService(wsdlURL:String, asessionID:String, target:IEventDispatcher=null)
               {
               super(target);
               this.webService.addEventListener(LoadEvent.LOAD, onWSDLLoaded);
               this.webService.addEventListener(FaultEvent.FAULT, onWebServiceFault);
               this.webService.loadWSDL(wsdlURL);
               this.sessionID = asessionID;
               }
              
               protected function onWSDLLoaded(e:LoadEvent) : void
               {
               this.isAvailable = true;
              
               this.webService.navigateToParentGraph.addEventListener(
               ResultEvent.RESULT, onNavigateToParentGraph);
               this.webService.navigateToParentGraph.resultFormat = "e4x";
              
               this.webService.expandCluster.addEventListener(
               ResultEvent.RESULT, onExpandCluster);
               this.webService.expandCluster.resultFormat = "e4x";
              
               this.webService.globalLayout.addEventListener(
               ResultEvent.RESULT, onGlobalLayout);
               this.webService.globalLayout.resultFormat = "e4x";
               }
              
               private function onWebServiceFault(e:FaultEvent) : void
               {
               var fault:Fault = e.fault;
               var message:String = "An error occurred. The details are as follows\ncode: " + fault.faultCode;
               message += "\ndetail: " + fault.faultDetail;
               Alert.show("Web Service Error", message);
               }
              
               public function isAvailable() : Boolean
               {
               return this.isAvailable;
               }
              
               public function navigateToParentGraph():void
               {
               this.webService.navigateToParentGraph(this.sessionID);
               }
              
               protected function onNavigateToParentGraph(e:ResultEvent) : void
               {
               this.dispatchEvent(new WebServiceEvent(
               WebServiceEvent.NAVIGATETOPARENTGRAPH, e.result));
               }
              
               public function expandCluster(nodeID:uint):void
               {
               this.webService.expandCluster(this.sessionID, String(nodeID));
               }
              
               protected function onExpandCluster(e:ResultEvent) : void
               {
               this.dispatchEvent(new WebServiceEvent(
               WebServiceEvent.EXPANDCLUSTER, e.result));
               }
              
               public function globalLayout(layoutStyle:String):void
               {
               this.webService.globalLayout(this.sessionID, layoutStyle);
               }
              
               protected function onGlobalLayout(e:ResultEvent) : void
               {
               this.dispatchEvent(new WebServiceEvent(
               WebServiceEvent.GLOBALLAYOUT, e.result));
               }
               }
              }
              


              My flex component is almost entirely implemented in Action Script and it draws diagrams that allow zooming, scrolling, and navigation up and down among a series of diagrams. Similar to a network diagram or a Visio chart.

              The WebServiceEvent is a class I wrote that allows users to register for AS3 events against the web service class.

              package com.clooster.as3.common.events
              {
               import flash.events.Event;
              
               [Event(name="PERFORMSEARCHFROMNODE", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="LOADSAVEDHEADLINESRESULT", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="NAVIGATETOPARENTGRAPH", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="EXPANDCLUSTER", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="GLOBALLAYOUT", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="PEFORMSEARCH", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="GETSAVEDHEADLINESRESULTNAMES", type="com.clooster.as3.common.events.WebServiceEvent")]
               [Event(name="SAVEHEADLINES", type="com.clooster.as3.common.events.WebServiceEvent")]
               public class WebServiceEvent extends Event
               {
               public static const PERFORMSEARCHFROMNODE:String = "performSearchFromNode";
               public static const LOADSAVEDHEADLINESRESULT:String = "loadSavedHeadlineResult";
               public static const NAVIGATETOPARENTGRAPH:String = "navigateToParentGraph";
               public static const EXPANDCLUSTER:String = "expandCluster";
               public static const GLOBALLAYOUT:String = "globalLayout";
               public static const PEFORMSEARCH:String = "performSearch";
               public static const GETSAVEDHEADLINESRESULTNAMES:String = "SavedHeadlineResultNames";
               public static const SAVEHEADLINES:String = "saveHeadlines";
              
               protected var result:Object;
              
               /**
               * Constructor
               */
               public function WebServiceEvent(type:String, aresult:Object, bubbles:Boolean=false, cancelable:Boolean=false)
               {
               super(type, bubbles, cancelable);
               this.result = aresult;
               }
              
               /**
               * Returns the WebService for this event
               */
               public function getResult() : Object
               {
               return this.result;
               }
              
               /**
               * Creates a copy of the current instance
               * @return A copy of the current instance
               */
               public override function clone() : Event
               {
               return new WebServiceEvent(this.type, this.result, this.bubbles, this.cancelable);
               }
               }
              }
              



              In one of my main flex application classes i create the web service and register for events as follows:

              
               public function getWebService() : CloosterFlashWebService
               {
               if (this.webService == null)
               {
               this.webService = new CloosterFlashWebService(
               this.getWebServiceURL(),
               this.getSessionID());
              
               registerWebServiceEventHandlers();
               }
              
               return this.webService;
               }
              
               protected function registerWebServiceEventHandlers() : void
               {
               this.getWebService().addEventListener(
               WebServiceEvent.NAVIGATETOPARENTGRAPH,
               onNewGraphXMLWebServiceHandler);
              
               this.getWebService().addEventListener(
               WebServiceEvent.EXPANDCLUSTER,
               onNewGraphXMLWebServiceHandler);
              
               this.getWebService().addEventListener(
               WebServiceEvent.GLOBALLAYOUT,
               onNewGraphXMLWebServiceHandler);
               }
              
               /**
               * Called when the web service returns an new graph xml result
               */
               protected function onNewGraphXMLWebServiceHandler(we:WebServiceEvent) : void
               {
               var xmlList:XMLList = XMLList(we.getResult());
               var graphXML:XML = xmlList[0];
              


              The trick is that the result from the web service in flex in an XMLList from my testing you can just graph the first item in the list and its your SOAP xml envelope. For me, all my results are themselves XML and you can get the actual xml from the envelope as follows:

              
               var returnNodes:XMLList = graphXML.elements("return");
              
               if (returnNodes != null && returnNodes.length() == 1)
               {
               var returnNode:XML = returnNodes[0];
               var xmlString:String = returnNode.toString();
              
               // This is the actual xml returned from the method minus the envelope.
               this.graphXML = new XML(xmlString);
               }
              
              



              Here is a small snippet of my backend service:

              /**
               *
               */
              package com.clooster.web.services.flash;
              
              import javax.ejb.Remote;
              import javax.ejb.Stateless;
              import javax.jws.WebMethod;
              import javax.jws.WebService;
              import javax.jws.soap.SOAPBinding;
              
              import org.jboss.annotation.ejb.RemoteBinding;
              import org.jboss.ws.annotation.WebContext;
              
              /**
               * @author PatrickMadden
               *
               */
              
              @WebService(name = "FlashServiceEndpointInterface", targetNamespace = "http://clooster.com/web/services/flash", serviceName = "FlashService")
              @SOAPBinding(style = SOAPBinding.Style.RPC)
              @Remote(EJB3RemoteFlashService.class)
              @RemoteBinding(jndiBinding = "/ejb3/EJB3FlashService")
              @Stateless
              @WebContext(transportGuarantee = "NONE", contextRoot = "/Clooster", urlPattern = "/common/services/FlashService")
              public class EJB3RemoteFlashServiceBean implements
               EJB3RemoteFlashService
              {
               /*
               * (non-Javadoc)
               *
               * @see com.clooster.web.services.EJB3RemoteFlashService#expandCluster(java.lang.String,
               * long)
               */
               @WebMethod
               public String expandCluster(String sessionID, long nodeID)
               {
              



              So you should be able to something very similar to use seam, jboss, webservices and flex.

              Just for completeness, I'll show you some of the xhtml with Rich Faces and JSF etc.

              
               <rich:tab label="Diagram">
               <head>
               <script type="text/javascript" src="./javascript/swfobject.js"></script>
               <script type="text/javascript" src="./javascript/cloosterflash.js"></script>
               </head>
               <div>
               <rich:toolBar>
               <table cellspacing="0" cellpadding="0" width="100%" border="0">
               <tr>
               <td class="menu_cell">
               <a href="javascript:flashNavigateToParentGraph()">
               <img title="Navigate Up" src="img/xjava/navigate_backward.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashFitInCanvas()">
               <img title="Fit In Canvas" src="img/toolbar/fitInCanvas.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashZoomIn()">
               <img title="Zoom In" src="img/toolbar/zoomIn.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashZoomOut()">
               <img title="Zoom Out" src="img/toolbar/zoomOut.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <select id="zoom" onchange="flashZoomComboChanged();" name="zoom">
               <option value="200">200%</option>
               <option value="150">150%</option>
               <option value="100">100%</option>
               <option value="50">50%</option>
               <option value="25">25%</option>
               <option value="10">10%</option>
               </select>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashToggleOverview()">
               <img title="Toggle Log Window" src="img/toolbar/view_overview.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashToggleLogWindow()">
               <img title="Toggle Overview" src="img/toolbar/view_overview.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashGlobalCLayout()">
               <img title="Circular Layout" src="img/toolbar/circular.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashGlobalHLayout()">
               <img title="Hierarchical Layout" src="img/toolbar/hierarchical.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashGlobalOLayout()">
               <img title="Orthogonal Layout" src="img/toolbar/othogonal.gif" border="0"/>
               </a>
               </td>
               <td class="menu_cell">
               <a href="javascript:flashGlobalSLayout()">
               <img title="Symmetric Layout" src="img/toolbar/symmetric.gif" border="0"/>
               </a>
               </td>
               </tr>
               </table>
               </rich:toolBar>
               </div>
               <div id="flashcontent" style="vertical-align: top;">
               <strong>You must update your Flash Player</strong>
               </div>
               <!-- Clooster.swf is the flex/flash movie and we name it 'GraphCanvas' for use in the cloosterflash.js -->
               <script type="text/javascript">
               var so = new FlashObject("./swf/Clooster.swf","GraphCanvas","100%","580px","9","#ffffff");
               so.addParam("scale", "noscale");
               so.addParam("align", "top");
               so.addParam("salign", "lt");
               so.addParam("wmode", "window");
              
               so.addVariable("appContextURL","#{search.externalApplicationRoot}");
               so.addVariable("graphURL","#{search.graphXMLDataURL}");
               so.addVariable("sessionID","#{search.sessionId}");
               so.addVariable("overviewControlVisible","false");
               so.addVariable("logWindowControlVisible", "false");
               so.write("flashcontent");
               </script>
               </rich:tab>
              


              Hope this helps,

              PVM

              • 19. Re: Seam and Adobe Flex

                Thanks. Actually I was looking for something more lightweight
                like calling seam component method (annotated with @WebRemote)
                from ActionScript and displaying results in Flex table.

                I've seen some constructs to call javascript from actionscript
                like

                getURL('javascript:fromFlash()')

                not sure though if they can return objects (as supported by seam remoting)

                • 20. Re: Seam and Adobe Flex

                  Hmm... In this very thread there is a description of a way to call
                  javascript from actionscript using actionscript's EnternalInterface

                  var customers = EnternalInterface.call(Seam.Component.getInstance("customerAction").getAllCustomers());
                  


                  http://www.adobe.com/devnet/flash/articles/external_interface_print.html

                  Are there any problems with this method (apart from requirement of using flash 8)?

                  Thanks

                  • 21. Re: Seam and Adobe Flex
                    patrickmadden

                    I use ExternalInterface in both directions - Flex/Flash to javascript and javascript to Flex/Flash. In my case user's can use the mouse wheel to zoom in and out on the diagram very easily. In my HTML page I have a toolbar that has a combobox showing the current zoom percent. When users uses mouse wheel inside flex I update the html page dynamically using External Interface method as follows:

                     /**
                     * Updates the zoom combobox in the html page owning this movie
                     */
                     public function updateZoomComboBox() : void
                     {
                     ExternalInterface.call("flashUpdateZoomComboBox",
                     String(Math.round(getCloosterApp().getGraphCanvas().scaleX * 100.0)));
                     }
                    


                    For the reverse direction I first register callbacks with the player. These methods can then be called from javascript.

                     /**
                     * The methods below can be called from javascript code in the browser.
                     */
                     protected function registerExternalFunctions() : void
                     {
                     ExternalInterface.addCallback("zoomIn", zoomIn);
                     ExternalInterface.addCallback("zoomOut", zoomOut);
                     ExternalInterface.addCallback("zoomTo", zoomTo);
                    ...
                    


                    It works for me and I would assume you would be able to use the seam remoting as long as you import the seam remoting javascript file in you xhtlm, or jsp page etc.

                    Thanks,

                    PVM

                    • 22. Re: Seam and Adobe Flex

                      FYI: If Patrick pretty cool WebService/Action library is not an option for what ever reason. The FlexAjaxbridge makes using the seam remoting(javascript) pretty easy. An example of the helloworld


                      ---Html page
                      
                      <script src="FABridge.js" ></script>
                      <script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>
                      <script type="text/javascript" src="seam/resource/remoting/interface.js?helloAction"></script>
                      
                      function sayHello(name) {
                       Seam.Component.getInstance("helloAction").sayHello(name, sayHelloCallback);
                      }
                      
                      
                      function sayHelloCallback(result) {
                       var flexApp = FABridge.flash.root();
                       var message = myActionScriptFunction(result);
                      }
                      
                      
                      ---ActionScript
                      
                      private function sayHello(): void {
                       var f:String = "sayHello";
                       ExternalInterface.call(f,txtName.Text);
                      }
                      
                      private function sayHelloCallBack(result:String): void {
                       lblName.Text = result;
                      }
                      


                      The downside is it is fairly code intensive. You could clean alot of this up by doing some dynamic javascript. The remoting js file is pretty nice as it propagates the conversation for you. I haven't quite figured out how to get a object that is returned from the server to translate in to action script properly.

                      1 2 Previous Next