[jboss-user] [JBoss Seam] - Re: Seam and Adobe Flex

PatrickMadden do-not-reply at jboss.com
Tue Jul 17 22:21:21 EDT 2007


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

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4065228#4065228

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4065228



More information about the jboss-user mailing list