package org.realityforge.gwt.webpoller.server;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.realityforge.gwt.webpoller.client.WebPoller;

/**
 * A web-poller that used the standard Timer class to schedule requests.
 */
public class TimerBasedWebPoller
  extends WebPoller
{
  @Nonnull
  private final ScheduledExecutorService _timer;
  @Nullable
  private ScheduledFuture<?> _future;
  private final ReentrantReadWriteLock _timerLock = new ReentrantReadWriteLock( true );

  public static class Factory
    implements WebPoller.Factory
  {
    private final ScheduledExecutorService _service;

    public Factory( @Nonnull final ScheduledExecutorService service )
    {
      _service = service;
    }

    @Nonnull
    @Override
    public WebPoller newWebPoller()
    {
      return new TimerBasedWebPoller( _service );
    }
  }

  public TimerBasedWebPoller( @Nonnull final ScheduledExecutorService timer )
  {
    _timer = timer;
  }

  @Override
  protected void startTimer()
  {
    doStartTimer( getInterRequestDuration() );
  }

  protected boolean isTimerActive()
  {
    _timerLock.readLock().lock();
    try
    {
      return null != _future;
    }
    finally
    {
      _timerLock.readLock().unlock();
    }
  }

  private void doStartTimer( final int pollDuration )
  {
    _timerLock.writeLock().lock();

    try
    {
      stopTimer();
      final Runnable command = new Runnable()
      {
        @Override
        public void run()
        {
          poll();
        }
      };
      _future = _timer.scheduleAtFixedRate( command, 0, pollDuration, TimeUnit.MILLISECONDS );
    }
    finally
    {
      _timerLock.writeLock().unlock();
    }
  }

  @Override
  protected void stopTimer()
  {
    doStopTimer();
  }

  private void doStopTimer()
  {
    _timerLock.writeLock().lock();
    try
    {
      if ( null != _future )
      {
        _future.cancel( true );
        _future = null;
      }
    }
    finally
    {
      _timerLock.writeLock().unlock();
    }
  }

  @Override
  protected void startErrorTimer()
  {
    doStartTimer( getInterErrorDuration() );
  }

  @Override
  protected void stopErrorTimer()
  {
    doStopTimer();
  }
}

@@ -212,38 +212,114 @@
 t.locks.
-ReentrantReadWriteLock
+Lock;%0Aimport java.util.concurrent.locks.ReentrantReadWriteLock;%0Aimport java.util.function.Supplier
 ;%0Aimport
@@ -722,22 +722,17 @@
 teLock _
-timerL
+l
 ock = ne
@@ -1379,149 +1379,67 @@
     
-_timerLock.readLock().lock();%0A    try%0A    %7B%0A      return null != _future;%0A    %7D%0A    finally%0A    %7B%0A      _timerLock.readLock().unlock();%0A    %7D
+return withLock( _lock.readLock(), () -%3E null != _future );
 %0A  %7D
@@ -1494,39 +1494,44 @@
 ation )%0A  %7B%0A    
-_timerL
+withLock( _l
 ock.writeLock().
@@ -1533,25 +1533,15 @@
 ck()
-.lock();%0A%0A    try
+, () -%3E
 %0A   
@@ -1811,71 +1811,11 @@
    %7D
-%0A    finally%0A    %7B%0A      _timerLock.writeLock().unlock();%0A    %7D
+ );
 %0A  %7D
@@ -1918,31 +1918,36 @@
 r()%0A  %7B%0A    
-_timerL
+withLock( _l
 ock.writeLoc
@@ -1953,24 +1953,15 @@
 ck()
-.lock();%0A    try
+, () -%3E
 %0A   
@@ -2073,71 +2073,11 @@
    %7D
-%0A    finally%0A    %7B%0A      _timerLock.writeLock().unlock();%0A    %7D
+ );
 %0A  %7D
@@ -2221,32 +2221,32 @@
 rrorTimer()%0A  %7B%0A
-
     doStopTimer(
@@ -2251,11 +2251,381 @@
 r();%0A  %7D
+%0A%0A  protected %3CT%3E T withLock( final Lock lock, final Supplier%3CT%3E action )%0A  %7B%0A    lock.lock();%0A    try%0A    %7B%0A      return action.get();%0A    %7D%0A    finally%0A    %7B%0A      lock.unlock();%0A    %7D%0A  %7D%0A%0A%0A  protected void withLock( final Lock lock, final Runnable action )%0A  %7B%0A    lock.lock();%0A    try%0A    %7B%0A      action.run();%0A    %7D%0A    finally%0A    %7B%0A      lock.unlock();%0A    %7D%0A  %7D
 %0A%7D%0A

Simplify usage of locks with lambdas