Wednesday 28 May 2008

Flex File Upload using Grails Backend

This file upload application is based off the one by Nocturnal at Coding Cowboys, a Flex client with a PHP backend. The client has been stripped down to it's core functions and PHP replaced with a Grails backend.

The Grails backend is a file controller with an action defined:

def upload = {
if(request.method == 'POST') {
Iterator itr = request.getFileNames();

while(itr.hasNext()) {
MultipartFile file = request.getFile(itr.next());
File destination = new File(file.getOriginalFilename())

if (!file.isEmpty()) {
file.transferTo(destination)
// success
}
else
{
// failure
}
}

// Trigger an Event.COMPLETE event, notifying the Flex client
response.sendError(200,'Done');
}
}


This is capable of uploading multiple files at once and can be tested using a view gsp:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Test Upload</title>
</head>
<body>
<div class="body">
<h1>Upload File</h1>
<g:form method="post" action="upload" enctype="multipart/form-data">
<input type="file" name="file_1"/><br/>
<input type="file" name="file_2"/><br/>
<input type="file" name="file_3"/><br/>
<input type="file" name="file_4"/><br/>
<input type="file" name="file_5"/><br/>
<input type="submit"/>
</g:form>
</div>
</body>
</html>


The Flex client has been pared down to 3 main functions, adding files to the upload list, removing them from the list and finally uploading the files to the server.

First the imports, global variables and initializer:

import mx.controls.*;
import mx.managers.*;
import mx.events.*;
import flash.events.*;
import flash.net.*;

// Convention: Underscore to differentiate global and local variables
private var _refAddFiles:FileReferenceList;
private var _refUploadFile:FileReference;
private var _arrUploadFiles:Array;
private var _numCurrentUpload:Number;

private function initApp():void {
_refAddFiles = new FileReferenceList();
_refAddFiles.addEventListener(Event.SELECT, onSelectFile);
_arrUploadFiles = new Array();
_numCurrentUpload = 0;
}


The add-files function opens the browse window and enable the selection of one or more files to add to the upload list:

// Called to add file(s) for upload
// The fileList property is populated anew each time browse() is called on that FileReferenceList object.
private function addFiles():void {
_refAddFiles.browse();
}

// Called when file(s) are selected
private function onSelectFile(event:Event):void {
// Add files to _arrUploadFiles
if (_refAddFiles.fileList.length >= 1) {
for (var k:Number = 0; k < _refAddFiles.fileList.length; k++) {
_arrUploadFiles.push({
name:_refAddFiles.fileList[k].name,
size:formatFileSize(_refAddFiles.fileList[k].size),
file:_refAddFiles.fileList[k]});
}
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = _arrUploadFiles.length - 1;
}
}


The remove-files function:

private function removeFiles():void {
var arrSelected:Array = listFiles.selectedIndices;
if (arrSelected.length >= 1) {
// Null selected files
for (var i:Number = 0; i < arrSelected.length; i++) {
_arrUploadFiles[Number(arrSelected[i])] = null;
}

// Remove the null entries
for (var j:Number = 0; j < _arrUploadFiles.length; j++) {
if (_arrUploadFiles[j] == null) {
_arrUploadFiles.splice(j, 1);
j--;
}
}
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = 0;
}
}


The upload function is where the point of integration with Grails is, in the request calling up the controller. Although the Grails backend can handle multiple files, Flex can only initiate the upload one file at a time. The event listener and the return response in the Grails controller allow the upload function to loop:

private function uploadFiles():void {
if (_arrUploadFiles.length > 0) {
listFiles.selectedIndex = _numCurrentUpload;

var request:URLRequest = new URLRequest();
request.data = sendVars;
request.url = "http://localhost:8080/App/file/upload";
request.method = URLRequestMethod.POST;
_refUploadFile = new FileReference();
_refUploadFile = listFiles.selectedItem.file;
_refUploadFile.addEventListener(Event.COMPLETE, onUploadComplete);
_refUploadFile.upload(request, "file", false);
}
}

private function onUploadComplete(event:Event):void {
_numCurrentUpload++;
if (_numCurrentUpload < _arrUploadFiles.length) {
uploadFiles();
} else {
_numCurrentUpload = 0;
_arrUploadFiles = new Array();
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = 0;
Alert.show("Files have been uploaded", "Upload Complete");
}
}


And lastly the UI:

<mx:Panel title="Files Upload" width="100%" height="100%">
<mx:DataGrid id="listFiles" allowMultipleSelection="true" verticalScrollPolicy="on"
draggableColumns="false" resizableColumns="false" sortableColumns="false" width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn headerText="File" dataField="name" wordWrap="true"/>
</mx:columns>
</mx:DataGrid>

<mx:ControlBar>
<mx:Button label="Add" click="addFiles()"/>
<mx:Button label="Remove" click="removeFiles()"/>
<mx:Button label="Upload" click="uploadFiles()"/>
</mx:ControlBar>
</mx:Panel>


The Flex mxml/swf files must be moved to the web-app folder of the Grails project and the embedded Jetty activated by 'grails run-app' in order to run this application.

The files will be uploaded to the project directory and thus are not accessible by the webapp. The line to amend is in the Grails controller:

File destination = new File("web-app/" + file.getOriginalFilename())

Note this only works while the project is in development mode. For war files, the base directory would depend on where the server is started, usually in the server home directory. So for a standalone Jetty server, the path to add would be "webapps/App/".

Using the war file in a Tomcat server has been problematic. Only one file can be successfully uploaded to the server, there is no looping.

Links:
Coding Cowboys: Flex upload component

Flex Client:
http://livedocs.adobe.com/flex/3/langref/flash/net/URLRequest.html
http://livedocs.adobe.com/flex/3/langref/flash/net/FileReference.html
http://livedocs.adobe.com/flex/3/langref/flash/net/FileReferenceList.html
http://livedocs.adobe.com/flex/3/html/help.html?content=17_Networking_and_communications_7.html

Grails Backend:
http://www.grails.org/Controllers+-+File+Uploads
http://docs.codehaus.org/display/GRAILS/File+Upload

Friday 23 May 2008

Flex Training - Last bit

Used list-based controls that accept a data array and display out depending on design. Then dealt with data forms, accepting user input, validating it and supposedly entering it into the database.

The last bit was how to create a release version of the Flex application.

Thursday 22 May 2008

Flex Training - Dynamic Data

Read an XML file using a HTTPService and displayed it. Autogenerated a PHP XML service based on database contents previously inserted. The Flex application was supposed to use the service to access the data in the database and display it on the page. However seems there's a problem with the service.

The videos make use of MAMP, a Mac-Apache-MySQL-PHP all-in-one webserver. There may be conflicts with the MySQL that was previously installed and the MAMP's version.

Wednesday 21 May 2008

Flex Training - Debugging and Event Handling

Debugging - How to set breakpoints and traces (logging to console). The breakpoints suspend the application, allowing one to see the variables and objects present at that particular time.

Event Handling - Dealing with events and how to listen for them. One can also create custom events. With a breakpoint, the anatomy of an event can be explored, showing the specific variables and the inherited ones that make up the event.

Tuesday 20 May 2008

Flex Training - 3 chapters down

Learned layouts, CSS and layered views.

VBox, HBox, Canvas and Panel layouts place their content vertically, horizontally or using absolute positioning.

A feature of the Flex CSS is embedding font(s) into the application so that the look remains the same for all. The drawback to that is the increased size of the application.

There are three layered view components, the ViewStack, TabNavigator (which extends ViewStack) and Accordian. The latter two contain their own switching mechanism, the first has to include in custom code utilizing the selectedIndex or selectedChild properties or one of these four bars: TabBar, LinkBar, ButtonBar and ToggleButtonBar.

Friday 16 May 2008

Flex Training - Of custom components and state changes

Went through the creation of a basic custom component and how to use it in a application project.

More information on the Design perspective, explaining the different areas such as the properties and controls. Designed view states that allow a login form to become a register form by a push of a button and vice versa.

Wednesday 14 May 2008

Flex Training - Day 2

Going into interesting territory. An explanation of the current programming language used, ActionScript 3, is given along with how MXML translates to it and vice versa. It then shows the visual design and their controls, correlating it with the mxml source that shows up as you drag and drop controls on the design.

Found out what was up with the bindable tags that are appended to ActionScript variables. Bindable enables a variable to broadcast its content when updated, alerting the elements that listen for and display or use such content. By default ActionScript variables are not bindable and each and every one must be appended for all to be bindable. MXML variables (eg. mx:Number) are automatically bindable however.

Tuesday 13 May 2008

Flex Training

Assisting in VMWare Server, Ubuntu 8.04 Server edition and Drupal installation took up the better part of the day. The Server edition was not necessary, however the Desktop edition downloaded cannot be used due to corruption/incomplete transfer. The advantage of the Server edition is that it allows the setup of the mail, LAMP and OpenSSH servers automatically, thus mail works and ssh to the installed OS is possible. The downside is that the user interface is the command-line. This is rectified by following How to install GNOME on Ubuntu Server
specifically these lines:


sudo apt-get update

sudo apt-get install ubuntu-desktop
sudo apt-get install gdm
sudo /etc/init.d/gdm start
sudo dpkg-reconfigure xserver-xorg


The resulting download is over 300MB, so it will take some time to finish with the process. In the meanwhile, one will have to suffer with the command-line ;).

After that, Flex training took up the rest of the day. Started out on the easy side, going over the 'Introduction' and 'Getting Started' videos. Mostly reinforcing what was already known, though there were a few interesting bits, like making full use of a two-monitor setup by detaching some of the Flex windows from the main application and putting it in the spare screen area. Then one can save that perspective and reuse it. It is applicable to Eclipse as well, seeing that the Flex Builder is built on it.

Wednesday 7 May 2008

Fisheye

Found the effect we're looking demoing here. The actual component is found here. Now to discover how to include it in the project.

Links of Interest:
Example: Flex Recipe App MXML for Drupal

Tuesday 6 May 2008

Flex and Drupal

The services module is responsible for exposing the Drupal data to any external app, with the amfphp module adding that particular functionality. The image, img_assist, pathauto and token modules are used to add images and text descriptions to Drupal. The views module has methods available in the services module, making it convinient to call.

Pulling the data from drupal yields a filepath for the image, the actual file is displayed by adding the IP address to the filepath, e.g. http://10.10.3.131/drupal5/files/images/pic.jpg.

Links of interest:
Reading And Writing Drupal With Flex
Howto: Ubuntu Linux convert DHCP network configuration to static IP configuration

Monday 5 May 2008

Setting up a test Drupal site

The old Gutsy Gibbon VM was totally screwed up so the Hardy Heron server edition was installed on a new one. It has Drupal 5.7 in the apt-get packages and so installation was a breeze. One thing it should have mentioned was the need to hit the install page, http://ip/drupal5/install.php, to initialize the db and everything else.

Turning clean urls on was as simple as typing two lines of code:
sudo a2enmod rewrite
sudo /etc/init.d/apache2 restart


Then testing the clean urls and turning it on. This may be Ubuntu-specific though.

A bunch of modules were downloaded and installed:
amfphp
cck
image
img_assist
pathauto
services
swfaddress
token
views

The amfphp is a plugin that requires the implementation available here.

Friday 2 May 2008

Dupal CMS with Flash/Flex Frontend

Found a site, cascadingStyle, that talks about Druplash and Druplex (Drupal-powered Flash and Flex) sites and has a presentation pdf available on that subject. The pdf lists two sites, Steven W. Merrill, Tenor and Martin Engineering, running on Drupal+Flash.

Three Drupal modules, SWFAddress, Services, AMFPHP are required to go about 'flashing' the site.

Here is another take on the subject, using the same modules.