Integrating ATG with Adobe Flex using BlazeDS

I have had a few inquiries about whether it is possible to integrate Adobe Flex with ATG via AMF. My short answer is Yes. It should be possible. The only issue that needs to be solved though is to access the nucleus components from flex. You need a factory for that e.g. the equivalent of ejbfactory(used for EJB 3) for ATG. At some stage when I have a bit of time in my hands I will create a factory for ATG Nucleus, if nobody creates one in the mean time.

Integrating Adobe Flex with Struts 2 and JBOSS Using BlazeDS

The first step of this process will be to able to run BlazeDS on JBOSS without struts 2. If that is not working yet for you please do that first.
The main reason that Struts 2 and BlazeDS out of the box fail to work together is because most configurations of Struts 2 intercept all HTTP requests to a web application. This is because of this piece of configuration in web.xml:

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
 <filter-name>struts2</filter-name>
 <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
 </filter>

This is a java filter that intercepts all requests and responses. This is a problem because most instructions on how to setup BlazeDS ask you declare the following servlet in your web.xml:

<!-- MessageBroker Servlet -->
<servlet>
<servlet-name>MessageBrokerServlet</servlet-name>
<display-name>MessageBrokerServlet</display-name>
<servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
<init-param>
<param-name>services.configuration.file</param-name>
<param-value>/WEB-INF/flex/services-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>MessageBrokerServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>

However this will never work with Struts 2 unless you restrict the url pattern to something less than /*. Filters seem to be executed always before any servlet declared in web.xml.

To solve this problem, instead of declaring the MessageBrokerServlet as a servlet lets declare it as filter in the filter chain. Filters declared in a filter chain are always executed in the order that they are declared in web.xml. For that reason make sure that this filter is always called before the Struts 2 filter(FilterDispatcher). If our filter determines that there is an incoming request that needs to be handled by BlazeDS, we call the MessageBrokerServlet, and we prevent any more filters in the chain to be called. If the request is not for BlazeDS the filter will not be called.

package uk.co.spltech.web.filter;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.mock.web.MockServletConfig;

import flex.messaging.MessageBrokerServlet;

/**
* The MessageBrokerServlet has a lower priority than Filters, regardless of the url-pattern
* we use. For that reason I created a filter that directly extends the MessageBrokerServlet but
* behaves as a filter. This might be quite dodgy but that's the only way I found to integrate struts
* 2 and Adobe Flex/BlazeDS. Anyone who knows a simpler way please email me at info at spltech.co.uk
*
* @author Armindo Cachada
*
*/
public class FlexFilter  extends MessageBrokerServlet implements Filter{

public void destroy() {
super.destroy();
}

/**
* If this method is called the parent service method of the MessageBrokerServlet is called,
* which does whatever BlazeDS needs to do to communicate with the flex client. Note Here
* that any subsequent filter will not be called because I am not invoking filterChain.doFilter/
* That is on purpose, because if it does, the normal struts 2 action mapping mechanism will be called.
*
*/
public void doFilter(ServletRequest servletrequest,
ServletResponse servletresponse, FilterChain filterchain)
throws IOException, ServletException {
this.service((HttpServletRequest)servletrequest, (HttpServletResponse)servletresponse);
}

/** Note the use here of MockServletConfig. This utility class is available in the spring framework. It is  meant
to be used for testing but I am actually giving it a real purpose :)
*/
public void init(FilterConfig filterconfig) throws ServletException {
System.out.println("filter called");
MockServletConfig servletConfig = new MockServletConfig(filterconfig.getServletContext());
Enumeration filterParameters = filterconfig.getInitParameterNames();

while (filterParameters.hasMoreElements()){
String filterParameter = (String)filterParameters.nextElement();
System.out.println("Found parameter: " + filterParameter);
String value =filterconfig.getInitParameter(filterParameter);
servletConfig.addInitParameter(filterParameter, value);

}
super.init(servletConfig);
}

}




Add the following to your filter chain in web.xml:

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>

<filter>
<filter-name>flex</filter-name>
<filter-class>uk.co.spltech.web.filter.FlexFilter</filter-class>
<init-param>
<param-name>services.configuration.file</param-name>
<param-value>/WEB-INF/flex/services-config.xml</param-value>
</init-param>
</filter>

This solution did the job for me. Please let me know if it also works for you!

Adding Drag and Drag functionality in Adobe Air

In this tutorial I will teach you step by step how to use the out of the box drag & drop functionality provided by flex list controls.

Just some basic theory before we go into code. The drag & drop process has three stages – initiation, dragging and dropping.

The initiation is when the user clicks on a flex component and keeps the button pressed. In this case the component that the user clicks on is the drag initiator. Any flex component that supports dragging will handle either the mouseDown() or mouseMove() event to initiate the drag & drop operation. The event handler will then create a DragSource object which contains data related to the object being dragged. For example if you are dragging a file between two components, the DragSource object will contain a reference to a File object. Once the DragSource is constructed the DragManager.doDrag() method is called where the first argument is a reference to the object that initiated the drag, the second argument is the DragSource object and the third argument is a reference to the mouse event that called the event handler. There is a fourth optional argument that allows to specify a drag proxy that may be used to represent the object being dragged on the screen(e.g. a semi-transparent version of the drag initiator)

In the Dragging stage the user moves the flex component across the screen up to the drop target. If you specify a drag proxy image, that is what is shown on the screen when dragging the component. If not specified a rectangle will be shown instead.

In the dropping stage when the component being dragged arrives to a potential drop target, a dragEnter event is raised. The event handler that handles this event should check whether the DragSource object contains data that is of an acceptable format. If that’s the case then DragManager.acceptDragDrop() is called indicating that the drop target is happy in accepting the dragged data.

In this tutorial I will teach you step by step how to use the out of the box drag & drop functionality provided by flex list controls.

Just some basic theory before we go into code. The drag & drop process has three stages – initiation, dragging and dropping.

The initiation is when the user clicks on a flex component and keeps the button pressed. In this case the component that the user clicks on is the drag initiator. Any flex component that supports dragging will handle either the mouseDown() or mouseMove() event to initiate the drag & drop operation. The event handler will then create a DragSource object which contains data related to the object being dragged. For example if you are dragging a file between two components, the DragSource object will contain a reference to a File object. Once the DragSource is constructed the DragManager.doDrag() method is called where the first argument is a reference to the object that initiated the drag, the second argument is the DragSource object and the third argument is a reference to the mouse event that called the event handler. There is a fourth optional argument that allows to specify a drag proxy that may be used to represent the object being dragged on the screen(e.g. a semi-transparent version of the drag initiator)

In the Dragging stage the user moves the flex component across the screen up to the drop target. If you specify a drag proxy image, that is what is shown on the screen when dragging the component. If not specified a rectangle will be shown instead.

In the dropping stage when the component being dragged arrives to a potential drop target, a dragEnter event is raised. The event handler that handles this event should check whether the DragSource object contains data that is of an acceptable format.  If that’s the case then DragManager.acceptDragDrop() is called indicating that the drop target is happy in accepting the dragged data.

Fortunately for list controls most of this work is already done for you. Implementing drag & drop is very simple:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
     <mx:ArrayCollection id="source">
            <mx:Array>
            <mx:Object singer="Michael Jackson" />
            <mx:Object singer="Jennifer Lopez" />
            <mx:Object singer="Janet Jackson" />
            <mx:Object singer="Paul Mcarthney" />
        </mx:Array>
    </mx:ArrayCollection>

   <mx:ArrayCollection id="destination">
      <mx:Array>
          <mx:Object singer="Sheryl Crowe"/>
      </mx:Array>
   </mx:ArrayCollection>
   <mx:DataGrid dataProvider="{source}" dragEnabled="true" dragMoveEnabled="true"/>
   <mx:DataGrid dataProvider="{destination}" dropEnabled="true"/>
</mx:Application>

In the example above by setting dragEnabled to <b>true</b> allows the rows inside the data grid to be dragged. For any dragged rows to be accepted by the other data grid we need to set dropEnabled to true on that target DataGrid. We also set dragMoveEnabled to true to enable moving rows between data grids.

Ok, now let’s see how we can add drag & drop support to our file system manager. The steps required to do this are:

Step 1

We need to set the dragEnabled and the dropEnabled properties to true on both FileSystemDataGrid. The reason we do on both is because we want to allow the user to copy or move files in both directions: from left to right and right to left.

Step 2

We need to override the default handler for the DragEvent.DRAG_DROP event. This is because the standard drag & drop behavior for the FileSystemDataGrid isn’t quite what we need. In this event handler we need to call event.preventDefault() so that the default event handler is not called. The event handler inspects what file is specified inside the DragSource object carried by the event and performs the copy/move operation as specified by the key that user pressed. If the user just drags a file between the two data grids while pressing the shift key a move file operation is performed. Otherwise the default is to do a copy operation. If the file operation goes is successful we refresh the contents of two FileSystemDataGrid’s, otherwise an alert box is shown.

Here is the code:

 /**
  * Determines what object was dropped in the data grid
  */
 private function handleDragDrop(event:DragEvent):void {
 	// we do this because we want to override the default drag and drop
 	// behaviour implemented in the DataGrid
 	event.preventDefault();
 	var dragSource:DragSource=event.dragSource;
 	if (dragSource.hasFormat("items")) {
 		var items:Array = dragSource.dataForFormat("items") as Array ;
 		for each (var item:File in items) {
 			// copy this file to the directory indicated by fs2
 			// make sure that the origin data grid is not the same as the dest
 			if (event.dragInitiator!= event.target) {
 				var fileDest:File = FileSystemDataGrid(event.target).directory.resolvePath(item.name)

 				var dataGrid:FileSystemDataGrid=event.currentTarget as FileSystemDataGrid;
 				item.addEventListener(Event.COMPLETE, refreshFileSystems);
 				// if the user has pressed the shift key then he just
 				// wants to copy the file
 				if (event.shiftKey)
 				{
 					this.copyFile(item, fileDest);

 				}
 				else {
 					this.moveFile(item, fileDest);
 				}

 			}
 		}
 	}
 }

Click here to download the File System Manager Air app with Drag and Drop support


It is very cool to drag and drop a file from one file system data grid to another. However wouldn’t it be even cooler to be able to drag and drop files from the operating system desktop to Air file manager? That kind of drag & drop requires native drag & drop support. If you are interested in native drag and drop support then read my post on Native Drag and Drop in Adobe Air with example

How to apply effects to components inside containers with automated layout

In this tutorial I will explain how to apply a tween effect to a component inside a container with automated layout.

Containers like VBox, HBox, Panel(except for layout=absolute), Grid, … automatically position items for you.

Lets try to apply a Move effect to a Button inside a VBox:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" height="500" width="500">
<mx:Script>
 <![CDATA[
     /**
     * This method runs an effect on a button to move it
     * to the right side.
     * 
     */
  public function moveButton(button:Button):void {
   this.moveEffect.target= button;
   this.moveEffect.play();
  }
 ]]>
</mx:Script>
 <mx:VBox id="box" clipContent="false" backgroundAlpha="1" backgroundColor="red">
  <mx:Button id="button1" label="Button 1" click="moveButton(button1)"/>
  <mx:Button id="button2" label="Button 2" click="moveButton(button2)"/>
  <mx:Button id="button3" label="Button 3" click="moveButton(button3)"/>
 </mx:VBox>
  <mx:Sequence id="moveEffect">
   <mx:Move duration="5000" xBy="300" yBy="300"/>
   <mx:Move duration="5000" xBy="-300" yBy="-300"/>
  </mx:Sequence>
</mx:Application>

Click here to run our example

In the example above we set clipContent to false to enable the button to be visible outside the VBox container after it moves.

To start the move effect you need to click in one of the buttons. You will then see the button you clicked move to the right bottom corner and then return to its original position. This example is not completely correct, but it works for this simple example.

To understand why it might not work lets add a Resize effect to the VBox to go along with the button Move effect:

<mx:Parallel id="moveEffect">
 <mx:Sequence>
  <mx:Move duration="5000" xBy="300" yBy="300"/>
  <mx:Move duration="5000" xBy="-300" yBy="-300"/>
 </mx:Sequence>
 <mx:Sequence>
  <mx:Resize target="{box}" duration="5000" heightBy="300" widthBy="300"/>
  <mx:Resize target="{box}" duration="5000" heightBy="-300" widthBy="-300"/>
 </mx:Sequence>
</mx:Parallel>

At the same time that we move the button to the right bottom corner and then back to its origin, we also increase the size of the VBox and then decrease it back to its original size. Note here the use of Sequence and Parallel. These two effects allow us to run a list of child effects in sequence or in parallel as you probably guessed.

Click here to try the example above

Did you notice anything wrong with the example above? Now the Move effect doens’t work anymore. This is because every time we change the size of the VBox, Flex needs to re-position the items inside the VBox. Because of this the x and y values of the button are re-calculated thus ruining our Move effect.
The solution to this problem is to set autoLayout=”false” immediately before the start of the effect:

<mx:VBox id="box" clipContent="false" backgroundAlpha="1" backgroundColor="red">
 <mx:Button id="button1" label="Button 1" click="moveButton(button1)"/>
 <mx:Button id="button2" label="Button 2" click="moveButton(button2)"/>
 <mx:Button id="button3" label="Button 3" click="moveButton(button3)"/>
</mx:VBox>




Click here to see the full working solution in action

Generating a random number in actionscript 3

Generating a random number in actionscript 3 is very similar to java.
To generate a random number betwen 0 and 100:

var number:Number = Math.round(Math.random() * 100);

Where Math.random() generates a random number between 0 and 1 and Math.round(), rounds the result to the nearest integer.
If you want to generate a number within a given range [start, end]:

var number:Number =Math.round( start +  Math.random() * (end - start));



The DisplayObject Blend Mode

The blend mode controls what happens when one display object is on top of another. The default setting in Adobe Flex is that the pixels of a display object override those that are displayed in the background. However you can change this behavior by modifying the blendMode setting. Read the language reference entry for DisplayObject. There you will find a detailed description of each blend mode.
In a nutshell the different blend modes available are:

  • BlendMode.NORMAL
  • BlendMode.LAYER
  • BlendMode.MULTIPLY
  • BlendMode.SCREEN
  • BlendMode.LIGHTEN
  • BlendMode.DARKEN
  • BlendMode.DIFFERENCE
  • BlendMode.DARKEN
  • BlendMode.OVERLAY
  • BlendMode.ADD
  • BlendMode.SUBTRACT
  • BlendMode.INVERT
  • BlendMode.ALPHA
  • BlendMode.ERASE
  • BlendMode.SHADE

Use the following flex code to try the different blend modes:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:core="*" xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" height="600" width="600" horizontalAlign="left">
 <mx:ArrayCollection id="blendModes">
  <mx:Array>
   <mx:Object label="Normal" data="normal"/>
   <mx:Object label="Layer" data="layer"/>
   <mx:Object label="Multiply" data="multiply"/>
   <mx:Object label="Screen" data="screen"/>
   <mx:Object label="Lighten" data="lighten"/>
   <mx:Object label="Darken" data="darken"/>
   <mx:Object label="Difference" data="difference"/> 
   <mx:Object label="Overlay" data="overlay"/>
   <mx:Object label="ADD" data="add"/>
   <mx:Object label="Subtract" data="subtract"/>
   <mx:Object label="Invert" data="invert"/>
   <mx:Object label="Alpha" data="alpha"/>
   <mx:Object label="Erase" data="erase"/>
  </mx:Array>
 </mx:ArrayCollection>
 <mx:Canvas height="200" width="400">
  <mx:VBox height="100" width="100" backgroundColor="{color1.selectedColor}" backgroundAlpha="1" blendMode="{blendMode1.selectedItem.data}" />
  <mx:VBox height="100" width="100" backgroundColor="{color2.selectedColor}" backgroundAlpha="1"  x="50" y="50" blendMode="{blendMode2.selectedItem.data}"/>
 </mx:Canvas>
 <mx:Panel title="Blend Modes" layout="horizontal">
  <mx:ComboBox id="blendMode1" dataProvider="{blendModes}" />
  <mx:ComboBox id="blendMode2" dataProvider="{blendModes}"/>
 </mx:Panel>
 <mx:Panel title="Colors">
  <mx:ColorPicker id="color1"/>
  <mx:ColorPicker id="color2" selectedColor="blue"/>
 </mx:Panel>
</mx:Application>




Click here to try the example.

Integrate Adobe Flex and JBOSS using BlazeDS – Part II

In the first part of this tutorial I showed you an example on how to integrate flex with JBOSS using BlazeDS. In this example we used RemoteObject in Actionscript to create a new instance of uk.co.spltech.remote.RemoteService and call the callMe() method remotely. The method returned a list of strings that we used to populate a datagrid.
In the second part of this tutorial we will do something slightly more useful. This time we will be invoking an EJB 3.0 bean managed by the application server.

Step 1

To be able to invoke EJB 3.0 from flex you need to download and copy FlexEJBFactory.jar to $JBOSS_HOME/server/default/lib. Or you can copy it to a local directory in your project separate from JBOSS e.g. example7/jbosslib and add the following line to $JBOSS_SERVER/server/default/conf/jboss-service.xml:

<classpath codebase="/usr/java/eclipse/workspace/example7/jbosslib" archives="*"/>

Previously all the BlazeDS jars were located in the WAR:WEB-INF/lib directory. But this is not going to work now because we need to see the jars within the context of the entire EAR. For that reason we need to move all those jars to to $JBOSS_SERVER/server/default/lib(or to a local directory inside your project e.g. jbosslib):

flex-ejb-factory.jar
flex-messaging-common.jar
flex-messaging-core.jar
flex-messaging-opt.jar
flex-messaging-proxy.jar
flex-messaging-remoting.jar
backport-util-concurrent.jar

Step 2

Because we will be invoking EJB 3.0 components we need to change the build process so that it creates an EAR file instead of a WAR. We add the following lines to the createjars target:

<jar jarfile="build/example7.jar">
 <fileset dir="${build.classes.dir}">
    <include name="uk/co/spltech/remote/*.class" />
 </fileset>
       
    </jar>

    <zip zipfile="build/example7.ear">
 <zipfileset dir="build">
  <include name="example7.war" />
 </zipfileset>
 <zipfileset dir="${build.dir}/resources" prefix="META-INF">
  <include name="application.xml" />
 </zipfileset>
       <zipfileset dir="build">
  <include name="example7.jar" />
 </zipfileset>
     </zip>

Step 3

Add the new ejb3 factory to flex/services-config.xml:

<factories>
     <factory id="ejb3" class="com.adobe.ac.ejb.EJB3Factory"/>
 </factories>

Step 4

Inside the uk.co.spltech.remote package create the following classes:

package uk.co.spltech.remote;

import java.util.List;

/**
 * This is an example of an interface where you can
 * declare all the methods that you want to call remotely
 * 
 * @author Armindo Cachada
 *
 */
public interface RemoteService {
 /**
  * I am not doing anything useful except to just show that I can be invoked remotely
  * from Adobe Flex using RemoteObject.
  * 
  */
 public List<String> callMe();
}

And the implementation of the interface:

package uk.co.spltech.remote;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Local;
import javax.ejb.Stateless;

/**
 * This remote service is called using BlazeDS/LiveCycle DS from Flex
 * 
 * @author Armindo Cachada
 *
 */
@Stateless(name = "remoteService")
@Local(RemoteService.class)
public class RemoteServiceImpl implements RemoteService {

 
 /**
  * I am not doing anything useful except to just show that I can be invoked remotely
  * from Adobe Flex using RemoteObject.
  * 
  */
 public List<String> callMe() {
  System.out.println("I was invoked!");
  List<String> result = new ArrayList<String>();
  result.add("Michael Jackson");
  result.add("Beatles");
  result.add("Tina Turner");
  return result;
 
 }
}

Step 5

Add the new destination to flex/remoting-config.xml:

<destination id="remoteService" >
        <properties>
              <factory>ejb3</factory>
              <source>example7/remoteService/local</source>
              <scope>application</scope>
         </properties>
   </destination>

There are two differences in the destination declaration:

  • The factory node indicates that we want to use the EJB3Factory declared in services-config.xml
  • The source instead of referencing a class name is changed to reference an EJB3 bean via JNDI.

Step 6

We are going to use the same mxml code as the one for Part I of this tutorial but we need to change the flex compiler settings:

-services "/usr/java/eclipse/workspace/example7/resources/flex/services-config.xml" -context-root "/example7" -locale en_US

After you have followed all these steps you should be good to go!




Download source code for JBOSS+Adobe Flex+BlazeDS project Part II

To save bandwidth I didn’t include all the jars needed:

flex-ejb-factory.jar
flex-messaging-common.jar
flex-messaging-core.jar
flex-messaging-opt.jar
flex-messaging-proxy.jar
flex-messaging-remoting.jar
backport-util-concurrent.jar

Copy these jars to the jbosslib directory inside the project. Don’t forget to change jboss-service.xml to reference this directory. Otherwise nothing will work.

Good luck!

Integrate Adobe Flex and JBOSS using BlazeDS – Part I

In this tutorial I will give you step by step instructions on how to integrate Adobe Flex and JBOSS using BlazeDS.
Although in this tutorial I am addressing BlazeDS, the steps in this tutorial should also apply to Adobe Flex LiveCycle Data Services. The only difference are the jars that you copy to your WEB-INF/lib directory. For those who want to integrate BlazeDS with Struts 2, the instructions in this tutorial should also be helpful.

In the Java Backend:

Step 1

Download blazeds.war from http://opensource.adobe.com/wiki/display/blazeds/Downloads

Step 2

Unzip blazeds.war. Copy the files in WEB-INF/lib and WEB-INF/flex to your web project under the same path in your web app.

Step 3

Edit web.xml and add the following lines:

    <!-- Http Flex Session attribute and binding listener support -->
    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>

    <!-- MessageBroker Servlet -->
    <servlet>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <display-name>MessageBrokerServlet</display-name>
        <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
        <init-param>
            <param-name>services.configuration.file</param-name>
            <param-value>/WEB-INF/flex/services-config.xml</param-value>
       </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>

Step 4

Create a simple java class with a simple method that we will invoke from Adobe Flex:

package uk.co.spltech.remote;

import java.util.ArrayList;
import java.util.List;

/**
 * This remote service is called using BlazeDS/LiveCycle DS from Flex
 * 
 * @author Armindo Cachada
 *
 */
public class RemoteService { 
 /**
  * I am not doing anything useful except to just show that I can be invoked remotely
  * from Adobe Flex using RemoteObject.
  * 
  */
 public List<String> callMe() {
  System.out.println("I am being invoked!");
  List<String> result = new ArrayList<String>();
  result.add("Michael Jackson");
  result.add("Beatles");
  result.add("Tina Turner");
  return result;
 }
}

Step 5

Create a new destination in remoting-config.xml:

<destination id="remoteService" >
   <properties>
        <source>uk.co.spltech.remote.RemoteService</source>
        <scope>application</scope>
   </properties>
</destination>

The source of the destination can be a fully qualified class name, a jndi reference or a spring bean. We will discuss that in a later post. For this example we just specify a class name.

The scope of the destination can be one of:

  • application – there is only one instance of the class for the entire application(i.e. global in atg, singleton in spring)
  • session – there is one instance per user session
  • request – for each http request a new instance of the class is created

In Adobe Flex:

Step 1

Create a new project in Adobe Flex. Please make sure that the Application Server type is set to none.
Why? Fair question to ask since most instructions say to do exactly the opposite. I found those instructions not really helpful in the case of JBOSS since they assume I can provide the directory containing the application after it is deployed to JBOSS. That works quite well for tomcat because it simply extracts the war file under webapps. The path is always the same. In the case of JBOSS the path to the application changes after each deployment…

Step 2

The only reason Adobe Flex asks you for the path to the root folder of your web application is so that it can provide two arguments to the flex compiler:

  • services – The path to the Adobe flex data services configuration file
  • context-root – The context root of your web application

After you create your web application add the following arguments to the flex compiler:

-services "/usr/java/eclipse/workspace/example6/resources/flex/services-config.xml" -context-root "/example6"

Step 3

Let’s create a very simple flex application that invokes the callMe() method in uk.co.spltech.remote.RemoteService. This method returns an ArrayList with a list of items:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" >
<mx:Script>
 <![CDATA[
  import mx.collections.ArrayCollection;
  import mx.controls.Alert;
  import mx.rpc.events.ResultEvent;
  import flash.utils.getQualifiedClassName;
  
  
  /**
   * Populates the data list using the results returned by callMe()
   */
  private function populateList(event:ResultEvent):void {
   var result:ArrayCollection= ArrayCollection(event.result);
   singerList.dataProvider= result;
  }
 ]]>
</mx:Script>
 <mx:RemoteObject id="myService" destination="remoteService" result="populateList(event)"/>
 <mx:List id="singerList" >
  
 </mx:List>
 <mx:Button click="myService.callMe();" label="Call Remote Function"  />
</mx:Application>

Step 4

Compile the flex app and copy all the generated swf/html/js to your jboss web app.

Step 5

Deploy the war file to JBOSS and test it under http://localhost:8080/example6

If you click in the “Call Remote Function” button you should see a list of results returned by the method callMe().

Download source code for JBOSS+Adobe Flex+BlazeDS project

Note that, in order to make the zip smaller, I didn’t include the BlazeDS jar files. You need to manually copy them to the lib directory before generating the war file.

Click here to read Part II

How to use verticalCenter and horizontalCenter in a container with absolute layout

In this tutorial I will explain how you can use the verticalCenter and horizontalCenter constraints in a container with absolute layout.

At this stage you probably already figured out how to use the left, right, top, bottom constraints. But what about horizontalCenter and verticalCenter?

horizontalCenter is the distance from the center of the container in the horizontal where you want your component to appear. If you give it a positive value, the component will show up in the right half of the container. If you give it a negative value the component will appear in the left half.

<mx:Canvas width="500" height="500">
   <mx:Button horizontalCenter="200" label="Right half of the container"/>
   <mx:Button horizontalCenter="-200" label="Left half of the container"/>
</mx:Canvas>

If you try to combine horizontalCenter with left or right constraints, they will always be ignored as the horizontalCenter constraint always takes precedence.

<mx:Canvas width="500" height="500">
   <mx:Button horizontalCenter="200" left="400" label="Button 1"/>
   <mx:Button horizontalCenter="200" right="200" label="Button 2"/>
</mx:Canvas>

In the example above the two buttons will overlap because the value of the left and right coordinate is ignored.

verticalCenter is the distance from the center of the container in the vertical where you want your component to appear. If you give it a positive value, the component will show up in the bottom half of the container. If you give it a negative value the component will appear in the top half.

<mx:Canvas width="500" height="500">
   <mx:Button verticalCenter="200" label="Bottom half of the container"/>
   <mx:Button verticalCenter="-200" label="Top half of the container"/>
</mx:Canvas>

If you try to combine verticalCenter with top or bottom constraints, they will always be ignored as the verticalCenter constraint always takes precedence.

<mx:Canvas width="500" height="500">
   <mx:Button verticalCenter="200" top="400" label="Button 1"/>
   <mx:Button verticalCenter="200" bottom="200" label="Button 2"/>
</mx:Canvas>

In the example above the two buttons will overlap because the value of the top and bottom constraint is ignored.

The code below shows possible combinations of horizontalCenter and verticalCenter that you can use to layout your components:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" height="520" width="520">
<mx:Button label="Left Center" horizontalCenter="-200" verticalCenter="0">
</mx:Button>

<mx:Button label="Center" horizontalCenter="0" verticalCenter="0">
</mx:Button>

<mx:Button label="Right Center" horizontalCenter="200" verticalCenter="0">
</mx:Button>


<mx:Button label="Top Left" horizontalCenter="-200" verticalCenter="-200">
</mx:Button>

<mx:Button label="Top Center" horizontalCenter="0" verticalCenter="-200">
</mx:Button>

<mx:Button label="Top Right" horizontalCenter="200" verticalCenter="-200">
</mx:Button>

<mx:Button label="Bottom Left" horizontalCenter="-200" verticalCenter="200">
</mx:Button>

<mx:Button label="Bottom Center" horizontalCenter="0" verticalCenter="200">
</mx:Button>

<mx:Button label="Bottom Right" horizontalCenter="200" verticalCenter="200">
</mx:Button>


<mx:Button label="Ignored right constraint" right="10" horizontalCenter="-200" verticalCenter="50">
</mx:Button>

<mx:Button label="Not ignored right constraint" right="10" verticalCenter="50">
</mx:Button>

<mx:Button label="Ignored top constraint" top="10" horizontalCenter="-200" verticalCenter="-50">
</mx:Button>

<mx:Button label="Not Ignored top constraint" top="10" horizontalCenter="-200">
</mx:Button>

</mx:Application>




Click here to try the example above

Recording a video stream with Red5

In this post I will show how simple it is to create an Adobe Flex client to record a video stream to a server running Adobe Media Server or Red5. Not only that I will also provide you with the code that you need to play the stream after you record it

Step 1

Connect to the Adobe Media Server or Red5 using NetConnection.connect()

private function connect():void {
   nc = new NetConnection();
   nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
   nc.connect("rtmp://localhost/vmspeak");
  ...   
}

In the case above we added an event listener to the NetConnection. Whether we are able to connect or not the method netStatusHandler is called. This method checks if the connection attempt is succcessful and enables/disables the record button based on that.

/**
  * When the connection is successful we can
  * enable the record button.
  * 
 */
private function netStatusHandler(event:NetStatusEvent):void
{
        trace(event.info.code);
 if(event.info.code == "NetConnection.Connect.Success")
 {
  this.recordButton.enabled=true; 
 }
 else {
  mx.controls.Alert.show("Failed to connect!");
 }
}

Step 2

Request access to the web camera and microphone:

   mic =Microphone.getMicrophone();
   mic.setUseEchoSuppression(true);
   mic.setSilenceLevel(0);
   cam = Camera.getCamera();

When executing this code Flash will show you a popup window requesting permission to access the video and microphone.

Step 3

To start recording you need to create a NetStream object using as argument the NetConnection you created in the step before.

  var ns:NetStream = new NetStream(nc);

Step 4

Attach the video and the camera to the NetStream and start recording.
You can also attach the camera to a Video object in order to see what the
camera is capturing during the recording. To record a stream one calls ns.publish(“stream-name”,”record”). It is also possible to create a live stream, and in that case one would call ns.publish(stream-name, “live”);

    ns.publish("test","record");
    ns.attachAudio(mic);
    ns.attachCamera(cam);
    this.video.attachCamera(cam);

Step 5

To stop the recording just call:

  ns.close();

Step 6

To play what you have just recorded:

private function playRecording():void {
 this.ns.play("test");
        this.video.attachNetStream(ns);
}

It looks really easy doesn’t it? The hardest part is to configure the media server in the backend.




Source for Video recorder with Red5 example

P.S. Before you can try the example you need to change the rtmp url to point to your media server.