Pages

Saturday, September 6, 2008

Use Flex in JSF with Exadel Fiji

Maybe you already saw this news at the serverside or by James Ward but Exadel just released Fiji. With Fiji you can use Flex applications in a JSF page and interact with the other JSF component or backing beans. I already tried this too but Exadel got it working with a lot of great options. You can develop now better looking and richer JSF applications with cool video or charts components. These flex applications can be a part of the jsf application without using blazeds or lifecycle. And of course you can use Flex to build complex parts of your jsf page ( like Charts, Drag and Drop, Video or Trees) and you can do it a lot faster and it is easier.

Here can you see the exadel jsf flex demos or read more about Fiji at the Exadel product page .

Fiji options
1) use f:param to pass values to the flex application
2) use HTTPService to retrieve any value of a backing bean method.
3) use DataService to retrieve the result using AMF format.
4) Invoking Ajax Request to send events to other parts of the jsf page.
5) Access to the flex api from the jsf page
6) New Flex Charts components in JSF without making a flex application

A little example
You can pass parameters to the flex application. Just use f:param and el

<fiji:swf src="/simpleHello/simpleHello.swf" id="simpleHello"
bgcolor="#FFFFFF" width="320" height="180">
<f:param name="userName" value="#{bean.simpleHelloUserName}" />
</fiji:swf>

And retrieve the parameters in Flex just use Application.application.parameters.userName

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Form x="22" y="10" width="280">
<mx:Label id="userName" styleName="text" text="{Application.application.parameters.userName}" />
</mx:Form>
</mx:Application>

Wednesday, September 3, 2008

Google Chrome with ADF 10G & 11G, Applet and Flash

Google released their new browser called Chrome, which is off course still beta ( that is normal for google). This browser not only looks fancy but it is very nice to browse the web. Andrej Koelewijn already talked about the internal memory page. Let's try some sites to know what the normal memory usage is. To do this you can open the taskmanager

This gives you already a nice overview.

or you can type about:memory in the url input. This gives you more memory info. So let's test some websites ( like cnn.com and my own blog), an ADF 10.1.3 , ADF 11g application, an applet and a flash application. Here are the results.

A normal website ( Tab 2 and 5 ) use about 26 MB of memory, the most complex 10g ADF page ( Tab 9) use 22MB and ADF 11g website gives me a not supported notice. Chrome also shows flash as a different memory process. A big flex application can take 50MB of memory and a small one 22MB.

Too bad I can't not run a java applet with the current installed jre. I need to install Java SE 6 Update 10 RC beta. You can download this at http://java.sun.com.
A simple Applet takes about 29MB of memory.

Happy browsing.

Monday, September 1, 2008

Associations with Ruby on Rails, Flex and RubyAMF

In this blog item I will you show how easy it is with RoR and RubyAMF to do CRUD operations on tables with associations. RoR and RubyAMF makes it very easy. I used for this blog a simple department and their employees use case.
Here is an picture of the result. A department has employees and an employee belongs to a department

First step is to create the RoR application
rails hr_app

change directory to the new application
cd hr_app

We need to edit the database configuration file
hr_app\config\database.yml

Install RubyAMF
ruby script/plugin install http://rubyamf.googlecode.com/svn/tags/current/rubyamf

Generate the department and employee table
ruby script/generate rubyamf_scaffold department
ruby script/generate rubyamf_scaffold employee


change department table configuration in hr_app/db/migrate folder

class CreateDepartments < ActiveRecord::Migration

def self.up
create_table :departments do |t|
t.string :name
t.string :location
t.timestamps
end
end

def self.down
drop_table :departments
end
end


change employee table also located in the hr_app/db/migrate folder

class CreateEmployees < ActiveRecord::Migration

def self.up
create_table :employees do |t|
t.integer :department_id
t.string :first_name
t.string :last_name
t.string :job
t.timestamps
end
end

def self.down
drop_table :employees
end
end

Let's create the department and employee table
rake db:migrate

We can add one to many associations in RoR
Edit hr_app/app/models/department.rb file where we will add has_many

class Department < ActiveRecord::Base
has_many :employees
end

Edit hr_app/app/models/employee.rb file where we will add belongs_to

class Employee < ActiveRecord::Base
belongs_to :department
end

The RoR configuration is ready we only have to configure RubyAMF

We can generate the class mappings and copy this to the rubyamf_config.rb configuration
ruby script/generate rubyamf_mappings

The generator detects the associations between department and employees
Copy the generated block of text into config/rubyamf_config.rb:
edit hr_app/config/rubyamf_config.rb

require 'app/configuration'
module RubyAMF
module Configuration
ClassMappings.ignore_fields = ['created_at','updated_at']
ClassMappings.translate_case = true
ClassMappings.assume_types = false
ParameterMappings.scaffolding = false

ClassMappings.register(
:actionscript => 'Department',
:ruby => 'Department',
:type => 'active_record',
:associations => ["employees"],
:attributes => ["id", "name", "location", "created_at", "updated_at"])

ClassMappings.register(
:actionscript => 'Employee',
:ruby => 'Employee',
:type => 'active_record',
:associations => ["department"],
:attributes => ["id", "first_name", "last_name", "job", "created_at", "updated_at", "department_id"])

ClassMappings.force_active_record_ids = true
ClassMappings.use_ruby_date_time = false
ClassMappings.use_array_collection = true
ClassMappings.check_for_associations = true
ParameterMappings.always_add_to_params = true
end
end

Now we can start the RoR application
ruby script/server

Create a new Flex application.
First we will create the employee and department actionscript class.
The employee field in the Department class is an arraycollection

package vo
{
import mx.collections.ArrayCollection;


[RemoteClass(alias="Department")]
[Bindable]
public class Department
{
public var id:int;
public var name:String;
public var location:String;
public var createdAt:Date;
public var updatedAt:Date;
public var employees:ArrayCollection;
public function Department()
{
}

}
}

In the Employee class we add the department field of type Department

package vo
{
[RemoteClass(alias="Employee")]
[Bindable]
public class Employee
{
public var id:int;
public var firstName:String;
public var lastName:String;
public var job:String;
public var departmentId:int;
public var createdAt:Date;
public var updatedAt:Date;
public var department:Department;
public function Employee()
{
}
}
}

Here is the mxml code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="loadAll(); loadAll2();">

<mx:Script>
<![CDATA[
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import vo.Department;
import vo.Employee;
import mx.collections.ArrayCollection;

[Bindable]
private var departments:ArrayCollection = new ArrayCollection();
[Bindable]
private var employees:ArrayCollection = new ArrayCollection();


private function loadAll():void {
var token:AsyncToken = AsyncToken(departmentService.find_all());
token.kind = "fill";
}
private function loadAll2():void {
var token:AsyncToken = AsyncToken(employeeService.find_all());
token.kind = "fill";
}

private function createDept():void {
var dept:Department = new Department();
dept.name = "Headquarters";
dept.location = "Putten";
dept.employees = new ArrayCollection;
var token:AsyncToken = AsyncToken(departmentService.save(dept));
token.kind = "create";
}

private function createDeptWithEmp():void {
var dept:Department = new Department();
dept.name = "Headquarters";
dept.location = "Putten";
dept.employees = new ArrayCollection;

var emp:Employee = new Employee;
emp.firstName = "pipo";
emp.lastName = "pipo";
emp.job = "clown"
dept.employees.addItem(emp);

var token:AsyncToken = AsyncToken(departmentService.save(dept));
token.kind = "create";
}

private function destroy():void {
var token:AsyncToken = AsyncToken(departmentService.destroy(dg.selectedItem.id));
token.kind = "delete";
}

private function faultHandler(event:FaultEvent):void {
Alert.show(event.fault.faultString + " : " + event.fault.faultCode + " : " + event.fault.faultDetail , "Error in LoginCommand");
}

private function resultHandler(event:ResultEvent):void {
if ( event.token.kind == "fill" ) {
departments = event.result as ArrayCollection;
} else {
loadAll();
loadAll2();
}
}
private function resultHandler2(event:ResultEvent):void {
if ( event.token.kind == "fill" ) {
employees = event.result as ArrayCollection;
} else {
loadAll2();
}
}
]]>
</mx:Script>


<mx:RemoteObject id="departmentService" destination="rubyamf"
endpoint="http://localhost:3000/rubyamf_gateway/"
source="DepartmentsController"
showBusyCursor="true"
result="resultHandler(event)"
fault="faultHandler(event)"
/>

<mx:RemoteObject id="employeeService" destination="rubyamf"
endpoint="http://localhost:3000/rubyamf_gateway/"
source="EmployeesController"
showBusyCursor="true"
result="resultHandler2(event)"
fault="faultHandler(event)" />

<mx:HBox>
<mx:VBox>
<mx:Label text="Departments with employees"/>
<mx:HBox>
<mx:Button label="Create Department" click="createDept()"/>
<mx:Button label="Create Department with Employee" click="createDeptWithEmp()"/>
<mx:Button label="Remove Department" click="destroy()"/>
</mx:HBox>
<mx:DataGrid id="dg" dataProvider="{departments}">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="Key"/>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="location" headerText="Location"/>
</mx:columns>
</mx:DataGrid>

<mx:DataGrid id="dg_2" dataProvider="{dg.selectedItem.employees}">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="Key"/>
<mx:DataGridColumn dataField="firstName" headerText="First Name"/>
<mx:DataGridColumn dataField="lastName" headerText="Last Name"/>
</mx:columns>
</mx:DataGrid>

</mx:VBox>
<mx:VBox>

<mx:Label text="Employees"/>

<mx:DataGrid id="dg2" dataProvider="{employees}" variableRowHeight="true">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="Key"/>
<mx:DataGridColumn dataField="firstName" headerText="First Name"/>
<mx:DataGridColumn dataField="lastName" headerText="Last Name"/>
<mx:DataGridColumn dataField="department">
<mx:itemRenderer>
<mx:Component>
<mx:VBox>
<mx:Text text="{data.department.name}"/>
<mx:Text text="{data.department.location}"/>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</mx:VBox>

</mx:HBox>
</mx:Application>

That's all. you can easily create and retrieve departments with it's employees with RoR and RubyAMF. RoR and RubyAMF do all the hard work.