/*****************************************************************************
* Copyright (c) 2006, 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 the
* g-Eclipse project founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributors:
* Pawel Wolniewicz
* Szymon Mueller
*****************************************************************************/
package eu.geclipse.core;
import java.util.Enumeration;
import java.util.Hashtable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import eu.geclipse.core.internal.Activator;
import eu.geclipse.core.internal.model.JobManager;
import eu.geclipse.core.model.IGridJob;
import eu.geclipse.core.model.IGridJobStatus;
import eu.geclipse.core.model.IGridJobStatusListener;
/**
* The class for updating job status in the background. There is one JobStatusUpdater
* for each job and it is started when a job is added to project.
* @see JobManager
* @see IGridJobStatus
* @see IGridJob
*
*/
public class JobStatusUpdater extends Job {
/**
* Hashtable that hold information about registered listeners and the statuses for
* which listener should be notified
* @seeIGridJobStatusListener
*/
private Hashtable<IGridJobStatusListener, Integer> listeners=new Hashtable<IGridJobStatusListener, Integer>();
private IGridJob job = null;
private IGridJobStatus lastStatus=null;
/**
* Flag set to <code>true</code>, when {@link IGridJob} is removed, so
* {@link JobStatusUpdater} should stop to check current job status
*/
private boolean jobRemoved;
/**
* Constructor
* @param job for which this updater is created
*/
public JobStatusUpdater( final IGridJob job ) {
super( Messages.getString("JobStatusUpdater.name") ); //$NON-NLS-1$
this.job = job;
}
/**
* @return Job for which this updater is running.
*/
public IGridJob getJob() {
return this.job;
}
@Override
protected IStatus run( final IProgressMonitor monitor ) {
SubMonitor subMonitor = SubMonitor.convert( monitor );
testCancelled( subMonitor );
if( Preferences.getUpdateJobsStatus() ) {
int oldType = -1;
if( this.lastStatus != null ) {
oldType = this.lastStatus.getType();
}
int newType = IGridJobStatus.UNKNOWN;
IGridJobStatus newStatus = null;
try {
if( this.job != null ) {
testCancelled( subMonitor );
this.job.updateJobStatus( subMonitor, false );
newStatus = this.job.getJobStatus();
}
if( newStatus != null ) {
newType = newStatus.getType();
this.lastStatus = newStatus;
}
if( oldType != newType ) {
for( Enumeration<IGridJobStatusListener> e = this.listeners.keys(); e.hasMoreElements(); )
{
testCancelled( subMonitor );
IGridJobStatusListener listener = e.nextElement();
int trigger = this.listeners.get( listener ).intValue();
if( ( newType & trigger ) > 0 ) {
listener.statusChanged( this.job );
}
listener.statusUpdated( this.job );
}
} else {
for( Enumeration<IGridJobStatusListener> e = this.listeners.keys(); e.hasMoreElements(); )
{
testCancelled( subMonitor );
IGridJobStatusListener listener = e.nextElement();
listener.statusUpdated( this.job );
}
}
} catch( RuntimeException e ) {
Activator.logException( e );
}
if( newStatus != null && newStatus.getReason() != null && newStatus.getReason().equals( "Token request canceled" ) ) {
if( Preferences.getJobUpdaterCancelBehaviour() ) {
Preferences.setUpdateJobsStatus( false );
JobManager.getManager().pauseUpdater( this );
}
}
if( !this.jobRemoved
&& !monitor.isCanceled()
&& newStatus != null
&& newStatus.canChange() )
{
int updatePeriod = Preferences.getUpdateJobsPeriod();
schedule( updatePeriod );
} else {
JobManager.getManager().removeJobStatusUpdater( this.job,
false,
monitor );
}
}
return Status.OK_STATUS;
}
private void testCancelled( final SubMonitor subMonitor ) {
if( subMonitor.isCanceled() ) {
throw new OperationCanceledException();
}
}
/**
* Used when job status was updated outside of the updater. Checks if status
* changed from previous update. If so informs all listeners that status has
* changed.
*
* @param newStatus Fetched status
*/
public void statusUpdated( final IGridJobStatus newStatus ) {
int oldType = -1;
if( this.lastStatus != null ) {
oldType = this.lastStatus.getType();
}
if( newStatus != null ) {
int newType = newStatus.getType();
if( oldType != newType ) {
this.lastStatus = newStatus;
for( Enumeration<IGridJobStatusListener> e = this.listeners.keys(); e.hasMoreElements(); )
{
IGridJobStatusListener listener = e.nextElement();
int trigger = this.listeners.get( listener ).intValue();
if( ( newType & trigger ) > 0 ) {
listener.statusChanged( this.job );
}
listener.statusUpdated( this.job );
}
} else {
for( Enumeration<IGridJobStatusListener> e = this.listeners.keys(); e.hasMoreElements(); )
{
IGridJobStatusListener listener = e.nextElement();
listener.statusUpdated( this.job );
}
}
}
}
/**
* Add status listener for the updater. The listener will be notify, when the
* status of the job will change.
*
* @param status - aggregate value of IGridJobStatus types, for which listener
* should be notified.
* @param listener - listener to be notifies about the change.
*/
public void addJobStatusListener( final int status, final IGridJobStatusListener listener ) {
this.listeners.put( listener, Integer.valueOf( status ) );
}
/**
* Removes registrered job status listener
* @param listener
*/
public void removeJobStatusListener( final IGridJobStatusListener listener ) {
this.listeners.remove( listener );
}
/**
* Mark {@link IGridJob} connected with this updater as removed, what means
* that this updater should stop to schedule itself.<br/> Note, that this is
* not the same as cancelled, because cancel interupt only currect updating,
* so next updating will be scheduled
*/
public void setRemoved() {
this.jobRemoved = true;
}
public void wakeUpdater() {
wakeUp();
}
}