BUI: Interacting with client files

Implementation Notes

The BBj subsystem that interacts with files on the client includes the following:

The BBj Java-based client is allowed to freely interact with the client filesystem. The BBj BUI client, on the other hand, runs as JavaScript inside a browser.  It has to live within significant constraints imposed by the browser security model.  In particular:

FILEOPEN (MODE="CLIENT")

The BUI client-side file chooser is implemented using the HTML <input type="file">.  We can't select directories or specify a particular directory; directory information is hidden from browser applications.  In Chrome on the Mac, the FILEOPEN() dialogue looks like this:

When the user clicks the "Choose File" button, the browser brings up a native file chooser:

When the user selects a file, the file name is displayed next to the button:

When the user clicks OK, the browser sends the selected file (along with a hidden field identifying the current BBj session) to the server, where it can be made available to the BBjClientFileSystem.  This is a key point:  BBjClientFile methods that retrieve information about the file [e.g.: BBjClientFile::size()] actually interact with this copy of the file on the server, not with the original file on the client.  This is because browsers do not allow programmatic access to arbitrary client files; they only allow for uploading files to the server when those files are chosen interactively by the user in a very controlled situation.

FILESAVE (MODE="CLIENT")

The FILESAVE() dialogue is identical to the FILEOPEN() dialogue, with the addition of a text field where the user can type in a file name.  If the user selects a file using the "Choose File" button, the simple file name (stripped of directory information) is copied to the text field; the user can accept it as is or edit it before clicking the OK button.  The BUI FILESAVE() works like the FILESAVE() in other environments:  It doesn't transfer any files; it just returns a file name to the application.

Methods of BBjFileChooser (Client)

Return Value

Method

void

addFileFilter(string name, BBjVector filters!)

addFileFilter(string name, string filter)

Fully supported.  With the client-side file chooser, setting a filter does not affect which files may be selected by the user.  When the user clicks OK, the selected filename(s) are compared to the current filter; the selection is only allowed if all selected filename(s) match the filter.

void

approveSelection()

Fully supported.

void

cancelSelection()

Fully supported.  Clears any selected filename(s) and anything typed into the SaveAs filename field.

void

changeToParentDirectory()

Ignored.

void

ensureFileNameIsVisible(string name)

Ignored.

string

getActiveFileFilter()

Fully supported.

string

getApproveButtonText()

Fully supported.

boolean

getControlButtonsAreShown()

Fully supported.

string

getCurrentDirectory()

Returns "".

BBjVector

getFileFilterContents(string name)

Fully supported.

BBjVector

getFileFilterNames()

Fully supported.

int

getFileSelectionMode()

Returns whatever value was set, but has no effect on the file chooser.  It's not possible to select directories with the client-side file chooser.

string

getSelectedFile()

Fully supported.

BBjVector

getSelectedFiles()

Fully supported.

boolean

isAcceptAllFileFilterUsed()

Fully supported.

boolean

isMultiSelectionEnabled()

Fully supported.

void

removeFileFilter(string name)

Fully supported.

void

rescanCurrentDirectory()

Ignored.

void

setAcceptAllFileFilterUsed(boolean used)

Fully supported.

void

setActiveFileFilter(string name)

Fully supported.

void

setApproveButtonText(string text)

Fully supported.

void

setControlButtonsAreShown(boolean shown)

Fully supported.

void

setCurrentDirectory(string name)

Ignored.

void

setFileSelectionMode(int mode)

Ignored.

void

setMultiSelectionEnabled(boolean enabled)

Fully supported.

void

setSelectedFile(string file)

Fully supported for the FILESAVE version.

Ignored for the FILEOPEN version.

void

setSelectedFiles(BBjVector files!)

The first item in the list sets the FILESAVE filename.

Ignored for the FILEOPEN version.

Methods of BBjAPI

Return Value

Method

BBjThinClient

getThinClient

Returns a BUI-specific version of BBjThinClient with the ability to interact with the browser.

Methods of BBjThinClient

Return Value

Method

void

browse(string url)

Opens the given URL using Window.open().

int

clientExec(string command)

clientExec(string command, string workingDir)

Rudimentary plumbing is in place, but it doesn't actually do anything useful at this point; it just displays the command string in an alert dialogue.  It's not clear what we can do with this in a browser.

string

getClientBBjVersion()

Returns the server BBj version.

string

getClientBuildDate()

Returns the server BBj build date.

BBjClientFileSystem

getClientFileSystem()

Returns a BUI-specific version of BBjClientFilesystem with the ability to interact with the browser.

string

getClientIPAddress()

Returns the browser client IP address.

string

getClientJavaVersion()

Returns the server Java version.

string

getClientName()

Returns the browser client name.

string

getClientOSName()

Returns the OS Name at the bridge layer.

string

getClientOSVersion()

Returns the server OS Version.

string

getClientPortID()

Returns the server BBj Port ID.

boolean

isInServerJVM()

Returns false.

Methods of BBjClientFileSystem

Return Value

Method

BBjClientFile

getClientFile(BBjClientFile parentDir, string filename)

getClientFile(string filename)

Returns a BBjClientFile object associated with the specified file name, which is treated as a raw string.  Think of the file name as a key to a list, which is in fact what it is -- a string key to a list of files stored within the web server.  The parent directory (if specified) is ignored.  The file name is not validated in any way when the BBjClientFile is constructed.

BBjClientFile

getHomeDirectory()

Returns null.  Browsers have no access to the user's actual home directory.

BBjVector

getRoots()

Returns a single value, "".  Browsers don't return path information, just plain file names.

Methods of BBjClientFile

Return Value

Method

boolean

canRead()

If the file exists in the web server cache, returns whether that copy of the file can be read (presumably this would always be true).  If the file does not exist in the web server cache, returns false.

boolean

canWrite()

If the file exists in the web server cache, returns whether that copy of the file can be written (presumably this would always be true).  If the file does not exist in the web server cache, returns false.

string

copyFromClient()

If the file exists in the web server cache, copies it to a temporary file on the server and returns the temporary server file name.  If the file does not exist in the web server cache, throws !ERROR=12.

void

copyToClient(string serverFilename)

If serverFilename exists, this copies it to the web server cache, then hands it off to the browser, where it will typically be downloaded to the client's Downloads directory.  When the browser has downloaded the file, it is removed from the web server cache.

boolean

createNewFile()

Creates a new file in the web server cache.

boolean

delete()

Deletes the file in the web server cache.

boolean

exists()

Returns whether the file exists in the web server cache.

BBjClientFile

getCanonicalFile()

Returns this same BBjClientFile object; the canonical file name is always equal to the file name.

string

getContents()

If the file exists in the web server cache, returns the contents.  If the file does not exist in the web server cache, throws !ERROR=12.

string

getName()

Returns the file name.

BBjClientFile

getParent()

Returns null.

string

getPath()

Returns the file name.

boolean

isDirectory()

If the file exists in the web server cache, returns whether it's a directory (probably not).  If the file does not exist in the web server cache, returns false.

boolean

isFile()

If the file exists in the web server cache, returns whether it's a file (probably true).  If the file does not exist in the web server cache, returns false.

boolean

isHidden()

If the file exists in the web server cache, returns whether it's hidden (probably not).  If the file does not exist in the web server cache, returns false.

long

lastModified()

If the file exists in the web server cache, returns the last modified time.  If the file does not exist in the web server cache, returns 0.

BBjVector

listFiles()

It's not currently possible to manipulate client directories; throws !ERROR=17.

boolean

mkdir()

This is a no-op; returns false.

boolean

mkdirs()

This is a no-op; returns false.

boolean

renameTo(BBjClientFile newName)

If the new filename does not already exist in the web server cache, renames this file to the new name.  If the new filename already exists in the web server cache, returns false.

void

setContents(string contents)

Sets the contents of the the web server cache file to the specified string, then copies the updated file to the client (see notes under copyToClient above).

void

setLastModified(long time)

Updates the last modified time of the file in the web server cache.

void

setReadOnly()

This is a no-op; returns false.

long

size()

If the file exists in the web server cache, returns the file size.  If the file does not exist in the web server cache, returns 0.

Test program

http://screencast.com/t/JvnYN83X0WvJ

rem ' clientfile.txt

tc! = bbjapi().getThinClient()

fs! = tc!.getClientFileSystem()

i = msgbox("Test client fileopen + copy file from client to server")

clientfile$ = fileopen("Pick a client file","","","",mode="client")

i = msgbox(clientfile$,0,"Selected client file")

if pos("::"=clientfile$) then goto eoj

cf! = fs!.getClientFile(clientfile$)

i = msgbox("Copy "+clientfile$+" to the server")

serverfile$ = cf!.copyFromClient()

serverfile = unt

open (serverfile)serverfile$

serverfile$ = fid(serverfile)(9)

bytes = dec(fin(serverfile)(1,4))

close (serverfile)

i = msgbox("Copied client file "+clientfile$+" to server file "+serverfile$+" ("+str(bytes)+" bytes)",0,"Copied from client to server")

i = msgbox("Test server fileopen + copy file from server to client")

serverfile$ = fileopen("Pick a server file","","","")

i = msgbox(serverfile$,0,"Selected server file")

if pos("::"=serverfile$) then goto eoj

clientfile! = new java.io.File(serverfile$)

clientfile$ = clientfile!.getName()

clientfile$ = filesave("Save to client","",clientfile$,"",mode="client")

if pos("::"=clientfile$) then goto eoj

i = msgbox("Copy server file "+serverfile$+" to client file "+clientfile$)

cf! = fs!.getClientFile(clientfile$)

cf!.copyToClient(serverfile$)

i = msgbox("Copied server file "+serverfile$+" to client file "+clientfile$,0,"Copied from server to client")

eoj:

release

Known Issues