Pages

Monday, June 16, 2008

ADF Faces templating in 10.1.3

Today I attended a presentation of Peter Koletzke at ODTUG, where he explains that jsf templating is possible in jdeveloper 10.1.3, so let's give it a try. Steve Muench wrote a nice article in the oracle magazine over how you can do it in 11G. In 10.1.3 this is called regions and JHeadstart is using this for branding, menu tabs etc. In this blog I will show you the basics how it works. The First step is to know what to template in your application. In my case I want to template the header of the page and the menu buttons. We need to make a new file called region-metadata.xml and put this in the web-inf folder. In this file we create templates entries.

<?xml version="1.0" encoding="windows-1252"?>
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<component>
<component-type>nl.ordina.jsf.templating.Header</component-type>
<component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
<component-extension>
<region-jsp-ui-def>/regions/header.jspx</region-jsp-ui-def>
</component-extension>
</component>
<component>
<component-type>nl.ordina.jsf.templating.Menu</component-type>
<component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
<attribute>
<attribute-name>name</attribute-name>
<attribute-class>java.lang.String</attribute-class>
<default-value>empty</default-value>
<attribute-extension>
<required>false</required>
</attribute-extension>
</attribute>
<component-extension>
<region-jsp-ui-def>/regions/menu.jspx</region-jsp-ui-def>
</component-extension>
</component>
</faces-config>
The things you should know, give an unique value to the component-type element of the template component.
This is important because your need this value to reference it in the jsf page. What is the path to region jsf page, this is defined in the region-jsp-ui-def and do I need to pass variables from the.Now we can create the menu template jsf page

<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:af="http://xmlns.oracle.com/adf/faces">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<af:regionDef var="menu">
<af:menuBar>
<af:commandMenuItem text="#{menu.name}" action="start" />
</af:menuBar>
</af:regionDef>
</jsp:root>

In the template page we have to define the regionDef component and by using the attribute var we can reference the template variables defined in the region-metadata.xml. In my case I can use #{menu.name} to get value of the main 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">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<jsp:directive.page contentType="text/html;charset=windows-1252"/>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/>
<title>main</title>
</head>
<body>
<af:messages/>
<h:form>
<af:panelPage title="Mainpage">
<f:facet name="menuGlobal">
<af:region id="menu" regionType="nl.ordina.jsf.templating.Menu">
<af:attribute name="name" value="MainPage"/>
</af:region>
</f:facet>
<f:facet name="branding">
<af:region id="header" regionType="nl.ordina.jsf.templating.Header"/>
</f:facet>
<af:outputText value="bodytext"/>
</af:panelPage>
</h:form>
</body>
</html>
</f:view>
</jsp:root>

In the main page we have to use a region component to reference the template page. The value of the regionType attribute must be the same as the region-metadata.xml. Because this template has also an attribute, we have to define an child element with the name attribute. Make sure if you using a template variable then you need create the region component inside a panel component else the variables are empty. You are now ready to run the main page

Tuesday, June 10, 2008

Openesb & Soa Suite comparison

Last week I have been testing the glassfish openesb opensource soa platform and I am very surprised to see how far the opensource community is. Ok I think it is not so far as Oracle but give it some time and it will be a strong soa suite for free. The main difference is there is no mediator or esb part in openesb like Oracle has. The second difference Oracle has a esb and bpel console where you can see the soa processes. In the esb console you can change the esb processes at runtime. In openesb you have to do with the output console of glassfish server. There are also positive things about openesb. I like the xlst mapper it even knows anytype type and you don't have to add many copy entries in the bpel assign step ( you can do this in one xslt window). More important you have to configure the wsdl for the bpel and the adapters yourself. This is a great advantage for experience developers, you now know what it does because you have to configure it yourself. In Oracle Soa Suite you have a lot of wizards which helps you to create a esb or bpel process. You don't have to know how it works internally. This is fine untils you got a error or you have performance problems.
Here you see the components which you can use in the openesb BPEL designer
The BPEL process with on the left side the bpel web service with the request and response. On the right a partnerlink for the file adapter and the jdbc partnerlink ( database adapter in Oracle). Openesb provides a wizard which generates the wsdl for the jdbc adapter.
The xslt editor of the assign step.
Openesb gives you the option to create a composite project ( Oracle has this in Soa Suite 11g) where you can import the bpel projects as a jar. In the composite project you can use many adapters and deploy it as one project to the glassfish server
Here a example of a composite project where a bpel project is added as jbi module. I also connected an file adapter and activemq jms adapter to the bpel process.
Openesb has a great future and let's hope it will be a great or the best soa suite there is.

Friday, June 6, 2008

Flex embedded youtube player

There is a new version 1.1, Click on this entry to go to that version.
In this blog I will provide you the Adobe Flex code to create your own embedded youtube player which you can use in own website. You don't have to use a proxy or php script. You only has to update a xml with the youtube video urls. This xml is loaded in a tree and just click on an entry. The selected video is shown in the window. You can display your own text over the video too.


The xml with the youtube videos looks like this

<videos category="overview">
<category category="2008">
<video category="auto cross movie" url="http://www.youtube.com/v/VLlrpOUO3Qs"/>
</category>
<category category="European">
<year category="2007">
<video category="Autocross Championship - Murça 1" url="http://www.youtube.com/v/8TZgXfqpd5I"/>
</year>
</category>
<category category="Netherlands">
<year category="2007">
<video category="EUROPOKAL AutoCross" url="http://www.youtube.com/v/kprW-snP5oI"/>
<video category="VEKA NK AutoCross Visvliet" url="http://www.youtube.com/v/5OxVm-p0mC0"/>
</year>
</category>
</videos>

You can easily extend this xml with extra levels or video's you only have to add a new element with an attribute with the name category. For a you tube video entry you have to add two attributes category and url.
Here is the source code
The main code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
backgroundGradientAlphas="[1.0, 1.0]"
backgroundGradientColors="[#CCCCCC, #CCCCCC]"
creationComplete="service.send()" height="700" width="875">

<mx:Style>
@font-face {
src:url("assets/arial.ttf");
font-family: Arial;
}

.timeStyle {
color: #FFFFFF;
font-family: Arial;
font-size: 12;
}

.playPauseStyle {
/* play button skins */
skin: Embed('assets/control_play.png');
downSkin: Embed('assets/control_play_blue.png');

/* pause button skins */
selectedUpSkin: Embed('assets/control_pause.png');
selectedOverSkin: Embed('assets/control_pause.png');
selectedDownSkin: Embed('assets/control_pause_blue.png');
}

.stopStyle {
skin: Embed('assets/control_stop.png');
downSkin: Embed('assets/control_stop_blue.png');
}

.controllerStyle {
bottom: 5;
left: 5;
right: 5;
paddingBottom: 5;
paddingLeft: 5;
paddingRight: 5;
paddingTop: 5;
alpha: 0;
background-color: #000000;
background-alpha: 0.5;
}
</mx:Style>


<mx:Script>
<![CDATA[
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.collections.HierarchicalData;
import mx.collections.XMLListCollection;
import mx.events.MetadataEvent;
import mx.utils.ObjectUtil;
import mx.events.VideoEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;

[Bindable]
private var youtubeOverLay:String = "You tube player";


private function videoDisplay_metadataReceived(evt:MetadataEvent):void {
var arr:Array = [];
var item:String;
var meta:Object = evt.info; // videoDisplay.metadata;
var value:*;
for (item in meta) {
if (ObjectUtil.isSimple(meta[item])) {
if (meta[item] is Array) {
value = "[Array]";
} else {
value = meta[item]
}
arr.push({name:item, value:value});
}
}
arr.sortOn("name", Array.CASEINSENSITIVE);
dataGrid.dataProvider = arr;
// dataGrid.visible = true;
}

private function showControls():void {
fadeIn.play([controls]);
}

private function hideControls():void {
fadeOut.play([controls]);
}

private function videoDisplay_playheadUpdate(evt:VideoEvent):void {
var pTime:Date = new Date(videoDisplay.playheadTime * 1000 || 100);
var tTime:Date = new Date(videoDisplay.totalTime * 1000);
time.text = dateFormatter.format(pTime) + " / " + dateFormatter.format(tTime);
// time2.text = "Tijd " + dateFormatter.format(pTime) + " / " + dateFormatter.format(tTime);

}

private function playPauseButton_click(evt:MouseEvent):void {
if (videoDisplay.playing) {
videoDisplay.pause();
} else {
videoDisplay.play();
}
}

private function stopButton_click(evt:MouseEvent):void {
videoDisplay.stop();
}

private function doStateChange(evt:VideoEvent):void {


switch (evt.currentTarget.state) {
case VideoEvent.CONNECTION_ERROR:
evt.currentTarget.visible = false;
Alert.show(evt.currentTarget.source, "Unable to connect to video");
break;
}
}


private var vidRequest:YouTubeVideo;
private var flvURL:String;
private var youtubeXml:XML;

public function getVideoURL():void
{
vidRequest = new YouTubeVideo(adg1.selectedItem.@url);
vidRequest.addEventListener(YouTubeVideoEvent.COMPLETE, onVideoComplete);
}

private function onVideoComplete(evt:YouTubeVideoEvent):void
{
flvURL = evt.video;
videoDisplay.source = flvURL;
videoDisplay.load();
copyToClipboard();
}

private function copyToClipboard():void
{
flash.system.System.setClipboard(flvURL);
}

private function resultHandler(event:ResultEvent):void {
youtubeXml = event.result as XML;

// init the tree
adg1.dataProvider= new HierarchicalData(youtubeXml);
var columns:Array = [];
var col:AdvancedDataGridColumn = new AdvancedDataGridColumn();
col.dataField = "@category";
col.headerText = "Video";
columns.push(col);
adg1.columns = columns;


}

]]>
</mx:Script>

<mx:HTTPService id="service" url="videos.xml"
result="resultHandler(event)"
resultFormat="e4x"
useProxy="false"
showBusyCursor="true" />

<mx:Fade id="fadeIn" alphaFrom="0.0" alphaTo="1.0" />
<mx:Fade id="fadeOut" alphaFrom="1.0" alphaTo="0.0" />

<mx:DateFormatter id="dateFormatter" formatString="NN:SS" />



<mx:HBox width="100%" borderColor="#CCCCCC" backgroundColor="#CCCCCC">
<mx:VBox>
<mx:HBox>
<mx:ApplicationControlBar width="100%">
<mx:Button label="expand all" click="adg1.expandAll()" />
<mx:Button label="collapse all" click="adg1.collapseAll()" />
</mx:ApplicationControlBar>
</mx:HBox>


<mx:AdvancedDataGrid x="75" y="27" id="adg1" width="300" height="500" selectionMode="singleRow"
click="getVideoURL()" themeColor="#91280B" creationComplete="adg1.expandAll();">
</mx:AdvancedDataGrid>


</mx:VBox>
<mx:VBox width="100%" height="100%">
<mx:VBox width="100%">
<mx:Text text="{adg1.selectedItem.@category}" fontSize="16" width="100%" fontWeight="bold" color="#91280B"/>
<mx:Text text="Move your mouse on the video to control it" fontSize="12" width="100%" fontWeight="bold" color="#000000"/>

</mx:VBox>

<mx:Canvas rollOver="showControls()" rollOut="hideControls()">
<mx:VideoDisplay id="videoDisplay"
autoPlay="true"
visible="true"
ready="videoDisplay.visible = true; progressBar.visible = true ; "
metadataReceived="videoDisplay_metadataReceived(event);"
playheadUpdate="videoDisplay_playheadUpdate(event)"
stateChange="doStateChange(event);" height="400" width="500" />
<mx:HBox id="controls" styleName="controllerStyle" alpha="0.0">
<mx:Text text="{youtubeOverLay}" x="10" y="50" fontSize="12" width="100%" fontWeight="bold" color="#91280B"/>

<mx:Button id="playPauseButton" styleName="playPauseStyle" toggle="true" selected="{videoDisplay.playing}" click="playPauseButton_click(event)" />
<mx:Button id="stopButton" styleName="stopStyle" click="stopButton_click(event)" />
<mx:Spacer width="100%" />
<mx:Label id="time" styleName="timeStyle" />
</mx:HBox>
</mx:Canvas>


<mx:VBox width="100%">
<mx:ProgressBar id="progressBar" color="#91280B" barColor="#CCCCCC"
visible="false" width="{videoDisplay.width}"
mode="polled"
source="{videoDisplay}"
label="%1 of %2 KB loaded (%3%%)"
conversion="1024"
labelPlacement="center" />
<!-- <mx:Label id="time2" styleName="timeStyle" /> -->

</mx:VBox>
<mx:HBox>
<mx:Button id="aan" visible="true" click="dataGrid.visible = true; aan.visible = false; uit.visible = true;" label="Details on"/>
<mx:Button id="uit" visible="false" click="dataGrid.visible = false; uit.visible = false; aan.visible = true;" label="Details off"/>
</mx:HBox>
<mx:DataGrid id="dataGrid" visible="false" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name:" sortable="false" />
<mx:DataGridColumn dataField="value" headerText="Value:" sortable="false" />
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:HBox>
</mx:Application>