Edwin Biemond
About Java, Adobe Flex, Oracle JDeveloper, JHeadstart and Oracle SOA suite
Updated: 14 hours 37 min ago
Dynamic Regions with Task Flow in Jdeveloper 11G
I made a new dynamic region example but now build with the JDeveloper 11G production release. In this project I have a jsf page which has a Tree and a dynamic region. This example uses the the department and employee tables of the HR demo schema.
Here are some pictures of the result.


These are the steps I did to get this result.
First I used the ADF Business Components wizard the fill the model project. I changed the Application Module so the tree has its own iterators.

Create a new JSF template in the viewcontroller project with 2 facets definitions. In this template I add a panel splitter with two facet ref's.
Open the adfc-config and create a view called mainPage to the Task Flow. Select the view and create the jsf page based on the just created template.
Drag the departmentsViewTree viewobject from the datacontrol to the Tree facet of the jsf page and select the ADF Tree option.

Also add the EmployeeTreeView to the tree binding.
Create two task flows called employee-task-flow-definition and department-task-flow-definition.

First we open employee-task-flow-definition where we add a view and we also drag the SetCurrentRowWithKeyValue operation of the employeesView to the task flow. ( do this from the datacontrol). Next we add a control flow case between the SetCurrentRowWithKeyValue method and the view. Make sure you set the SetCurrentRowWithKeyValue method as the default activity ( so it fires when the region is loaded).
It looks a bit strange to add an SetCurrentRowWithKeyValue operation in the Task Flow to lookup the right employee because in JDeveloper 10.1.3 we used an invoke action in the page definition to fire the SetCurrentRowWithKeyValue operation on an iterator. Invoke action in JDeveloper still works but has some side effects.
Select the employee_region view and create the JSF page fragment. In this page fragment we can drag the employeesView from the datacontrol and select a read only form option.
The last step is to add an input parameter to the Task Flow so this parameter can be used by the SetCurrentRowWithKeyValue method.

Select the SetCurrentRowWithKeyValue method and go to the page definition of this task flow method, where we will use the input parameter value.

Do the same with the department task flow.
Go the main jsf page where we will drag the employee or department Task Flow to the body facet of the main jsf page. We will get an option if we want to create a dynamic region.

JDeveloper gives you the option to create a new backing bean where it will add the necessary code for the dynamic region. Here the code of the backing bean.
We have to change this backing bean scope to session or application. Open the adfc-config for this

Now we can change the tree in the mainpage so the right key is passed on and the right region is activated. We use a switcher and setActionListener for this. The setActionListener copies the department or employee Id to a pageflowscope variable. The value is passed on to the input parameter of the region task flow. ( This happens in the page definition of the main page)
The last step is to change the page definition of the main page. Where we need to change the refresh conditions and the value of the inputparameter. This inputparameter has to have the same name as the inputparameter name of the region task flows.

We are finished. Here you can download the project
Here are some pictures of the result.


These are the steps I did to get this result.
First I used the ADF Business Components wizard the fill the model project. I changed the Application Module so the tree has its own iterators.

Create a new JSF template in the viewcontroller project with 2 facets definitions. In this template I add a panel splitter with two facet ref's.
Open the adfc-config and create a view called mainPage to the Task Flow. Select the view and create the jsf page based on the just created template.
Drag the departmentsViewTree viewobject from the datacontrol to the Tree facet of the jsf page and select the ADF Tree option.

Also add the EmployeeTreeView to the tree binding.
Create two task flows called employee-task-flow-definition and department-task-flow-definition.

First we open employee-task-flow-definition where we add a view and we also drag the SetCurrentRowWithKeyValue operation of the employeesView to the task flow. ( do this from the datacontrol). Next we add a control flow case between the SetCurrentRowWithKeyValue method and the view. Make sure you set the SetCurrentRowWithKeyValue method as the default activity ( so it fires when the region is loaded).
It looks a bit strange to add an SetCurrentRowWithKeyValue operation in the Task Flow to lookup the right employee because in JDeveloper 10.1.3 we used an invoke action in the page definition to fire the SetCurrentRowWithKeyValue operation on an iterator. Invoke action in JDeveloper still works but has some side effects.
Select the employee_region view and create the JSF page fragment. In this page fragment we can drag the employeesView from the datacontrol and select a read only form option.
The last step is to add an input parameter to the Task Flow so this parameter can be used by the SetCurrentRowWithKeyValue method.

Select the SetCurrentRowWithKeyValue method and go to the page definition of this task flow method, where we will use the input parameter value.

Do the same with the department task flow.
Go the main jsf page where we will drag the employee or department Task Flow to the body facet of the main jsf page. We will get an option if we want to create a dynamic region.

JDeveloper gives you the option to create a new backing bean where it will add the necessary code for the dynamic region. Here the code of the backing bean.
package nl.ordina.view.backing;
import oracle.adf.controller.TaskFlowId;
public class MainPageBean {
private String taskFlowId = "/WEB-INF/employee-task-flow-definition.xml#employee-task-flow-definition";
public MainPageBean() {
}
public TaskFlowId getDynamicTaskFlowId() {
return TaskFlowId.parse(taskFlowId);
}
public String employeeRegionLayout() {
taskFlowId = "/WEB-INF/employee-task-flow-definition.xml#employee-task-flow-definition";
return null;
}
public String departmentRegionLayout() {
taskFlowId = "/WEB-INF/department-task-flow-definition.xml#department-task-flow-definition";
return null;
}
}
We have to change this backing bean scope to session or application. Open the adfc-config for this

Now we can change the tree in the mainpage so the right key is passed on and the right region is activated. We use a switcher and setActionListener for this. The setActionListener copies the department or employee Id to a pageflowscope variable. The value is passed on to the input parameter of the region task flow. ( This happens in the page definition of the main page)
<af:panelHeader text="Department Employee Tree">
<af:tree value="#{bindings.DepartmentsViewTree.treeModel}"
var="node"
selectionListener="#{bindings.DepartmentsViewTree.treeModel.makeCurrent}"
rowSelection="single">
<f:facet name="nodeStamp">
<af:switcher facetName="#{node.hierType.viewDefName}">
<f:facet name="nl.ordina.model.dataaccess.DepartmentsView">
<af:commandLink text="#{node}"
action="#{MainPage.departmentRegionLayout}">
<af:setActionListener from="#{node.DepartmentId}"
to="#{pageFlowScope.TreeKey}"/>
</af:commandLink>
</f:facet>
<f:facet name="nl.ordina.model.dataaccess.EmployeesView">
<af:commandLink text="#{node}"
action="#{MainPage.employeeRegionLayout}">
<af:setActionListener from="#{node.EmployeeId}"
to="#{pageFlowScope.TreeKey}"/>
</af:commandLink>
</f:facet>
</af:switcher>
</f:facet>
</af:tree>
</af:panelHeader>
The last step is to change the page definition of the main page. Where we need to change the refresh conditions and the value of the inputparameter. This inputparameter has to have the same name as the inputparameter name of the region task flows.

We are finished. Here you can download the project
Categories: Development, Fusion Middleware
JMS in JDeveloper 11g and WebLogic 10.3
JMS is a bit different in JDeveloper 11G and WebLogic 10.3 then when you use OC4J 10.1.3. This blog will show you how you can create a Queue and Connection Factory in WebLogic and use this in one of your JDeveloper 11g projects.
First you have to add two libraries to the project, The first is the AQJMS library ( even when we don't use AQ ) and the second library is the WebLogic 10.3 thin Client
Start the weblogic server. Menu Run , Start Server Instance

The url is http://localhost:7101/console. Username weblogic password weblogic.

Default the weblogic server has an empty configuration. We need to create a new jms server with a database of file persistance. We need this for the queue or topic persistence
create a new jms system module. In this module we will create a new connection factory and queue
Select the just created jms module and create a new connection factory first.

Create a new queue

Make sure that the queue uses the jms server. See the targets this can't be empty

And here is the java code to test the connection factory and the queue
The difference with oc4j is that you use other jndi properties. This are the right properties for WebLogic 10.3 in JDeveloper 11g
java.naming.factory.initial weblogic.jndi.WLInitialContextFactory
java.naming.provider.url t3://localhost:7101
java.naming.security.principal weblogic
java.naming.security.credentials weblogic
First you have to add two libraries to the project, The first is the AQJMS library ( even when we don't use AQ ) and the second library is the WebLogic 10.3 thin Client
Start the weblogic server. Menu Run , Start Server Instance
The url is http://localhost:7101/console. Username weblogic password weblogic.

Default the weblogic server has an empty configuration. We need to create a new jms server with a database of file persistance. We need this for the queue or topic persistence
create a new jms system module. In this module we will create a new connection factory and queue
Select the just created jms module and create a new connection factory first.
Create a new queue
Make sure that the queue uses the jms server. See the targets this can't be empty
And here is the java code to test the connection factory and the queue
The difference with oc4j is that you use other jndi properties. This are the right properties for WebLogic 10.3 in JDeveloper 11g
java.naming.factory.initial weblogic.jndi.WLInitialContextFactory
java.naming.provider.url t3://localhost:7101
java.naming.security.principal weblogic
java.naming.security.credentials weblogic
package nl.ordina.jms;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Properties;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
public class WeblogicClient {
private QueueConnection connection = null;
private QueueSession session = null;
private QueueSender sender = null;
private QueueReceiver receiver = null;
private Queue queue = null;
private long waitTime = 0;
public WeblogicClient() {
setUp();
put();
get();
tearDown();
}
public static void main(String[] args) {
WeblogicClient weblogicClient = new WeblogicClient();
}
public void tearDown() {
try {
sender.close();
receiver.close();
session.close();
connection.close();
} catch (JMSException je) {
je.printStackTrace();
} finally {
}
}
public void get(){
try {
javax.jms.TextMessage textMessage = (javax.jms.TextMessage)receiver.receive();
System.out.println("Receiving message [" + textMessage.getJMSMessageID() + "] enqueued at " + new Timestamp(textMessage.getJMSTimestamp()).toString());
String xmlText = textMessage.getText();
System.out.println(xmlText);
} catch (JMSException jmse) {
jmse.printStackTrace();
}
}
public void put(){
String messageId = null;
String xmlData = "";
FileInputStream fis;
try {
fis = new FileInputStream("D:\\projecten\\mhs_esb\\delfor.xml");
int x= fis.available();
byte b[]= new byte[x];
fis.read(b);
xmlData = new String(b);
} catch (FileNotFoundException e) {
// TODO
} catch (IOException e) {
// TODO
}
try {
TextMessage message = session.createTextMessage(xmlData);
sender.send(message);
} catch (JMSException jmse) {
jmse.printStackTrace();
}
}
protected void setUp() {
String queueName = "jms/QTest";
String queueConnectionFactoryName = "jms/CFTest";
Context ctx;
try {
Properties parm = new Properties();
parm.setProperty("java.naming.factory.initial","weblogic.jndi.WLInitialContextFactory");
parm.setProperty("java.naming.provider.url","t3://localhost:7101");
parm.setProperty("java.naming.security.principal","weblogic");
parm.setProperty("java.naming.security.credentials","weblogic");
ctx = new InitialContext(parm);
QueueConnectionFactory connectionFactory =
(QueueConnectionFactory)ctx.lookup(queueConnectionFactoryName);
connection = connectionFactory.createQueueConnection();
connection.start();
session = connection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
queue = (Queue)ctx.lookup(queueName);
sender = session.createSender(queue);
receiver = session.createReceiver(queue);
} catch (JMSException je) {
throw new RuntimeException("Fout opgetreden bij het starten ",je);
} catch (Throwable t) {
throw new RuntimeException("Fout opgetreden bij het starten ",t);
}
}
}
Categories: Development, Fusion Middleware
Group column in an ADF Rich Table
I noticed a small new group feature in the new JDeveloper 11G Rich Table component. You can group table columns together in a group column. Here you see an example of a rich table with two groups.
You can achieve this by dragging a viewobject from the datacontrol and selecting a table layout. Just select a few columns and press the group button.
JDeveloper creates a new column with the selected employee columns as childern 
You can achieve this by dragging a viewobject from the datacontrol and selecting a table layout. Just select a few columns and press the group button.
JDeveloper creates a new column with the selected employee columns as childern 
Categories: Development, Fusion Middleware
Debugging Task Flow in JDeveloper 11G
With the final release of JDeveloper 11g we can debug Task Flows. This is a major step especially when you realize it is just xml definitions. To debug a Task Flow you only have to select a calling task flow, view, method or router in this Task Flow and use the right button to toggle the Breakpoint.
When Weblogic reaches a breakpoint you will return to JDeveloper where you will see the debugging information in one of the following tabs, Smart Data, Data or ADF Data or EL Evaluator.
When Weblogic reaches a breakpoint you will return to JDeveloper where you will see the debugging information in one of the following tabs, Smart Data, Data or ADF Data or EL Evaluator.
Here I add a breakpoint to a router to see the result of the method. The method returns a pageflowscope variable.
The value of this pageflowscope variable can be seen in the EL evaluator. In this it is false because the salary is higher then 2000.

I wish you happy Debugging.
Categories: Development, Fusion Middleware
Debugging Task Flow in JDeveloper 11G
With the final release of JDeveloper 11g we can debug Task Flows. This is a major step especially when you realize it is just xml definitions. To debug a Task Flow you only have to select a calling task flow, view, method or router in this Task Flow and use the right button to toggle the Breakpoint.
When Weblogic reaches a breakpoint you will return to JDeveloper where you will see the debugging information in one of the following tabs, Smart Data, Data or ADF Data or EL Evaluator.
When Weblogic reaches a breakpoint you will return to JDeveloper where you will see the debugging information in one of the following tabs, Smart Data, Data or ADF Data or EL Evaluator.
Here I add a breakpoint to a router to see the result of the method. The method returns a pageflowscope variable.
The value of this pageflowscope variable can be seen in the EL evaluator. In this it is false because the salary is higher then 2000.

I wish you happy Debugging.
Categories: Development, Fusion Middleware
Lookup Oracle database queue (AQ) with jndi and LDAP
In my previous blog entry I explained how you can register tnsnames entries and database connections in OpenLDAP, this blog entry goes a little further. This blog explains how you can register Oracle database queues (AQ) in ldap and use them with JNDI. I don't use OID because the product takes too many resources. I just want to lookup some queues. So I downloaded openldap and create the oracle ldap schema and add this to openldap. Now I can register oracle object in LDAP and use it in java.
Here you see how my LDAP tree looks like. Click here to get the LDIF file
SCOTT.TEST is a queue called test in the scott oracle schema. SCOTT.TEST_TABLE is the queue table of the test queue.
The LDAP attributes of the queue entry and this queue has a pointer to the queue table (first attribute)
The queue table attributes
The database connection registration which you can use for the connection factory
Here is the plsql code to create the queue and queue table
The java code where we do a lookup of the database connection to create the connection factory and do a lookup to create a queue.
That's all.
Here you see how my LDAP tree looks like. Click here to get the LDIF file
SCOTT.TEST is a queue called test in the scott oracle schema. SCOTT.TEST_TABLE is the queue table of the test queue.
The LDAP attributes of the queue entry and this queue has a pointer to the queue table (first attribute)
The queue table attributes
The database connection registration which you can use for the connection factory
Here is the plsql code to create the queue and queue table
begin
sys.dbms_aqadm.create_queue_table(
queue_table => 'TEST_TABLE',
queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
sort_list => 'PRIORITY',
compatible => '10.0.0',
primary_instance => 0,
secondary_instance => 0,
storage_clause => 'tablespace USERS pctfree 10 initrans 1 maxtrans 255 storage ( initial 64K minextents 1 maxextents unlimited )');
end;
/
begin
sys.dbms_aqadm.create_queue(
queue_name => 'TEST',
queue_table => 'TEST_TABLE',
queue_type => sys.dbms_aqadm.normal_queue,
max_retries => 5,
retry_delay => 0,
retention_time => 0);
end;
/
The java code where we do a lookup of the database connection to create the connection factory and do a lookup to create a queue.
package jms2;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
//import oracle.jms.AQjmsOracleDebug;
public class jmsclient2 {
Hashtable env = null;
boolean envSet = false;
private QueueConnection connection = null;
private QueueSession session = null;
private QueueSender sender = null;
private QueueReceiver receiver = null;
private QueueConnectionFactory queueConnectionFact = null;;
private Queue queue = null;;
public void testRegistration() {
// AQjmsOracleDebug.setLogStream(out);
// AQjmsOracleDebug.setTraceLevel(AQjmsOracleDebug.AQ_ORA_TR6);
// AQjmsOracleDebug.setDebug(true);
env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL , "ldap://localhost:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL , "o=sgi,c=us");
env.put(Context.SECURITY_CREDENTIALS , "secret");
DirContext dirContext = null;
try {
dirContext = new InitialDirContext(env);
dirContext=(DirContext)dirContext.lookup("cn=ORCL, cn=OracleContext, ou=Services, o=sgi,c=us");
DirContext destctxCF = (DirContext)dirContext.lookup("cn=oracledbconnections");
DirContext destctxQF = (DirContext)dirContext.lookup("cn=OracleDBQueues");
queueConnectionFact = (QueueConnectionFactory)destctxCF.lookup("cn=SCOTT");
queue = (Queue) destctxQF.lookup("cn=SCOTT.TEST");
connection = queueConnectionFact.createQueueConnection();
session = connection.createQueueSession(true, QueueSession.AUTO_ACKNOWLEDGE);
connection.start();
sender = session.createSender(queue);
String xmlData = "1111";
TextMessage message = session.createTextMessage(xmlData);
sender.send(message);
receiver = session.createReceiver(queue);
TextMessage textMessage = (javax.jms.TextMessage)receiver.receive();
String xmlText = textMessage.getText();
System.out.println(xmlText);
} catch (NamingException ne) {
ne.printStackTrace();
} catch (JMSException jmse) {
jmse.printStackTrace();
}
}
public static void main (String[] args) {
jmsclient2 client = new jmsclient2();
client.testRegistration();
}
}
That's all.
Categories: Development, Fusion Middleware
Lookup Oracle database queue (AQ) with jndi and LDAP
In my previous blog entry I explained how you can register tnsnames entries and database connections in OpenLDAP, this blog entry goes a little further. This blog explains how you can register Oracle database queues (AQ) in ldap and use them with JNDI. I don't use OID because the product takes too many resources. I just want to lookup some queues. So I downloaded openldap and create the oracle ldap schema and add this to openldap. Now I can register oracle object in LDAP and use it in java.
Here you see how my LDAP tree looks like. Click here to get the LDIF file
SCOTT.TEST is a queue called test in the scott oracle schema. SCOTT.TEST_TABLE is the queue table of the test queue.
The LDAP attributes of the queue entry and this queue has a pointer to the queue table (first attribute)
The queue table attributes
The database connection registration which you can use for the connection factory
Here is the plsql code to create the queue and queue table
The java code where we do a lookup of the database connection to create the connection factory and do a lookup to create a queue.
That's all.
Here you see how my LDAP tree looks like. Click here to get the LDIF file
SCOTT.TEST is a queue called test in the scott oracle schema. SCOTT.TEST_TABLE is the queue table of the test queue.
The LDAP attributes of the queue entry and this queue has a pointer to the queue table (first attribute)
The queue table attributes
The database connection registration which you can use for the connection factory
Here is the plsql code to create the queue and queue table
begin
sys.dbms_aqadm.create_queue_table(
queue_table => 'TEST_TABLE',
queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
sort_list => 'PRIORITY',
compatible => '10.0.0',
primary_instance => 0,
secondary_instance => 0,
storage_clause => 'tablespace USERS pctfree 10 initrans 1 maxtrans 255 storage ( initial 64K minextents 1 maxextents unlimited )');
end;
/
begin
sys.dbms_aqadm.create_queue(
queue_name => 'TEST',
queue_table => 'TEST_TABLE',
queue_type => sys.dbms_aqadm.normal_queue,
max_retries => 5,
retry_delay => 0,
retention_time => 0);
end;
/
The java code where we do a lookup of the database connection to create the connection factory and do a lookup to create a queue.
package jms2;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
//import oracle.jms.AQjmsOracleDebug;
public class jmsclient2 {
Hashtable env = null;
boolean envSet = false;
private QueueConnection connection = null;
private QueueSession session = null;
private QueueSender sender = null;
private QueueReceiver receiver = null;
private QueueConnectionFactory queueConnectionFact = null;;
private Queue queue = null;;
public void testRegistration() {
// AQjmsOracleDebug.setLogStream(out);
// AQjmsOracleDebug.setTraceLevel(AQjmsOracleDebug.AQ_ORA_TR6);
// AQjmsOracleDebug.setDebug(true);
env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL , "ldap://localhost:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL , "o=sgi,c=us");
env.put(Context.SECURITY_CREDENTIALS , "secret");
DirContext dirContext = null;
try {
dirContext = new InitialDirContext(env);
dirContext=(DirContext)dirContext.lookup("cn=ORCL, cn=OracleContext, ou=Services, o=sgi,c=us");
DirContext destctxCF = (DirContext)dirContext.lookup("cn=oracledbconnections");
DirContext destctxQF = (DirContext)dirContext.lookup("cn=OracleDBQueues");
queueConnectionFact = (QueueConnectionFactory)destctxCF.lookup("cn=SCOTT");
queue = (Queue) destctxQF.lookup("cn=SCOTT.TEST");
connection = queueConnectionFact.createQueueConnection();
session = connection.createQueueSession(true, QueueSession.AUTO_ACKNOWLEDGE);
connection.start();
sender = session.createSender(queue);
String xmlData = "1111";
TextMessage message = session.createTextMessage(xmlData);
sender.send(message);
receiver = session.createReceiver(queue);
TextMessage textMessage = (javax.jms.TextMessage)receiver.receive();
String xmlText = textMessage.getText();
System.out.println(xmlText);
} catch (NamingException ne) {
ne.printStackTrace();
} catch (JMSException jmse) {
jmse.printStackTrace();
}
}
public static void main (String[] args) {
jmsclient2 client = new jmsclient2();
client.testRegistration();
}
}
That's all.
Categories: Development, Fusion Middleware
Generate Edifact message from a xml
The people of DataDirect made a great product called XML convertors with this you can generate an Edifact message from a xml and back. This is not new but this java software can easily embedded in your own java program. In this blog entry I will show how you can generate an edifact message in a few hours and very flexible.

This are the steps to generate an APERAK Edifact message from an Oracle table.
Step 1 generate the xsd from xml convertor for our edifact message.
In this example I want to generate an Aperak Edifact message so I first need a xml schema,then I know how the xml must look like. You have to do this only once.
This how the xsd looks like.

Step 2 generate a xml from the oracle database with xmldb
With Oracle xmldb we can generate the following xml from the database.
You probably noticed I do not have all the required elements in this database xml to generate a complete edifact message. But we will solve this in the next step.
With Altova XMLSPY I will generate a new XSD based on this example xml.

Now we have two xsd's and a database xml, we can use Altova Mapforce to create a xslt which can transform the database xml to the more complex edifact aperak xml.
Step 3 Use Mapforce to create a XSLT.
I will use Altova Mapforce because with this program I can visual make a xslt and immediately see the result of the xlst. We need to import the two xsd's in mapforce and make the mappings between these two xsd's and add the missing data to the edifact aperak schema.

This is the output of the xslt.
Now we can generate the database xml and have an xlst to transform the xml to the edifact aparak xml. In the last step we can make the edifact message with the xml convertor software.
Step 4 Generate the edifact message
What really cool is that xml convertor can detect the xml message and transforms it to the right edifact message so you only need this code for all your outgoing edifact messages.
This is the generated edifact message
UNA:+,? '
UNB+UNOC:3+8712423009097:14+8716867999990:14+080928:1347+1001++++++1'
UNH+1001+APERAK:D:96A:ZZ:EDINE1'
BGM+12E::9+A_200508030000603782+27'
DTM+137:200508031112:203'
DTM+178:200508031113:203'
DTM+735:2:805'
RFF+AAN:T200508031110N002'
NAD+GRP+8716867999990::9'
NAD+GRU+8712423009097::9'
ERC+00023::60'
FTX+AAO+++ (E)'
UNT+11+1001'
UNZ+1+1001'
Conclusion, this is an flexible solution to generate an Edifact message. In your java application you can easily embed the xml convertor software and use the xslt to transform the xml. With this solution you can change your backoffice application or edifact message. You only have to change the xslt which is very easy in Altova Mapforce.

This are the steps to generate an APERAK Edifact message from an Oracle table.
Step 1 generate the xsd from xml convertor for our edifact message.
In this example I want to generate an Aperak Edifact message so I first need a xml schema,then I know how the xml must look like. You have to do this only once.
ConverterFactory factory = new ConverterFactory();
try {
Result xsdResult = new StreamResult("d:/projecten/xml_edi/aperak.xsd");
String uri = "EDI:dialect=EDIFACT:version=D96A:message=APERAK:tbl=no";
SchemaGenerator generator = factory.newSchemaGenerator(uri);
generator.getSchema(xsdResult);
System.out.println("schema generator finished: --> aperak.xsd");
}
catch (Exception e)
{
System.out.println("schema generator failed with exception: " + e);
}
This how the xsd looks like.
Step 2 generate a xml from the oracle database with xmldb
With Oracle xmldb we can generate the following xml from the database.
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="db.xsd"
type="APERAK" date="080928" time="1347" runId="1001" test="true">
<records>
<aperak_rff nr="1" message_id="A_200508030000603782" ref_qlfier="AAN" ref_nr="T200508031110N002" message_function="27"/>
<aperak_nad nr="1" message_id="A_200508030000603782" code_ontv_afz="A" party_qlfier="GRP" ean_code_party="8716867999990"/>
<aperak_nad nr="2" message_id="A_200508030000603782" code_ontv_afz="O" party_qlfier="GRU" ean_code_party="8712423009097"/>
<aperak_dtm nr="1" message_id="A_200508030000603782" dt_qualifier="137" dt_period="200508031112" dt_format_qlfier="203"/>
<aperak_dtm nr="2" message_id="A_200508030000603782" dt_qualifier="178" dt_period="200508031113" dt_format_qlfier="203"/>
<aperak_dtm nr="3" message_id="A_200508030000603782" dt_qualifier="735" dt_period="2" dt_format_qlfier="805"/>
<aperak_erc nr="1" message_id="A_200508030000603782" error_code="00023" nr_text="1" volgnummer="505484510" error_text=" (E) "/>
</records>
</message>
You probably noticed I do not have all the required elements in this database xml to generate a complete edifact message. But we will solve this in the next step.
With Altova XMLSPY I will generate a new XSD based on this example xml.
Now we have two xsd's and a database xml, we can use Altova Mapforce to create a xslt which can transform the database xml to the more complex edifact aperak xml.
Step 3 Use Mapforce to create a XSLT.
I will use Altova Mapforce because with this program I can visual make a xslt and immediately see the result of the xlst. We need to import the two xsd's in mapforce and make the mappings between these two xsd's and add the missing data to the edifact aperak schema.
This is the output of the xslt.
<?xml version="1.0" encoding="UTF-8"?>
<EDIFACT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="D:/projecten/xml_edi/aperak.xsd">
<UNB>
<UNB01>
<UNB0101>UNOC</UNB0101>
<UNB0102>3</UNB0102>
</UNB01>
<UNB02>
<UNB0201>8712423009097</UNB0201>
<UNB0202>14</UNB0202>
</UNB02>
<UNB03>
<UNB0301>8716867999990</UNB0301>
<UNB0302>14</UNB0302>
</UNB03>
<UNB04>
<UNB0401>080928</UNB0401>
<UNB0402>1347</UNB0402>
</UNB04>
<UNB05>1001</UNB05>
<UNB11>1</UNB11>
</UNB>
<APERAK>
<UNH>
<UNH01>1001</UNH01>
<UNH02>
<UNH0201>APERAK</UNH0201>
<UNH0202>D</UNH0202>
<UNH0203>96A</UNH0203>
<UNH0204>ZZ</UNH0204>
<UNH0205>EDINE1</UNH0205>
</UNH02>
</UNH>
<BGM>
<BGM01>
<BGM0101>12E</BGM0101>
<BGM0103>9</BGM0103>
</BGM01>
<BGM02>A_200508030000603782</BGM02>
<BGM03>27</BGM03>
</BGM>
<DTM>
<DTM01>
<DTM0101>137</DTM0101>
<DTM0102>200508031112</DTM0102>
<DTM0103>203</DTM0103>
</DTM01>
</DTM>
<DTM>
<DTM01>
<DTM0101>178</DTM0101>
<DTM0102>200508031113</DTM0102>
<DTM0103>203</DTM0103>
</DTM01>
</DTM>
<DTM>
<DTM01>
<DTM0101>735</DTM0101>
<DTM0102>2</DTM0102>
<DTM0103>805</DTM0103>
</DTM01>
</DTM>
<GROUP_1>
<RFF>
<RFF01>
<RFF0101>AAN</RFF0101>
<RFF0102>T200508031110N002</RFF0102>
</RFF01>
</RFF>
</GROUP_1>
<GROUP_2>
<NAD>
<NAD01>GRP</NAD01>
<NAD02>
<NAD0201>8716867999990</NAD0201>
<NAD0203>9</NAD0203>
</NAD02>
</NAD>
<NAD>
<NAD01>GRU</NAD01>
<NAD02>
<NAD0201>8712423009097</NAD0201>
<NAD0203>9</NAD0203>
</NAD02>
</NAD>
</GROUP_2>
<GROUP_3>
<ERC>
<ERC01>
<ERC0101>00023</ERC0101>
<ERC0103>60</ERC0103>
</ERC01>
</ERC>
<FTX>
<FTX01>AAO</FTX01>
<FTX04>
<FTX0401> (E) </FTX0401>
</FTX04>
</FTX>
</GROUP_3>
<UNT>
<UNT02>1001</UNT02>
</UNT>
</APERAK>
<UNZ>
<UNZ01>1</UNZ01>
<UNZ02>1001</UNZ02>
</UNZ>
</EDIFACT>
Now we can generate the database xml and have an xlst to transform the xml to the edifact aparak xml. In the last step we can make the edifact message with the xml convertor software.
Step 4 Generate the edifact message
What really cool is that xml convertor can detect the xml message and transforms it to the right edifact message so you only need this code for all your outgoing edifact messages.
try {
Source converterSource = new StreamSource("d:/projecten/xml_edi/aperak_gen.xml");
Result converterResult = new StreamResult("d:/projecten/xml_edi/aperak.edn3");
Converter fromXml = factory.newConvertFromXML("converter:EDI");
fromXml.convert(converterSource, converterResult);
System.out.println("fromXML finished: aperak.xml -> aperak.edn2");
}
catch (Exception e)
{
System.out.println("fromXML failed with exception: " + e);
}
This is the generated edifact message
UNA:+,? '
UNB+UNOC:3+8712423009097:14+8716867999990:14+080928:1347+1001++++++1'
UNH+1001+APERAK:D:96A:ZZ:EDINE1'
BGM+12E::9+A_200508030000603782+27'
DTM+137:200508031112:203'
DTM+178:200508031113:203'
DTM+735:2:805'
RFF+AAN:T200508031110N002'
NAD+GRP+8716867999990::9'
NAD+GRU+8712423009097::9'
ERC+00023::60'
FTX+AAO+++ (E)'
UNT+11+1001'
UNZ+1+1001'
Conclusion, this is an flexible solution to generate an Edifact message. In your java application you can easily embed the xml convertor software and use the xslt to transform the xml. With this solution you can change your backoffice application or edifact message. You only have to change the xslt which is very easy in Altova Mapforce.
Categories: Development, Fusion Middleware
Generate Edifact message from a xml
The people of DataDirect made a great product called XML convertors with this you can generate an Edifact message from a xml and back. This is not new but this java software can easily embedded in your own java program. In this blog entry I will show how you can generate an edifact message in a few hours and very flexible.

This are the steps to generate an APERAK Edifact message from an Oracle table.
Step 1 generate the xsd from xml convertor for our edifact message.
In this example I want to generate an Aperak Edifact message so I first need a xml schema,then I know how the xml must look like. You have to do this only once.
This how the xsd looks like.

Step 2 generate a xml from the oracle database with xmldb
With Oracle xmldb we can generate the following xml from the database.
You probably noticed I do not have all the required elements in this database xml to generate a complete edifact message. But we will solve this in the next step.
With Altova XMLSPY I will generate a new XSD based on this example xml.

Now we have two xsd's and a database xml, we can use Altova Mapforce to create a xslt which can transform the database xml to the more complex edifact aperak xml.
Step 3 Use Mapforce to create a XSLT.
I will use Altova Mapforce because with this program I can visual make a xslt and immediately see the result of the xlst. We need to import the two xsd's in mapforce and make the mappings between these two xsd's and add the missing data to the edifact aperak schema.

This is the output of the xslt.
Now we can generate the database xml and have an xlst to transform the xml to the edifact aparak xml. In the last step we can make the edifact message with the xml convertor software.
Step 4 Generate the edifact message
What really cool is that xml convertor can detect the xml message and transforms it to the right edifact message so you only need this code for all your outgoing edifact messages.
This is the generated edifact message
UNA:+,? '
UNB+UNOC:3+8712423009097:14+8716867999990:14+080928:1347+1001++++++1'
UNH+1001+APERAK:D:96A:ZZ:EDINE1'
BGM+12E::9+A_200508030000603782+27'
DTM+137:200508031112:203'
DTM+178:200508031113:203'
DTM+735:2:805'
RFF+AAN:T200508031110N002'
NAD+GRP+8716867999990::9'
NAD+GRU+8712423009097::9'
ERC+00023::60'
FTX+AAO+++ (E)'
UNT+11+1001'
UNZ+1+1001'
Conclusion, this is an flexible solution to generate an Edifact message. In your java application you can easily embed the xml convertor software and use the xslt to transform the xml. With this solution you can change your backoffice application or edifact message. You only have to change the xslt which is very easy in Altova Mapforce.

This are the steps to generate an APERAK Edifact message from an Oracle table.
Step 1 generate the xsd from xml convertor for our edifact message.
In this example I want to generate an Aperak Edifact message so I first need a xml schema,then I know how the xml must look like. You have to do this only once.
ConverterFactory factory = new ConverterFactory();
try {
Result xsdResult = new StreamResult("d:/projecten/xml_edi/aperak.xsd");
String uri = "EDI:dialect=EDIFACT:version=D96A:message=APERAK:tbl=no";
SchemaGenerator generator = factory.newSchemaGenerator(uri);
generator.getSchema(xsdResult);
System.out.println("schema generator finished: --> aperak.xsd");
}
catch (Exception e)
{
System.out.println("schema generator failed with exception: " + e);
}
This how the xsd looks like.
Step 2 generate a xml from the oracle database with xmldb
With Oracle xmldb we can generate the following xml from the database.
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="db.xsd"
type="APERAK" date="080928" time="1347" runId="1001" test="true">
<records>
<aperak_rff nr="1" message_id="A_200508030000603782" ref_qlfier="AAN" ref_nr="T200508031110N002" message_function="27"/>
<aperak_nad nr="1" message_id="A_200508030000603782" code_ontv_afz="A" party_qlfier="GRP" ean_code_party="8716867999990"/>
<aperak_nad nr="2" message_id="A_200508030000603782" code_ontv_afz="O" party_qlfier="GRU" ean_code_party="8712423009097"/>
<aperak_dtm nr="1" message_id="A_200508030000603782" dt_qualifier="137" dt_period="200508031112" dt_format_qlfier="203"/>
<aperak_dtm nr="2" message_id="A_200508030000603782" dt_qualifier="178" dt_period="200508031113" dt_format_qlfier="203"/>
<aperak_dtm nr="3" message_id="A_200508030000603782" dt_qualifier="735" dt_period="2" dt_format_qlfier="805"/>
<aperak_erc nr="1" message_id="A_200508030000603782" error_code="00023" nr_text="1" volgnummer="505484510" error_text=" (E) "/>
</records>
</message>
You probably noticed I do not have all the required elements in this database xml to generate a complete edifact message. But we will solve this in the next step.
With Altova XMLSPY I will generate a new XSD based on this example xml.
Now we have two xsd's and a database xml, we can use Altova Mapforce to create a xslt which can transform the database xml to the more complex edifact aperak xml.
Step 3 Use Mapforce to create a XSLT.
I will use Altova Mapforce because with this program I can visual make a xslt and immediately see the result of the xlst. We need to import the two xsd's in mapforce and make the mappings between these two xsd's and add the missing data to the edifact aperak schema.
This is the output of the xslt.
<?xml version="1.0" encoding="UTF-8"?>
<EDIFACT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="D:/projecten/xml_edi/aperak.xsd">
<UNB>
<UNB01>
<UNB0101>UNOC</UNB0101>
<UNB0102>3</UNB0102>
</UNB01>
<UNB02>
<UNB0201>8712423009097</UNB0201>
<UNB0202>14</UNB0202>
</UNB02>
<UNB03>
<UNB0301>8716867999990</UNB0301>
<UNB0302>14</UNB0302>
</UNB03>
<UNB04>
<UNB0401>080928</UNB0401>
<UNB0402>1347</UNB0402>
</UNB04>
<UNB05>1001</UNB05>
<UNB11>1</UNB11>
</UNB>
<APERAK>
<UNH>
<UNH01>1001</UNH01>
<UNH02>
<UNH0201>APERAK</UNH0201>
<UNH0202>D</UNH0202>
<UNH0203>96A</UNH0203>
<UNH0204>ZZ</UNH0204>
<UNH0205>EDINE1</UNH0205>
</UNH02>
</UNH>
<BGM>
<BGM01>
<BGM0101>12E</BGM0101>
<BGM0103>9</BGM0103>
</BGM01>
<BGM02>A_200508030000603782</BGM02>
<BGM03>27</BGM03>
</BGM>
<DTM>
<DTM01>
<DTM0101>137</DTM0101>
<DTM0102>200508031112</DTM0102>
<DTM0103>203</DTM0103>
</DTM01>
</DTM>
<DTM>
<DTM01>
<DTM0101>178</DTM0101>
<DTM0102>200508031113</DTM0102>
<DTM0103>203</DTM0103>
</DTM01>
</DTM>
<DTM>
<DTM01>
<DTM0101>735</DTM0101>
<DTM0102>2</DTM0102>
<DTM0103>805</DTM0103>
</DTM01>
</DTM>
<GROUP_1>
<RFF>
<RFF01>
<RFF0101>AAN</RFF0101>
<RFF0102>T200508031110N002</RFF0102>
</RFF01>
</RFF>
</GROUP_1>
<GROUP_2>
<NAD>
<NAD01>GRP</NAD01>
<NAD02>
<NAD0201>8716867999990</NAD0201>
<NAD0203>9</NAD0203>
</NAD02>
</NAD>
<NAD>
<NAD01>GRU</NAD01>
<NAD02>
<NAD0201>8712423009097</NAD0201>
<NAD0203>9</NAD0203>
</NAD02>
</NAD>
</GROUP_2>
<GROUP_3>
<ERC>
<ERC01>
<ERC0101>00023</ERC0101>
<ERC0103>60</ERC0103>
</ERC01>
</ERC>
<FTX>
<FTX01>AAO</FTX01>
<FTX04>
<FTX0401> (E) </FTX0401>
</FTX04>
</FTX>
</GROUP_3>
<UNT>
<UNT02>1001</UNT02>
</UNT>
</APERAK>
<UNZ>
<UNZ01>1</UNZ01>
<UNZ02>1001</UNZ02>
</UNZ>
</EDIFACT>
Now we can generate the database xml and have an xlst to transform the xml to the edifact aparak xml. In the last step we can make the edifact message with the xml convertor software.
Step 4 Generate the edifact message
What really cool is that xml convertor can detect the xml message and transforms it to the right edifact message so you only need this code for all your outgoing edifact messages.
try {
Source converterSource = new StreamSource("d:/projecten/xml_edi/aperak_gen.xml");
Result converterResult = new StreamResult("d:/projecten/xml_edi/aperak.edn3");
Converter fromXml = factory.newConvertFromXML("converter:EDI");
fromXml.convert(converterSource, converterResult);
System.out.println("fromXML finished: aperak.xml -> aperak.edn2");
}
catch (Exception e)
{
System.out.println("fromXML failed with exception: " + e);
}
This is the generated edifact message
UNA:+,? '
UNB+UNOC:3+8712423009097:14+8716867999990:14+080928:1347+1001++++++1'
UNH+1001+APERAK:D:96A:ZZ:EDINE1'
BGM+12E::9+A_200508030000603782+27'
DTM+137:200508031112:203'
DTM+178:200508031113:203'
DTM+735:2:805'
RFF+AAN:T200508031110N002'
NAD+GRP+8716867999990::9'
NAD+GRU+8712423009097::9'
ERC+00023::60'
FTX+AAO+++ (E)'
UNT+11+1001'
UNZ+1+1001'
Conclusion, this is an flexible solution to generate an Edifact message. In your java application you can easily embed the xml convertor software and use the xslt to transform the xml. With this solution you can change your backoffice application or edifact message. You only have to change the xslt which is very easy in Altova Mapforce.
Categories: Development, Fusion Middleware
Flex Ruby performance with XML, JSON and RubyAMF
One of the great things when you use Flex in combination Ruby is that you can easily change the communication method. For instance you can use xml rpc or json rpc or RubyAMF, just by changing the ruby controller. Off course when you use json then you need to download the corelib for Flex and when you use RubyAMF we need to install this plugin in ruby.
But when you have a choice then you need to know what is the best communication method for your project. In this test I will measure the performance of the three methods. For this I made a simple Flex / Ruby project.

Here are the average results in ms (100 times executed) with the total records count in our test table.records101004001000amf159213380731json4575252781xml4357197612
Conclusion
RubyAMF has a little overhead and is fast with a large recordset and you can use remoteobject in Flex. Xml is fast but the performance can vary. With 1000 records it can take 200ms but sometimes 2000ms. It looks like Ruby can cache xml and sometimes refresh the cache. Json is very stable and fast with small recordsets. If you just want to retrieve some data in Flex, I would use json but when you want to do more with this data in Flex then RubyAMF has many benefits, like association between objects, conversion to actionscript class and a lot more.
The Ruby Code
you can test the output by adding the format parameter to the url http://localhost:3000/departments/find_all?format=json or format=xml.
Here is the controller code I used
department table created in a mysql database
RubyAMF configuration
The Flex code
But when you have a choice then you need to know what is the best communication method for your project. In this test I will measure the performance of the three methods. For this I made a simple Flex / Ruby project.

Here are the average results in ms (100 times executed) with the total records count in our test table.records101004001000amf159213380731json4575252781xml4357197612
Conclusion
RubyAMF has a little overhead and is fast with a large recordset and you can use remoteobject in Flex. Xml is fast but the performance can vary. With 1000 records it can take 200ms but sometimes 2000ms. It looks like Ruby can cache xml and sometimes refresh the cache. Json is very stable and fast with small recordsets. If you just want to retrieve some data in Flex, I would use json but when you want to do more with this data in Flex then RubyAMF has many benefits, like association between objects, conversion to actionscript class and a lot more.
The Ruby Code
you can test the output by adding the format parameter to the url http://localhost:3000/departments/find_all?format=json or format=xml.
Here is the controller code I used
class DepartmentsController < ApplicationController
# return all Departments
def find_all
respond_to do |format|
format.amf { render :amf => Department.find(:all) }
format.json { render :text => Department.find(:all).to_json }
format.xml { render :xml => Department.find(:all) }
end
end
end
department table created in a mysql database
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
RubyAMF configuration
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',
:attributes => ["id", "name", "location", "created_at", "updated_at"])
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
The Flex code
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import vo.Timing;
private var idNum:int;
private var maxNum:int = 100;
[Bindable]
private var timing:ArrayCollection = new ArrayCollection();
private function startRubyAMF():void {
timing = new ArrayCollection();
idNum = 0;
loadAll();
}
private function startJSON():void {
timing = new ArrayCollection();
idNum = 0;
loadAllJson();
}
private function startXML():void {
timing = new ArrayCollection();
idNum = 0;
loadAllXML();
}
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.collections.ArrayCollection;
[Bindable]
private var departments:ArrayCollection = new ArrayCollection();
private var rubyDateFrom:Date;
private function loadAll():void {
rubyDateFrom = new Date();
var token:AsyncToken = AsyncToken(departmentService.find_all());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyDateFrom;
timing.addItem(time);
}
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 {
departments = event.result as ArrayCollection;
var rubyDateFinish:Number = new Date().valueOf() - rubyDateFrom.valueOf() ;
rubyLabel.text="RubyAMF departments "+rubyDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.rubyamf = rubyDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAll();
} else {
var average:Number = 0;
for ( var i:int = 0 ; i < timing.length ; i++ ) {
var time2:Timing = timing.getItemAt(i) as Timing;
average = average + time2.rubyamf;
}
average = average / timing.length;
rubyLabel.text="RubyAMF departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HBox>
<mx:Button label="refresh RubyAMF" click="startRubyAMF()"/>
<mx:Button label="refresh JSON" click="startJSON()"/>
<mx:Button label="refresh XML" click="startXML()"/>
</mx:HBox>
<mx:RemoteObject id="departmentService" destination="rubyamf"
endpoint="http://localhost:3000/rubyamf_gateway/"
source="DepartmentsController"
showBusyCursor="true"
result="resultHandler(event)"
fault="faultHandler(event)"
/>
<mx:Label id="rubyLabel" text="RubyAMF departments"/>
<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:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
[Bindable]
private var dp:ArrayCollection = new ArrayCollection() ;
private var rubyJsonDateFrom:Date;
private function loadAllJson():void {
rubyJsonDateFrom = new Date();
var token:AsyncToken = AsyncToken(json.send());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyJsonDateFrom;
timing.addItem(time);
}
private function resultHandlerJSON(event:ResultEvent):void
{
dp = new ArrayCollection();
var rawData:String = String(event.result);
var arr:Array = (JSON.decode(rawData) as Array);
for ( var i:int = 0 ; i < arr.length ; i++ ) {
dp.addItem(arr[i].department);
}
var rubyJsonDateFinish:Number = new Date().valueOf() - rubyJsonDateFrom.valueOf() ;
rubyJSONLabel.text="JSON departments "+rubyJsonDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.json = rubyJsonDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAllJson();
} else {
var average:Number = 0;
for ( var ii:int = 0 ; ii < timing.length ; ii++ ) {
var time2:Timing = timing.getItemAt(ii) as Timing;
average = average + time2.json;
}
average = average / timing.length;
rubyJSONLabel.text="JSON departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HTTPService id="json"
url="http://localhost:3000/departments/find_all?format=json"
result="resultHandlerJSON(event)" useProxy="false" />
<mx:Label id="rubyJSONLabel" text="JSON departments"/>
<mx:DataGrid id="dg4" dataProvider="{dp}">
<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:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
[Bindable]
private var dp2:ArrayCollection = new ArrayCollection() ;
private var rubyXmlDateFrom:Date;
private function loadAllXML():void {
rubyXmlDateFrom = new Date();
var token:AsyncToken = AsyncToken(xml.send());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyJsonDateFrom;
timing.addItem(time);
}
private function resultHandlerXML(event:ResultEvent):void
{
if ( event.result != null ) {
dp2 = event.result.departments.department;
}
var rubyXmlDateFinish:Number = new Date().valueOf() - rubyXmlDateFrom.valueOf() ;
rubyXmlLabel.text="XML departments "+rubyXmlDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.xml = rubyXmlDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAllXML();
} else {
var average:Number = 0;
for ( var ii:int = 0 ; ii < timing.length ; ii++ ) {
var time2:Timing = timing.getItemAt(ii) as Timing;
average = average + time2.xml;
}
average = average / timing.length;
rubyXmlLabel.text="XML departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HTTPService id="xml" url="http://localhost:3000/departments/find_all?format=xml"
result="resultHandlerXML(event)" useProxy="false" />
<mx:Label id="rubyXmlLabel" text="XML departments"/>
<mx:DataGrid id="dg5" dataProvider="{dp2}">
<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:Application>
Categories: Development, Fusion Middleware
Flex Ruby performance with XML, JSON and RubyAMF
One of the great things when you use Flex in combination Ruby is that you can easily change the communication method. For instance you can use xml rpc or json rpc or RubyAMF, just by changing the ruby controller. Off course when you use json then you need to download the corelib for Flex and when you use RubyAMF we need to install this plugin in ruby.
But when you have a choice then you need to know what is the best communication method for your project. In this test I will measure the performance of the three methods. For this I made a simple Flex / Ruby project.

Here are the average results in ms (100 times executed) with the total records count in our test table.records101004001000amf159213380731json4575252781xml4357197612
Conclusion
RubyAMF has a little overhead and is fast with a large recordset and you can use remoteobject in Flex. Xml is fast but the performance can vary. With 1000 records it can take 200ms but sometimes 2000ms. It looks like Ruby can cache xml and sometimes refresh the cache. Json is very stable and fast with small recordsets. If you just want to retrieve some data in Flex, I would use json but when you want to do more with this data in Flex then RubyAMF has many benefits, like association between objects, conversion to actionscript class and a lot more.
The Ruby Code
you can test the output by adding the format parameter to the url http://localhost:3000/departments/find_all?format=json or format=xml.
Here is the controller code I used
department table created in a mysql database
RubyAMF configuration
The Flex code
But when you have a choice then you need to know what is the best communication method for your project. In this test I will measure the performance of the three methods. For this I made a simple Flex / Ruby project.

Here are the average results in ms (100 times executed) with the total records count in our test table.records101004001000amf159213380731json4575252781xml4357197612
Conclusion
RubyAMF has a little overhead and is fast with a large recordset and you can use remoteobject in Flex. Xml is fast but the performance can vary. With 1000 records it can take 200ms but sometimes 2000ms. It looks like Ruby can cache xml and sometimes refresh the cache. Json is very stable and fast with small recordsets. If you just want to retrieve some data in Flex, I would use json but when you want to do more with this data in Flex then RubyAMF has many benefits, like association between objects, conversion to actionscript class and a lot more.
The Ruby Code
you can test the output by adding the format parameter to the url http://localhost:3000/departments/find_all?format=json or format=xml.
Here is the controller code I used
class DepartmentsController < ApplicationController
# return all Departments
def find_all
respond_to do |format|
format.amf { render :amf => Department.find(:all) }
format.json { render :text => Department.find(:all).to_json }
format.xml { render :xml => Department.find(:all) }
end
end
end
department table created in a mysql database
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
RubyAMF configuration
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',
:attributes => ["id", "name", "location", "created_at", "updated_at"])
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
The Flex code
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import vo.Timing;
private var idNum:int;
private var maxNum:int = 100;
[Bindable]
private var timing:ArrayCollection = new ArrayCollection();
private function startRubyAMF():void {
timing = new ArrayCollection();
idNum = 0;
loadAll();
}
private function startJSON():void {
timing = new ArrayCollection();
idNum = 0;
loadAllJson();
}
private function startXML():void {
timing = new ArrayCollection();
idNum = 0;
loadAllXML();
}
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.collections.ArrayCollection;
[Bindable]
private var departments:ArrayCollection = new ArrayCollection();
private var rubyDateFrom:Date;
private function loadAll():void {
rubyDateFrom = new Date();
var token:AsyncToken = AsyncToken(departmentService.find_all());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyDateFrom;
timing.addItem(time);
}
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 {
departments = event.result as ArrayCollection;
var rubyDateFinish:Number = new Date().valueOf() - rubyDateFrom.valueOf() ;
rubyLabel.text="RubyAMF departments "+rubyDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.rubyamf = rubyDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAll();
} else {
var average:Number = 0;
for ( var i:int = 0 ; i < timing.length ; i++ ) {
var time2:Timing = timing.getItemAt(i) as Timing;
average = average + time2.rubyamf;
}
average = average / timing.length;
rubyLabel.text="RubyAMF departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HBox>
<mx:Button label="refresh RubyAMF" click="startRubyAMF()"/>
<mx:Button label="refresh JSON" click="startJSON()"/>
<mx:Button label="refresh XML" click="startXML()"/>
</mx:HBox>
<mx:RemoteObject id="departmentService" destination="rubyamf"
endpoint="http://localhost:3000/rubyamf_gateway/"
source="DepartmentsController"
showBusyCursor="true"
result="resultHandler(event)"
fault="faultHandler(event)"
/>
<mx:Label id="rubyLabel" text="RubyAMF departments"/>
<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:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
[Bindable]
private var dp:ArrayCollection = new ArrayCollection() ;
private var rubyJsonDateFrom:Date;
private function loadAllJson():void {
rubyJsonDateFrom = new Date();
var token:AsyncToken = AsyncToken(json.send());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyJsonDateFrom;
timing.addItem(time);
}
private function resultHandlerJSON(event:ResultEvent):void
{
dp = new ArrayCollection();
var rawData:String = String(event.result);
var arr:Array = (JSON.decode(rawData) as Array);
for ( var i:int = 0 ; i < arr.length ; i++ ) {
dp.addItem(arr[i].department);
}
var rubyJsonDateFinish:Number = new Date().valueOf() - rubyJsonDateFrom.valueOf() ;
rubyJSONLabel.text="JSON departments "+rubyJsonDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.json = rubyJsonDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAllJson();
} else {
var average:Number = 0;
for ( var ii:int = 0 ; ii < timing.length ; ii++ ) {
var time2:Timing = timing.getItemAt(ii) as Timing;
average = average + time2.json;
}
average = average / timing.length;
rubyJSONLabel.text="JSON departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HTTPService id="json"
url="http://localhost:3000/departments/find_all?format=json"
result="resultHandlerJSON(event)" useProxy="false" />
<mx:Label id="rubyJSONLabel" text="JSON departments"/>
<mx:DataGrid id="dg4" dataProvider="{dp}">
<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:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
[Bindable]
private var dp2:ArrayCollection = new ArrayCollection() ;
private var rubyXmlDateFrom:Date;
private function loadAllXML():void {
rubyXmlDateFrom = new Date();
var token:AsyncToken = AsyncToken(xml.send());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyJsonDateFrom;
timing.addItem(time);
}
private function resultHandlerXML(event:ResultEvent):void
{
if ( event.result != null ) {
dp2 = event.result.departments.department;
}
var rubyXmlDateFinish:Number = new Date().valueOf() - rubyXmlDateFrom.valueOf() ;
rubyXmlLabel.text="XML departments "+rubyXmlDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.xml = rubyXmlDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAllXML();
} else {
var average:Number = 0;
for ( var ii:int = 0 ; ii < timing.length ; ii++ ) {
var time2:Timing = timing.getItemAt(ii) as Timing;
average = average + time2.xml;
}
average = average / timing.length;
rubyXmlLabel.text="XML departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HTTPService id="xml" url="http://localhost:3000/departments/find_all?format=xml"
result="resultHandlerXML(event)" useProxy="false" />
<mx:Label id="rubyXmlLabel" text="XML departments"/>
<mx:DataGrid id="dg5" dataProvider="{dp2}">
<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:Application>
Categories: Development, Fusion Middleware
Flex Ruby performance with XML, JSON and RubyAMF
One of the great things when you use Flex in combination Ruby is that you can easily change the communication method. For instance you can use xml rpc or json rpc or RubyAMF, just by changing the ruby controller. Off course when you use json then you need to download the corelib for Flex and when you use RubyAMF we need to install this plugin in ruby.
But when you have a choice then you need to know what is the best communication method for your project. In this test I will measure the performance of the three methods. For this I made a simple Flex / Ruby project.

Here are the average results in ms (100 times executed) with the total records count in our test table.records101004001000amf159213380731json4575252781xml4357197612
Conclusion
RubyAMF has a little overhead and is fast with a large recordset and you can use remoteobject in Flex. Xml is fast but the performance can vary. With 1000 records it can take 200ms but sometimes 2000ms. It looks like Ruby can cache xml and sometimes refresh the cache. Json is very stable and fast with small recordsets. If you just want to retrieve some data in Flex, I would use json but when you want to do more with this data in Flex then RubyAMF has many benefits, like association between objects, conversion to actionscript class and a lot more.
The Ruby Code
you can test the output by adding the format parameter to the url http://localhost:3000/departments/find_all?format=json or format=xml.
Here is the controller code I used
department table created in a mysql database
RubyAMF configuration
The Flex code
But when you have a choice then you need to know what is the best communication method for your project. In this test I will measure the performance of the three methods. For this I made a simple Flex / Ruby project.

Here are the average results in ms (100 times executed) with the total records count in our test table.records101004001000amf159213380731json4575252781xml4357197612
Conclusion
RubyAMF has a little overhead and is fast with a large recordset and you can use remoteobject in Flex. Xml is fast but the performance can vary. With 1000 records it can take 200ms but sometimes 2000ms. It looks like Ruby can cache xml and sometimes refresh the cache. Json is very stable and fast with small recordsets. If you just want to retrieve some data in Flex, I would use json but when you want to do more with this data in Flex then RubyAMF has many benefits, like association between objects, conversion to actionscript class and a lot more.
The Ruby Code
you can test the output by adding the format parameter to the url http://localhost:3000/departments/find_all?format=json or format=xml.
Here is the controller code I used
class DepartmentsController < ApplicationController
# return all Departments
def find_all
respond_to do |format|
format.amf { render :amf => Department.find(:all) }
format.json { render :text => Department.find(:all).to_json }
format.xml { render :xml => Department.find(:all) }
end
end
end
department table created in a mysql database
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
RubyAMF configuration
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',
:attributes => ["id", "name", "location", "created_at", "updated_at"])
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
The Flex code
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import vo.Timing;
private var idNum:int;
private var maxNum:int = 100;
[Bindable]
private var timing:ArrayCollection = new ArrayCollection();
private function startRubyAMF():void {
timing = new ArrayCollection();
idNum = 0;
loadAll();
}
private function startJSON():void {
timing = new ArrayCollection();
idNum = 0;
loadAllJson();
}
private function startXML():void {
timing = new ArrayCollection();
idNum = 0;
loadAllXML();
}
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.collections.ArrayCollection;
[Bindable]
private var departments:ArrayCollection = new ArrayCollection();
private var rubyDateFrom:Date;
private function loadAll():void {
rubyDateFrom = new Date();
var token:AsyncToken = AsyncToken(departmentService.find_all());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyDateFrom;
timing.addItem(time);
}
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 {
departments = event.result as ArrayCollection;
var rubyDateFinish:Number = new Date().valueOf() - rubyDateFrom.valueOf() ;
rubyLabel.text="RubyAMF departments "+rubyDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.rubyamf = rubyDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAll();
} else {
var average:Number = 0;
for ( var i:int = 0 ; i < timing.length ; i++ ) {
var time2:Timing = timing.getItemAt(i) as Timing;
average = average + time2.rubyamf;
}
average = average / timing.length;
rubyLabel.text="RubyAMF departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HBox>
<mx:Button label="refresh RubyAMF" click="startRubyAMF()"/>
<mx:Button label="refresh JSON" click="startJSON()"/>
<mx:Button label="refresh XML" click="startXML()"/>
</mx:HBox>
<mx:RemoteObject id="departmentService" destination="rubyamf"
endpoint="http://localhost:3000/rubyamf_gateway/"
source="DepartmentsController"
showBusyCursor="true"
result="resultHandler(event)"
fault="faultHandler(event)"
/>
<mx:Label id="rubyLabel" text="RubyAMF departments"/>
<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:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
[Bindable]
private var dp:ArrayCollection = new ArrayCollection() ;
private var rubyJsonDateFrom:Date;
private function loadAllJson():void {
rubyJsonDateFrom = new Date();
var token:AsyncToken = AsyncToken(json.send());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyJsonDateFrom;
timing.addItem(time);
}
private function resultHandlerJSON(event:ResultEvent):void
{
dp = new ArrayCollection();
var rawData:String = String(event.result);
var arr:Array = (JSON.decode(rawData) as Array);
for ( var i:int = 0 ; i < arr.length ; i++ ) {
dp.addItem(arr[i].department);
}
var rubyJsonDateFinish:Number = new Date().valueOf() - rubyJsonDateFrom.valueOf() ;
rubyJSONLabel.text="JSON departments "+rubyJsonDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.json = rubyJsonDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAllJson();
} else {
var average:Number = 0;
for ( var ii:int = 0 ; ii < timing.length ; ii++ ) {
var time2:Timing = timing.getItemAt(ii) as Timing;
average = average + time2.json;
}
average = average / timing.length;
rubyJSONLabel.text="JSON departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HTTPService id="json"
url="http://localhost:3000/departments/find_all?format=json"
result="resultHandlerJSON(event)" useProxy="false" />
<mx:Label id="rubyJSONLabel" text="JSON departments"/>
<mx:DataGrid id="dg4" dataProvider="{dp}">
<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:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
[Bindable]
private var dp2:ArrayCollection = new ArrayCollection() ;
private var rubyXmlDateFrom:Date;
private function loadAllXML():void {
rubyXmlDateFrom = new Date();
var token:AsyncToken = AsyncToken(xml.send());
token.kind = idNum.toString();
var time:Timing = new Timing();
time.id = idNum;
time.startDate = rubyJsonDateFrom;
timing.addItem(time);
}
private function resultHandlerXML(event:ResultEvent):void
{
if ( event.result != null ) {
dp2 = event.result.departments.department;
}
var rubyXmlDateFinish:Number = new Date().valueOf() - rubyXmlDateFrom.valueOf() ;
rubyXmlLabel.text="XML departments "+rubyXmlDateFinish.toString()+" ms";
var time:Timing = timing.getItemAt(event.token.kind) as Timing;
time.endDate = new Date();
time.xml = rubyXmlDateFinish;
idNum = idNum +1;
if (idNum < maxNum ) {
loadAllXML();
} else {
var average:Number = 0;
for ( var ii:int = 0 ; ii < timing.length ; ii++ ) {
var time2:Timing = timing.getItemAt(ii) as Timing;
average = average + time2.xml;
}
average = average / timing.length;
rubyXmlLabel.text="XML departments average "+average.toString()+" ms";
trace("end");
}
}
]]>
</mx:Script>
<mx:HTTPService id="xml" url="http://localhost:3000/departments/find_all?format=xml"
result="resultHandlerXML(event)" useProxy="false" />
<mx:Label id="rubyXmlLabel" text="XML departments"/>
<mx:DataGrid id="dg5" dataProvider="{dp2}">
<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:Application>
Categories: Development, Fusion Middleware
Google Maps for JSF (GMaps4JSF) in JDeveloper 11G
A new version of GMaps4JSF was released. GMaps4JSF is a Google maps jsf component. This blog entry will show you how you can use it in your own 11g application.
In this example you can hide and show markers. Add markers from a backing bean and add an click event on these markers so when you click on a marker you will get an alert.

The first step to get this jsf component in JDeveloper 11g is to download the GMaps4JSF jar and import this jsp tag library in your own project.

You need your own api key. Use this url http://code.google.com/apis/maps/signup.html to get the api key
Now we are ready to use it. It is very important not to use af:document else you won't see a map. I will investigate this later. Change my api key in the javascript and use your own.
GMaps4JSF is a good start but it is not ready yet. You still need to write your own javascript and you can not click on a marker to see a description.For this you need to add an eventhandler and use javascript to fire something.
Here is the code for the JSF page.
The backing bean I used
faces-config.xml
In this example you can hide and show markers. Add markers from a backing bean and add an click event on these markers so when you click on a marker you will get an alert.

The first step to get this jsf component in JDeveloper 11g is to download the GMaps4JSF jar and import this jsp tag library in your own project.

You need your own api key. Use this url http://code.google.com/apis/maps/signup.html to get the api key
Now we are ready to use it. It is very important not to use af:document else you won't see a map. I will investigate this later. Change my api key in the javascript and use your own.
GMaps4JSF is a good start but it is not ready yet. You still need to write your own javascript and you can not click on a marker to see a description.For this you need to add an eventhandler and use javascript to fire something.
Here is the code for the JSF page.
<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
xmlns:yui="http://code.google.com/p/gmaps4jsf/">
<jsp:directive.page contentType="text/html;charset=windows-1252"/>
<body onunload="GUnload()">
<f:view>
<f:verbatim>
<![CDATA[
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAM7FSGSscPTbXiOt1No2LPRRKSto2PHtB06oPKyRV-hhKjT8WCBSTy2uiK1M8ViuI9Xm8mMLb7d1aKQ"
type="text/javascript">
</script>
]]>
</f:verbatim>
<af:form id="form">
<af:panelGroupLayout>
<f:verbatim>
<![CDATA[
<script type="text/javascript">
function hideMarker() {
office1.hide();
office2.hide();
}
function showMarker() {
office1.show();
office2.show();
}
function marker1ClickHandler() {
alert("You clicked on the headoffice");
}
function marker2ClickHandler() {
alert("You clicked on a office");
}
</script>
]]>
</f:verbatim>
<af:panelHeader text="GMaps4JSF">
<input type="button" value="Hide Offices" onclick="hideMarker();"/>
<input type="button" value="Show Offices" onclick="showMarker();"/>
<yui:map width="500px" height="500px" zoom="7"
binding="#{GoogleBean.map}">
<yui:mapControl name="GLargeMapControl"
position="G_ANCHOR_BOTTOM_RIGHT"/>
<yui:mapControl name="GMapTypeControl"/>
</yui:map>
</af:panelHeader>
</af:panelGroupLayout>
</af:form>
</f:view>
</body>
</jsp:root>
The backing bean I used
package nl.ordina.google.backing;
import com.googlecode.gmaps4jsf.component.map.Map;
import com.googlecode.gmaps4jsf.component.marker.Marker;
import com.googlecode.gmaps4jsf.component.eventlistener.EventListener;
public class GoogleBean {
private Map map;
public void setMap(Map map) {
this.map = map;
map.setLatitude("52.05");
map.setLongitude("5.11");
Marker mark = new Marker();
mark.setLatitude("52.05");
mark.setLongitude("5.11");
mark.setJsVariable("office1");
mark.setId("mark1");
EventListener event = new EventListener();
event.setEventName("click");
event.setJsFunction("marker1ClickHandler");
mark.getChildren().add(event);
map.getChildren().add(mark);
Marker mark2 = new Marker();
mark2.setLatitude("53.19");
mark2.setLongitude("6.53");
mark2.setJsVariable("office2");
mark.setId("mark2");
EventListener event2 = new EventListener();
event2.setEventName("click");
event2.setJsFunction("marker2ClickHandler");
mark2.getChildren().add(event2);
map.getChildren().add(mark2);
}
public Map getMap() {
return map;
}
}
faces-config.xml
<?xml version="1.0" encoding="windows-1252"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
<application>
<default-render-kit-id>oracle.adf.rich</default-render-kit-id>
</application>
<managed-bean>
<managed-bean-name>GoogleBean</managed-bean-name>
<managed-bean-class>nl.ordina.google.backing.GoogleBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
Categories: Development, Fusion Middleware
Google Maps for JSF (GMaps4JSF) in JDeveloper 11G
A new version of GMaps4JSF was released. GMaps4JSF is a Google maps jsf component. This blog entry will show you how you can use it in your own 11g application.
In this example you can hide and show markers. Add markers from a backing bean and add an click event on these markers so when you click on a marker you will get an alert.

The first step to get this jsf component in JDeveloper 11g is to download the GMaps4JSF jar and import this jsp tag library in your own project.

You need your own api key. Use this url http://code.google.com/apis/maps/signup.html to get the api key
Now we are ready to use it. It is very important not to use af:document else you won't see a map. I will investigate this later. Change my api key in the javascript and use your own.
GMaps4JSF is a good start but it is not ready yet. You still need to write your own javascript and you can not click on a marker to see a description.For this you need to add an eventhandler and use javascript to fire something.
Here is the code for the JSF page.
The backing bean I used
faces-config.xml
In this example you can hide and show markers. Add markers from a backing bean and add an click event on these markers so when you click on a marker you will get an alert.

The first step to get this jsf component in JDeveloper 11g is to download the GMaps4JSF jar and import this jsp tag library in your own project.

You need your own api key. Use this url http://code.google.com/apis/maps/signup.html to get the api key
Now we are ready to use it. It is very important not to use af:document else you won't see a map. I will investigate this later. Change my api key in the javascript and use your own.
GMaps4JSF is a good start but it is not ready yet. You still need to write your own javascript and you can not click on a marker to see a description.For this you need to add an eventhandler and use javascript to fire something.
Here is the code for the JSF page.
<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
xmlns:yui="http://code.google.com/p/gmaps4jsf/">
<jsp:directive.page contentType="text/html;charset=windows-1252"/>
<body onunload="GUnload()">
<f:view>
<f:verbatim>
<![CDATA[
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAM7FSGSscPTbXiOt1No2LPRRKSto2PHtB06oPKyRV-hhKjT8WCBSTy2uiK1M8ViuI9Xm8mMLb7d1aKQ"
type="text/javascript">
</script>
]]>
</f:verbatim>
<af:form id="form">
<af:panelGroupLayout>
<f:verbatim>
<![CDATA[
<script type="text/javascript">
function hideMarker() {
office1.hide();
office2.hide();
}
function showMarker() {
office1.show();
office2.show();
}
function marker1ClickHandler() {
alert("You clicked on the headoffice");
}
function marker2ClickHandler() {
alert("You clicked on a office");
}
</script>
]]>
</f:verbatim>
<af:panelHeader text="GMaps4JSF">
<input type="button" value="Hide Offices" onclick="hideMarker();"/>
<input type="button" value="Show Offices" onclick="showMarker();"/>
<yui:map width="500px" height="500px" zoom="7"
binding="#{GoogleBean.map}">
<yui:mapControl name="GLargeMapControl"
position="G_ANCHOR_BOTTOM_RIGHT"/>
<yui:mapControl name="GMapTypeControl"/>
</yui:map>
</af:panelHeader>
</af:panelGroupLayout>
</af:form>
</f:view>
</body>
</jsp:root>
The backing bean I used
package nl.ordina.google.backing;
import com.googlecode.gmaps4jsf.component.map.Map;
import com.googlecode.gmaps4jsf.component.marker.Marker;
import com.googlecode.gmaps4jsf.component.eventlistener.EventListener;
public class GoogleBean {
private Map map;
public void setMap(Map map) {
this.map = map;
map.setLatitude("52.05");
map.setLongitude("5.11");
Marker mark = new Marker();
mark.setLatitude("52.05");
mark.setLongitude("5.11");
mark.setJsVariable("office1");
mark.setId("mark1");
EventListener event = new EventListener();
event.setEventName("click");
event.setJsFunction("marker1ClickHandler");
mark.getChildren().add(event);
map.getChildren().add(mark);
Marker mark2 = new Marker();
mark2.setLatitude("53.19");
mark2.setLongitude("6.53");
mark2.setJsVariable("office2");
mark.setId("mark2");
EventListener event2 = new EventListener();
event2.setEventName("click");
event2.setJsFunction("marker2ClickHandler");
mark2.getChildren().add(event2);
map.getChildren().add(mark2);
}
public Map getMap() {
return map;
}
}
faces-config.xml
<?xml version="1.0" encoding="windows-1252"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
<application>
<default-render-kit-id>oracle.adf.rich</default-render-kit-id>
</application>
<managed-bean>
<managed-bean-name>GoogleBean</managed-bean-name>
<managed-bean-class>nl.ordina.google.backing.GoogleBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
Categories: Development, Fusion Middleware
Google Maps for JSF (GMaps4JSF) in JDeveloper 11G
A new version of GMaps4JSF was released. GMaps4JSF is a Google maps jsf component. This blog entry will show you how you can use it in your own 11g application.
In this example you can hide and show markers. Add markers from a backing bean and add an click event on these markers so when you click on a marker you will get an alert.

The first step to get this jsf component in JDeveloper 11g is to download the GMaps4JSF jar and import this jsp tag library in your own project.

You need your own api key. Use this url http://code.google.com/apis/maps/signup.html to get the api key
Now we are ready to use it. It is very important not to use af:document else you won't see a map. I will investigate this later. Change my api key in the javascript and use your own.
GMaps4JSF is a good start but it is not ready yet. You still need to write your own javascript and you can not click on a marker to see a description.For this you need to add an eventhandler and use javascript to fire something.
Here is the code for the JSF page.
In this example you can hide and show markers. Add markers from a backing bean and add an click event on these markers so when you click on a marker you will get an alert.

The first step to get this jsf component in JDeveloper 11g is to download the GMaps4JSF jar and import this jsp tag library in your own project.

You need your own api key. Use this url http://code.google.com/apis/maps/signup.html to get the api key
Now we are ready to use it. It is very important not to use af:document else you won't see a map. I will investigate this later. Change my api key in the javascript and use your own.
GMaps4JSF is a good start but it is not ready yet. You still need to write your own javascript and you can not click on a marker to see a description.For this you need to add an eventhandler and use javascript to fire something.
Here is the code for the JSF page.
<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
xmlns:yui="http://code.google.com/p/gmaps4jsf/">
<jsp:directive.page contentType="text/html;charset=windows-1252"/>
<body onunload="GUnload()">
<f:view>
<f:verbatim>
<![CDATA[
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAM7FSGSscPTbXiOt1No2LPRRKSto2PHtB06oPKyRV-hhKjT8WCBSTy2uiK1M8ViuI9Xm8mMLb7d1aKQ"
type="text/javascript">
</script>
]]>
</f:verbatim>
<af:form id="form">
<af:panelGroupLayout>
<f:verbatim>
<


