Edwin Biemond

Syndicate content
Updated: 54 min 37 sec ago

Flex and web services using blazeds

12 hours 19 min ago
I had a request how you can use a web service created with JDeveloper and use it in a flex client. For this I use blazeds (it acts like a proxy), this is not really necessary because you can call the web service from an other domain directly from flex if you use the crossdomain xml.
In this blog I use a normal java class and create with jdeveloper (I use the right mouse button on this class ) a java web service. In the wizard I also check the rest property so I can call this web service as a rest service. This is how the java class looks.

package nl.ordina.ws;

import java.util.ArrayList;
import java.util.List;
import javax.jws.WebService;
import oracle.webservices.annotations.Deployment;

@WebService(name = "CitiesService")
@Deployment(restSupport = true)
public class Cities {
public Cities() {
}
public List getCities(String countryCode) {
List result = new ArrayList();
if ( countryCode.equalsIgnoreCase("nl") ) {
City c = new City();
c.setCountry("NL");
c.setName("PUTTEN");
result.add(c);
City c2 = new City();
c2.setCountry("NL");
c2.setName("AMSTERDAM");
result.add(c2);
} else if ( countryCode.equalsIgnoreCase("de") ) {
City c = new City();
c.setCountry("DE");
c.setName("BERLIN");
result.add(c);
City c2 = new City();
c2.setCountry("DE");
c2.setName("FRANKFURT");
result.add(c2);
} else {
City c = new City();
c.setCountry(countryCode);
c.setName("NOT FOUND");
result.add(c);
}
return result;
}
}

It has a method getCities with one parameter countryCode and it returns arraylist with cities.
I can run the rest webservice by /CitiesServiceSoapHttpPort/getCities?countryCode=nl
with the following result

<ns0:getCitiesResponse xmlns:ns0="http://ws.ordina.nl/">
<ns0:return xsi:type="ns1:arrayList" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:item xsi:type="ns0:City" xmlns:ns1="http://www.oracle.com/webservices/internal/literal">
<ns0:country>NL</ns0:country>
<ns0:name>PUTTEN</ns0:name>
</ns1:item>
<ns1:item xsi:type="ns0:City" xmlns:ns1="http://www.oracle.com/webservices/internal/literal">
<ns0:country>NL</ns0:country>
<ns0:name>AMSTERDAM</ns0:name>
</ns1:item>
</ns0:return>
</ns0:getCitiesResponse>

This is the web service call

<soap:Body xmlns:ns1="http://ws.ordina.nl/">
<ns1:getCities>
<ns1:countryCode>NL</ns1:countryCode>
</ns1:getCities>
</soap:Body>

result envelope

<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns0="http://ws.ordina.nl/"
xmlns:ns1="http://www.oracle.com/webservices/internal/literal">
<env:Body>
<ns0:getCitiesResponse>
<ns0:return
xsi:type="ns1:arrayList">
<ns1:item
xsi:type="ns0:City">
<ns0:country>NL</ns0:country>
<ns0:name>PUTTEN</ns0:name>
</ns1:item>
<ns1:item
xsi:type="ns0:City">
<ns0:country>NL</ns0:country>
<ns0:name>AMSTERDAM</ns0:name>
</ns1:item>
</ns0:return>
</ns0:getCitiesResponse>
</env:Body>
</env:Envelope>

Now we know how the result look like, this is important for displaying the result in Flex
Let's look at the flex configuration xml, First the services-config.xml which import the proxy-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service-include file-path="proxy-config.xml" />

<default-channels>
<channel ref="my-amf"/>
</default-channels>
</services>

<channels>
<channel-definition id="my-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>false</polling-enabled>
</properties>
</channel-definition>
<channel-definition id="my-http" class="mx.messaging.channels.HTTPChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/http" class="flex.messaging.endpoints.HTTPEndpoint"/>
</channel-definition>

</channels>

<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Debug">
<properties>
<prefix>[Flex] </prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
</target>
</logging>
</services-config>

The proxy-config.xml has two definitions one for the rest service and one for the web service.

<?xml version="1.0" encoding="UTF-8"?>
<service id="proxy-service" class="flex.messaging.services.HTTPProxyService">

<properties>
<connection-manager>
<max-total-connections>100</max-total-connections>
<default-max-connections-per-host>2</default-max-connections-per-host>
</connection-manager>
<allow-lax-ssl>true</allow-lax-ssl>
</properties>

<default-channels>
<channel ref="my-http"/>
<channel ref="my-amf"/>
</default-channels>

<adapters>
<adapter-definition id="http-proxy" class="flex.messaging.services.http.HTTPProxyAdapter" default="true"/>
<adapter-definition id="soap-proxy" class="flex.messaging.services.http.SOAPProxyAdapter"/>
</adapters>

<destination id="ws-rest-cities">
<properties>
<url>http://{server.name}:{server.port}/flex_ws-ws-context-root/CitiesServiceSoapHttpPort/getCities?</url>
</properties>
</destination>
<destination id="ws-cities">
<properties>
<wsdl>http://{server.name}:{server.port}/flex_ws-ws-context-root/CitiesServiceSoapHttpPort?WSDL</wsdl>
<soap>*</soap>
</properties>
<adapter ref="soap-proxy"/>
</destination>
</service>

We are ready for flex application, make sure you select the j2ee server.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#FFFFFF">

<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;

[Bindable]
private var items:ArrayCollection;

private function resultHandler(event:ResultEvent):void {
if ( event.result != null ) {
// ws
items= event.result.item;
// this is for the rest service
if ( items == null ) {
items= event.result.getCitiesResponse['return'].item;
}
grid1.dataProvider=items;
}
}
]]>
</mx:Script>

<mx:HTTPService id="ws_rest"
destination="ws-rest-cities"
result="resultHandler(event)"
useProxy="true"
showBusyCursor="true">
<mx:request>
<countryCode>{country.selectedItem.data}</countryCode>
</mx:request>
</mx:HTTPService>


<mx:WebService id="ws"
destination="ws-cities"
result="resultHandler(event)"
useProxy="true"
showBusyCursor="true">
<mx:operation name="getCities">
<mx:request>
<countryCode>{country.selectedItem.data}</countryCode>
</mx:request>
</mx:operation>
</mx:WebService>

<mx:Form label="Search geonames" id="form" width="332">
<mx:FormItem label="Country">
<mx:ComboBox id="country" width="150">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<mx:Object label="Netherlands" data="NL"/>
<mx:Object label="Germany" data="DE"/>
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
<mx:Button label="Get Data with WS Rest" click="ws_rest.send()"/>
<mx:Button label="Get Data with WS" click="ws.getCities()"/>
</mx:Form>

<mx:DataGrid id="grid1" width="337" height="175">
<mx:columns>
<mx:DataGridColumn dataField="country" headerText="country"/>
<mx:DataGridColumn dataField="name" headerText="city"/>
</mx:columns>
</mx:DataGrid>


</mx:Application>

I use for the rest web service mx:HTTPService and mx:request to add the parameter countryCode and for the web service I use mx:WebService with the mx:operation getCities and use mx:request to add the parameter countryCode. To handle the result I made resultHandler in actionscript.
This how the flex app looks like.

Here is the jdeveloper and flex example code

Customize and personalize your jsf pages with MDS

Sat, 2008-07-05 16:07
This large blog entry is about MDS (Metadata Services) which was introduced jdev 10.1.3.2 but for this MDS example I use JDeveloper 11g TP4. In 11g you can use mds in your jsf applications. In this blog I will show you, how to customize a table in a jsf page for a particular user. This is called seeded customization. For this you have to start jdeveloper in the customize mode and change the properties of the jsf components for this particular user. The changes are saved in a separate xml file. Off course this should never be done for a user ( use a role ). When this particular user start the web application the customized page is shown. Other users will only see the original page.
We can also use MDS to personalize the jsf pages. The user can change the jsf pages at runtime. This is called User Customization or change persistence. In the web application we have to define what the user can change. In this blog I will allow the user to change the order of columns in a table and the user can change the width of a column. The changes are saved in a MDS repository ( I will use a file based mds repository).
Step 1 is to create a fusion web application. Add database table to the bc4j model project. So we can use this as table in a jsf page then we have to change the mds properties of the viewcontroller project. See the picture what to change.
  • We have to enable Enable User customations then Across Sessions using MDS and at last Enable Seeded Customizations. Across sessions will store the changes in the mds repository, so the next time the user still sees the changes.
    Step 2 is the configuration of the adf-config.xml file

    In this file we have to add three things. The first thing we have to do is to define a mds repository. Make sure that you add the following folders ViewController/public_html , ViewController/adfmsrc and Model/src to the metadata-path property.
    The second thing are the customizations classes. You can use different classes at the same time. I use in this blog only one ( UserCC ) . You can also use SiteCC or SecurityRoleCC.

  • Now we only have to define which changes are stored in the mds repository


      In my case you can change the order of culumns in a table and the width of the column.
      Here is my adf-config.xml

      <?xml version="1.0" encoding="windows-1252" ?>
      <adf-config xmlns="http://xmlns.oracle.com/adf/config"
      xmlns:sec="http://xmlns.oracle.com/adf/security/config">
      <sec:adf-security-child xmlns="http://xmlns.oracle.com/adf/security/config">
      <CredentialStoreContext credentialStoreClass="oracle.adf.share.security.providers.jps.CSFCredentialStore"
      credentialStoreLocation="../../src/META-INF/jps-config.xml"/>
      <sec:JaasSecurityContext initialContextFactoryClass="oracle.adf.share.security.JAASInitialContextFactory"
      jaasProviderClass="oracle.adf.share.security.providers.jps.JpsSecurityContext"
      authorizationEnforce="true"
      authenticationRequire="true"/>
      </sec:adf-security-child>
      <app-config type="MDS" name="default"
      xmlns="http://xmlns.oracle.com/adf/mds/config">
      <mds-config version="11.1.1.000" xmlns="http://xmlns.oracle.com/mds/config">
      <persistence-config>
      <metadata-namespaces>
      <namespace path="/" metadata-store-usage="one"/>
      </metadata-namespaces>
      <metadata-store-usages>
      <metadata-store-usage id="one">
      <metadata-store name="mymetadatastore"
      class-name="oracle.mds.persistence.stores.file.FileMetadataStore">
      <property name="metadata-path"
      value="D:/projecten/workspace/11g/mds_user_cc/ViewController/public_html;D:/projecten/workspace/11g/mds_user_cc/ViewController/adfmsrc;D:/projecten/workspace/11g/mds_user_cc/Model/src"/>
      </metadata-store>
      </metadata-store-usage>
      </metadata-store-usages>
      </persistence-config>
      <cust-config>
      <match>
      <customization-class name="oracle.adf.share.config.UserCC"/>
      </match>
      </cust-config>
      </mds-config>
      </app-config>
      <adf-faces-config xmlns="http://xmlns.oracle.com/adf/faces/config">
      <persistent-change-manager>
      <persistent-change-manager-class>
      oracle.adf.view.rich.change.MDSDocumentChangeManager
      </persistent-change-manager-class>
      </persistent-change-manager>
      <taglib-config>
      <taglib uri="http://xmlns.oracle.com/adf/faces/rich">
      <tag name="column">
      <attribute name="displayIndex">
      <persist-changes>true</persist-changes>
      </attribute>
      <attribute name="width">
      <persist-changes>true</persist-changes>
      </attribute>
      </tag>
      </taglib>
      </taglib-config>
      </adf-faces-config>
      </adf-config>

      We are ready with the MDS settings. Now we can add security to the project and add some example users. I use the ADF Security wizard for this. The wizard is located in the tools menu. This are the wizard steps. 1. enforce authorization 2. no identity store 3. Enable Credential store 4. No policy store 5. No anomymous providor 6. Select idstore.loginmodule 7. HTTP Basic authentication with jazn.com as realm and press finish.
      Let's create two test users named test and test1. Go the tools menu and select the preferences menu item.

      Open the embedded oc4j server preferences and add the user test and test1 to the jazn.com identity store. Create a new role users and those users to this role.
      At last we can create the jsf page with a table ( drag a viewobject from the datacontrol and drop this on the page select a readonly table). You have to add a button with no action to the page too. This is necessary else the changes are not submitted to mds repository.

      We have to check if the customization is enabled on the page. Select the jsp:root in the structure window and see in the property window if customization is allowed. The second thing we have to check if there is a unique customizationId on every table column. Select the table column, go to the property window -> behavior -> advanced -> customizationId
      Now we can go the page definition to add security to this page. Select the page definition permission value by the permission class combobox and select the view action to all the operations.

      We have to add the view permission to the users role. go to the structure window of the pagedef and the select the pagedef. Use the right button to select edit authorization menu item.

      Select all the options by the users role.

      Finally we can run the web application. If we log in as test or test1 and change the size of a column ( press the submit button) or the change the column order we will see that these setting are stored in the public_html folder. Every user has it's own folder and page xml.

      This is how a mds xml looks like for a particular user.


      The second part is about seeded customizations. Here can the developer customize the page for a particular user. In this blog I will make sure the salary column has a red background with white characters for only the user test. First we have to change the CustomizationLayerValues.xml in the jdev folder. Here we have to add the users test and test1 to the user custimatization layer.

      Startup jdeveloper and select the customization developer. If you don't get this option you have to go the preferences windows ( tools menu) and go to the roles entry. Here you can change the role.

      We can see a new window called Customizations. In this window we can select the test user.

      If we open the jsf page and change the properties of the jsf components then these changes are stored in the mds repository under the selected user in the customizations window.
      We can start the web application again. First we use the test user.

      Now we use the test1 user.

      I hope you got a good impression what MDS can do for you.

      Flex scrolling text component with html support

      Tue, 2008-07-01 14:26
      For one of my websites I would like to have a scrolling text bar with the lasted updates of that website. This is easy in flex, Peter Ent already made a flex builder 3 library project. Only this project only supports scrolling text. I want to click on the scrolling text and flex should redirect the browser to the right update. So I changed Peter Ent project so it supports the htmlText and Link event. With htmlText you can markup the scrolling text.
      With this new library project I made a flex application which reads a xml with all the scrolling text entries. Now I only have to update the xml if I make a change to the website. You can click on one of the scrolling entries and the link event redirects this to the right url. Here is an picture of the scrolling bar.
      Here is the xml which I use as input for the scrolling htmlText.

      <updates>
      <update date="28-06-2008" link="http://www.sbsframes.nl/raceteam/raceteam.html" label="Raceteam"/>
      <update date="26-06-2008" link="http://www.sbsframes.nl/youtube/youtube.html#video=119" label="Kerkdriel race 2"/>
      <update date="26-06-2008" link="http://www.sbsframes.nl/youtube/youtube.html#video=118" label="Kerkdriel race 1"/>
      <update date="24-06-2008" link="http://www.sbsframes.nl/fotos/Fotos.html" label="Fotoalbum"/>
      </updates>

      My Flex project code which reads the input xml and handles the link event.

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comp="com.keaura.controls.*"
      applicationComplete="init()"
      layout="absolute" width="500" height="20"
      backgroundGradientColors="[#CCCCCC, #CCCCCC]">


      <mx:Script>
      <![CDATA[
      import flash.events.TextEvent;
      import mx.rpc.events.ResultEvent;

      private function init():void
      {
      service.send();
      }

      public function linkHandler(event:TextEvent):void {
      // Open the link in a new browser window.
      navigateToURL(new URLRequest(event.text), '_self')
      }

      private function resultHandler(event:ResultEvent):void {
      var resultObj:Object = event.result as Object;
      var i:int;
      var updatesText:String = "<font color='#000000' size='14'>"
      +"Klik op de update, Laatste updates: ";
      for ( i = 0 ; i < resultObj.updates.update.length ; i++ ) {
      updatesText += "<a href='event:"+resultObj.updates.update[i].link+"'>"
      +resultObj.updates.update[i].date+" "
      +resultObj.updates.update[i].label+"</a> ";

      trace(resultObj.updates.update[i].label);
      }
      scroll.htmlText = updatesText;
      scroll.addEventListener("link", linkHandler);
      scroll.start();
      }

      ]]>
      </mx:Script>

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

      <mx:Canvas id="myCanvas" width="500" height="20" >
      <comp:ScrollingText id="scroll" width="500" color="black" speed="3"/>
      </mx:Canvas>
      </mx:Application>

      Flex embedded youtube player

      Wed, 2008-06-25 15:58
      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>

      Flex embedded youtube player 1.1

      Wed, 2008-06-25 15:56
      A few weeks ago I already made a blog about the flex embedded youtube player. This blog is about version 1.1. You can use this youtube player in your own website. You don't have to use a proxy or php script. You only has to update a xml with your own youtube video url's. This xml is loaded in a tree and just click on an entry. The selected video is shown in the video window.
      Version 1.1 change list.
      • I now use a Tree for the movies overview so I know when a node is a branch and when it is a youtube movie.
      • Search your movies.
      • The player now supports bookmarks, you can add #video=101 to the page url and the player directly plays movie 101.
      To let bookmarking work we have to add a css and javascript reference to the html page where the flash is embedded.
      <!-- BEGIN Browser History required section -->
      <link rel="stylesheet" type="text/css" href="history/history.css" />
      <!-- END Browser History required section -->
      <!-- BEGIN Browser History required section -->
      <script src="history/history.js" language="javascript"></script>
      <!-- END Browser History required section -->

      Here is a screenshot of the new player



      For version 1.1 I had to change the xml. Every element has the name "node" and has to have the id and category attribute. Id is necessary for the bookmarking and category is necessary for the search and the label.

      <node id="0" category="main">
      <node id="0" category="own">
      <node id="101" category="viper" url="http://www.youtube.com/v/ejlbNl3y5y8"/>
      </node>
      <node id="0" category="race">
      <node id="0" category="European">
      <node id="2012" category="Bauska 2008" url="http://www.youtube.com/v/c9BqEm7zxU4"/>
      <node id="2010" category="autocross photo's" url="http://www.youtube.com/v/SMshJRp1YR8"/>
      </node>
      </node>
      <node id="0" category="etc">
      <node id="301" category="cross movie" url="http://www.youtube.com/v/VLlrpOUO3Qs"/>
      </node>
      </node>

      Here is the source code of the new youtube player

      For the Dutch people: Oproep enquête

      Mon, 2008-06-23 15:53
      Names een ordina collega Peter Minkjan een oproep om mee te doen aan een enquete over corporate blogs. Hier bij zijn oproep.
      Een paar jaar geleden kwamen (corporate) blogs enorm in opkomst. Nu lijkt de interesse in dit fenomeen wat aan het afnemen. Toch onderhouden veel bedrijven een eigen blog. Vooral in de ICT branche zijn er veel organisaties die een corporate blog hebben. Als student bedrijfskunde doe ik op dit moment onderzoek naar corporate blogs van ICT bedrijven. Ben jij werkzaam in de ICT branche? En bezoek jij wel eens corporate blogs? Dan ben jij de ideale respondent voor mijn enquête. Deze kan je invullen via deze link. Het invullen van de enquête kost je slechts 5 minuten. Door de enquête in te vullen lever je een belangrijke bijdrage aan mijn onderzoek. De gegevens worden anoniem verwerkt. Hopelijk kan ik rekenen op jullie medewerking, alvast hartelijk bedankt voor de moeite.

      Ik zal de resultaten van de enquête hier posten.

      Advanced TaskFlow Train Features

      Sun, 2008-06-22 11:27
      In this blog I will explain you more about some features of a bounded taskflow train. A train is a wizard with stops or steps which helps the user to complete the transaction. In this blog I'll show how you can skip or disable a train stop, this can be handy when a user already did this step or this step is in this case not necessary. The second part of the blog explains how you can use a other taskflow as a train stop.Here an example of a train with four steps. If you the user to go from step 1 to Step 3 we have to set the sequential to false. You can always use a method in a bean to control this To disable a step we have to add true to the skip flied of the property editor of a train stop. You don't only have to use views for the train stops you can also use bounded taskflows as a train stop. This taskflow has to be a bounded train with only one view page and a taskflow return ( else you can't navigate back to the main train). Here is an example of the main train taskflow. Train_step2-flow-definition is the sub train taskflow. You can see I have added two control flow cases next and previous to this taskflow, else we can't navigate to step 1.5 and step3 from this sub taskflow. Next and previous are the outcome values of the two taskflow returns. Here you can see an example of the sub train taskflow. The two taskflow returns have the outcome values next and previous. I have to add two buttons to the step2 page which call the next or previous action. At last a more complex example of a train. You can find this example in the oracle documentation. It gives an impression what you can do in taskflow.

      ODTUG ADF & SOA highlights

      Wed, 2008-06-18 11:45
      This week I saw a lot of interesting things about ADF and Soa suite 11G. Clemens Utschig did show in BPEL how to use the sdo webservice created with adf bc and use this in a bpel bind entity activity. The bind entity can be used to update a particuler record without using a database adapter, it binds to the sdo web service. You can use the xslt editor to put in a new value on a element and the soa suite updates the right record in the database. And off course the soa suite is all about events. Publish an event from ADF or from a Complex event processing (CEP) and use a Mediator which can listen for these event. You may think why this is important. It is very important because in the old days you have to make one big process. This can be a very complex process. With events you can split up this big process in smaller parts which are much easier to maintain.
      Duncan Mills did some nice ADF demo with excel as a gui client. He had a webapp where a flash graph is shown. He opens the excel document and the data was retrieved from the webapp (this is done with a servlet , no odbc). Duncan updates the data in excel and the graph detects the updated records and refreshes the graph. There will be an adf installer for office with this you can create a excel document, which can cummunicate with ADF in the webapp. This installer will be released in Jdev 11g TP6.
      Steven Davelaar did a nice presentation how JSF components internally work and what the impact of the immediate option is. He also presented with Wilfred van der Deijl the new JHeadstart with OraFormsFaces integration. With this solution you can easily generate new webapp and embed your existing Oracle Forms into this webapp. So you can mix new and old technology and generate it all with jheadstart.

      ADF Faces templating in 10.1.3

      Sun, 2008-06-15 20:34
      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

      Openesb & Soa Suite comparison

      Tue, 2008-06-10 15:23
      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.

      Using Siebel WS in your ADF application

      Fri, 2008-05-30 08:53
      For our Siebel Unit I was making a demo which can search siebel accounts, displays a single account with the addresses and an insert page. The goal was to do this with the Siebel web service. This example gives an good example how to deal with complex web services, because the ADF Web Service Datacontrol only works with simple web services. You have a example on otn which use the ws datacontrol, but this only works on a simple web service method. When you want to search or create a new account you have to do more.
      This is how it looks. The search page show all accounts ( calls SiebelAccountQueryByExample ). In this example you can search on Id and Name. You can also click on the Id then the account detail page is loaded.
      When the detail page is loaded it calls SiebelAccountQueryById with the Id of the search page.

      And the last page is the insert page

      I did this by making a web service proxy on the local saved wsdl. To test this web service you have to do a lot.

      nl.ordina.siebel.model.proxy.DefaultClient myPort = new nl.ordina.siebel.model.proxy.DefaultClient();
      System.out.println("calling " + myPort.getEndpoint());
      // Add your own code here
      ListOfAccountInterfaceTopElmt inter = new ListOfAccountInterfaceTopElmt();
      Account[] result = new Account[1];
      Account acc = new Account();
      acc.setAccountId("1-7SL");;
      result[0]= acc;
      inter.setListOfAccountInterface(result);
      ListOfAccountInterfaceTopElmtHolder holder = new ListOfAccountInterfaceTopElmtHolder(inter);
      myPort.siebelAccountQueryByExample(holder);
      Account[] accs = holder.value.getListOfAccountInterface();
      acc = accs[0];

      This is to complex so I made it a bit easier. I created a java class where I call these ws methods and on this class I am making a datacontrol.

      package nl.ordina.siebel;

      import nl.ordina.siebel.model.proxy.DefaultClient;
      import nl.ordina.siebel.model.proxy.holders.ListOfAccountInterfaceTopElmtHolder;
      import nl.ordina.siebel.model.proxy.types.com.siebel.xml.account_interface.Account;
      import nl.ordina.siebel.model.proxy.types.com.siebel.xml.account_interface.ListOfAccountInterfaceTopElmt;

      public class SiebelActions {
      public SiebelActions() {
      }

      public Account[] SearchAccount( Account msg ){
      try {
      DefaultClient myPort = new DefaultClient();
      System.out.println("calling " + myPort.getEndpoint());
      ListOfAccountInterfaceTopElmt inter = new ListOfAccountInterfaceTopElmt();
      Account[] result = new Account[1];
      result[0]= msg;
      inter.setListOfAccountInterface(result);
      ListOfAccountInterfaceTopElmtHolder holder = new ListOfAccountInterfaceTopElmtHolder(inter);
      myPort.siebelAccountQueryByExample(holder);
      return holder.value.getListOfAccountInterface();
      }
      catch (Exception ex) {
      ex.printStackTrace();
      }
      return null;
      }

      public Account[] GetAccount( String id ){
      try {
      DefaultClient myPort = new DefaultClient();
      System.out.println("calling " + myPort.getEndpoint());
      ListOfAccountInterfaceTopElmt result = myPort.siebelAccountQueryById(id);
      return result.getListOfAccountInterface();
      }
      catch (Exception ex) {
      ex.printStackTrace();
      }
      return null;
      }

      public static void main(String[] args) {

      SiebelActions sa = new SiebelActions();
      Account acc = new Account();
      acc.setAccountId("1-7SL");
      Account[] result = sa.SearchAccount(acc);
      acc = result[0];
      System.out.println("account info "+acc.getAlias()+" name "+acc.getName());

      result = sa.GetAccount("1-7SL");
      acc = result[0];
      System.out.println("account info 2 "+acc.getAlias()+" name 2 "+acc.getName());
      }
      }

      I created an ADF Datacontrol on this class and use this datacontrol in the ADF JSF Pages. Because the input parameters of the ws methods are complex types, I had to create a bean with a method which returns the input parameter. In this bean I also added the search parameters field.
      getAccount is used in the pagedef as input parameter on SiebelAccountQueryByExample.

      package nl.ordina.siebel;

      import nl.ordina.siebel.model.proxy.types.com.siebel.xml.account_interface.Account;

      public class SiebelBean {

      protected java.lang.String accountId;
      protected java.lang.String showAccountId;
      protected java.lang.String alias;
      protected java.lang.String name;

      public SiebelBean() {
      }

      public Account getAccount(){
      Account acc = new Account();
      acc.setAccountId(accountId);
      acc.setAlias(alias);
      acc.setName(name);
      return acc;
      }

      public void setAccountId(String accountId) {
      this.accountId = accountId;
      }

      public String getAccountId() {
      return accountId;
      }

      public void setShowAccountId(String showAccountId) {
      this.showAccountId = showAccountId;
      }

      public String getShowAccountId() {
      return showAccountId;
      }

      public void setAlias(String alias) {
      this.alias = alias;
      }

      public String getAlias() {
      return alias;
      }

      public void setName(String name) {
      this.name = name;
      }

      public String getName() {
      return name;
      }
      }

      Here is a guide with all the steps I did. And here is the jdeveloper 10.1.3.3 project. To let it work on your own siebel 8 you only have to change the url of the ENDPOINT_ADDRESS_PROPERTY in the stub file created by the web service proxy and put in the right username / password else you can't insert new accounts.
      _setProperty(ENDPOINT_ADDRESS_PROPERTY, "http://10.100.17.1/eai_nld/start.swe?SWEExtSource=WebService&SWEExtCmd=Execute&UserName=normani&Password=normani");

      PDF previewer in jdeveloper 10.1.3

      Mon, 2008-05-26 10:30
      This blog I will show you how can make a free pdf previewer by generating images of pdf files and stream this png with a servlet to the objectImage of the jsf page.
      If you have a web application where people can download pdf files, then this can be handy to provide a sort of previewer where the first page is shown, so they don't have to download or open every pdf file in acrobat reader to find the right document.
      I use for the pdf to image generation the library of jpedal and some great code of Richard Braman for the scaling and generating of the png files.
      Here is how it looks. First you have to select a pdf document.

      If we press the load button then the first page is shown with the total pagecount of the document.


      Here is 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"
      xmlns:afh="http://xmlns.oracle.com/adf/faces/html"
      xmlns:cust="http://xmlns.oracle.com/adf/faces/customizable">
      <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>view</title>
      </head>
      <body>
      <h:form id="form1">
      <af:panelGroup layout="vertical">
      <af:panelGroup layout="horizontal">
      <af:selectOneChoice id="choice" label="Document"
      valueChangeListener="#{ViewerBean.changeChoice}">
      <af:selectItem label="doc1" value="javascript"/>
      <af:selectItem label="doc2" value="threads"/>
      </af:selectOneChoice>
      <af:commandButton text="Load" id="laden"/>
      </af:panelGroup>
      <af:panelGroup rendered="#{ViewerBean.showImage}" >
      <af:commandButton text="Previous" id="vorige" actionListener="#{ViewerBean.vorigePagina}">
      </af:commandButton>
      <af:outputText value="#{ViewerBean.pagesOverview}"/>
      <af:commandButton text="Next" id="volgende" actionListener="#{ViewerBean.volgendePagina}">
      </af:commandButton>
      </af:panelGroup>
      <af:objectImage id="objectImage1"
      partialTriggers="volgende vorige laden"
      binding="#{ViewerBean.image}" rendered="#{ViewerBean.showImage}" />
      </af:panelGroup>
      </h:form>
      </body>
      </html>
      </f:view>
      </jsp:root>

      I have to use partialtriggers on the objectImage else it won't refresh from the servlet if I press the load or previous / next buttons.

      In the faces-config.xml I have defined two beans, the first is for the jsf page and the second is for the servlet. This hashmap I use to pass the parameters to the servlet

      <managed-bean>
      <managed-bean-name>ViewerBean</managed-bean-name>
      <managed-bean-class>nl.ordina.pdf.backing.Viewer</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      </managed-bean>
      <managed-bean>
      <managed-bean-name>ImageParametersBean</managed-bean-name>
      <managed-bean-class>java.util.HashMap</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      </managed-bean>

      The backing bean of the jsf page. Basically I fill the servlet hashmap with the right values.

      package nl.ordina.pdf.backing;

      import java.util.HashMap;
      import javax.faces.context.FacesContext;
      import javax.faces.event.ActionEvent;
      import javax.faces.event.ValueChangeEvent;
      import nl.ordina.pdf.ImageGenerator;
      import oracle.adf.view.faces.component.core.output.CoreObjectImage;

      public class Viewer {

      private String tempPath = "d:/temp/";
      private String imageUrl = "http://XPCND7010XMP:8988/pdf_previewer-ViewController-context-root/preview";
      private String pdfArchivePath = "D:/documenten/MyeBooks/";
      private int page = 1;
      private int totalPages = 1;
      private String pagesOverview;
      private ImageGenerator img = new ImageGenerator();
      private CoreObjectImage image;
      private boolean showImage = false;
      private HashMap parameters;

      public Viewer() {
      parameters = getHashMapServlet();
      parameters.put("temppath",tempPath);
      parameters.put("pdfarchivepath",pdfArchivePath);
      }

      public void volgendePagina(ActionEvent event){
      if ( page <> 1 ){
      page = page -1;
      setServletPage(page);
      }
      }

      public void changeChoice(ValueChangeEvent valueChangeEvent) {
      page = 1;
      setServletPage(page);
      setServletDocument(valueChangeEvent.getNewValue().toString());
      image.setSource(imageUrl);
      showImage = true;
      totalPages = img.pdfTotalPages(pdfArchivePath,valueChangeEvent.getNewValue().toString());
      }

      private HashMap getHashMapServlet(){
      FacesContext fctx = FacesContext.getCurrentInstance();
      return (HashMap)fctx.getApplication().createValueBinding("#{ImageParametersBean}").getValue(fctx);
      }
      private void setServletDocument(String doc){
      parameters.put("document",doc);
      }
      private void setServletPage(int page){
      parameters.put("page",page);
      }

      public void setImage(CoreObjectImage image) {
      this.image = image;
      }

      public CoreObjectImage getImage() {
      return image;
      }

      public void setShowImage(boolean showImage) {
      this.showImage = showImage;
      }

      public boolean isShowImage() {
      return showImage;
      }

      public String getPagesOverview() {
      pagesOverview = page + " / " + totalPages;
      return pagesOverview;
      }
      }


      The servlet code which reads the hashmap , generates the png and streams it back to the jsf page

      package nl.ordina.pdf.servlet;

      import java.io.IOException;
      import java.util.HashMap;
      import javax.servlet.ServletConfig;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import nl.ordina.pdf.ImageGenerator;

      public class PreviewServlet extends HttpServlet {

      public void init(ServletConfig config) throws ServletException {
      super.init(config);
      }

      public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      doPost(request, response);
      }

      public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      HashMap parameters = (HashMap)request.getSession().getAttribute("ImageParametersBean");
      Integer page = 1;
      String documentName = null, temp = null, archive = null;

      if (parameters != null) {
      documentName = parameters.get("document").toString();
      page = new Integer(parameters.get("page").toString());
      temp = parameters.get("temppath").toString();
      archive = parameters.get("pdfarchivepath").toString();
      }
      ImageGenerator img = new ImageGenerator();
      byte[] data = img.getPic(documentName,page.intValue(),temp,archive );
      response.setContentType("image/png");
      response.setContentLength( data.length );
      response.getOutputStream().write( data );
      response.getOutputStream().flush();
      response.setHeader("Cache-Control", "no-cache");
      }
      }

      Here is the example project with the jpedal code for the png generations.

      To get this working change the select one choice of the jsf page with not secured pdf files and without the .pdf extension. Change the variables in the viewer bean with your own values

      private String tempPath = "d:/temp/";
      private String imageUrl = "http://XPCND7010XMP:8988/pdf_previewer-ViewController-context-root/preview";
      private String pdfArchivePath = "D:/projecten/justid/cdd_archief/PEN_ARCH/01/01/45/";

      Update
      JPedal released a new jar where they changed something and you can get the following exception 08/05/26 17:07:21 java.awt.HeadlessException
      08/05/26 17:07:21 at sun.java2d.HeadlessGraphicsEnvironment.getDefaultScreenDevice(HeadlessGraphicsEnvironment.java:65)

      Here is the code of the new imagegenerator

      package nl.ordina.pdf;

      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import org.jpedal.*;
      import org.jpedal.exception.PdfException;
      import java.io.*;
      import java.awt.Graphics2D;
      import java.awt.Image;
      import java.awt.image.BufferedImage;


      public class ImageGenerator {
      public ImageGenerator() {
      }

      public byte[] getPic( String document,Integer picture
      , String temp, String archive, String generateAlways) {
      byte[] data = null;
      String path = temp+document+"_"+picture+".png";

      try {
      boolean exists = (new File(path)).exists();
      if (exists && generateAlways.equals("no") ) {
      data = read(path);
      } else {
      path= PDFToPic(archive,document,picture,temp);
      data = read(path);
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      return data;

      }

      public int pdfTotalPages(String filepath,String doc)
      {
      try
      {
      PdfDecoder decoder = new PdfDecoder();
      decoder.openPdfFile(filepath+doc+".pdf");
      if (decoder.isFileViewable()) {

      int PageCount = decoder.getPageCount() ;
      return PageCount;
      }
      } catch(Exception err) {
      err.printStackTrace();
      }
      return 0;
      }



      public byte[] read(String file) throws IOException {
      InputStream in = new FileInputStream(file);
      byte[] data = new byte[in.available()];
      in.read(data);
      return data;
      }

      public String PDFToPic(String filepath,String doc, int picture,String temppath)
      {
      try
      {
      PdfDecoder decoder = new PdfDecoder();
      decoder.openPdfFile(filepath+doc+".pdf");
      if (decoder.isFileViewable()) {

      int PageCount = decoder.getPageCount() ;
      double ImageWidth = 0;
      double ImageHeight = 0;

      if ( picture <= PageCount) {
      //generate png files
      generatePNGfromPDF(decoder, picture, ImageWidth, ImageHeight, doc,temppath);
      return temppath+doc+"_"+picture+".png";

      } else {
      generatePNGfromPDF(decoder, PageCount, ImageWidth, ImageHeight, doc,temppath);
      return temppath+doc+"_"+PageCount+".png";

      }
      }
      } catch(Exception err) {
      err.printStackTrace();
      }
      return null;
      }


      private void generatePNGfromPDF( PdfDecoder decoder
      , int PageNumber
      , double width
      , double height
      , String doc
      , String temppath){
      //int size = 100;
      decoder.useHiResScreenDisplay(true);
      decoder.setExtractionMode(PdfDecoder.RAWIMAGES+PdfDecoder.FINALIMAGES);


      int scaling = 100;

      try {
      BufferedImage PDF = decoder.getPageAsImage(PageNumber);
      if(scaling!=100){
      int newWidth=PDF.getWidth()*scaling/100;
      //only 1 new co-ord needed so use -1 for other as aspect ration does not change
      Image scaledImage= PDF.getScaledInstance(newWidth,-1,BufferedImage.SCALE_SMOOTH);
      PDF = new BufferedImage(scaledImage.getWidth(null),scaledImage.getHeight(null) , BufferedImage.TYPE_INT_RGB);
      Graphics2D g2 = PDF.createGraphics();
      g2.drawImage(scaledImage, 0, 0,null);

      }
      File fileToSave = new File( temppath+doc+"_"+PageNumber+".png");
      boolean failed=decoder.getObjectStore().saveStoredImage(temppath+doc+"_"+PageNumber+".png",PDF,true,false,"png");
      } catch (PdfException e) {
      // TODO
      e.printStackTrace();
      }

      }

      }

      Using OpenLDAP for net8 and AQ connection factory

      Sun, 2008-05-25 11:01
      In this blog I will show you can use OpenLDAP to lookup your Oracle Net (tnsnames) connections or AQ connection factories. Now you don't need to have an Oracle Internet Directory (OID) installed. The first step is to download openldap. Install this and download my oracle.schema and put this in the schema folder of openldap. This file has to be included in the slapd.conf.
      Edit slapd.conf and add
      "include schema/java.schema"
      "include schema/oracle.schema" .
      Make sure anonymous can read the tnsnames entries.
      access to dn="" by * read
      access to *
      by self write
      by users read
      by anonymous read
      We have to configure the ldap for Oracle by making an OracleContext and oracledbconnections entry.

      I do this with ldapbrowser. You can download it here. For this free java application I made some templates which you can use.



      Do the same for oracledbconnections ( this is for the AQ entries) Now use the queue template in ldapbrowser.

      To make a tnsnames entry I select the OracleContext ldap entry and I use the orclNetService template to create a new Oracle connection.

      We are ready to use it, we only has to create ldap.ora in the network\admin folder. The ldap.ora looks like this.
      DIRECTORY_SERVERS= (localhost:389:636)

      DEFAULT_ADMIN_CONTEXT = "o=sgi,c=us"

      DIRECTORY_SERVER_TYPE = OID

      We start sqlplus and use the ldap name as tnsnames entry. I can also start net manager and go the Directory menuitem to see our ldap entry

      The second part shows you can lookup an AQ connection factory with JNDI and ldap. first let's register a new connection in the ldap server. For this I only need the following jars files. jndi-1.2.1.jar,jta-1.0.1.jar, jms-1.1.jar,aqapi.jar and the jdbc jar of oracle



      package jms2;

      import java.util.Hashtable;
      import java.util.Properties;
      import javax.jms.JMSException;
      import javax.naming.Context;
      import oracle.jms.AQjmsFactory;

      public class register_jms_to_oid {
      public register_jms_to_oid() {
      Hashtable 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("server_dn", "o=sgi,c=us");
      env.put(Context.SECURITY_AUTHENTICATION, "simple");
      env.put(Context.SECURITY_PRINCIPAL, "o=sgi,c=us");
      env.put(Context.SECURITY_CREDENTIALS, "secret");
      String url = "jdbc:oracle:thin:@XPCND7010XMP:1521:orcl";
      Properties properties = new Properties();
      properties.setProperty("user","scott");
      properties.setProperty("password","tiger");
      try {
      AQjmsFactory.registerConnectionFactory(env, "scott3", url ,properties, "queue");
      } catch ( JMSException e) {
      e.printStackTrace();
      }
      }
      public static void main(String[] args) {
      register_jms_to_oid register_jms_to_oid = new register_jms_to_oid();
      }
      }

      Now we can lookup this entry with standard jms calls.

      package jms2;

      import java.util.Hashtable;
      import javax.jms.JMSException;
      import javax.jms.Queue;
      import javax.jms.QueueConnection;
      import javax.jms.QueueSender;
      import javax.jms.QueueSession;
      import javax.jms.TextMessage;
      import javax.jms.QueueConnectionFactory;
      import javax.naming.Context;
      import javax.naming.directory.DirContext;
      import javax.naming.directory.InitialDirContext;
      import javax.naming.NamingException;

      public class lookup_jndi_queue {

      private QueueConnection connection = null;
      private QueueSession session = null;
      private QueueSender sender = null;

      public lookup_jndi_queue() {

      Hashtable env = new Hashtable(5, 0.75f);
      DirContext ctx;
      QueueConnectionFactory queueConnectionFact;
      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");

      try {
      ctx = new InitialDirContext(env);
      ctx = (DirContext)ctx.lookup("cn=connections, o=sgi,c=us");
      Object reference = ctx.lookup("cn=scott");
      queueConnectionFact = (QueueConnectionFactory)reference;
      try {
      connection = queueConnectionFact.createQueueConnection();
      session = connection.createQueueSession(true, QueueSession.CLIENT_ACKNOWLEDGE);
      connection.start();
      QueueSession session = connection.createQueueSession(true, QueueSession.AUTO_ACKNOWLEDGE);
      Queue queue = session.createQueue("JMS_IN");
      sender = session.createSender(queue);
      String xmlData = "1111";
      TextMessage message = session.createTextMessage(xmlData);
      sender.send(message);
      session.commit();
      } catch (JMSException e) {
      // TODO
      e.printStackTrace();
      }
      } catch (NamingException ee) {
      // TODO
      ee.printStackTrace();
      }
      }

      public static void main(String[] args) {
      lookup_jndi_queue lookup_jndi_queue = new lookup_jndi_queue();
      }
      }


      You can also use the ldapbrowser template. The entry look this in ldap.

      Employee search jsf page on Coherence with JPA

      Thu, 2008-05-22 13:54
      This I had this week a great coherence training for Oracle partners, where I learned a lot of interesting things about Coherence . This product is from tangosol ( Now owned byOracle ) and is a memory distributed data grid solution for clustered applications and application servers.

      You may think coherence is a very complex product but it is a very easy to handle. It does everything automatically like backing up the cache on different nodes, distribute the load and recover from lost cache servers or adding new coherence servers to the cluster.
      In this blog I will show how you can make a jsf employee search page on the coherence cache which get its data from a JPA datasource. Coherence runs above JPA. In this blog I will also update the cache entries with a salary raise and coherence will take care to update the right records in the employee table.
      If you want to do it yourself you have to download coherence from Oracle. Add coherence.jar and tangosol.jar to the project libraries. Then we can create a entity bean ( entities from tables ( JPA / EJB3.0) on the employee table ( HR schema). Jdeveloper create a persistence.xml which we have to change with the right class and database parameters. persistence-unit name must match with the property of JpaCacheStore in the coherence jpa xml.

      <?xml version="1.0" encoding="windows-1252" ?>
      <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
      http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
      version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
      <persistence-unit name="JPA">
      <provider>oracle.toplink.essentials.PersistenceProvider</provider>
      <class>nl.ordina.coherence.model.Employees</class>
      <properties>
      <property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
      <property name="toplink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>
      <property name="toplink.jdbc.user" value="hr"/>
      <property name="toplink.jdbc.password" value="hr"/>
      </properties>
      </persistence-unit>
      </persistence>
      Next I created jpa-cache-config-web.xml

      <?xml version="1.0" encoding="windows-1252" ?>
      <cache-config>
      <caching-scheme-mapping>
      <cache-mapping>
      <!-- Set the name of the cache to be the entity name -->
      <cache-name>Employees</cache-name>
      <!-- Configure this cache to use the scheme defined below -->
      <scheme-name>jpa-distributed</scheme-name>
      </cache-mapping>
      </caching-scheme-mapping>
      <caching-schemes>
      <distributed-scheme>
      <scheme-name>jpa-distributed</scheme-name>
      <service-name>JpaDistributedCache</service-name>
      <backing-map-scheme>
      <read-write-backing-map-scheme>
      <internal-cache-scheme>
      <local-scheme/>
      </internal-cache-scheme>
      <cachestore-scheme>
      <class-scheme>
      <class-name>com.tangosol.coherence.jpa.JpaCacheStore</class-name>
      <init-params>
      <init-param>
      <param-type>java.lang.String</param-type>
      <param-value>{cache-name}</param-value>
      </init-param>
      <init-param>
      <param-type>java.lang.String</param-type>
      <param-value>nl.ordina.coherence.model.{cache-name}</param-value>
      </init-param>
      <init-param>
      <param-type>java.lang.String</param-type>
      <param-value>JPA</param-value>
      </init-param>
      </init-params>
      </class-scheme>
      </cachestore-scheme>
      </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
      </distributed-scheme>
      </caching-schemes>
      </cache-config>

      Add this file to the run options of the cache-server.cmd and the jdeveloper web project runtime options. -Dtangosol.coherence.cacheconfig=D:\oracle\coherence\bin\jpa-cache-config-web.xml
      Now we can load the Employees cache. Do this with the following code
      private NamedCache employees = CacheFactory.getCache("Employees");
      For searching through the cache for the right employees I use a filter.

      public void search(ActionEvent actionEvent) {

      Filter filter = null;
      if ( firstName.getValue() != null && lastName.getValue() != null ) {
      filter = new OrFilter( new LikeFilter("getFirstName", firstName.getValue().toString())
      , new LikeFilter("getLastName" , lastName.getValue().toString()));
      } else if ( firstName.getValue() != null && lastName.getValue() == null ) {
      filter = new LikeFilter("getFirstName", firstName.getValue().toString());
      } else if ( firstName.getValue() == null && lastName.getValue() != null ) {
      filter = new LikeFilter("getLastName", lastName.getValue().toString());
      } else {
      seeAll(actionEvent);
      return;
      }

      Set empSet = employees.entrySet(filter);

      int size = empSet.size();
      List list = new ArrayList();

      for (Iterator it = empSet.iterator(); it.hasNext(); ) {
      Map.Entry entry = (Map.Entry)it.next();
      Employees empl = (Employees)entry.getValue();
      list.add(empl);
      }
      model = new ArrayDataModel(list.toArray());
      }

      To update the employee records. I first need to have a class which I can invoke on the cache

      package nl.ordina.coherence.backing;

      import com.tangosol.util.processor.AbstractProcessor;
      import com.tangosol.util.InvocableMap.Entry;
      import nl.ordina.coherence.model.Employees;

      public class RaiseSalary extends AbstractProcessor {
      public RaiseSalary() {
      }

      public Object process(Entry entry ) {
      Employees emp = (Employees)entry.getValue();
      emp.setSalary(emp.getSalary() * 1.10);
      entry.setValue(emp);
      return null;
      }
      }


      We invoke this by the following statement employees.invokeAll(AlwaysFilter.INSTANCE, new RaiseSalary());. Coherence updates the affected records.
      Here you can download the example project. You have to start 1 cache server on your network and you can start the webapp on different clients. Coherence connects automatically to the cache server. You can search the cache immediately. Start for example more cache servers and look at the timing. And update the cache by doing a salary raise on 1 webapp and query the changed employees in the other webapp.

      To run this example you have to change some files.
      Change the path parameters with the right folders of jpa-cache-server-web2.cmd file (this included in the zip) and the classpath of the employee bean
      :launch
      set java_opts="-Xms%memory% -Xmx%memory% -Dtangosol.coherence.cacheconfig=D:\oracle\coherence\bin\jpa-cache-config-web.xml"
      "%java_exec%" -server -showversion "%java_opts%" -cp "%coherence_home%\lib\coherence.jar;%coherence_home%\lib\coherence-jpa.jar;D:\oracle\jdevstudio10133\jdbc\lib\ojdbc14.jar;D:\oracle\jdevstudio10133\toplink\jlib\toplink-essentials.jar;D:\projecten\workspace\10.1.3.3\coherence\web\public_html\WEB-INF\classes" com.tangosol.net.DefaultCacheServer %1
      Change the run options and the libraries of the project and off course the persistence.xml for the database parmaters.

      ADF JDeveloper 11g TP4 need to knows

      Tue, 2008-05-20 03:18
      Oracle just released jdeveloper 11g TP4 in this release they changed some ADF things and there some bugs which you should need to know when you are a ADF developer.
      The changes are there is no ADF Create Form in TP4 ( See Steve Muench quote), to solve this drag the right create operation of the viewobject from the datacontrol to the taskflow. A method call is created, make sure this method call runs before the page is loaded and the page is now in insert mode.
      Steve Muench quotes "Notice that in TP4 there is no longer an "ADF Create Form" and that we're encouraging you to create a create form using a method activity that declaratively invokes the create operation, then forwards to a page with a regular ADF Form on it. This is due to the numerous confusions that have always surrounded the ADF "invokeAction" now that we have a visual, declarative mechanism to model this type of initialization activity, we will prefer users adopting that. Also, notice that the page definition for the method activity has the new "SkipValidation" property set to true."
      Andrejus made a create sample how to use a lov when the form is in create mode. If you don't do this you get validation errors and the lov is empty.
      A other issue is that the Commit operation fails with a table, you get a null pointer exception. This is bug in the JSF 1.2 reference implementation's validator tag (issue# 641): This issue is fixed in JSF 1.2_05. The TP4 release still uses JSF 1.2_04 that has this bug. The workaround to comment out the tag.
      In the datacontrol there is a bug
      In TP3 you could reference to a valuebinding of a other pagedef (Task Flow memory scope), this fails in TP4 but there there is a workaround you can update the DataBindings.cpx file with the right pagedef id. At the pageMap remove the package name part of the usageId attribute and at the pageDefinitionUsages element remove also the package name part of id attribute. Now everything works again.
      If you know other TP4 issues let me know and please update the oracle wiki yourself
      http://wiki.oracle.com/page/Known+issues+and+limitations

      Using sdo web services with service based entities (ADF BC)

      Fri, 2008-05-16 07:58
      If you ever need to make a web application build on services ( because of SOA or it has to be demilitarized zone application) then you can use the new service based entity and view of ADF BC. With this it is easy to make a service based application and there are no differences with normal ADF database development.
      ADF BC can also create the sdo web service for you. You can use this service not only for ADF BC but also for the new soa suite 11g. It can be an alternative for the the database adapter See my previous blog for more details. In this blog entry I will show you how to create a adf bc sdo web service and use this service in an other application.
      With 11g you can easily create a SDO web service. You only have to create a bc4j model project and add an entity with a viewobject. The viewobject which you want to service has to be added to the applicationmodule. The only thing you have to do now is open the applicationmodule and add a new service interface.

      Add the viewobject and select the wanted operations on this viewobject

      When it finishes you see JDeveloper generates a few xml schema's and java classes.
      To test the new service run the ServiceImpl of the application module. This class is located in the serviceinterface package.
      We have to make a ADF BC service deployment profile.


      We can deploy the service to the local j2ee server. First start the oc4j container with JDEV_HOME/binoc4j.cmd -start. create a application server connection in your project and deploy this to this container. We have know two things, first we need our deployment profile name, this is CustomerService plus we add __MiddleTier. In my case the jndi lookup name will be CustomerService_MiddleTier. The second thing is the wdsl url this is http://localhost:8888/oe_sdo_service-model-context-root/CustomerModuleService?WDSL .
      We are almost ready with sdo web service we only have to copy the reference from the connection.xml


      Create a new fusion application where we add the just copied reference entry to this application connection.xml plus we add a few extra jndi entries

      <?xml version = '1.0' encoding = 'UTF-8'?>
      <ns2:References xmlns:ns2="http://xmlns.oracle.com/adf/jndi">
      <Reference className="oracle.jbo.client.svc.Service" name="{/nl/ordina/sdo/service/common/}CustomerModuleService">
      <Factory className="oracle.jbo.client.svc.ServiceFactory"/>
      <RefAddresses>
      <StringRefAddr addrType="serviceInterfaceName">
      <Contents>nl.ordina.sdo.service.common.serviceinterface.CustomerModuleService</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="serviceEndpointProvider">
      <Contents>ADFBC</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="jndiName">
      <Contents>nl.ordina.sdo.service.common.CustomerModuleServiceBean</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="jndiFactoryInitial">
      <Contents>oracle.j2ee.rmi.RMIInitialContextFactory</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="jndiProviderURL">
      <Contents>ormi://localhost:23791/CustomerService_MiddleTier</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="jndiSecurityPrincipal">
      <Contents>fmwadmin</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="jndiSecurityCredentials">
      <Contents>welcome</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="serviceSchemaName">
      <Contents>CustomerModuleService.xsd</Contents>
      </StringRefAddr>
      <StringRefAddr addrType="serviceSchemaLocation">
      <Contents>nl/ordina/sdo/service/common/serviceinterface/</Contents>
      </StringRefAddr>
      </RefAddresses>
      </Reference>
      </ns2:References>

      Add the CustomerService_Common.jar to the project library. This jar is located in the deploy folder.
      Finally we can create a entity based on a service. Create a new entity and select the service option where we add the ws wdsl url

      And we can create in the last step an application and a viewobject.
      Now start the bc4j tester by running the application