/* * $Id$ */ /* * Copyright (C) 2008 Ed Huott * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package wjhk.jupload2; import wjhk.jupload2.gui.JUploadPanel; import wjhk.jupload2.policies.UploadPolicy; import wjhk.jupload2.filedata.FileData; import wjhk.jupload2.exception.JUploadException; /** * Separate thread spawned by the (signed) applet at initialization time so it * will run in a context with the same privileges. Does nothing but wait to be * notified of the presence of a command to be executed in the jsCommand String * variable. */ public class JavascriptHandler extends Thread { /** * Command code, for upload. */ public final static String COMMAND_START_UPLOAD = "startUpload"; /** * Command code, select files. */ public final static String COMMAND_SELECT_FILES = "selectFiles"; public final static String COMMAND_SELECT_FILE = "selectFile"; public final static String COMMAND_GET_FILE = "getFile"; /** * Command code, select files. */ public final static String COMMAND_GET_STATS = "getStats"; /** * Command code, cancel upload */ public final static String COMMAND_CANCEL_UPLOAD = "cancelUpload"; /** * Command code, cancel upload */ public final static String COMMAND_STOP_UPLOAD = "stopUpload"; /** * One return code for doCommand: indicates that the thread is busy, and can * execute this command. */ public final static String RETURN_BUSY = "busy"; /** * One return code for doCommand: indicates that the thread is busy, and can * execute this command. */ public final static String RETURN_STARTED = "started"; /** * Reference to the current upload policy. */ private UploadPolicy uploadPolicy = null; /** * Reference to the main panel of the applet. */ private JUploadPanel jUploadPanel = null; /** * The current command, or null if the thread is not currently running * command. */ private String jsCommand = null; private String jsResponse = null; private boolean jscmdEmpty = true; private boolean jsrespReady = false; private Object[] jsArgs; /** * The command result, or null if the thread is not currently running * command. */ private String jsCommandResult = null; /** * Constructor for JavascriptHandler * * @param uploadPolicy The current upload policy. Used for debug output. * @param theJUploadPanel Whose methods will will be invoked in order to * execute the received commands */ public JavascriptHandler(UploadPolicy uploadPolicy, JUploadPanel theJUploadPanel) { this.uploadPolicy = uploadPolicy; this.jUploadPanel = theJUploadPanel; //Let's start our thread. this.start(); } /** * Method for passing a command (String) to be executed (asynchronously) by * the run() method of this object's thread. Commands are accepted only if * there is no previous command still executing. (Commands are not queued.) * Return value indicates if command was successfully submitted. * * @param command * @return the command string argument on success, empty string on failure. */ public synchronized String doCommandX(String command) { if (this.jsCommand != null) { // The previous command not yet finished, we do nothing, and // indicate it. return RETURN_BUSY; } this.jsCommand = command; uploadPolicy.displayDebug( "JavascriptHandler - doCommandX(): jsCommand is: [" + this.jsCommand + "]", 50); // send notify() to waiting thread so that command gets executed. this.notify(); // The job will go on. return RETURN_STARTED; } public synchronized String doCommand(String command, Object... args) { if (!this.jscmdEmpty) { return RETURN_BUSY; } //Toggle status. this.jscmdEmpty = false; this.jsrespReady = false; this.jsCommand = command; this.jsArgs = args; uploadPolicy.displayDebug( "JavascriptHandler - doCommand(): jsCommand is: [" + getCommand() + "]", 50); this.notify(); // wait for response - note that some operations need to return immediately, especially those that would generate an event. if (!this.jsrespReady) { try { wait(); } catch (InterruptedException ex) { uploadPolicy.displayDebug( "Interrupted - proceeding",50);} } String outp = (this.jsResponse==null ? "NULL" : this.jsResponse); uploadPolicy.displayDebug( "JavascriptHandler - doCommand(): finished : [" + outp+ "]", 50); this.jscmdEmpty = true; return this.jsResponse; } /** * Synchronized method allows for safely accessing jsCommand string * * @return Returns the current command */ public synchronized String getCommand() { uploadPolicy.displayDebug("getCommand(): jsCommand is: [" + this.jsCommand + "]", 50); return this.jsCommand; } public synchronized Object[] getArgs() { return this.jsArgs; } /** * Synchronized method allows for safely clearing jsCommand string */ public synchronized void clearCommand() { this.jsCommand = null; uploadPolicy.displayDebug("clearCommand(): jsCommand is: [" + this.jsCommand + "]", 50); } /** * Synchronized method to enable call to wait() * * @throws InterruptedException */ public synchronized void doWait() throws InterruptedException { wait(); } public synchronized void doNotify() throws InterruptedException { this.notify(); } /** * Method to run when thread is started. */ public void run() { boolean notified=false; // Run in continuous loop waiting for commands to execute while (true) { try { // simply wait to be notified that a command is ready to run doWait(); notified =false; uploadPolicy.displayDebug("run(): Exited doWait()...", 50); // handle new command String curCommand = getCommand(); // TODO consolidate to one call. Object[] args = getArgs(); if (curCommand != null) { if (curCommand.equals(COMMAND_START_UPLOAD)) { //* ASYNCHRONOUS -- don't wait the calling thread // start the upload notified=true; doNotify(); // don't wait - uploadPolicy.displayDebug( "run(): Calling doStartUpload()", 50); if (args.length>0 && (args[0]!=null)) { // do single upload of a particular file if (args[0] instanceof String) { uploadPolicy.displayDebug( "Argument is "+args[0], 50); jUploadPanel.doStartUpload(); } else if (args[0] instanceof Integer){ uploadPolicy.displayDebug( "Argument is an int"+ args[0].toString(), 50); jUploadPanel.doStartUpload(); //jUploadPanel.doStartUploadSingle((Integer) args[0]); } } else { jUploadPanel.doStartUpload(); // this.jsResponse=null; } } if (curCommand.equals(COMMAND_STOP_UPLOAD)) { // start the upload uploadPolicy.displayDebug( "run(): Calling doStopUpload()", 50); jUploadPanel.doStopUpload(); } if (curCommand.equals(COMMAND_CANCEL_UPLOAD)) { //* ASYNCHRONOUS, sort of -- don't wait the calling thread // stop the upload notified=true; doNotify(); // don't wait - uploadPolicy.displayDebug( "run(): Calling doCancelUpload()", 50); uploadPolicy.displayDebug( "Argument length is "+args.length, 50); if (args.length>0 && (args[0]!=null)) { // do single upload of a particular file if (args[0] instanceof String) { uploadPolicy.displayDebug( "cancel upload Argument is "+args[0], 50); String id = (String) args[0]; if (id.length() >0) jUploadPanel.getFilePanel().removeFilebByExternalId(args[0].toString()); else{ uploadPolicy.displayDebug( "Argument is empty", 50); jUploadPanel.getFilePanel().removeFilebByExternalId(null); // } } else { uploadPolicy.displayDebug( "Bad Argument ", 50); } } else { // cancel the current upload jUploadPanel.doStopUpload(); jUploadPanel.getFilePanel().removeFilebByExternalId(null); // this.jsResponse=null; } } if (curCommand.equals(COMMAND_GET_STATS)) { // update the stats int[] a5 = jUploadPanel.doGetUploadStats(); String rval; rval = "{ \"in_progress\" : "+(a5[0])+", \"files_queued\" : "+a5[4]+", \"successful_uploads\" : "+a5[1]+ ", \"upload_errors\" : "+a5[3]+" , \"upload_cancelled\" : "+a5[2]+", \"queue_errors\": "+0+"}"; // whew. String gsj = rval; // start the upload uploadPolicy.displayDebug( "run(): Calling getStats()", 50); uploadPolicy.displayDebug( gsj, 50); //jUploadPanel.doStopUpload(); this.jsResponse = gsj; } if (curCommand.equals(COMMAND_GET_FILE)) { uploadPolicy.displayDebug( "run(): Calling getFile()", 50); if (args.length > 0 && (args[0] != null)) { if (args[0] instanceof String) { uploadPolicy.displayDebug( "Argument is " + args[0], 50); FileData fd = jUploadPanel.getFilePanel().getFileByExternalId((String)args[0]); this.jsResponse = (fd == null ? null : fd.getJSON()); } else if (args[0] instanceof Integer) { uploadPolicy.displayDebug( "Argument is an int" + args[0].toString(), 50); FileData fd = jUploadPanel.getFilePanel().getFileByExternalIndex((Integer) args[0]); this.jsResponse = (fd == null ? null : fd.getJSON()); } else this.jsResponse = null; } else { this.jsResponse = null; uploadPolicy.displayDebug( "before getFile() -- no argument", 50); } } if (curCommand.equals(COMMAND_SELECT_FILES)) { //* ASYNCHRONOUS -- don't wait the calling thread // pop the select file dialog, but signal for the other thread to continue, fist notified=true; doNotify(); // don't wait - uploadPolicy.displayDebug( "run(): Calling selectFiles()", 50); jUploadPanel.doSelectFiles(); this.jsResponse = null; //jUploadPanel.doStopUpload(); } this.jsrespReady = true; if (!notified) doNotify(); } } catch (InterruptedException eInterrupted) { uploadPolicy.displayDebug("Interrupted: [" + eInterrupted.getMessage() + "]", 50); } catch (Exception eOther) { try { throw new JUploadException(eOther); } catch (Exception ex) { uploadPolicy.displayDebug("Exception: [" + eOther.toString()+eOther.getMessage() + "]", 50); } } } } // run() } // class JavascriptHandler