/*
GASHAdminDispatch.java
Logical interface class that provides the connectivity between the
Ganymede admin console and the server, bidirectionally.
Created: 28 May 1996
Module By: Jonathan Abbey, jonabbey@arlut.utexas.edu
-----------------------------------------------------------------------
Ganymede Directory Management System
Copyright (C) 1996-2013
The University of Texas at Austin
Ganymede is a registered trademark of The University of Texas at Austin
Contact information
Author Email: ganymede_author@arlut.utexas.edu
Email mailing list: ganymede@arlut.utexas.edu
US Mail:
Computer Science Division
Applied Research Laboratories
The University of Texas at Austin
PO Box 8029, Austin TX 78713-8029
Telephone: (512) 835-3200
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, see <http://www.gnu.org/licenses/>.
*/
package arlut.csd.ganymede.admin;
import java.awt.Color;
import java.awt.Dialog;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.text.NumberFormat;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import arlut.csd.JDialog.DialogRsrc;
import arlut.csd.JDialog.JDialogBuff;
import arlut.csd.JDialog.StandardDialog;
import arlut.csd.JDialog.StringDialog;
import arlut.csd.JTable.rowTable;
import arlut.csd.Util.PackageResources;
import arlut.csd.Util.TranslationService;
import arlut.csd.Util.VectorUtils;
import arlut.csd.ganymede.common.AdminEntry;
import arlut.csd.ganymede.common.ReturnVal;
import arlut.csd.ganymede.common.adminAsyncMessage;
import arlut.csd.ganymede.common.scheduleHandle;
import arlut.csd.ganymede.rmi.AdminAsyncResponder;
import arlut.csd.ganymede.rmi.SchemaEdit;
import arlut.csd.ganymede.rmi.Server;
import arlut.csd.ganymede.rmi.adminSession;
/*------------------------------------------------------------------------------
class
GASHAdminDispatch
------------------------------------------------------------------------------*/
/**
* Logical interface class that provides the connectivity between the
* Ganymede admin console and the server, bidirectionally. This class
* is part of the Ganymede admin console code, not the Ganymede
* server.
*/
class GASHAdminDispatch implements Runnable {
static final boolean debug = false;
/**
* TranslationService object for handling string localization in
* the Ganymede server.
*/
static final TranslationService ts = TranslationService.getTranslationService("arlut.csd.ganymede.admin.GASHAdminDispatch");
private GASHAdminFrame frame = null;
private Server server = null; // remote reference
private adminSession aSession = null; // remote reference
private boolean tasksLoaded = false;
private AdminAsyncResponder asyncPort = null; // remote reference
private Thread asyncPollThread = null;
private volatile boolean okayToPoll = false;
private ImageIcon errorBallIcon = null;
private ImageIcon playIcon = null;
private ImageIcon okayIcon = null;
private NumberFormat numberFormatter = NumberFormat.getInstance();
/* -- */
/**
* <p>Constructor.</p>
*
* @param server A remote RMI reference to the Ganymede server we're monitoring.
*/
public GASHAdminDispatch(Server server)
{
this.server = server;
}
/**
* <p>This method connects the admin console to the server RMI
* reference that was provided to the GASHAdminDispatch constructor.
* If the server returns a failure message, connect() will pop up a
* dialog providing the error text. If the connection failed
* through a RemoteException, it will be passed up for the calling
* code to handle.</p>
*/
public boolean connect(String name, String pass) throws RemoteException
{
ReturnVal retVal = handleReturnVal(server.admin(name, pass));
if (retVal == null || !retVal.didSucceed())
{
return false;
}
aSession = retVal.getAdminSession();
// if we get a null session despite having a
// success-encoding ReturnVal, throw an exception. The
// server *should* pass back a proper error report in the
// ReturnVal, and this NullPointerException should
// never be thrown.
if (aSession == null)
{
throw new NullPointerException("Bad null valued admin session received from server");
}
if (debug)
{
System.err.println("Got Admin");
}
return true;
}
public void setFrame(GASHAdminFrame f)
{
if (frame == null)
{
frame = f;
}
else
{
System.err.println("I already have a frame, thank you very much.");
}
}
public void startAsyncPoller() throws RemoteException
{
asyncPort = aSession.getAsyncPort();
if (asyncPort == null)
{
throw new RemoteException("Couldn't find admin console asyncPort");
}
okayToPoll = true;
asyncPollThread = new Thread(this, "Async Server Poll Thread");
asyncPollThread.start();
}
public void stopAsyncPoller()
{
okayToPoll = false;
}
/**
* <p>Generates the localized time formatting for the admin console,
* with special short formatting for times that occurred in the
* current calendar day.</p>
*/
public String formatDate(Date time)
{
return this.formatDate(time, true);
}
/**
* <p>Generates the localized time formatting for the admin console,
* with optional short formatting for times that occurred in this
* calendar day.</p>
*
* @param todayIsSpecial If true, a shorter time format will be used
* for time if it occurred today.
*/
public String formatDate(Date time, boolean todayIsSpecial)
{
if (time == null)
{
return "";
}
SimpleDateFormat formatter;
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(new Date());
cal2.setTime(time);
if (todayIsSpecial &&
(cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)) &&
(cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)))
{
formatter = new SimpleDateFormat(ts.l("global.todayTimeFormat"));
}
else
{
formatter = new SimpleDateFormat(ts.l("global.timeFormat"));
}
return formatter.format(time);
}
/**
* <p>This method spins continuously, polling the server for {@link
* arlut.csd.ganymede.common.adminAsyncMessage adminAsyncMessages}.
* The server will block until something happens, then download a
* set of adminAsyncMessages. This run method will then dispatch
* those messages to the appropriate GASHAdminDispatch methods for
* propagation into the admin console's GUI.</p>
*/
public void run()
{
adminAsyncMessage events[] = null;
adminAsyncMessage event = null;
/* -- */
if (asyncPort == null)
{
return;
}
try
{
while (okayToPoll)
{
events = asyncPort.getNextMsgs(); // will block on server
if (events == null || events.length == 0)
{
return;
}
for (int i = 0; i < events.length; i++)
{
event = events[i];
switch (event.getMethod())
{
case adminAsyncMessage.SETSERVERSTART:
setServerStart((Date) event.getParam(0));
break;
case adminAsyncMessage.SETLASTDUMPTIME:
setLastDumpTime((Date) event.getParam(0));
break;
case adminAsyncMessage.SETTRANSACTIONS:
setTransactionsInJournal(event.getInt(0));
break;
case adminAsyncMessage.SETOBJSCHECKOUT:
setObjectsCheckedOut(event.getInt(0));
break;
case adminAsyncMessage.SETLOCKSHELD:
setLocksHeld(event.getInt(0), event.getInt(1));
break;
case adminAsyncMessage.CHANGESTATE:
changeState(event.getString(0));
break;
case adminAsyncMessage.LOGAPPEND:
logAppend(((StringBuffer) event.getParam(0)).toString());
break;
case adminAsyncMessage.CHANGEADMINS:
changeAdmins(event.getString(0));
break;
case adminAsyncMessage.CHANGEUSERS:
changeUsers(event.getParams());
break;
case adminAsyncMessage.CHANGETASKS:
changeTasks(event.getParams());
break;
case adminAsyncMessage.SETMEMORYSTATE:
setMemoryState(event.getLong(0), event.getLong(1));
break;
case adminAsyncMessage.FORCEDISCONNECT:
forceDisconnect(event.getString(0));
break;
default:
System.err.println("Unrecognized adminAsyncMessage: " + event);
}
}
}
}
catch (RemoteException ex)
{
}
finally
{
asyncPort = null;
}
}
/**
* <p>Updates the display of the server start date in the admin
* console.</p>
*/
public void setServerStart(Date date)
{
if (debug)
{
System.err.println("GASHAdminDispatch.setServerStart()");
}
if (frame == null)
{
return;
}
final Date lDate = date;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// always use long format date as the server start time will
// not be updated once set
frame.startField.setText(formatDate(lDate, false));
}
});
}
/**
* <p>Updates the display of the server's last dump date in the admin
* console.</p>
*/
public void setLastDumpTime(Date date)
{
if (debug)
{
System.err.println("GASHAdminDispatch.setLastDumpTime()");
}
if (frame == null)
{
return;
}
final Date lDate = date;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (lDate == null)
{
frame.dumpField.setText("no dump since server start");
}
else
{
frame.dumpField.setText(formatDate(lDate));
}
}
});
}
/**
* <p>Updates the display of the number of transactions in the server's
* journal in the admin console.</p>
*/
public void setTransactionsInJournal(int trans)
{
if (debug)
{
System.err.println("GASHAdminDispatch.setTransactionsInJournal()");
}
if (frame == null)
{
return;
}
final int lTrans = trans;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.journalField.setText("" + lTrans);
}
});
}
/**
* <p>Updates the display of the number of objects checked out on the
* server in the admin console.</p>
*/
public void setObjectsCheckedOut(int objs)
{
if (debug)
{
System.err.println("GASHAdminDispatch.setObjectsCheckedOut()");
}
if (frame == null)
{
return;
}
final int lObjs = objs;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.checkedOutField.setText("" + lObjs);
}
});
}
/**
* <p>Updates the display of the number of server locks waiting to be
* established / established in the admin console.</p>
*/
public void setLocksHeld(int locks, int waiting)
{
if (debug)
{
System.err.println("GASHAdminDispatch.setLocksHeld()");
}
if (frame == null)
{
return;
}
final int lLocks = locks;
final int lWaiting = waiting;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.locksField.setText(lWaiting + " / " + lLocks);
}
});
}
/**
* <p>Updates the memory statistics display in the admin console.</p>
*/
public void setMemoryState(long freeMemory, long totalMemory)
{
if (debug)
{
System.err.println("GASHAdminDispatch.setMemoryState()");
}
if (frame == null)
{
return;
}
final long lFreeMemory = freeMemory;
final long lTotalMemory = totalMemory;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String inuse = numberFormatter.format(lTotalMemory - lFreeMemory);
String free = numberFormatter.format(lFreeMemory);
String total = numberFormatter.format(lTotalMemory);
frame.usedMemField.setText(inuse);
frame.freeMemField.setText(free);
frame.totalMemField.setText(total);
}
});
}
/**
* <p>Appends to the server log display in the admin console.</p>
*
* @param status A string to add to the console's log display, with
* the trailing newline included.
*/
public void logAppend(String status)
{
if (debug)
{
System.err.println("GASHAdminDispatch.logAppend()");
}
if (frame == null)
{
return;
}
final String lStatus = status;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.appendStyledLogText(lStatus);
}
});
}
/**
* <p>Updates the display of the number of admin consoles attached to
* the server.</p>
*/
public void changeAdmins(String adminStatus)
{
if (debug)
{
System.err.println("GASHAdminDispatch.changeAdmins()");
}
if (frame == null)
{
return;
}
final String lAdminStatus = adminStatus;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.adminField.setText(lAdminStatus);
}
});
}
/**
* <p>Updates the admin console's server state display.</p>
*/
public void changeState(String state)
{
if (debug)
{
System.err.println("GASHAdminDispatch.changeState()");
}
if (frame == null)
{
return;
}
final String lState = state;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.stateField.setText(lState);
}
});
}
/**
* <p>Updates the admin console's connected user table.</p>
*
* @param entries a Vector of {@link arlut.csd.ganymede.common.AdminEntry AdminEntry}
* login description objects.
*/
public void changeUsers(Object entries[])
{
if (debug)
{
System.err.println("GASHAdminDispatch.changeUsers()");
}
if (frame == null)
{
return;
}
/* -- */
final Object localEntries[] = entries;
// And refresh our table.. we'll wait until this succeeds so we
// don't get the server sending us more updates before the table
// finishes drawing
try
{
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
AdminEntry e;
frame.table.clearCells();
// Process entries from the server
for (int i = 0; i < localEntries.length; i++)
{
e = (AdminEntry) localEntries[i];
frame.table.newRow(e.sessionName);
// the sessionName from the AdminEntry is constant,
// and gives us a unique session name for the session.
//
// if we don't have a persona name, we'll display that
// unique session name, otherwise we'll show the
// user's persona name, so as to show the user's
// active privilege level.
//
// either way, the table tracks the unique session
// name for us, so that when the user right-clicks on
// the entry to kick a user off, the proper session is
// targeted.
if (e.personaName == null || e.personaName.equals(""))
{
frame.table.setCellText(e.sessionName, 0, e.sessionName, false);
}
else
{
frame.table.setCellText(e.sessionName, 0, e.personaName, false);
}
frame.table.setCellText(e.sessionName, 1, e.hostname, false);
// frame.table.setCellText(e.sessionName, 2, e.status, false);
frame.table.setCellText(e.sessionName, 2, formatDate(e.connecttime), e.connecttime, false);
if (e.eventtime == null)
{
frame.table.setCellText(e.sessionName, 3, e.event, false);
}
else
{
frame.table.setCellText(e.sessionName, 3, formatDate(e.eventtime) + " " + e.event, e.eventtime, false);
}
frame.table.setCellText(e.sessionName, 4, Integer.toString(e.objectsCheckedOut), false);
}
frame.table.resort(false);
frame.table.refreshTable();
}
});
}
catch (InvocationTargetException ite)
{
ite.printStackTrace();
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
}
/**
* <p>This method is remotely called by the Ganymede server to
* update the admin console's task tables.</p>
*
* @param tasks an array of {@link
* arlut.csd.ganymede.common.scheduleHandle scheduleHandle} objects
* describing the tasks registered in the Ganymede server.
*/
public void changeTasks(Object tasks[])
{
if (debug)
{
System.err.println("GASHAdminDispatch.changeTasks()");
}
if (frame == null)
{
return;
}
scheduleHandle handle;
/* -- */
if (!tasksLoaded)
{
// System.err.println("changeTasks: tasks size = " + tasks.size());
// Sort entries according to their incep date,
// to prevent confusion if new tasks are put into
// the server-side hashes, and as they are shuffled
// from hash to hash
java.util.Arrays.sort(tasks,
new Comparator()
{
public int compare(Object a, Object b)
{
scheduleHandle aH, bH;
aH = (scheduleHandle) a;
bH = (scheduleHandle) b;
if (aH.incepDate.before(bH.incepDate))
{
return -1;
}
else if (aH.incepDate.after(bH.incepDate))
{
return 1;
}
else
{
return 0;
}
}
}
);
}
Vector<scheduleHandle> syncTasks = new Vector<scheduleHandle>();
Vector<scheduleHandle> scheduledTasks = new Vector<scheduleHandle>();
Vector<scheduleHandle> manualTasks = new Vector<scheduleHandle>();
for (int i = 0; i < tasks.length; i++)
{
handle = (scheduleHandle) tasks[i];
switch (handle.getTaskType())
{
case SCHEDULED:
scheduledTasks.addElement(handle);
break;
case MANUAL:
manualTasks.addElement(handle);
break;
case BUILDER:
case UNSCHEDULEDBUILDER:
case SYNCINCREMENTAL:
case SYNCFULLSTATE:
case SYNCMANUAL:
syncTasks.addElement(handle);
}
}
updateSyncTaskTable(frame.syncTaskTable, syncTasks);
updateScheduledTaskTable(frame.taskTable, scheduledTasks);
updateManualTaskTable(frame.manualTaskTable, manualTasks);
}
/**
* <p>Updated the scheduled task table</p>
*/
private void updateScheduledTaskTable(rowTable table, Vector<scheduleHandle> tasks)
{
Vector<String> taskNames = new Vector<String>();
/* -- */
for (scheduleHandle handle: tasks)
{
taskNames.add(handle.name);
if (!table.containsKey(handle.name))
{
table.newRow(handle.name);
}
table.setCellText(handle.name, 0, handle.name, false); // task name
if (handle.isRunning() && handle.isSuspended())
{
// "Suspended upon completion"
table.setCellText(handle.name, 1, ts.l("changeTasks.runningSuspendedState"), false);
table.setCellColor(handle.name, 1, Color.red, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else if (handle.isRunning())
{
// "Running ({0}s)"
table.setCellText(handle.name, 1, ts.l("changeTasks.runningState", handle.getAge()), false);
table.setCellColor(handle.name, 1, Color.blue, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else if (handle.isSuspended())
{
// "Suspended"
table.setCellText(handle.name, 1, ts.l("changeTasks.suspendedState"), false);
table.setCellColor(handle.name, 1, Color.red, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else if (handle.startTime != null)
{
// "Scheduled"
table.setCellText(handle.name, 1, ts.l("changeTasks.scheduledState"), false);
table.setCellColor(handle.name, 1, Color.black, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
table.setCellText(handle.name, 2, handle.intervalString, false);
if (handle.startTime != null)
{
table.setCellText(handle.name, 3, formatDate(handle.startTime), handle.startTime, false);
}
else
{
// "On Demand"
table.setCellText(handle.name, 3, ts.l("changeTasks.onDemandState"), false);
}
if (handle.lastTime != null)
{
table.setCellText(handle.name, 4, formatDate(handle.lastTime), handle.lastTime, false);
}
}
// and take any rows out that are gone
Vector tasksKnown = new Vector();
Enumeration en = table.keys();
while (en.hasMoreElements())
{
tasksKnown.addElement(en.nextElement());
}
Vector removedTasks = VectorUtils.difference(tasksKnown, taskNames);
for (int i = 0; i < removedTasks.size(); i++)
{
table.deleteRow(removedTasks.elementAt(i), false);
}
// And refresh our table.. we'll wait until this succeeds so we
// don't get the server sending us more updates before the table
// finishes drawing
final rowTable localTableRef = table;
try
{
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
localTableRef.resort(false);
localTableRef.refreshTable();
}
});
}
catch (InvocationTargetException ite)
{
ite.printStackTrace();
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
}
/**
* <p>Updated the manual task table</p>
*/
private void updateManualTaskTable(rowTable table, Vector<scheduleHandle> tasks)
{
Vector<String> taskNames = new Vector();
/* -- */
for (scheduleHandle handle: tasks)
{
taskNames.add(handle.name);
if (!table.containsKey(handle.name))
{
table.newRow(handle.name);
}
table.setCellText(handle.name, 0, handle.name, false); // task name
if (handle.isRunning() && handle.isSuspended())
{
// "Suspended upon completion"
table.setCellText(handle.name, 1, ts.l("changeTasks.runningSuspendedState"), false);
table.setCellColor(handle.name, 1, Color.red, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else if (handle.isRunning())
{
// "Running ({0}s)"
table.setCellText(handle.name, 1, ts.l("changeTasks.runningState", handle.getAge()), false);
table.setCellColor(handle.name, 1, Color.blue, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else if (handle.isSuspended())
{
// "Suspended"
table.setCellText(handle.name, 1, ts.l("changeTasks.suspendedState"), false);
table.setCellColor(handle.name, 1, Color.red, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else if (handle.startTime != null)
{
// "Scheduled"
table.setCellText(handle.name, 1, ts.l("changeTasks.scheduledState"), false);
table.setCellColor(handle.name, 1, Color.black, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
else
{
// "Waiting"
table.setCellText(handle.name, 1, ts.l("changeTasks.waitingState"), false);
table.setCellColor(handle.name, 1, Color.black, false);
table.setCellBackColor(handle.name, 1, Color.white, false);
}
if (handle.lastTime != null)
{
table.setCellText(handle.name, 2, formatDate(handle.lastTime), handle.lastTime, false);
}
}
// and take any rows out that are gone
Vector tasksKnown = new Vector();
Enumeration en = table.keys();
while (en.hasMoreElements())
{
tasksKnown.addElement(en.nextElement());
}
Vector removedTasks = VectorUtils.difference(tasksKnown, taskNames);
for (int i = 0; i < removedTasks.size(); i++)
{
table.deleteRow(removedTasks.elementAt(i), false);
}
// And refresh our table.. we'll wait until this succeeds so we
// don't get the server sending us more updates before the table
// finishes drawing
final rowTable localTableRef = table;
try
{
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
localTableRef.resort(false);
localTableRef.refreshTable();
}
});
}
catch (InvocationTargetException ite)
{
ite.printStackTrace();
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
}
/**
* <p>Update the sync monitor tasks</p>
*/
private void updateSyncTaskTable(rowTable table, Vector<scheduleHandle> tasks)
{
Vector<String> taskNames = new Vector();
/* -- */
boolean error_seen = false;
boolean running = false;
// now reload the table with the current stats
for (scheduleHandle handle: tasks)
{
taskNames.add(handle.name);
if (!table.containsKey(handle.name))
{
table.newRow(handle.name);
}
Color background = null;
Color foreground = null;
if (handle.isRunning() && handle.isSuspended())
{
foreground = Color.white;
background = Color.red;
}
else if (handle.isRunning())
{
foreground = Color.white;
background = Color.blue;
running = true;
}
else if (handle.isSuspended())
{
foreground = Color.white;
background = Color.red;
}
else
{
switch (handle.getTaskStatus())
{
case OK:
case EMPTYQUEUE:
case NONEMPTYQUEUE:
foreground = Color.black;
background = Color.white;
break;
default:
foreground = Color.white;
background = Color.red;
error_seen = true;
}
}
table.setCellText(handle.name, 0, handle.name, false); // task name
table.setCellColor(handle.name, 0, foreground, false);
table.setCellBackColor(handle.name, 0, background, false);
table.setCellText(handle.name, 1, handle.getTaskType().toString(), false);
table.setCellColor(handle.name, 1, foreground, false);
table.setCellBackColor(handle.name, 1, background, false);
table.setCellText(handle.name, 2, handle.getTaskStatus().getMessage(handle.queueSize, handle.condition), false);
table.setCellColor(handle.name, 2, foreground, false);
table.setCellBackColor(handle.name, 2, background, false);
if (handle.isRunning() && handle.isSuspended())
{
// "Suspended upon completion"
table.setCellText(handle.name, 3, ts.l("changeTasks.runningSuspendedState"), false);
}
else if (handle.isRunning())
{
if (handle.runAgain())
{
// "Running ({0}s), Pending"
table.setCellText(handle.name, 3, ts.l("changeTasks.runningAndPending", handle.getAge()), false);
}
else
{
// "Running ({0}s)"
table.setCellText(handle.name, 3, ts.l("changeTasks.runningState", handle.getAge()), false);
}
}
else if (handle.isSuspended())
{
// "Suspended"
table.setCellText(handle.name, 3, ts.l("changeTasks.suspendedState"), false);
}
else if (handle.startTime != null)
{
// "Scheduled"
table.setCellText(handle.name, 3, ts.l("changeTasks.scheduledState"), false);
}
else
{
// "Waiting"
table.setCellText(handle.name, 3, ts.l("changeTasks.waitingState"), false);
}
table.setCellColor(handle.name, 3, foreground, false);
table.setCellBackColor(handle.name, 3, background, false);
if (handle.lastTime != null)
{
table.setCellText(handle.name, 4, formatDate(handle.lastTime), handle.lastTime, false);
}
table.setCellColor(handle.name, 4, foreground, false);
table.setCellBackColor(handle.name, 4, background, false);
}
if (running)
{
frame.tabPane.setIconAt(1, getPlayIcon());
}
else if (error_seen)
{
frame.tabPane.setIconAt(1, getErrorBall());
}
else
{
frame.tabPane.setIconAt(1, getOkIcon());
}
// and take any rows out that are gone
Vector tasksKnown = new Vector();
Enumeration en = table.keys();
while (en.hasMoreElements())
{
tasksKnown.addElement(en.nextElement());
}
Vector removedTasks = VectorUtils.difference(tasksKnown, taskNames);
for (int i = 0; i < removedTasks.size(); i++)
{
table.deleteRow(removedTasks.elementAt(i), false);
}
// And refresh our table.. we'll wait until this succeeds so we
// don't get the server sending us more updates before the table
// finishes drawing
final rowTable localTableRef = table;
try
{
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
localTableRef.resort(false);
localTableRef.refreshTable();
}
});
}
catch (InvocationTargetException ite)
{
ite.printStackTrace();
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
}
/**
* This method is called by admin console code to force a complete
* rebuild of all external builds. This means that all databases
* will have their last modification timestamp cleared and all
* builder tasks will be scheduled for immediate execution.
*/
public void forceBuild() throws RemoteException
{
handleReturnVal(aSession.forceBuild());
}
public void disconnect() throws RemoteException
{
aSession.logout();
}
/**
* Callback: The server can tell us to disconnect if the server is
* going down.
*/
public void forceDisconnect(String reason)
{
// "Disconnected: {0}\n"
logAppend(ts.l("forceDisconnect.disconnectMessage", reason));
server = null;
}
// ------------------------------------------------------------
// convenience methods for our GASHAdminFrame
// ------------------------------------------------------------
void refreshMe() throws RemoteException
{
aSession.refreshMe();
}
void kill(String username) throws RemoteException
{
handleReturnVal(aSession.kill(username));
}
void runTaskNow(String taskName) throws RemoteException
{
handleReturnVal(aSession.runTaskNow(taskName));
}
void stopTask(String taskName) throws RemoteException
{
handleReturnVal(aSession.stopTask(taskName));
}
void disableTask(String taskName) throws RemoteException
{
handleReturnVal(aSession.disableTask(taskName));
}
void enableTask(String taskName) throws RemoteException
{
handleReturnVal(aSession.enableTask(taskName));
}
void killAll() throws RemoteException
{
handleReturnVal(aSession.killAll());
}
boolean shutdown(boolean waitForUsers, String reason) throws RemoteException
{
ReturnVal retVal = handleReturnVal(aSession.shutdown(waitForUsers, reason));
return (retVal == null || retVal.didSucceed());
}
void dumpDB() throws RemoteException
{
handleReturnVal(aSession.dumpDB());
}
void runInvidTest() throws RemoteException
{
handleReturnVal(aSession.runInvidTest());
}
void runInvidSweep() throws RemoteException
{
handleReturnVal(aSession.runInvidSweep());
}
void runEmbeddedTest() throws RemoteException
{
handleReturnVal(aSession.runEmbeddedTest());
}
void runEmbeddedSweep() throws RemoteException
{
handleReturnVal(aSession.runEmbeddedSweep());
}
GASHSchema pullSchema() throws RemoteException
{
SchemaEdit editor = null;
/* -- */
if (debug)
{
System.err.println("Trying to get SchemaEdit handle");
}
try
{
editor = aSession.editSchema();
}
catch (RemoteException ex)
{
System.err.println("editSchema() exception: " + ex);
}
if (editor == null)
{
System.err.println("null editor handle");
return null;
}
else
{
if (debug)
{
System.err.println("Got SchemaEdit handle");
}
// the GASHSchema constructor pops itself up at the end of
// initialization
// "Schema Editor"
return new GASHSchema(ts.l("pullSchema.schemaEditingTitle"), editor, this);
}
}
/**
* This method is designed to be called by the GASHSchema schema editor when
* it closes down.
*/
public void clearSchemaEditor()
{
frame.schemaMI.setEnabled(true);
frame.schemaEditor = null;
}
/**
* <p>This method takes a ReturnVal object from the server and, if
* necessary, runs through a wizard interaction sequence, possibly
* displaying several dialogs before finally returning a final
* result code.</p>
*
* <p>Use the ReturnVal returned from this function after this
* function is called to determine the ultimate success or failure
* of any operation which returns ReturnVal, because a wizard
* sequence may determine the ultimate result.</p>
*/
public ReturnVal handleReturnVal(ReturnVal retVal)
{
Hashtable dialogResults;
DialogRsrc resource;
/* -- */
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): Entering");
try
{
throw new RuntimeException("TRACE");
}
catch (RuntimeException ex)
{
ex.printStackTrace();
}
}
while ((retVal != null) && (retVal.getDialog() != null))
{
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): retrieving dialog");
}
JDialogBuff jdialog = retVal.getDialog();
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): extracting dialog");
}
if (frame == null)
{
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): null frame");
}
resource = jdialog.extractDialogRsrc(new JFrame(), this.getClass());
}
else
{
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): good frame");
}
resource = jdialog.extractDialogRsrc(frame, null);
}
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): constructing dialog");
}
StringDialog dialog = new StringDialog(resource, StandardDialog.ModalityType.DOCUMENT_MODAL);
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): displaying dialog");
}
// display the Dialog sent to us by the server, get the
// result of the user's interaction with it.
dialogResults = dialog.showDialog();
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): dialog done");
}
if (retVal.getCallback() != null)
{
try
{
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): Sending result to callback: " + dialogResults);
}
// send the dialog results to the server
retVal = retVal.getCallback().respond(dialogResults);
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): Received result from callback.");
}
}
catch (RemoteException ex)
{
throw new RuntimeException("Caught remote exception: " + ex.getMessage());
}
}
else
{
if (debug)
{
System.err.println("GASHAdminDispatch.handleReturnVal(): No callback, breaking");
}
break; // we're done
}
}
if (debug)
{
if (retVal != null)
{
if (retVal.didSucceed())
{
System.err.println("GASHAdminDispatch.handleReturnVal(): returning success code");
}
else
{
System.err.println("GASHAdminDispatch.handleReturnVal(): returning failure code");
}
}
else
{
System.err.println("GASHAdminDispatch.handleReturnVal(): returning null retVal (success)");
}
}
return retVal;
}
public ImageIcon getErrorBall()
{
if (errorBallIcon == null)
{
errorBallIcon = new ImageIcon(PackageResources.getImageResource(frame, "error-ball.png", getClass()));
}
return errorBallIcon;
}
public ImageIcon getPlayIcon()
{
if (playIcon == null)
{
playIcon = new ImageIcon(PackageResources.getImageResource(frame, "playing-icon.png", getClass()));
}
return playIcon;
}
public ImageIcon getOkIcon()
{
if (okayIcon == null)
{
okayIcon = new ImageIcon(PackageResources.getImageResource(frame, "okay-status.png", getClass()));
}
return okayIcon;
}
}