/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Norris Boyd * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ import org.mozilla.javascript.*; import java.io.*; import java.util.List; import java.util.ArrayList; /** * Define a simple JavaScript File object. * * This isn't intended to be any sort of definitive attempt at a * standard File object for JavaScript, but instead is an example * of a more involved definition of a host object. * * Example of use of the File object: *
* js> defineClass("File")
* js> file = new File("myfile.txt");
* [object File]
* js> file.writeLine("one"); only now is file actually opened
* js> file.writeLine("two");
* js> file.writeLine("thr", "ee");
* js> file.close(); must close file before we can reopen for reading
* js> var a = file.readLines(); creates and fills an array with the contents of the file
* js> a;
* one,two,three
* js>
*
*
*
* File errors or end-of-file signaled by thrown Java exceptions will
* be wrapped as JavaScript exceptions when called from JavaScript,
* and may be caught within JavaScript.
*
* @author Norris Boyd
*/
public class File extends ScriptableObject {
/**
*
*/
private static final long serialVersionUID = 2549960399774237828L;
/**
* The zero-parameter constructor.
*
* When Context.defineClass is called with this class, it will
* construct File.prototype using this constructor.
*/
public File() {
}
/**
* The Java method defining the JavaScript File constructor.
*
* If the constructor has one or more arguments, and the
* first argument is not undefined, the argument is converted
* to a string as used as the filename.* * Otherwise System.in or System.out is assumed as appropriate * to the use. */ public static Scriptable jsConstructor(Context cx, Object[] args, Function ctorObj, boolean inNewExpr) { File result = new File(); if (args.length == 0 || args[0] == Context.getUndefinedValue()) { result.name = ""; result.file = null; } else { result.name = Context.toString(args[0]); result.file = new java.io.File(result.name); } return result; } /** * Returns the name of this JavaScript class, "File". */ @Override public String getClassName() { return "File"; } /** * Get the name of the file. * * Used to define the "name" property. */ public String jsGet_name() { return name; } /** * Read the remaining lines in the file and return them in an array. * * Implements a JavaScript function.
*
* This is a good example of creating a new array and setting
* elements in that array.
*
* @exception IOException if an error occurred while accessing the file
* associated with this object
*/
public Object jsFunction_readLines()
throws IOException
{
List
*
* This function takes a variable number of arguments, converts
* each argument to a string, and writes that string to the file.
* @exception IOException if an error occurred while accessing the file
* associated with this object
*/
public static void jsFunction_write(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws IOException
{
write0(thisObj, args, false);
}
/**
* Write strings and a newline.
*
* Implements a JavaScript function.
* @exception IOException if an error occurred while accessing the file
* associated with this object
*
*/
public static void jsFunction_writeLine(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws IOException
{
write0(thisObj, args, true);
}
public int jsGet_lineNumber()
throws FileNotFoundException
{
return getReader().getLineNumber();
}
/**
* Close the file. It may be reopened.
*
* Implements a JavaScript function.
* @exception IOException if an error occurred while accessing the file
* associated with this object
*/
public void jsFunction_close() throws IOException {
if (reader != null) {
reader.close();
reader = null;
} else if (writer != null) {
writer.close();
writer = null;
}
}
/**
* Finalizer.
*
* Close the file when this object is collected.
*/
@Override
protected void finalize() {
try {
jsFunction_close();
}
catch (IOException e) {
}
}
/**
* Get the Java reader.
*/
public Object jsFunction_getReader() {
if (reader == null)
return null;
// Here we use toObject() to "wrap" the BufferedReader object
// in a Scriptable object so that it can be manipulated by
// JavaScript.
Scriptable parent = ScriptableObject.getTopLevelScope(this);
return Context.javaToJS(reader, parent);
}
/**
* Get the Java writer.
*
* @see File#jsFunction_getReader
*
*/
public Object jsFunction_getWriter() {
if (writer == null)
return null;
Scriptable parent = ScriptableObject.getTopLevelScope(this);
return Context.javaToJS(writer, parent);
}
/**
* Get the reader, checking that we're not already writing this file.
*/
private LineNumberReader getReader() throws FileNotFoundException {
if (writer != null) {
throw Context.reportRuntimeError("already writing file \""
+ name
+ "\"");
}
if (reader == null)
reader = new LineNumberReader(file == null
? new InputStreamReader(System.in)
: new FileReader(file));
return reader;
}
/**
* Perform the guts of write and writeLine.
*
* Since the two functions differ only in whether they write a
* newline character, move the code into a common subroutine.
*
*/
private static void write0(Scriptable thisObj, Object[] args, boolean eol)
throws IOException
{
File thisFile = checkInstance(thisObj);
if (thisFile.reader != null) {
throw Context.reportRuntimeError("already writing file \""
+ thisFile.name
+ "\"");
}
if (thisFile.writer == null)
thisFile.writer = new BufferedWriter(
thisFile.file == null ? new OutputStreamWriter(System.out)
: new FileWriter(thisFile.file));
for (int i=0; i < args.length; i++) {
String s = Context.toString(args[i]);
thisFile.writer.write(s, 0, s.length());
}
if (eol)
thisFile.writer.newLine();
}
/**
* Perform the instanceof check and return the downcasted File object.
*
* This is necessary since methods may reside in the File.prototype
* object and scripts can dynamically alter prototype chains. For example:
*
* js> defineClass("File");
* js> o = {};
* [object Object]
* js> o.__proto__ = File.prototype;
* [object File]
* js> o.write("hi");
* js: called on incompatible object
*
* The runtime will take care of such checks when non-static Java methods
* are defined as JavaScript functions.
*/
private static File checkInstance(Scriptable obj) {
if (obj == null || !(obj instanceof File)) {
throw Context.reportRuntimeError("called on incompatible object");
}
return (File) obj;
}
/**
* Some private data for this class.
*/
private String name;
private java.io.File file; // may be null, meaning to use System.out or .in
private LineNumberReader reader;
private BufferedWriter writer;
}