/******************************************************************************
* Copyright (c) 2016 Oracle
* 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
*
* Contributors:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
* Danny Ju - [257456} DelayedTasksExecutor does not restart
******************************************************************************/
package org.eclipse.sapphire.ui;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.sapphire.LoggingService;
import org.eclipse.sapphire.Sapphire;
import org.eclipse.swt.widgets.Display;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
* @author <a href="mailto:danny.ju@oracle.com">Danny Ju</a>
*/
public final class DelayedTasksExecutor
{
private static final long DELAY = 300;
private static final long WORKER_THREAD_SHUTDOWN_DELAY = 10 * 60 * 1000;
private static final Task[] NO_TASKS = new Task[ 0 ];
private static final TaskPriorityComparator TASK_PRIORITY_COMPARATOR = new TaskPriorityComparator();
private static final Set<Task> tasks = new LinkedHashSet<Task>();
private static long timeOfLastAddition = 0;
private static long timeOfLastWork = System.currentTimeMillis();
private static WorkerThread workerThread = null;
public static void schedule( final Task task )
{
syncExec
(
new Runnable()
{
public void run()
{
boolean taskScheduled = false;
for( Task t : tasks )
{
if( t.subsumes( task ) )
{
taskScheduled = true;
break;
}
else if( task.subsumes( t ) )
{
tasks.remove( t );
break;
}
}
if( ! taskScheduled )
{
tasks.add( task );
}
timeOfLastAddition = System.currentTimeMillis();
if( workerThread == null || ! workerThread.isAlive() )
{
timeOfLastWork = System.currentTimeMillis();
workerThread = new WorkerThread();
workerThread.start();
}
}
}
);
}
public static void sweep()
{
process( true );
}
private static void process( final boolean doNotDelay )
{
syncExec
(
new Runnable()
{
public void run()
{
Task[] tasksToProcess = NO_TASKS;
if( ! tasks.isEmpty() )
{
boolean process = doNotDelay;
if( ! process )
{
final long now = System.currentTimeMillis();
final long diff = now - timeOfLastAddition;
process = ( diff >= DELAY );
}
if( process )
{
tasksToProcess = tasks.toArray( new Task[ tasks.size() ] );
tasks.clear();
timeOfLastAddition = 0;
}
}
if( tasksToProcess.length > 0 )
{
Arrays.sort( tasksToProcess, TASK_PRIORITY_COMPARATOR );
for( final Runnable task : tasksToProcess )
{
try
{
task.run();
}
catch( Exception e )
{
Sapphire.service( LoggingService.class ).log( e );
}
}
timeOfLastWork = System.currentTimeMillis();
}
}
}
);
}
private static void syncExec( final Runnable op )
{
final Display display = Display.getDefault();
if( Thread.currentThread() == display.getThread() )
{
op.run();
}
else
{
display.syncExec( op );
}
}
public static abstract class Task implements Runnable
{
public int getPriority()
{
return 0;
}
public boolean subsumes( final Task task )
{
return equals( task );
}
}
private static final class TaskPriorityComparator implements Comparator<Task>
{
public int compare( final Task t1, final Task t2 )
{
return t2.getPriority() - t1.getPriority();
}
}
private static final class WorkerThread extends Thread
{
public WorkerThread()
{
super( "Sapphire Delayed Tasks Executor" );
}
public void run()
{
while( true )
{
process( false );
if( System.currentTimeMillis() - timeOfLastWork >= WORKER_THREAD_SHUTDOWN_DELAY )
{
return;
}
try
{
sleep( DELAY );
}
catch( InterruptedException e ) {}
}
}
}
}