Binary Objects - Representing File Contents

Site Map
 
Home
 
Application Guide
  Quick Start
  PHP and ASP
  Writing Apps
  Applications
  Tutorials
    Replication
    Postgres Interface
    XML Processing
    Using XPath
    Binary Object
    Using HttpRequest
    SmtpRequest
    Session
    Meta Data
    Iterators
    Memb Services
    Page Look&feel
    Authentication+
    Questionnaires
    Message Groups
    Form Handling
  Samples
Reference
Community
Contact Whitebeam
To-Do
Download
Credits
Licence
Whitebeam Users
 
 
 

Binary Objects - Representing File Contents

Subject

This tutorial discusses the use of the Whitebeam 'Binary' class, how to use the class to read and manipulate file data, transfer data between browser, templates and the file system. The following topics are covered:


Overview

The Whitebeam System provides a special JavaScript class called Binary. This class is used to encapsulate 'foreign' data. The object contains data in any format - the size of the data only being limited by available memory. The data itself can be anything and is treated by the system as an opaque (i.e. has no meaning to the system) sequence of octets.

Binary objects are commonly used to contain the contents of a file - either a real one or the contents of a file pushed from a client side application (e.g. a web browser). For most applications the Presentation Page doesn't need to directly access the data within the object. It is often simply carried either from the file system to the client, the client to a template or a template to the client. The data itself is never actually inspected.

There are two ways that a Binary object can be created. The simplest - but least common - is by using the new JavaScript operation. The other is for them to be created by other operations within the system. For example a template method can be defined to return a Binary object. When the method is invoked it will return an instance of the Binary class.

The Binary Object class defines a number of methods that can be used to manipulate binary objects and their contents.

The Binary object can be used for many applications. The following is not meant to be a complete list - and is for information only.

Receiving 'Files' From Users.

The HTTP protocol allows clients to send files to the application using the 'POST' method. The end-user selects a file from the file system and the client application sends the name, mime-type and contents of that file to the web server. Because files can contain arbitrary data the client must know to use a special 'encoding' in order to send the data to the application. This is known as a 'multi-part mime' encoding. You tell the client to use this encoding using the 'enctype' attribute on the <form.../> HTML tag. For example - suppose an application allows a user to upload a picture (eg GIF) file of themselves as part of a user profile. The HTML form tag might look like:

<form action="profile.rhtm" method="post" enctype="multipart/form-data">
   ...
</form>

The important parts of this tag are the method (must be "POST") and the enctype, (must be "multipart/form-data").

In the Whitebeam environment the application gets the contents of that file using the rb.page.formdata(). This method creates an object with a property for each parameter send from the client browser. Where that parameter is a file the method creates an instance of the Binary object.

If you don't set the method and enctype as described above the files - if loaded at all will appear as simple JavaScript strings.

Sending 'Files' To Users

This is the opposite operation from that described above. In this case there exists some file on the server that needs to be sent to the client from a Presentation Page. The most common example of this a Presentation Page that provides authenticated access to things like images. The following Presentation Page fragment will load an file from the file system and send it to the browser:

var filecontents = new Binary();
filecontents.load("picture.gif");
rb.page.setMimeType("image/gif");
rb.page.writeraw(filecontents);

Storing Data in the File Template

The File template stores arbitrary data in a conceptual file. The primary intention of this template is to store things like 'GIF' images of product items. In practice it can store any set of data - up to a maximum of 120Kbytes. A template 'file' therefore provides an excellent place to store sets of application data in a consistent and persistent way.

It is also possible to store Metadata in the file template using exactly the same model as for storing Metadata in templates (such as Catalogue). However the benefit in using the file template is that it allows much larger objects to be stored (up to about 120Kbytes). The Presentation Page can store the data in the object using the bin.fromObj() method, store the resulting binary object in the File template using rb.file.create() method and subsequently recover that data using the bin.toObj() method.

Creating a 'File' in a Binary

In content management applications you may wish to dynamically create HTML or XML text and save it in the File template for subsequent display. This is quite easy to accomplish. Assuming that the variable docText is a string that holds the dynamically created document:

var filecontents = new Binary();
filecontents.set(docText);
filecontents.mime("text/html"); // Give it a mime type and
filecontents.fname("generated.xml"); // a name

and then doing an rb.file.create() will save the dynamically created file using the File template. So - for example - to store the above file in the database you might use the following code:

// Get the uploaded file from the form data.
var params = rb.page.formdata();

// Find the file from the name we gave the <input file
// element in the form tag.
var theFile = params.uploadFile;

// Now create a database entry for this file.
var fileDescr = new Object;
fileDescr.name = 'Fred Bloggs Profile Picture';
fileDescr.owner = 'Application';
fileDescr.description = '';
fileDescr.fileDef = theFile

// Finally - call the template to store the image in the database for us.
var fileId = rb.file.create(fileDescr);

// The method returns the ID of the newly created file object. This
// needs to be stored so we can find the file again later! Generally
// this ID would be stored in a catalogue item or a contact record -
// in the meta data for those objects.

Supposing we'd stored the returned ID in the contact record for this user we can send it back to the client browser using something like the following code.

// The user ID is a parameter called 'userId' passed from the browser - get it
var params = rb.page.formdata();
var userId = params.userId;
if (userId!=null) {
   // Load the contact record.
   var usr = rb.contact.individualInfo(userId);
   if (usr==null)
      rb.debug.error('Invalid userId from client');

   // Have the user - get the fileID.
   var fileId = usr.customData.profileImage;
   if (fileId>0) {
      // Load the file from the database.
      var fileIterator = rb.file.get({fileID:fileId});
      if (fileIterator.getNextRow()) {
         // The file is in fileIterator.fileDef - a Binary object.
         // Assuming this is a display page - write it to the user
         // using the 'writeraw' method.
         rb.page.setMimeType(fileIterator.fileDef.mime());
         rb.page.sendHTTPheaders();
         rb.page.writeraw(fileIterator.fileDef);
      }
   }
}

The above example illustrates the entire cycle of uploading a file from browser - storing that in the file template and then writing it back to a client. Obviously any data can be stored in the file object itself. Common examples are data created by the application itself, including complex, serialised JavaScript objects, audit logs, reports etc that can subsequently be retrieved.

Mime Types and Arbitrary, non-HTML output

The example above also illustrates how to write arbitrary data to a client in such a way that the client can correctly deal with it. File contents are nominally identified to the client via a 'mime-type'. By default the mime-type is set to 'text/html' - so if you want to write some other kind of data you must first set the correct mime type for your application. This could be either an image (image/gif) or just plain text (text/plain) that you don't want the browser to treat as HTML.

Generally having set the mime-type to something other than HTML, you will want to send your data (of course!). By default the Presentation Engine is constructing output as it executes the page. While it is perfectly possible to write the Presentation Page generating only the output you want. a much easier way is to call the rb.page.writeraw() method. This bypasses all the XML/HTML processing of the Presentation Engine and writes data directly to the client. Note however that if you use this you should call rb.page.sendHTTPheaders() first. If you don't then you are limited to one call the rb.page.writeraw (because the browser will be told how much data to receive in the first chunk and not wait for any more).

Once you'v called rb.page.sendHTTPheaders you can call rb.page.writeraw as many times as you like. Each call results in data being sent directly to the client. This is a very useful technique if you have a page that takes a very long time to execute, such as a long report - you can construct a page that is continually updated.

Advantages of Binary Objects and the File template

The Whitebeam environment is designed to be very highly scaleable - to allow the capacity of the data center to be extended simply by the addition of a new front-end processor (FEP). In order to achieve the scaleability in the most efficient way all the FEPs must be identical. In turn, to achieve this, the FEPs must be stateless. Using the database to store files achieves this - one FEP can store a file in the database and the next moment a separate FEP can retrieve this data.

Whitebeam release 1.3.27
(loadtime : 14ms)