com.sun.electric.tool.Job Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Job.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.Environment;
import com.sun.electric.database.Snapshot;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.id.IdReader;
import com.sun.electric.database.id.IdWriter;
import com.sun.electric.database.id.LibId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.text.Pref;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.technology.TechPool;
import com.sun.electric.technology.Technology;
import com.sun.electric.tool.user.ActivityLogger;
import com.sun.electric.tool.user.CantEditException;
import com.sun.electric.tool.user.ErrorLogger;
import com.sun.electric.tool.util.concurrent.debug.Debug;
import com.sun.electric.util.ElapseTimer;
import java.io.IOException;
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.swing.SwingUtilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Jobs are processes that will run in the background, such as DRC, NCC,
* Netlisters, etc. Each Job gets placed in a Job window, and reports its
* status. A job can be canceled.
*
*
* To start a new job, do:
*
* Job job = new Job(name);
*
* job.start();
*
*
* Job subclass must implement "doIt" method, it may override "terminateOK"
* method.
*
* Job subclass is activated by "Job.startJob()". In case of exception in
* constructor it is not activated. Hence "doIt" and "terminateOK" method are
* not called.
*
* Job subclass must be serializable for CHANGE and REMOTE_EXAMINE mode.
* Serialization occurs at the moment when "Job.startJob()" is called. Fields
* that are not needed on the server are escaped from serialization by
* "transient" keyword. "doIt" is executed on serverDatabase for CHANGE and
* REMOTE_EXAMINE mode. "doIt" is executed on clientDatabase for EXAMINE mode,
* Job subclass need not be serializable.
*
* "doIt" may return true, may return false, may throw JobException or any other
* Exception/Error. Return true is considered normal termination. Return false
* and throwing any Exception/Throwable are failure terminations.
*
* On normal termination in CHANGE or REMOTE_EXAMINE mode "fieldVariableChanged"
* variables are serialized. In case of REMOTE_EXAMINE they are serialized on
* read-only database state. In case of CHANGE they are serialized on database
* state after Constraint propagation. In case of EXAMINE they are not
* serialized, but they are checked for valid field names. Some time later the
* changed variables are deserialized on client database. If serialization on
* server and deserialization on client was OK then terminateOK method is called
* on client database for all three modes CHANGE, REMOTE_EXAMINE, EXAMINE. If
* serialization/deserialization failed then terminateOK is not called, error
* message is issued.
*
* In case of failure termination no terminateOK is called, error message is
* issued,
*
*
* The extending class may override getProgress(), which returns a string
* indicating the current status. Job also contains boolean abort, which gets
* set when the user decides to abort the Job. The extending class' code should
* check abort when/where applicable.
*
*
* Note that if your Job calls methods outside of this thread that access shared
* data, those called methods should be synchronized.
*
* @author gainsley
*/
public abstract class Job implements Serializable {
private static boolean GLOBALDEBUG = false;
static final int PROTOCOL_VERSION = 20; // Mar 17
public static boolean LOCALDEBUGFLAG; // Gilda's case
// private static final String CLASS_NAME = Job.class.getName();
static final Logger logger = LoggerFactory.getLogger(Job.class);
/**
* Method to tell whether Electric is running in "debug" mode. If the
* program is started with the "-debug" switch, debug mode is enabled.
*
* @return true if running in debug mode.
*/
public static boolean getDebug() {
return GLOBALDEBUG;
}
public static void setDebug(boolean f) {
GLOBALDEBUG = f;
Debug.setDebug(GLOBALDEBUG);
}
// ---------------------------- public methods ---------------------------
/**
* Type is a typesafe enum class that describes the type of job (CHANGE or
* EXAMINE).
*/
public static enum Type {
/** Describes a server database change. */
CHANGE,
/** Describes a server database undo/redo. */
UNDO,
/** Describes a server database examination. */
SERVER_EXAMINE,
/** Describes a client database examination. */
CLIENT_EXAMINE;
public boolean isExamine() {
return this == Job.Type.CLIENT_EXAMINE || this == Job.Type.SERVER_EXAMINE;
}
}
/**
* Priority is a typesafe enum class that describes the priority of a job.
*/
public static enum Priority {
/** The highest priority: from the user. */
USER,
/** Next lower priority: visible changes. */
VISCHANGES,
/** Next lower priority: invisible changes. */
INVISCHANGES,
/** Lowest priority: analysis. */
ANALYSIS;
}
/** default execution time in milliseconds */
/* private */public static final int MIN_NUM_SECONDS = 60000;
/** job manager */
/* private */static ServerJobManager serverJobManager;
/** job manager */
/* private */static ClientJobManager clientJobManager;
static AbstractUserInterface currentUI;
static Thread clientThread;
/** delete when done if true */
/* private */boolean deleteWhenDone;
// Job Status
/** job start time */
public/* protected */ElapseTimer timer = ElapseTimer.createInstance();
/** was job started? */
/* private */boolean started;
/** is job finished? */
/* private */public boolean finished;
/** thread aborted? */
/* private */boolean aborted;
/** schedule thread to abort */
/* private */boolean scheduledToAbort;
/** report execution time regardless MIN_NUM_SECONDS */
/* private */public boolean reportExecution = false;
/** tool running the job */
/* private */Tool tool;
/** current technology */
final TechId curTechId;
/** current library */
final LibId curLibId;
/** current Cell */
final CellId curCellId;
// /** priority of job */ private Priority priority;
// /** bottom of "up-tree" of cells affected */private Cell upCell;
// /** top of "down-tree" of cells affected */ private Cell downCell;
// /** status */ private String status = null;
transient EJob ejob;
transient EDatabase database;
public static void initJobManager(int numThreads, String loggingFilePath, int socketPort, AbstractUserInterface ui,
Job initDatabaseJob) {
currentUI = ui;
serverJobManager = new ServerJobManager(numThreads, loggingFilePath, false, socketPort);
serverJobManager.runLoop(initDatabaseJob);
}
public static void pipeServer(int numThreads, String loggingFilePath, int socketPort) {
Pref.forbidPreferences();
EDatabase.setServerDatabase(new EDatabase(IdManager.stdIdManager.getInitialSnapshot()));
Tool.initAllTools();
serverJobManager = new ServerJobManager(numThreads, loggingFilePath, true, socketPort);
}
public static void socketClient(String serverMachineName, int socketPort, AbstractUserInterface ui,
Job initDatabaseJob) {
currentUI = ui;
try {
clientJobManager = new ClientJobManager(serverMachineName, socketPort);
clientJobManager.runLoop(initDatabaseJob);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void pipeClient(Process process, AbstractUserInterface ui, Job initDatabaseJob, boolean skipOneLine) {
currentUI = ui;
try {
clientJobManager = new ClientJobManager(process, skipOneLine);
clientJobManager.runLoop(initDatabaseJob);
} catch (IOException e) {
e.printStackTrace();
}
}
// public static Mode getRunMode() { return threadMode; }
// public static int getNumThreads() { return recommendedNumThreads; }
/**
* Constructor creates a new instance of Job.
*
* @param jobName
* a string that describes this Job.
* @param tool
* the Tool that originated this Job.
* @param jobType
* the Type of this Job (EXAMINE or CHANGE).
* @param upCell
* the Cell at the bottom of a hierarchical "up cone" of change.
* If this and "downCell" are null, the entire database is
* presumed.
* @param downCell
* the Cell at the top of a hierarchical "down tree" of
* changes/examinations. If this and "upCell" are null, the
* entire database is presumed.
* @param priority
* the priority of this Job.
*/
public Job(String jobName, Tool tool, Type jobType, Cell upCell, Cell downCell, Priority priority) {
UserInterface ui = getUserInterface();
EditingPreferences ep;
if (ui != null) {
ep = ui.lowLevelGetEditingPreferences();
} else {
ep = new EditingPreferences(true, TechPool.getThreadTechPool());
}
ejob = new EJob(this, jobType, jobName, ep);
database = ui != null ? ui.getDatabase() : EDatabase.clientDatabase();
this.tool = tool;
this.deleteWhenDone = true;
Technology curTech = ui != null ? ui.getCurrentTechnology() : null;
curTechId = curTech != null ? curTech.getId() : null;
Library curLib = ui != null ? ui.getCurrentLibrary() : null;
curLibId = curLib != null ? curLib.getId() : null;
Cell curCell = ui != null ? ui.getCurrentCell() : null;
curCellId = curCell != null ? curCell.getId() : null;
// started = finished = aborted = scheduledToAbort = false;
// thread = null;
}
/**
* Start a job. By default displays Job on Job List UI, and delete Job when
* done. Jobs that have state the user would like to use after the Job
* finishes (like DRC, NCC, etc) should call
* startJob(true, true)
.
*/
public void startJob() {
startJob(true);
}
/**
* Start a job on snapshot obtained at the end of current job. By default
* displays Job on Job List UI, and delete Job when done.
*/
public void startJobOnMyResult() {
startJob(true, true);
}
/**
* Start the job by placing it on the JobThread queue. If
* deleteWhenDone
is true, Job will be deleted after it is done
* (frees all data and references it stores/created)
*
* @param deleteWhenDone
* delete when job is done if true, otherwise leave it around
*/
public void startJob(boolean deleteWhenDone) {
startJob(deleteWhenDone, false);
}
/**
* Start the job by placing it on the JobThread queue. If
* deleteWhenDone
is true, Job will be deleted after it is done
* (frees all data and references it stores/created)
*
* @param deleteWhenDone
* delete when job is done if true, otherwise leave it around
*/
private void startJob(boolean deleteWhenDone, boolean onMySnapshot) {
this.deleteWhenDone = deleteWhenDone;
UserInterface ui = getUserInterface();
Job.Key curJobKey = ui.getJobKey();
boolean startedByServer = curJobKey.doItOnServer;
boolean doItOnServer = ejob.jobType != Job.Type.CLIENT_EXAMINE;
if (startedByServer) {
assert doItOnServer;
ejob.client = Job.serverJobManager.serverConnections.get(curJobKey.clientId);
ejob.jobKey = ejob.client.newJobId(startedByServer, doItOnServer);
timer.start();
ejob.serialize(EDatabase.serverDatabase());
ejob.clientJob = null;
Job.serverJobManager.addJob(ejob, onMySnapshot);
} else {
ejob.client = Job.currentUI;
ejob.jobKey = ejob.client.newJobId(startedByServer, doItOnServer);
timer.start();
ejob.serverJob = null;
if (doItOnServer) {
ejob.serialize(EDatabase.clientDatabase());
Job.currentUI.putProcessingEJob(ejob, onMySnapshot);
if (serverJobManager != null) {
serverJobManager.addJob(ejob, onMySnapshot);
} else {
assert SwingUtilities.isEventDispatchThread();
try {
clientJobManager.writeEJob(ejob);
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
Job.currentUI.putProcessingEJob(ejob, onMySnapshot);
}
}
}
protected void showSnapshot() {
assert ejob.jobType == Type.CHANGE;
EThread thread = (EThread)Thread.currentThread();
assert thread.isServerThread;
assert thread.ejob == ejob;
Snapshot snapshot = EDatabase.serverDatabase().backup();
Client.fireServerEvent(new Client.SnapshotEvent(snapshot));
}
/**
* Method to remember that a field variable of the Job has been changed by
* the doIt() method.
*
* @param variableName
* the name of the variable that changed.
*/
protected void fieldVariableChanged(String variableName) {
ejob.fieldVariableChanged(variableName);
}
// --------------------------ABSTRACT METHODS--------------------------
/**
* This is the main work method. This method should perform all needed
* tasks.
*
* @throws JobException
* TODO
*/
public abstract boolean doIt() throws JobException;
/**
* This method executes in the Client side after termination of doIt method.
* This method should perform all needed termination actions.
*
* @param jobException
* null if doIt terminated normally, otherwise exception thrown
* by doIt.
*/
public void terminateIt(Throwable jobException) {
if (jobException == null)
terminateOK();
else
terminateFail(jobException);
}
/**
* This method executes in the Client side after normal termination of doIt
* method. This method should perform all needed termination actions.
*/
public void terminateOK() {
}
/**
* This method executes in the Client side after exceptional termination of
* doIt method.
*
* @param jobException
* null exception thrown by doIt.
*/
public void terminateFail(Throwable jobException) {
if (jobException instanceof CantEditException) {
((CantEditException) jobException).presentProblem();
} else if (jobException instanceof JobException) {
String message = jobException.getMessage();
if (message == null)
message = "Job " + ejob.jobName + " failed";
System.out.println(message);
} else {
ActivityLogger.logException(jobException);
}
}
// --------------------------PRIVATE JOB METHODS--------------------------
// --------------------------PROTECTED JOB METHODS-----------------------
/** Set reportExecution flag on/off */
protected void setReportExecutionFlag(boolean flag) {
reportExecution = flag;
}
// --------------------------PUBLIC JOB METHODS--------------------------
// /**
// * Method to end the current batch of changes and start another.
// * Besides starting a new batch, it cleans up the constraint system, and
// */
// protected void flushBatch()
// {
// if (jobType != Type.CHANGE) return;
// Undo.endChanges();
// Undo.startChanges(tool, jobName, /*upCell,*/ savedHighlights,
// savedHighlightsOffset);
// }
protected synchronized void setProgress(String progress) {
if (serverJobManager != null)
serverJobManager.setProgress(ejob, progress);
else
ejob.progress = progress;
}
private synchronized String getProgress() {
return ejob.progress;
}
/** Return run status */
public boolean isFinished() {
return finished;
}
/**
* Tell thread to abort. Extending class should check abort when/where
* applicable
*/
public synchronized void abort() {
// if (ejob.jobType != Job.Type.EXAMINE) return;
if (aborted) {
System.out.println("Job already aborted: " + getStatus());
return;
}
scheduledToAbort = true;
if (ejob.jobType != Job.Type.CLIENT_EXAMINE && ejob.serverJob != null)
ejob.serverJob.scheduledToAbort = true;
// Job.getUserInterface().wantToRedoJobTree();
}
/** Confirmation that thread is aborted */
private synchronized void setAborted() {
aborted = true; /* Job.getUserInterface().wantToRedoJobTree(); */
}
/** get scheduled to abort status */
protected synchronized boolean getScheduledToAbort() {
return scheduledToAbort;
}
/**
* Method to get abort status. Please leave this function as private. To
* retrieve abort status from another class, use checkAbort which also
* checks if job is scheduled to be aborted.
*
* @return
*/
private synchronized boolean getAborted() {
return aborted;
}
/** get deleteWhenDone status */
public boolean getDeleteWhenDone() {
return deleteWhenDone;
}
/**
* Check if we are scheduled to abort. If so, print message if non null and
* return true. This is because setAbort and getScheduledToAbort are
* protected in Job.
*
* @return true on abort, false otherwise. If job is scheduled for abort or
* aborted. and it will report it to standard output
*/
public boolean checkAbort() {
// if (ejob.jobType != Job.Type.EXAMINE) return false;
if (getAborted())
return (true);
boolean scheduledAbort = getScheduledToAbort();
if (scheduledAbort) {
System.out.println(this + ": aborted"); // should call
// Job.toString()
setReportExecutionFlag(true); // Force reporting
setAborted(); // Job has been aborted
}
return scheduledAbort;
}
/** get all jobs iterator */
public static Iterator getAllJobs() {
return serverJobManager != null ? serverJobManager.getAllJobs() : currentUI.getAllJobs().iterator();
}
/**
* If this current thread is a EThread running a Job return the Job. Return
* null otherwise.
*
* @return a running Job or null
*/
public static Job getRunningJob() {
Thread thread = Thread.currentThread();
return thread instanceof EThread ? ((EThread) thread).getRunningJob() : null;
}
/**
* Returns true if this current thread is a EThread running a server Job.
*
* @return true if this current thread is a EThread running a server Job.
*/
public static boolean inServerThread() {
Thread thread = Thread.currentThread();
return thread instanceof EThread && ((EThread) thread).isServerThread;
}
public static void setCurrentLibraryInJob(Library lib) {
EThread thread = (EThread) Thread.currentThread();
assert thread.ejob.jobType == Type.CHANGE;
thread.userInterface.curLibId = lib != null ? lib.getId() : null;
}
/** get status */
public String getStatus() {
switch (ejob.state) {
// case CLIENT_WAITING: return "cwaiting";
case WAITING:
return "waiting";
case RUNNING:
return getProgress() == null ? "running" : getProgress();
case SERVER_DONE:
return getProgress() == null ? "done" : getProgress();
case CLIENT_DONE:
return "cdone";
}
if (!started)
return "waiting";
if (aborted)
return "aborted";
if (finished)
return "done";
if (scheduledToAbort)
return "scheduled to abort";
if (getProgress() == null)
return "running";
return getProgress();
}
/** Remove job from Job list if it is done */
public boolean remove() {
if (!finished && !aborted) {
// System.out.println("Cannot delete running jobs. Wait till finished or abort");
return false;
}
if (serverJobManager != null)
serverJobManager.removeJob(this);
else
currentUI.removeProcessingEJob(getKey());
return true;
}
private static final ThreadLocal threadUserInterface = new ThreadLocal() {
// @Override
// protected UserInterface initialValue() {
// throw new IllegalStateException();
// }
};
public static UserInterface getUserInterface() {
Thread currentThread = Thread.currentThread();
if (currentThread instanceof EThread)
return ((EThread) currentThread).getUserInterface();
else if (currentThread == clientThread)
return currentUI;
else
return threadUserInterface.get();
}
public static void setUserInterface(UserInterface ui) {
Thread currentThread = Thread.currentThread();
assert !(currentThread instanceof EThread) && currentThread != clientThread;
if (ui == null)
throw new UnsupportedOperationException();
threadUserInterface.set(ui);
}
/**
* Low-level method.
*/
public static AbstractUserInterface getExtendedUserInterface() {
// if (!isClientThread())
// ActivityLogger.logException(new IllegalStateException());
return currentUI;
}
public static boolean isClientThread() {
return Thread.currentThread() == clientThread;
}
public EDatabase getDatabase() {
return database;
}
public Environment getEnvironment() {
return database.getEnvironment();
}
public TechPool getTechPool() {
return database.getTechPool();
}
public Tool getTool() {
return tool;
}
public EditingPreferences getEditingPreferences() {
return ejob.editingPreferences;
}
public static void updateNetworkErrors(Cell cell, List errors) {
if (currentUI != null)
currentUI.updateNetworkErrors(cell, errors);
}
public static void updateIncrementalDRCErrors(Cell cell, List newErrors,
List delErrors) {
currentUI.updateIncrementalDRCErrors(cell, newErrors, delErrors);
}
/**
* Find some valid snapshot in cache.
*
* @return some valid snapshot
*/
public static Snapshot findValidSnapshot() {
return EThread.findValidSnapshot();
}
// -------------------------------JOB UI--------------------------------
public String toString() {
return ejob.jobName + " (" + getStatus() + ")";
}
/**
* Print a message, dump a stack trace, and throw a RuntimeException if
* errorHasOccurred argument is true.
*
* @param errorHasOccurred
* indicates a runtime error has been detected
* @param msg
* the message to print when an error occurs
* @throws RuntimeException
* if errorHasOccurred is true
*/
public static void error(boolean errorHasOccurred, String msg) {
if (!errorHasOccurred)
return;
RuntimeException e = new RuntimeException(msg);
// The following prints a stack trace on the console
ActivityLogger.logException(e);
// The following prints a stack trace in the Electric messages window
throw e;
}
/** Get info on Job */
public String getInfo() {
StringBuffer buf = new StringBuffer();
buf.append("Job " + toString());
// buf.append(" start time: "+start+"\n");
if (finished) {
// Date end = new Date(endTime);
// buf.append(" end time: "+end+"\n");
buf.append(" took: " + timer);
Date start = new Date(timer.getStart());
buf.append(" (started at " + start + ")");
} else if (getProgress() == null) {
buf.append(" has not finished. Current running time: " + timer);
} else {
buf.append(" did not successfully finish.");
}
return buf.toString();
}
// static void runTerminate(EJob ejob) {
// Throwable jobException = ejob.deserializeResult();
// Job job = ejob.clientJob;
// try {
// job.terminateIt(jobException);
// } catch (Throwable e) {
// System.out.println("Exception executing terminateIt");
// e.printStackTrace(System.out);
// }
// job.endTime = System.currentTimeMillis();
// job.finished = true; // is this redundant with Thread.isAlive()?
//
// // say something if it took more than a minute by default
// if (job.reportExecution || (job.endTime - job.startTime) >=
// MIN_NUM_SECONDS) {
// if (User.isBeepAfterLongJobs()) {
// Toolkit.getDefaultToolkit().beep();
// }
// System.out.println(job.getInfo());
// }
// }
public Key getKey() {
return ejob.jobKey;
}
public Inform getInform() {
return new Inform(this);
}
/**
* Method to tell whether this Job is an examine or change job.
* @return true for Examine, false for Change.
*/
public boolean isExamine() {
return ejob.isExamine();
}
/**
* Identifies a Job in a given Electric client/server session. Job obtains
* its Key in startJob method. Also can identify Jobless context (for
* example Client's Gui)
*/
public static class Key implements Serializable {
/**
* Client which launched the Job
*/
public final int clientId;
/**
* Job id. 0 - Jobless context positive - Job started from server side
* negative - Job started from client side
*/
public final int jobId;
public final boolean doItOnServer;
Key(int clientId, int jobId, boolean doItOnServer) {
this.clientId = clientId;
this.jobId = jobId;
this.doItOnServer = doItOnServer;
}
Key(Client client, int jobId, boolean doItOnServer) {
this(client.connectionId, jobId, doItOnServer);
}
public boolean startedByServer() {
return jobId > 0;
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Key) {
Key that = (Key) o;
if (this.clientId == that.clientId && this.jobId == that.jobId) {
assert this.doItOnServer == that.doItOnServer;
return true;
}
}
return false;
}
@Override
public int hashCode() {
return jobId;
}
public void write(IdWriter writer) throws IOException {
writer.writeInt(clientId);
writer.writeInt(jobId);
writer.writeBoolean(doItOnServer);
}
public static Key read(IdReader reader) throws IOException {
int clientId = reader.readInt();
int jobId = reader.readInt();
boolean doItOnServer = reader.readBoolean();
return new Key(clientId, jobId, doItOnServer);
}
}
public static class Inform implements Serializable {
private final Key jobKey;
private final boolean isChange;
private final String toString;
private final int finished;
private ElapseTimer timer;
Inform(Job job) {
jobKey = job.getKey();
isChange = (job.ejob.jobType == Type.CHANGE) || (job.ejob.jobType == Type.UNDO);
toString = job.toString();
timer = job.timer;
if (job.finished)
finished = 1;
else if (job.getProgress() == null)
finished = 0;
else
finished = -1;
}
Inform(Key jobKey, boolean isChange, String toString, ElapseTimer timer, int finished) {
this.jobKey = jobKey;
this.isChange = isChange;
this.toString = toString;
this.timer = timer;
this.finished = finished;
}
public void abort() {
for (Iterator it = getAllJobs(); it.hasNext();) {
Job job = it.next();
if (job.getKey().equals(jobKey)) {
job.abort();
break;
}
}
}
public boolean remove() {
return false; /* return job.remove(); */
}
public Key getKey() {
return jobKey;
}
@Override
public String toString() {
return toString;
}
public String getInfo() {
StringBuilder buf = new StringBuilder();
buf.append("Job " + toString());
// buf.append(" start time: "+start+"\n");
if (finished == 1) {
// Date end = new Date(endTime);
// buf.append(" end time: "+end+"\n");
buf.append(" took: " + timer);
Date start = new Date(timer.getStart());
buf.append(" (started at " + start + ")");
} else if (finished == 0) {
buf.append(" has not finished. Current running time: " + timer.currentTimeString());
} else {
buf.append(" did not successfully finish.");
}
return buf.toString();
}
public boolean isChangeJobQueuedOrRunning() {
return finished != 1 && isChange;
}
public void write(IdWriter writer) throws IOException {
jobKey.write(writer);
writer.writeBoolean(isChange);
writer.writeString(toString);
writer.writeLong(timer.getStart());
writer.writeLong(timer.getEnd());
writer.writeInt(finished);
}
public static Inform read(IdReader reader) throws IOException {
Key jobKey = Key.read(reader);
boolean isChange = reader.readBoolean();
String toString = reader.readString();
long startTime = reader.readLong();
long endTime = reader.readLong();
ElapseTimer timer = ElapseTimer.createInstanceByValues(startTime, endTime);
int finished = reader.readInt();
return new Inform(jobKey, isChange, toString, timer, finished);
}
}
}