Development

APEX 3.1.2 patch applied successfully

Dimitri Gielis - 9 hours 4 min ago
If you didn't hear about it yet, you must only read this blog and no others ;-)

Yesterday a new Patch came out for Oracle Application Express. If you look at the number of fixes I think it's worthwhile to apply the patch. Depending the version of APEX you're running you need to install the full patch or get the patch from Metalink (patch number 7313609).


I applied the patch today to some of my systems and it went like a charm. Don't forget to read the Patch Notes before you apply the patch. Two commands to run: "SQL>@apxpatch.sql" and "SQL>@apxldimg.sql /tmp/patch" (if you run with XMLDB) or copying the images directory (if you run with Apache).

The patch took just over 3 minutes to finish.


John Scott did an excellent post about Bug Number 7298389. He proves that the patch does what it needs to do to minimise the redirects, which hopefully improves our Google ranking of our APEX sites.
Categories: Development

Oracle APEX 3.1.2 is out!

Patrick Wolf - 13 hours 4 min ago
The Oracle APEX team has released a new patchset for Oracle Application Express (APEX). According to the readme file the new version 3.1.2 contains 28 new bug fixes (Note: the list also contains the bugs from the previous patchset).

The full release can be downloaded from the OTN download side.
The patchset with just the changed files can be found on Metalink with the patch number 7313609.
Categories: Development

Flex and Ruby on Rails with RubyAMF

Edwin Biemond - 17 hours 36 min ago
My earlier Flex blogs often talks about Flex in combination with java but you don't need to java you can use Ruby on Rails too. There are a lot blog entries how to do this. I already made a little demo application where I use RoR and the HttpService in Flex. This solution is based on REST Web Services. RoR gives xml as output.
In this Blog entry I will use RubyAMF. With RubyAMF I can use RemoteObject, RubyAMF will convert the Ruby datatypes to the Flex datatypes and it is really fast.
If you want more information on RubyAMF just click here or go to the RubyAMF discussion groups

Let's create a new Flex Ruby application where we will use RubyAMF. I will create a small comic entry application.

Create a new RoR application:
rails comics_catalog

Change directory to the new comics_catalog folder:
cd comics_catalog

Edit the database connection file ( comics_catalog\config\database.yml ) with the right connection.

Update the project with RubyAMF:
ruby script/plugin install http://rubyamf.googlecode.com/svn/tags/current/rubyamf
This will download RubyAMF code and configuration from subversion to your project.

Create the comic table and controller
ruby script/generate rubyamf_scaffold comic

Edit the comic table configuration. Go to comics_catalog\db\migrate\ folder and edit the 20080827214400_create_comics.rb file. You will have an other filename because of the timestamp. The script need to look like this.

class CreateComics < ActiveRecord::Migration
def self.up
create_table :comics do |t|
t.string :name
t.string :description
t.float :price
t.timestamps
end
end

def self.down
drop_table :comics
end
end

Let's create the comic table in the database
rake db:migrate

The last step in RoR is to configure RubyAMF. For this we need to go the comics_catalog\config folder where we will edit the rubyamf_config.rb file.

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


ClassMappings.register(:actionscript => 'Comic',
:ruby => 'Comic',
:type => 'active_record',
:attributes => ["id","name","description","price", "created_at", "updated_at"])

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

I use ClassMappings.ignore_fields because I want to ignore the automatic created fields Ruby will fill these field automatically.
ClassMappings.translate_case is important if you want to Java naming style. RubyAMF will convert created_at to createdAt.
ClassMappings.assume_types is important if you do your know class mapping. In our case we will create the comic class in Flex too so we don't need this. This will give us a little more performance.
ParameterMappings.scaffolding is handy if you just want to pass an comic object or id to the delete method else you need to use {id:dg.selecteditem.id}
ClassMappings.register(:actionscript => 'Comic'. Don't use the package name just put in the actionscript class name.

Start the Ruby server
ruby script/server

Now we can go to Flex, where we create an new application.

first create a comic actionscript object

package vo
{

[RemoteClass(alias="Comic")]
[Bindable]
public class Comic
{
public var id:int;
public var name:String;
public var description:String;
public var price:Number;
public var createdAt:Date;
public var updatedAt:Date;
public function Comic()
{
}


}
}

And here is the mxml code.

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

<mx:Script>
<![CDATA[
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import vo.Comic;

[Bindable]
private var comics:Array = new Array();

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

private function save2():void {
var comic:Comic = new Comic();
comic.id = dg2.selectedItem.id;
comic.name = Name2.text;
comic.description = Description2.text;
var token:AsyncToken = AsyncToken(comicService.save(comic));
token.kind = "save";

}

private function create2():void {
var comic:Comic = new Comic();
comic.name = Name2.text;
comic.description = Description2.text;
var token:AsyncToken = AsyncToken(comicService.save(comic));
token.kind = "create";
}


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

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

private function resultHandler2(event:ResultEvent):void {
if ( event.token.kind == "fill" ) {
comics = event.result as Array;
} else {
loadAll2();
}
}



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

<mx:ApplicationControlBar>
<mx:Button label="Create" click="create2()"/>
<mx:Button label="Update" click="save2()"/>
<mx:Button label="Delete" click="destroy2()"/>
<mx:Button label="Refresh" click="loadAll2()"/>
</mx:ApplicationControlBar>

<mx:DataGrid id="dg2" dataProvider="{comics}">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="Key"/>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="description" headerText="Description"/>
</mx:columns>
</mx:DataGrid>
<mx:Form >
<mx:FormItem label="Name">
<mx:TextInput id="Name2" text="{dg2.selectedItem.name}" />
</mx:FormItem>
<mx:FormItem label="Description">
<mx:TextInput id="Description2" text="{dg2.selectedItem.description}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>


That's All

Out Now!! Application Express 3.1.2

Anthony Rayner - 20 hours 32 min ago
APEX 3.1.2 is now available for download and fixes the following bugs. You can get hold of it by either:
  • Downloading the full version from OTN.

  • Download the patchset 7313609 from METALINK.
If your unsure about which download you need, please read Joel's blog. As Joel says, if your upgrading from any APEX version pre-3.1, then you'll need to use the full OTN release (which includes the version that comes pre-installed with 11gR1).

For details on future plans, please take a look at our Statement of Direction, which was updated just under 3 weeks ago with details of the 'Forms Converter' of APEX 3.2 and 'Websheets', 'Updateable Interactive Reports', 'Extensible Item Framework' and much more of APEX 4.0.

Happy patching!
Anthony.

Categories: Development

What's wrong with the Oracle Forum?

Denes Kubicek - Thu, 2008-08-28 08:12
As you probably noticed, the forums are either:

- not available at all or

- taking a lot of time to load or

- if they ever load, they are not working properly and showing errors if you try to create or update a posting.

If you manage to load those pages, you will notice that there are some new featueres implemented. Some of them are usefull. Like the new text editor (I realy like that one). Some of them are however questionable:

- the new reward system where you can get some points if you provide a helpfull or even a correct answer. The funniest thing is that the asker is supposed to say the answer someone provided is "correct".

- the fonts were changed to 11px which is not readable at all,

- the visited property they implemented are i.m.h.o. unneccessary because of the image showing if the posting was opened before or updated since. It is anoying too. Hard to read because of the grey color on a grey background.

I already asked the people who set it up if they are realy sure this makes sense. They didn't answer. Well, I am probably not the only one who asked.

Despite of the changes made, features I like or those I don't like, the most important thing though is the availability of the forum. And the fact is - it is not available since almost a week. Have they done a test before they upgraded? How did they test it? Did they ask the comunity about the changes? Maybe they should roll it back once again and consider a redisign using ApEx.

Categories: Development

Give Back/Help Out

Greg Pavlik - Wed, 2008-08-27 10:19
I (slightly) modified the right hand side of my blog to include some charities that I support. In some cases, I have good friends that have dedicated their professional lives to helping to build these organizations.

These don't even begin to scratch the surface of great organizations that offer great ways to help others. I listed these because I know a bit more about them personally and I'm confident that they do good (efficiently!). Another good friend, Edwin, recently added a blog post on Abilities United, which works with kids experiencing challenges in development and gives them special attention based on their needs. Take a careful look at Abilities United: they deserve support and all the help they can get.

Oracle Text in Five Short Steps

Denes Kubicek - Wed, 2008-08-27 06:10
Almost every application I create contains a BLOB (file) table for storing files available for a download. In the most of the cases it will store some documentation related to the application - user manuals, howto's and similar stuff. The download functionality is a nice thing but how about searching the content of those files? There are some examples arround showing how to do that in ApEx but in my opinion the most of them are far to complex. I created an example in my Demo Application, showing how to do that in less than five minutes:

http://apex.oracle.com/pls/otn/f?p=31517:76



This example includes the most frequently used functionalities:

1. mixed case search

2. highlighted snippets

3. index synchronization on commit

If you need more, you can always look into the Oracle Text Documentation.

Enjoy.

Categories: Development

Form Validation and User Friendly Messages

Denes Kubicek - Tue, 2008-08-26 17:10
I am getting this kind of questions quite often:

"I have report with form for modifications. After clicking on the link the form related to this report pops up. Often this is done by at least two users trying to modify one and the same record simultaneously. In such cases the application raises - "ORA-20001: Current version of data in database has changed since initiated update process. Error Unable to process row ....(table name)".

Could you give some advice or give and example how to handle this in a more user friendly manner?"

I created an example in my Demo Application showing how this can be done:

http://apex.oracle.com/pls/otn/f?p=31517:210

which also includes a step by step guideline.



There, you may test the validation by starting a concurrent update process and trying to update the data on the parent page.

Categories: Development

Oracle Forms running with MapViewer. Maps and Oracle Forms!!

Grant Ronald - Tue, 2008-08-26 13:15

Jacob Madsen from Brandsoft in Denmark has written a community white paper on how his company has integrated MapViewer with Oracle Forms. Having seen a demo from Jacob, its pretty amazing stuff. Highlighing a region on a map queries data into you Forms block from that map area.

You can get a copy of the paper here.

Categories: Development

How to use the Sun plug in with Oracle Forms

Grant Ronald - Tue, 2008-08-26 04:07

With Oracle Forms we are moving towards certification with the Sun plug-in. We already certify 1.4, 1.5 and 1.6 with various versions of Oracle Forms. If you want to know how to set up Oracle Forms to run with the Java Plug-in then you can read this article.

Categories: Development

JHeadstart R11 at Oracle Open World 2008

JHeadstart - Tue, 2008-08-26 03:04
JHeadstart will be present at Oracle Open World 2008 in San Francisco. With the upcoming JDeveloper release 11, and the progress we have made in the last months with JHeadstart release 11, we recently decided to make this a release-11... steven.davelaar
Categories: Development

Advanced Algorithm: Sequencing Dependencies

Kenneth Downs - Mon, 2008-08-25 06:56

Some database applications require you to perform a series of actions where you know only that some actions must be performed before others. Before you can perform the actions, you must work out a safe sequence that takes into account all of the dependencies. This week in The Database Programmer we will see an algorithm for doing this.

Examples

There are many examples where a programmer must work out dependencies before doing something.

A manufacturing package may track many steps in the manufacture of an item. Some steps cannot be performed until others are complete. A simple system would require the end-user to work out the entire process, but a better system would let the user enter only the dependencies: which processes require others to be complete. In this kind of system the computer can be used to schedule manufacturing tasks.

All popular Linux distributions have a package installation system in which each package lists its required dependencies. If you want to install a large number of packages in one shot, producing a tangled bunch of related dependencies, today's algorithm can be used to work them all out.

If you are using a data dictionary to build tables, every foreign key represents a dependency, where the child table requires the parent table to exist before it can be built. Today's algorithm can be used to sequence the tables and build them in order.

Another database example is generating code to perform calculations. Some calculations will depend on previous calculations, so your code generator must be able to sequence them all so that the calculations are performed in the proper order.

Big Words: Directed Acyclic Graph

The examples abvoe are all cases of what mathematicians call a Directed Acyclic Graph. If you do not want to read the entire Wikipedia article, the main points are these:

  • We have a set of items. These can be anything you are keeping track of in your database.
  • Any item may be connected to zero or more other items.
  • The connection is one-way only. So if we say A requires B, we are not saying that B also requires A (in fact it is forbidden).
  • There can be no loops (cycles). If A requires B, B may not require A. Further, if A requires B, and B requires C, C may not require A.

Whenever I can, I like to point out that it is very useful to read up on the mathematical foundations of certain programming techniques. We can often pick up very useful insights from those who think of these things at the most abstract level. It is also much easier to get advice from the more abstract-minded database people if you are at least marginally familiar with the mathematical terms.

The Tables

So now let us proceed to the tables and the code. The tables below show a data dictionary that will be used to generate DDL to build a database:

Table: TABLES

TABLE       | DESCRIPTION            | SEQUENCE
------------+------------------------+---------
ORDERS      | Sales Orders Headers   |  ?
ORDER_LINES | Sales order lines      |  ?
CUSTOMERS   | Customers              |  ?
ITEMS       | Items                  |  ?


Table: DEPENDENCIES

CHILD_TABLE  | PARENT_TABLE
-------------+---------------
ORDERS       | CUSTOMERS
ORDER_LINES  | ORDERS
ORDER_LINES  | ITEMS

The problem here is knowing the safe order in which to build the tables. If I try to build ORDER_LINES before I have built ITEMS, then I cannot put a foreign key onto ORDER_LINES, because ITEMS is not there. In short, I need to know the value of the SEQUENCE column in the example above.

The Expected Answer

The example above is simple enough that we can work it out by hand. This is actually a good idea, because we want to get an idea of what the answer will look like:

TABLE       | DESCRIPTION            | SEQUENCE
------------+------------------------+---------
ORDERS      | Sales Orders Headers   |  1
ORDER_LINES | Sales order lines      |  2
CUSTOMERS   | Customers              |  0
ITEMS       | Items                  |  0

This answer should be self-explanatory, except maybe for the fact that both CUSTOMERS and ITEMS have the same value. We need to look at that before we can see the code that produces it. Is it OK that two entries have the same value, and how would our program handle that?

The short answer is that it is perfectly OK and natural for two or more entries to have the same value. All this means is that they can be done in any order relative to each other, so long as they are done before the other entries.

In terms of the example, where we want to build these tables in a database, it means that:

  • We would query the list of tables and sort by SEQUENCE
  • We would loop through and build each table
  • We don't care about ITEMS and CUSTOMERS having the same value, they get built in whatever which-way the server gives us the list.

The same concept applies to the other potential examples: manufacturing, software packages, and generating calculations. So long as you follow the sequence, we don't care about items that have the same value.

Stating the Solution in Plain English

We are now ready to work out a program that will generate the SEQUENCE column. The basic steps the program must perform are:

  1. Initialize the column to -1. A value of -1 means "Not sequenced."
  2. Update the column to zero for all items that have no dependencies.
  3. Repeat the following action until the affected rows are zero: Update the SEQUENCE column to 1 (then 2, then 3) for all rows that have all of their dependencies sequenced already.
  4. Once the command in step 3 is no longer affecting any rows, check for any rows that have -1, these are involved in circular dependencies and we cannot proceed until the user straightens them out.
Stating the Solution in Code

The first step is very easy, we initialize the table with this command:

UPDATE TABLES SET SEQUENCE = -1;

The next step is also very easy, we mark with a '0' all of the tables that have no dependencies. The basic idea is to find all of the entries that have no entries in DEPENDENCIES.

UPDATE TABLES SET SEQUENCE = 0
 WHERE NOT EXISTS (SELECT child FROM DEPENDENCIES
                    WHERE child = TABLES.TABLE)

Now for the hard part. We now have to execute a loop. On each pass of the loop we are looking for all items whose dependencies have all been sequenced. We will do this over and over until the command is not affecting any rows. It is important that we cannot exit the loop by testing if all rows are sequenced, because a circular dependency will prevent this from happening and we will have an infinite loop.

You can control this loop from client code, but I wrote mine as a Postgres stored procedure. This algorithm turns out to be surprisingly complicated. The UPDATE command below may not be all that self-explanatory. What it works out is:

  • Get a list of child tables from the DEPENDENCIES table
  • JOIN through to TABLES to look at the SEQUENCE value of their parents.
  • Group and check that the minimum value is greater than zero, if it is it means all parents are sequenced and the table can be sequenced.
  • Update the SEQUENCE value for the tables we found
CREATE OR REPLACE FUNCTION zdd.Table_Sequencer() RETURNS void AS
$BODY$
DECLARE
    -- Note that rowcount is initialized to be > 0, this makes
    -- the loop work properly
    rowcount integer := 1;
    
    -- This tracks the value we are assigning to SEQUENCE.  We
    -- initialize it to 1 because we already took care of the
    -- the rows that have value 0
    lnSeq integer := 1;
BEGIN
    while rowcount > 0 LOOP
        UPDATE tables set SEQUENCE = lnSeq
          FROM (SELECT t1.CHILD 
                  FROM DEPENDENCIES t1 
                  JOIN TABLES       t2 ON t1.PARENT = t2.TABLE
                 GROUP BY t1.CHILD
                HAVING MIN(t2.SEQUENCE) >= 0
                ) fins
          WHERE TABLES.TABLE = fins.CHILD
            AND TABLES.SEQUENCE = -1;

  lnSeq := lnSeq + 1;
  GET DIAGNOSTICS rowcount = ROW_COUNT;
 END LOOP;
 
 RETURN;
END;
$BODY$
LANGUAGE plpgsql;

The stored procedure above will stop executing once the UPDATE command is no longer having any effect. Once that happens, your final step is to make sure that all rows have a valid SEQUENCE value, which is to say that no entry has SEQUENCE of -1. If any of the rows have that value then you have a circular dependency. You must report those rows to the user, and you can also report the dependencies that are causing the loop.

Conclusion

Sequencing dependencies is a fundamental algorithm that has a lot of use cases in database applications. It is easy enough to accomplish, but the innermost UPDATE command can be a little puzzling when you first look at it. Once you have mastered this algorithm you are on the way to the "big leagues" of database applications such as ERP, MRP and others.

Categories: Development

Flex upload and download with Blazeds

Edwin Biemond - Sun, 2008-08-24 15:59
With Actionscript 3 and Flashplayer 10 you can now use the new FileReference features. For example you download and upload a file with RemoteObjects ( Blazeds / LifeCycle ). In the early days you had to use a upload and download servlets.
To use the new FileReference features please read these two articles flexexamples.com and using flashplayer 10

Here are some screenshots of the flex application.
First we can upload a file. The datagrid show the status of the uploaded files.

Off course we can download some files from a remote server. First we need to get a list of the remote files. For this we need to press the Get remote files button.

We can select a file and press the Retrieve File Button. When the status is ready we can save this file by pressing the Save File Button.

Here you can download the Flex source code

The code of the upload panel

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" width="100%" height="100%"
title="Upload Files">


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

private var refUploadFile:FileReference;

private var UploadFiles:Array = new Array();


// Called to add file(s) for upload
private function addFiles():void {
refUploadFile = new FileReference();
refUploadFile.browse();
refUploadFile.addEventListener(Event.SELECT,onFileSelect);
refUploadFile.addEventListener(Event.COMPLETE,onFileComplete);
}

// Called when a file is selected
private function onFileSelect(event:Event):void {
UploadFiles.push({ name:refUploadFile.name,
size:formatFileSize(refUploadFile.size),
status:"initial"});
listFiles.dataProvider = UploadFiles;
listFiles.selectedIndex = UploadFiles.length - 1;

refUploadFile.load();
for ( var i:int = 0 ; i < UploadFiles.length ; i++ ) {
if( UploadFiles[i].name == refUploadFile ) {
UploadFiles[i].status = "loaded";
listFiles.dataProvider = UploadFiles;
break;
}
}
}

// Called to format number to file size
private function formatFileSize(numSize:Number):String {
var strReturn:String;
numSize = Number(numSize / 1000);
strReturn = String(numSize.toFixed(1) + " KB");
if (numSize > 1000) {
numSize = numSize / 1000;
strReturn = String(numSize.toFixed(1) + " MB");
if (numSize > 1000) {
numSize = numSize / 1000;
strReturn = String(numSize.toFixed(1) + " GB");
}
}
return strReturn;
}



private function onFileComplete(event:Event):void
{
refUploadFile = event.currentTarget as FileReference;
var data:ByteArray = refUploadFile.data;
var loader:Loader = new Loader();
loader.loadBytes(data);

var token:AsyncToken = AsyncToken(
remoteUpload.doUpload(data, refUploadFile.name)
);

token.kind = refUploadFile.name;

for ( var i:int = 0 ; i < UploadFiles.length ; i++ ) {
if( UploadFiles[i].name == refUploadFile ) {
UploadFiles[i].status = "upload";
listFiles.dataProvider = UploadFiles;
break;
}
}
}

private function uploadResultHandler(event:ResultEvent):void
{
for ( var i:int = 0 ; i < UploadFiles.length ; i++ ) {
if( UploadFiles[i].name == event.token.kind ) {
UploadFiles[i].status = "finished";
listFiles.dataProvider = UploadFiles;
break;
}
}
}

private function faultResultHandler(event:FaultEvent):void
{
for ( var i:int = 0 ; i < UploadFiles.length ; i++ ) {
if( UploadFiles[i].name == event.token.kind ) {
UploadFiles[i].status = "error";
listFiles.dataProvider = UploadFiles;
break;
}
}
}


]]>
</mx:Script>

<mx:RemoteObject id="remoteUpload" destination="FileUtils"
result="uploadResultHandler(event)"
fault="faultResultHandler(event)"/>


<mx:Canvas width="100%" height="100%">
<mx:DataGrid id="listFiles" left="0" top="0" bottom="0" right="0"
allowMultipleSelection="true" verticalScrollPolicy="on"
draggableColumns="false" resizableColumns="false" sortableColumns="false">
<mx:columns>
<mx:DataGridColumn headerText="File" width="150" dataField="name" wordWrap="true"/>
<mx:DataGridColumn headerText="Size" width="50" dataField="size" textAlign="right"/>
<mx:DataGridColumn headerText="Status" width="50" dataField="status" textAlign="right"/>
</mx:columns>
</mx:DataGrid>
</mx:Canvas>
<mx:ControlBar horizontalAlign="center" verticalAlign="middle">
<mx:Button id="btnAdd" toolTip="Add file(s)" click="addFiles()"
label="Upload Files" width="150"/>
</mx:ControlBar>
</mx:Panel>


The code of the download panel

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
width="100%" height="100%" title="Download Files">

<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.AsyncToken;

private var UploadFiles:Array = new Array();
private var UploadFilesColl:ArrayCollection = new ArrayCollection();
private var fileData:ByteArray = new ByteArray();
private var fileName:String;


private function uploadResultHandler(event:ResultEvent):void
{
if ( event.token.kind == "remoteFileList") {
UploadFilesColl = event.result as ArrayCollection;
for ( var i:int = 0 ; i < UploadFilesColl.length ; i++ ) {
UploadFiles.push({ name:UploadFilesColl[i]
, status:"initial"});
}
listFiles.dataProvider = UploadFiles;
} else {
fileData = event.result as ByteArray;
fileName = event.token.kind;
for ( var b:int = 0 ; b < UploadFiles.length ; b++ ) {
if( UploadFiles[b].name == event.token.kind ) {
UploadFiles[b].status = "Ready";
listFiles.dataProvider = UploadFiles;
break;
}
}

}
}

private function faultResultHandler(event:FaultEvent):void
{
}

private function saveFile(event:Event):void
{
var fileReference:FileReference = new FileReference();
fileReference.save(fileData,fileName);
}

private function getRemoteFiles(event:Event):void
{
var token:AsyncToken = AsyncToken(remoteDownload.getDownloadList());
token.kind = "remoteFileList";
}

private function getDownload(event:Event):void
{
var token:AsyncToken = AsyncToken(
remoteDownload.doDownload(listFiles.selectedItem.name));
token.kind = listFiles.selectedItem.name;
}
]]>
</mx:Script>


<mx:RemoteObject id="remoteDownload" destination="FileUtils"
result="uploadResultHandler(event)"
fault="faultResultHandler(event)"/>


<mx:Canvas width="100%" height="100%">
<mx:DataGrid id="listFiles" left="0" top="0" bottom="0" right="0"
verticalScrollPolicy="on"
draggableColumns="false" resizableColumns="false" sortableColumns="false">
<mx:columns>
<mx:DataGridColumn headerText="File" width="150" dataField="name" wordWrap="true"/>
<mx:DataGridColumn headerText="Status" width="50" dataField="status" textAlign="right"/>
</mx:columns>

</mx:DataGrid>
</mx:Canvas>
<mx:ControlBar horizontalAlign="center" verticalAlign="middle">
<mx:Button id="btnList" toolTip="List remote files"
width="150"
label="Get Remote Files"
click="getRemoteFiles(event)"/>
<mx:Button id="btnRetrieve" toolTip="Retrieve file"
width="150" click="getDownload(event)" label="Retrieve File"/>
<mx:Button id="btnSave" toolTip="Save file"
width="150" click="saveFile(event)" label="Save File"/>
</mx:ControlBar>



</mx:Panel>

The java code

package nl.ordina.flex;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

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

public class FileUtils {


public String doUpload(byte[] bytes, String fileName) throws Exception
{
fileName = System.getProperty("java.io.tmpdir") + "/" + fileName;
File f = new File(fileName);
FileOutputStream fos = new FileOutputStream(f);
fos.write(bytes);
fos.close();
return "success";
}

public List getDownloadList()
{
File dir = new File(System.getProperty('java.io.tmpdir'));
String[] children = dir.list();
List dirList = new ArrayList();
if (children == null) {
// Either dir does not exist or is not a directory
} else {
for (int i=0; i<children.length; i++) {
// Get filename of file or directory
dirList.add( children[i]);
}
}
return dirList;
}

public byte[] doDownload(String fileName)
{
FileInputStream fis;
byte[] data =null;
FileChannel fc;

try {
fis = new FileInputStream(System.getProperty("java.io.tmpdir") + "/" + fileName);
fc = fis.getChannel();
data = new byte[(int)(fc.size())];
ByteBuffer bb = ByteBuffer.wrap(data);
fc.read(bb);
} catch (FileNotFoundException e) {
// TODO
} catch (IOException e) {
// TODO
}
return data;
}
}

Add Rows to a Standard Tabular Form using Item Value

Denes Kubicek - Sun, 2008-08-24 09:36
There are many threads regarding this issue in the forum. Many of them without any answer. So, how do you add rows to your standard tabular form based on an item value?
If you follow this example:

http://apex.oracle.com/pls/otn/f?p=31517:209

you will see that you need three small adjustments to the standard process:

1. extend your SQL using UNION_ALL by adding a small SQL selecting NULL's from DUAL followed by CONNECT BY LEVEL <= :P1_ADD_ROWS_ITEM,

2. add a conditional branch, first in the sequence, passing a request ADD to your page

3. do a modification to the standard add rows process to add 0 rows

and there you go. You don't need to write a manual process to get that functionality
applied on your standard tabular form.



Enjoy.

Categories: Development

Cisco launches Russia/CIS fund

Greg Pavlik - Sun, 2008-08-24 00:10
Brent Marcus left a note that Cisco recently announced a Russia focused venture fund. I will be in Moscow in a few weeks and will try to get some first hand information to blog about.

Updated Oracle Forums - time to get into again

Dimitri Gielis - Sat, 2008-08-23 13:46
I just noticed that the Oracle Forums changed again to the new version.
Justin Kestelyn gives more information about the upgrade here.

There's a new pointing system going on, so people like Scott and John who were top posters in the APEX Forum can start again to get to that position ;-)

The new forum soft looks better than last time when it got upgraded (see my blog post about that upgrade here). It's a lot faster for me know, so that's already good. I did a reply to a question and everything went fine so far.
Categories: Development

Alternative Weekend Watching - ADF 11g Overview

Shay Shmeltzer - Fri, 2008-08-22 14:52
Tired of looking at the summer Olympics? Here is an alternative, watch the fastest and strongest Java development framework - Oracle ADF 11g. Last week I did a web seminar for our partners showing off Oracle ADF 11g - you... shay.shmeltzer
Categories: Development

APEX for 55+ people - The first steps

Dimitri Gielis - Fri, 2008-08-22 05:53
This article is following some previous articles:
- The concept (the idea)
- The landscape (more info about 55+ person and the environment)

So how do you start with a 55+ year old person to explain what APEX is, what it can do and how to use it?

We started with a meeting. I didn't use a ppt, just my laptop and my Apex instance.

I started with something he knew: Excel. I asked him an Excel file he uses a lot. Weeks before, we already discussed why APEX would be better in his case, so no time on that at this stage.
Before we turned the Excel into an Oracle technology, I started to explain more about the concept of an Oracle database and how it works. I believe it was important to explain the relationship between database - scheme / user - tables - relationships.

Next to do, getting an APEX account on apex.oracle.com and turning his Excel file into an APEX application. It's important to explain what's happening. Once the application was created and he understood what had been going on we played around with this app.

Next we agreed he had to read and try things in APEX himself:
- I told him to follow the Getting Started with Oracle Application Express guide
- Read documentation about APEX and its architecture.
- Run some demonstration Application which was showing more of the possibilities
- Send me mails and call if things were not clear

Now he knew more about it, but it wasn't as easy as I write here. It took some time to get familiar with it (so don't give up if you find the doc to difficult in the beginning!)
The theory is not everything, it's important that he tried things himself. So we started with the 2 Day + Application Express Developer’s Guide.
The problem with this guide however is that you already need to know quiet a bit about Oracle (especially SQL) to understand fully what's happening. Everything is well explained how to create the application, but his feedback was that it was not clear to him what all the SQL (and others) meant he had to type/do or what was going on at the different points in time.

He had the reflex to search himself for some things in the Application Express User’s Guide, but how to get rid of a table for ex isn't well explained. It's funny, all the steps are clearly in the guide, but if you don't know that "to delete" a table in Oracle is called "drop" you're in trouble. So most of the first questions I got were not about APEX itself, but more about the Oracle terminology.

At this time he had made several applications in APEX (from Excel and from the guide) and seen other examples.

We met again and discussed his evolution and what to learn next. I explained more about APEX and gave him his next exercise, which was one we use in our APEX beginners training.

After that he felt confident to do other exercises, so he tried more exercises related to his job.
But then we hit another problem. Knowing Oracle and how to create a good ERD (table design, relationships etc) are key for an APEX application. So we had to go over that as well...

Next post, next week: the good, the bad and the ugly!
Categories: Development

APEX Experts Panel at OOW on Sunday

Dimitri Gielis - Thu, 2008-08-21 16:11
On Sunday the two big Oracle user groups are organizing an APEX session.

Sunday, from 10.00-11.30, I'm hosting the Oracle Application Express SIG: Ask the Experts session for IOUG. Just like the last two years this will be your chance to ask questions to a panel of APEX experts.
I'm very pleased to announce this time my panel exists out of:
- Denes Kubicek, known for his famous APEX Demo Application and frequently poster in the APEX Forum
- Anton Nielsen, has an excellent knowledge of APEX, especially in the security area
- David Peake, Product Manager of Oracle Application Express
- John Scott, Oracle ACE and a well known contributor in the APEX Forum (posts as JES)
- Scott Spendolini, known name in the APEX community, and host of the ODTUG APEX Symposiums

Sunday, in the afternoon, Scott Spendolini is hosting the ODTUG Oracle Application Express Symposium session. Just as at Kaleidoscope different people come to talk about their APEX case studies. Apex Evangelists will also be in stage with one of our customers, AMGEN. We are 5th I believe and we'll talk about "Oracle Application Express--Power to the People". Most of the time Rich Mutell of Amgen will do the talking, but John and I will be there to do the intro and answer the more technical questions.

There'll be a lot of APEX sessions at Oracle Open World this year, as due to the large number some sessions overlap eachother, so you would need to make a choice which one you want to see! I might post my session schedule later, but it was a difficult choice to pick the sessions!

See you at OOW...
Categories: Development

Can Oracle Forms Run on WebLogic

Grant Ronald - Thu, 2008-08-21 05:20

I've been seeing this question come up more and more given recent events. Jan Carlin as posted a response to this.
The bottom line is that one element of the Oracle Application Server in release 11 (OC4J) will now be WLS. This affects Forms in a minimal way since Forms is a C process and only uses the Java container for serving up HTML and for comms management. So, Forms 11g, the next version, will run on a server which uses WLS. It doesn't mean your Forms 9i applications can now be run on some existing WebLogic versions.

Hope that addresses the questions for people.

Categories: Development