/* * Helma License Notice * * The contents of this file are subject to the Helma License * Version 2.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://adele.helma.org/download/helma/license.txt * * Copyright 1998-2007 Helma Software. All Rights Reserved. * * $RCSfile: File.js,v $ * $Author: czv $ * $Revision: 1.4 $ * $Date: 2007/02/07 23:37:23 $ */ /** * @fileoverview Default properties and methods of * the File prototype. */ /** * Define the global namespace if not existing */ if (!global.helma) { global.helma = {}; } /** * Constructor for File objects, providing read and * write access to the file system. * @class This class represents a local file or directory * @param {String} path as String, can be either absolute or relative to the helma home directory * @constructor */ helma.File = function(path) { var BufferedReader = java.io.BufferedReader; var File = java.io.File; var Reader = java.io.Reader; var Writer = java.io.Writer; var FileReader = java.io.FileReader; var FileWriter = java.io.FileWriter; var PrintWriter = java.io.PrintWriter; var EOFException = java.io.EOFException; var IOException = java.io.IOException; var IllegalStateException = java.lang.IllegalStateException; var IllegalArgumentException = java.lang.IllegalArgumentException var self = this; var file; try { // immediately convert to absolute path - java.io.File is // incredibly stupid when dealing with relative file names if (arguments.length > 1) file = new File(path, arguments[1]).getAbsoluteFile(); else file = new File(path).getAbsoluteFile(); } catch (e) { throw(e); } var readerWriter; var atEOF = false; var lastLine = null; var setError = function(e) { this.lastError = e; }; this.lastError = null; /** @ignore */ this.toString = function() { return file.toString(); }; /** * Returns the name of the file or directory represented by this File object. *

* This is just the last name in the pathname's name sequence. * If the pathname's name sequence is empty, then the empty * string is returned. * * @returns String containing the name of the file or directory * @type String */ this.getName = function() { var name = file.getName(); return (name == null ? "" : name); }; /** * Returns true if the file represented by this File object * is currently open. * * @returns Boolean * @type Boolean */ this.isOpened = function() { return (readerWriter != null); }; /** * Opens the file represented by this File object. * * @returns Boolean * @type Boolean */ this.open = function() { if (self.isOpened()) { setError(new IllegalStateException("File already open")); return false; } // We assume that the BufferedReader and PrintWriter creation // cannot fail except if the FileReader/FileWriter fails. // Otherwise we have an open file until the reader/writer // get garbage collected. try{ if (file.exists()) { readerWriter = new BufferedReader(new FileReader(file)); } else { readerWriter = new PrintWriter(new FileWriter(file)); } return true; } catch (e) { setError(e); return false; } return; }; /** * Tests whether the file or directory represented by this File object exists. * * @returns Boolean true if the file or directory exists; false otherwise * @type Boolean */ this.exists = function() { return file.exists(); }; /** * Returns the pathname string of this File object's parent directory. * * @returns String containing the pathname of the parent directory * @type String */ this.getParent = function() { if (!file.getParent()) return null; return new helma.File(file.getParent()); }; /** * This methods reads characters until an end of line/file is encountered * then returns the string for these characters (without any end of line * character). * * @returns String of the next unread line in the file * @type String */ this.readln = function() { if (!self.isOpened()) { setError(new IllegalStateException("File not opened")); return null; } if (!(readerWriter instanceof BufferedReader)) { setError(new IllegalStateException("File not opened for reading")); return null; } if (atEOF) { setError(new EOFException()); return null; } if (lastLine != null) { var line = lastLine; lastLine = null; return line; } var reader = readerWriter; // Here lastLine is null, return a new line try { var line = readerWriter.readLine(); if (line == null) { atEOF = true; setError(new EOFException()); } return line; } catch (e) { setError(e); return null; } return; }; /** * Appends a string to the file represented by this File object. * * @param {String} what as String, to be written to the file * @returns Boolean * @type Boolean * @see #writeln */ this.write = function(what) { if (!self.isOpened()) { setError(new IllegalStateException("File not opened")); return false; } if (!(readerWriter instanceof PrintWriter)) { setError(new IllegalStateException("File not opened for writing")); return false; } if (what != null) { readerWriter.print(what.toString()); } return true; }; /** * Appends a string with a platform specific end of * line to the file represented by this File object. * * @param {String} what as String, to be written to the file * @returns Boolean * @type Boolean * @see #write */ this.writeln = function(what) { if (self.write(what)) { readerWriter.println(); return true; } return false; }; /** * Tests whether this File object's pathname is absolute. *

* The definition of absolute pathname is system dependent. * On UNIX systems, a pathname is absolute if its prefix is "/". * On Microsoft Windows systems, a pathname is absolute if its prefix * is a drive specifier followed by "\\", or if its prefix is "\\". * * @returns Boolean if this abstract pathname is absolute, false otherwise * @type Boolean */ this.isAbsolute = function() { return file.isAbsolute(); }; /** * Deletes the file or directory represented by this File object. * * @returns Boolean * @type Boolean */ this.remove = function() { if (self.isOpened()) { setError(new IllegalStateException("An openened file cannot be removed")); return false; } return file["delete"](); }; /** * List of all files within the directory represented by this File object. *

* You may pass a RegExp Pattern to return just files matching this pattern. * * @example var xmlFiles = dir.list(/.*\.xml/); * @param {RegExp} pattern as RegExp, optional pattern to test each file name against * @returns Array the list of file names */ this.list = function(pattern) { if (self.isOpened()) return null; if (!file.isDirectory()) return null; if (pattern) { var fileList = file.list(); var result = []; for (var i in fileList) { if (pattern.test(fileList[i])) result.push(fileList[i]); } return result; } return file.list(); }; /** * Purges the content of the file represented by this File object. * * @returns Boolean * @type Boolean */ this.flush = function() { if (!self.isOpened()) { setError(new IllegalStateException("File not opened")); return false; } if (readerWriter instanceof Writer) { try { readerWriter.flush(); } catch (e) { setError(e); return false; } } else { setError(new IllegalStateException("File not opened for write")); return false; // not supported by reader } return true; }; /** * Closes the file represented by this File object. * * @returns Boolean * @type Boolean */ this.close = function() { if (!self.isOpened()) return false; try { readerWriter.close(); readerWriter = null; return true; } catch (e) { setError(e); readerWriter = null; return false; } }; /** * Returns the pathname string of this File object. *

* The resulting string uses the default name-separator character * to separate the names in the name sequence. * * @returns String of this file's pathname * @type String */ this.getPath = function() { var path = file.getPath(); return (path == null ? "" : path); }; /** * Contains the last error that occured, if any. * @returns String * @type String * @see #clearError */ this.error = function() { if (this.lastError == null) { return ""; } else { var exceptionName = this.lastError.getClass().getName(); var l = exceptionName.lastIndexOf("."); if (l > 0) exceptionName = exceptionName.substring(l + 1); return exceptionName + ": " + this.lastError.getMessage(); } }; /** * Clears any error message that may otherwise be returned by the error method. * * @see #error */ this.clearError = function() { this.lastError = null; return; }; /** * Tests whether the application can read the file * represented by this File object. * * @returns Boolean true if the file exists and can be read; false otherwise * @type Boolean */ this.canRead = function() { return file.canRead(); }; /** * Tests whether the file represented by this File object is writable. * * @returns Boolean true if the file exists and can be modified; false otherwise. * @type Boolean */ this.canWrite = function() { return file.canWrite(); }; /** * Returns the absolute pathname string of this file. *

* If this File object's pathname is already absolute, then the pathname * string is simply returned as if by the getPath() method. If this * abstract pathname is the empty abstract pathname then the pathname * string of the current user directory, which is named by the system * property user.dir, is returned. Otherwise this pathname is resolved * in a system-dependent way. On UNIX systems, a relative pathname is * made absolute by resolving it against the current user directory. * On Microsoft Windows systems, a relative pathname is made absolute * by resolving it against the current directory of the drive named by * the pathname, if any; if not, it is resolved against the current user * directory. * * @returns String The absolute pathname string * @type String */ this.getAbsolutePath = function() { var absolutPath = file.getAbsolutePath(); return (absolutPath == null ? "" : absolutPath); }; /** * Returns the length of the file represented by this File object. *

* The return value is unspecified if this pathname denotes a directory. * * @returns Number The length, in bytes, of the file, or 0L if the file does not exist * @type Number */ this.getLength = function() { return file.length(); }; /** * Tests whether the file represented by this File object is a directory. * * @returns Boolean true if this File object is a directory and exists; false otherwise * @type Boolean */ this.isDirectory = function() { return file.isDirectory(); }; /** * Tests whether the file represented by this File object is a normal file. *

* A file is normal if it is not a directory and, in addition, satisfies * other system-dependent criteria. Any non-directory file created by a * Java application is guaranteed to be a normal file. * * @returns Boolean true if this File object is a normal file and exists; false otherwise * @type Boolean */ this.isFile = function() { return file.isFile(); }; /** * Returns the time when the file represented by this File object was last modified. *

* A number representing the time the file was last modified, * measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970), * or 0L if the file does not exist or if an I/O error occurs. * * @returns Number in milliseconds since 00:00:00 GMT, January 1, 1970 * @type Number */ this.lastModified = function() { return file.lastModified(); }; /** * Creates the directory represented by this File object. * * @returns Boolean true if the directory was created; false otherwise * @type Boolean */ this.makeDirectory = function() { if (self.isOpened()) return false; // don't do anything if file exists or use multi directory version return (file.exists() || file.mkdirs()); }; /** * Renames the file represented by this File object. *

* Whether or not this method can move a file from one * filesystem to another is platform-dependent. The return * value should always be checked to make sure that the * rename operation was successful. * * @param {String} toFile as String, new pathname for the named file * @returns true if the renaming succeeded; false otherwise * @type Boolean */ this.renameTo = function(toFile) { if (toFile == null) { setError(new IllegalArgumentException("Uninitialized target File object")); return false; } if (self.isOpened()) { setError(new IllegalStateException("An openened file cannot be renamed")); return false; } if (toFile.isOpened()) { setError(new IllegalStateException("You cannot rename to an openened file")); return false; } return file.renameTo(new java.io.File(toFile.getAbsolutePath())); }; /** * Returns true if the file represented by this File object * has been read entirely and the end of file has been reached. * * @returns Boolean * @type Boolean */ this.eof = function() { if (!self.isOpened()) { setError(new IllegalStateException("File not opened")); return true; } if (!(readerWriter instanceof BufferedReader)) { setError(new IllegalStateException("File not opened for read")); return true; } if (atEOF) return true; if (lastLine != null) return false; try { lastLine = readerWriter.readLine(); if (lastLine == null) atEOF = true; return atEOF; } catch (e) { setError(e); return true; } }; /** * This methods reads all the lines contained in the * file and returns them. * * @return String of all the lines in the file * @type String */ this.readAll = function() { // Open the file for readAll if (self.isOpened()) { setError(new IllegalStateException("File already open")); return null; } try { if (file.exists()) { readerWriter = new BufferedReader(new FileReader(file)); } else { setError(new IllegalStateException("File does not exist")); return null; } if (!file.isFile()) { setError(new IllegalStateException("File is not a regular file")); return null; } // read content line by line to setup proper eol var buffer = new java.lang.StringBuffer(file.length() * 1.10); while (true) { var line = readerWriter.readLine(); if (line == null) break; if (buffer.length() > 0) buffer.append("\n"); // EcmaScript EOL buffer.append(line); } // Close the file readerWriter.close(); readerWriter = null; return buffer.toString(); } catch (e) { readerWriter = null; setError(e); return null; } }; /** * This method removes a directory recursively . *

* DANGER! DANGER! HIGH VOLTAGE! * The directory is deleted recursively without * any warning or precautious measures. */ this.removeDirectory = function() { if (!file.isDirectory()) return false; var arr = file.list(); for (var i=0; i
* Useful for passing it to a function instead of an request object. */ this.toByteArray = function() { if (!this.exists()) return null; var body = new java.io.ByteArrayOutputStream(); var stream = new java.io.BufferedInputStream( new java.io.FileInputStream(this.getAbsolutePath()) ); var buf = java.lang.reflect.Array.newInstance( java.lang.Byte.TYPE, 1024 ); var read; while ((read = stream.read(buf)) > -1) body.write(buf, 0, read); stream.close(); return body.toByteArray(); }; for (var i in this) this.dontEnum(i); return this; } /** @ignore */ helma.File.toString = function() { return "[helma.File]"; }; helma.File.separator = java.io.File.separator; helma.lib = "File"; helma.dontEnum(helma.lib); for (var i in helma[helma.lib]) helma[helma.lib].dontEnum(i); for (var i in helma[helma.lib].prototype) helma[helma.lib].prototype.dontEnum(i); delete helma.lib;