/******************************************************************************
* Copyright (c) 2007 g-Eclipse consortium
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Initial development of the original code was made for
* project g-Eclipse founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributor(s):
* UCY (http://www.cs.ucy.ac.cy)
* - Harald Gjermundrod (harald@cs.ucy.ac.cy)
*
*****************************************************************************/
package eu.geclipse.batch.ui.internal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import org.eclipse.compare.IContentChangeListener;
import org.eclipse.compare.IContentChangeNotifier;
import org.eclipse.core.runtime.ListenerList;
import eu.geclipse.batch.BatchJobInfo;
import eu.geclipse.batch.IBatchJobInfo;
import eu.geclipse.batch.IBatchJobManager;
import eu.geclipse.batch.IBatchService;
import eu.geclipse.batch.IBatchJobInfo.JobState;
import eu.geclipse.core.reporting.ProblemException;
/**
* The <code>BatchJobManager</code> manages all types of jobs present in the
* batch system.
*/
public class BatchJobManager implements IBatchJobManager, IContentChangeNotifier {
/**
* The internal list of managed jobs.
*/
private LinkedHashMap< String, IBatchJobInfo > jobs;
/**
* This list holds the currently registered IContentChangeListeners.
*/
private ListenerList ccListeners;
private boolean done;
/**
* Constructor
*/
public BatchJobManager() {
this.jobs = new LinkedHashMap< String, IBatchJobInfo > ();
this.ccListeners = new ListenerList();
this.done = false;
}
/**
* Searches for a job that matches the specified jobId. If no job
* could be found <code>null</code> is returned.
*
* @param jobId The unique id of the job.
* @return The job with the specific jobId or null if no such job could be
* found.
*/
public synchronized IBatchJobInfo findJob( final String jobId ) {
return this.jobs.get( jobId );
}
/**
* Update our local state with the current state, by only keeping the
* active jobs. I.e. remove all the jobs that are not active anymore.
*
* @param currentActiveJobs These are the currently active jobs.
*/
public synchronized void removeOld( final List< IBatchJobInfo > currentActiveJobs ) {
IBatchJobInfo jobInfo;
boolean changed = false;
Iterator< String > iter = this.jobs.keySet().iterator();
while ( iter.hasNext() ) {
String jobId = iter.next();
boolean found = false;
for ( int i = 0; i < currentActiveJobs.size(); ++i ) {
jobInfo = currentActiveJobs.get( i );
if ( jobId.equals( jobInfo.getJobId() ) )
found = true;
}
// Queue is removed
if ( !found ) {
iter.remove();
//this.removedResources.add( this.jobs.get( jobId ) );
changed = true;
}
}
if ( changed )
this.fireContentChanged();
}
/**
* Either add the following job if it doesn't exist or merge the state
* if it already exists.
*
* @param jobId The unique id of the job.
* @param jobName The name of the job.
* @param userAccount The name of the pool account that are used to execute
* this job.
* @param timeUse How much time this job have used.
* @param status The current status of this job.
* @param queueName The name of the queue where this job is placed.
* @param batchWrapper The wrapper to access the batch service where this
* job is queued.
* @return Returns the created job.
*/
public synchronized IBatchJobInfo addMerge( final String jobId, final String jobName, final String userAccount,
final String timeUse, final JobState status, final String queueName,
final IBatchService batchWrapper ) {
IBatchJobInfo jobInfo = null;
boolean changed = false;
// We don't update any of the jobs when we are done
if ( !this.done ) {
jobInfo = this.findJob( jobId );
if ( null == jobInfo ) {
jobInfo = new BatchJobInfo( jobId, jobName, userAccount, timeUse, status, queueName, batchWrapper );
this.jobs.put( jobId, jobInfo );
changed = true;
} else { // Did the state of this job change ??
if ( jobInfo.getStatus() != status ) {
jobInfo.setStatus( status );
changed = true;
}
if ( !jobInfo.getTimeUse().equals( timeUse ) ) {
jobInfo.setTimeUse( timeUse );
changed = true;
}
}
}
if ( changed )
this.fireContentChanged();
return jobInfo;
}
/**
* Get all jobs that are currently available.
*
* @return A copy of the internal list of managed jobs.
*/
public synchronized List< IBatchJobInfo > getJobs() {
return new ArrayList< IBatchJobInfo >( this.jobs.values() );
}
/**
* Get all jobs in the specified queue that are currently available.
*
* @param queueName The name of the queue that we want the jobs from
* @return A copy of the internal list of managed jobs in the specified
* queue.
*/
public synchronized List< IBatchJobInfo > getJobs( final String queueName ) {
IBatchJobInfo jobInfo;
List < IBatchJobInfo > retJobs = new ArrayList< IBatchJobInfo >();
Iterator< IBatchJobInfo > iter = this.jobs.values().iterator();
while ( iter.hasNext() ) {
jobInfo = iter.next();
if ( jobInfo.getQueueName().equals( queueName ) ) {
retJobs.add( jobInfo );
}
}
return retJobs;
}
/**
* Returns a list of the jobs that are specified in the incoming list.
* @param jobIds A list of Ids for the jobs to be returned.
* @return Returns a list of {@link IBatchJobInfo} jobs.
*/
public synchronized List< IBatchJobInfo > getJobs( final List< String > jobIds ) {
IBatchJobInfo jobInfo;
List < IBatchJobInfo > retJobs = new ArrayList< IBatchJobInfo >();
for ( String jobId : jobIds ) {
jobInfo = this.jobs.get( jobId );
if ( null != jobInfo )
retJobs.add( jobInfo );
}
return retJobs;
}
/**
* Get the number of currently available jobs.
*
* @return The number of jobs that are currently contained in the internal
* list of jobs in the batch system.
*/
public synchronized int getJobCount() {
return this.jobs.size();
}
/**
* Determine if this job manager's list of managed jobs is currently empty.
*
* @return True if there are no jobs available, false otherwise.
*/
public synchronized boolean isEmpty() {
return getJobCount() == 0;
}
/**
* Add a new {@link IContentChangeListener} to the list of listeners. The
* listeners are always informed when a new job is added to or an old job
* is removed from the internal list of managed jobs.
*
* @param listener The {@link IContentChangeListener} that should be added
* to the list of listeners.
* @see #removeContentChangeListener(IContentChangeListener)
* @see org.eclipse.compare.IContentChangeNotifier#
* addContentChangeListener(org.eclipse.compare.IContentChangeListener)
*/
public void addContentChangeListener( final IContentChangeListener listener ) {
this.ccListeners.add( listener );
}
/**
* Remove the specified {@link IContentChangeListener} from the list of
* listener. This listener will not longer be informed about changes made
* to the list of managed jobs.
*
* @param listener The {@link IContentChangeListener} that should be removed.
* @see org.eclipse.compare.IContentChangeNotifier#
* removeContentChangeListener(org.eclipse.compare.IContentChangeListener)
*/
public void removeContentChangeListener( final IContentChangeListener listener ) {
this.ccListeners.remove( listener );
}
/**
* Remove the specified job from the list of managed jobs.
*
* @param job The job to be removed.
* @return True if the job was contained in the list of managed jobs.
*/
protected /*synchronized */boolean removeJob( final IBatchJobInfo job ) {
IBatchJobInfo removedJob = this.jobs.remove( job.getJobId() );
// if ( null != removedJob ) {
// fireContentChanged();
// }
return null != removedJob;
}
/**
* Delete the specified {@link IBatchJobInfo}. This means especially that the
* specified job is removed from the list of currently managed jobs.
*
* @param job The {@link IBatchJobInfo} to be deleted.
* @throws ProblemException If the job could not be successfully deleted.
*/
public /*synchronized */void deleteJob( final IBatchJobInfo job ) throws ProblemException {
if ( job.isDeletable() ) {
job.deleteJob();
removeJob( job );
}
}
/**
* Move the specified {@link IBatchJobInfo}. This means especially that the
* specified job is also removed from the list of currently managed jobs.
*
* @param job The {@link IBatchJobInfo} to be deleted.
* @param destQueue The destination queue.
* @param destServer The destination server.
* @throws ProblemException If the job could not be successfully moved.
*/
public /*synchronized */void moveJob( final IBatchJobInfo job, final String destQueue,
final String destServer ) throws ProblemException {
if ( job.isMovable() ) {
job.moveJob( destQueue, destServer );
removeJob( job );
}
}
/**
* Puts the specified {@link IBatchJobInfo} on hold.
*
* @param job The {@link IBatchJobInfo} to be put on hold.
* @throws ProblemException If command is not executed successfully
*/
public /*synchronized */void holdJob( final IBatchJobInfo job ) throws ProblemException {
if ( job.isHoldable() ) {
job.holdJob();
job.setStatus( IBatchJobInfo.JobState.H );
// fireContentChanged();
}
}
/**
* Release the specified {@link IBatchJobInfo}.
*
* @param job The {@link IBatchJobInfo} to be released.
* @throws ProblemException If command is not executed successfully
*/
public /*synchronized */void releaseJob( final IBatchJobInfo job ) throws ProblemException {
if ( job.isReleasable() ) {
job.releaseJob();
job.setStatus( IBatchJobInfo.JobState.Q );
// fireContentChanged();
}
}
/**
* ReRun the specified {@link IBatchJobInfo}.
*
* @param job The {@link IBatchJobInfo} to be reRun.
* @throws ProblemException If command is not executed successfully
*/
public /*synchronized */void reRunJob( final IBatchJobInfo job ) throws ProblemException {
if ( job.isReRunnable() ) {
job.reRunJob();
// fireContentChanged();
}
}
/**
* This method clears all the jobs managed by this manager.
*/
public synchronized void removeAll() {
this.done = true;
this.jobs.clear();
this.fireContentChanged();
}
/**
* Notify all registered IContentChangeListeners about content changes,
* i.e. a new job was added or an existing job was removed.
* NOTE: WARNING make sure that all the methods that are called performs
* their actions within a asyncExec block.
*/
protected synchronized void fireContentChanged() {
Object[] list = this.ccListeners.getListeners();
for ( int i = 0 ; i < list.length ; i++ ) {
if ( list[i] instanceof IContentChangeListener ) {
IContentChangeListener listener = ( IContentChangeListener ) list[i];
listener.contentChanged( this );
}
}
}
}