Author: andy
Date: Thu Apr 18 20:59:24 2013
New Revision: 1469570

URL: http://svn.apache.org/r1469570
Log:
Synchronize operations.
Protect against cancel vs call back being called.

Modified:
    jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
    jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java
    
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java

Modified: 
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java?rev=1469570&r1=1469569&r2=1469570&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java 
(original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java 
Thu Apr 18 20:59:24 2013
@@ -23,11 +23,13 @@ import java.util.Set ;
 import java.util.Timer ;
 
 /** An AlarmClock is an object that will make a call back at a preset time.
- * It addes to java.util.Timer by having an active Timer (and its thread)
- * only when callbacks are outstanding.  The Timer's thread can stop the JVM 
exiting.
+ * It adds tracking to a java.util.Time and also by having
+ * an active Timer (and its thread) only when callbacks are outstanding. 
+ * The Timer's thread can stop the JVM exiting.
  */
 public class AlarmClock
 {
+    // ** Switch to ScheduledThreadPoolExecutor
     // Our callback-later instance
     // Wrap a TimerTask so that the TimerTask.cancel operation can not be 
called
     // directly by the app. We need to go via AlarmClock tracking of callbacks 
so
@@ -89,13 +91,32 @@ public class AlarmClock
         if ( timer == null )
             // Nothing outstanding.
             return ;
-        outstanding.remove(pingback) ;
+        // Calls remove$
+        pingback.cancel();
         // Throw timer, and it's thread, away if no outstanding pingbacks.
-        // This helps apps exit properly (daemon threads don't always seem to 
be as clean as porimised)
-        // but may be troublesome in large systems.  May reconsider. 
+        // This helps apps exit properly but may be troublesome in large 
systems.
+        // May reconsider. 
         if ( clearTimer && getCount() == 0 )
         {
-            timer.cancel();
+            release() ;
+        }
+    }
+    
+    /*package*/ void remove$(Pingback<?> pingback)
+    {
+        outstanding.remove(pingback) ;
+    }
+    
+    public synchronized void release() 
+    {
+        release$() ;
+    }
+    
+    private void release$()
+    {
+        if ( timer != null )
+        {
+            timer.cancel() ;
             timer = null ;
         }
     }
@@ -106,6 +127,5 @@ public class AlarmClock
             timer = new Timer(true) ;
         return timer ;
     }
-    
-    public long timeStart = System.currentTimeMillis() ;
-}
+}  
+ 

Modified: 
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java?rev=1469570&r1=1469569&r2=1469570&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java 
(original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java 
Thu Apr 18 20:59:24 2013
@@ -20,23 +20,39 @@ package org.apache.jena.atlas.lib;
 
 import java.util.TimerTask ;
 
+/** Wrapper around a TimerTask, adding a callback with argument. */
 public class Pingback<T>
 {
+    private final AlarmClock alarmClock ;
     final TimerTask timerTask ;
     final Callback<T> callback ;
     final T arg ;
+    // As good as an AtomicBoolean which is implemented as a volative int for 
get/set.
+    private volatile boolean cancelled = false ;
 
     Pingback(final AlarmClock alarmClock, final Callback<T> callback, T 
argument)
     {
+        this.alarmClock = alarmClock ;
         this.callback = callback ;
         this.arg = argument ;
         this.timerTask = new TimerTask() {
             @Override
             public void run()
             {
+                if ( cancelled )
+                    return ;
+                cancelled = true ;
+                alarmClock.remove$(Pingback.this) ;
                 callback.proc(arg) ;
-                alarmClock.cancel(Pingback.this) ;
             }
         } ;
     }
+    
+    void cancel()
+    {
+        timerTask.cancel() ;
+        cancelled = true ;
+        alarmClock.remove$(this) ;
+    }
 }
+

Modified: 
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java?rev=1469570&r1=1469569&r2=1469570&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java 
(original)
+++ 
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java 
Thu Apr 18 20:59:24 2013
@@ -19,6 +19,9 @@
 package org.apache.jena.atlas.lib;
 
 import static org.apache.jena.atlas.lib.Lib.sleep ;
+
+import java.util.concurrent.atomic.AtomicInteger ;
+
 import org.apache.jena.atlas.junit.BaseTest ;
 import org.apache.jena.atlas.lib.AlarmClock ;
 import org.apache.jena.atlas.lib.Callback ;
@@ -27,8 +30,20 @@ import org.junit.Test ;
 
 public class TestAlarmClock extends BaseTest
 {
-    Callback<?> callback = new Callback<Object>() { @Override
-    public void proc(Object arg) {} } ; 
+    static class CallbackTest implements Callback<Object> 
+    {
+        AtomicInteger count = new AtomicInteger(0) ;
+        
+        public int getCount() { return count.get() ; }
+        
+        @Override
+        public void proc(Object arg)
+        {
+            count.getAndIncrement() ;
+        }
+    } ;
+    
+    CallbackTest callback = new CallbackTest() ;
     
     @Test public void alarm_01()
     {
@@ -39,6 +54,8 @@ public class TestAlarmClock extends Base
         assertEquals(1, alarmClock.getCount()) ;
         alarmClock.cancel(ping) ;
         assertEquals(0, alarmClock.getCount()) ;
+        assertEquals(0, callback.getCount()) ;
+        alarmClock.release() ;
     }
     
     @Test public void alarm_02()
@@ -49,10 +66,12 @@ public class TestAlarmClock extends Base
         Pingback<?> ping = alarmClock.add(callback, 10) ;
         sleep(100) ;
         assertEquals(0, alarmClock.getCount()) ;
+        assertEquals(1, callback.getCount()) ;
         
         // try to cancel anyway.
-        alarmClock.cancel(ping) ;
+        ping.cancel() ;
         assertEquals(0, alarmClock.getCount()) ;
+        alarmClock.release() ;
     }
 
     @Test public void alarm_03()
@@ -65,25 +84,44 @@ public class TestAlarmClock extends Base
         sleep(200) ;
         // ping1 went off.
         assertEquals(1, alarmClock.getCount()) ;
-        alarmClock.cancel(ping1) ;
+        assertEquals(1, callback.getCount()) ;
+        ping1.cancel() ;
+        
         assertEquals(1, alarmClock.getCount()) ;
         alarmClock.cancel(ping2) ;
         assertEquals(0, alarmClock.getCount()) ;
+        assertEquals(1, callback.getCount()) ;
+        alarmClock.release() ;
     }
 
     @Test public void alarm_04()
     {
         AlarmClock alarmClock = new AlarmClock() ;
         assertEquals(0, alarmClock.getCount()) ;
+        Pingback<?> ping1 = alarmClock.add(callback, 10) ;
+        Pingback<?> ping2 = alarmClock.add(callback, 20) ;
+        assertEquals(2, alarmClock.getCount()) ;
+        sleep(200) ;
+        // ping1 went off.  ping2 went off.
+        assertEquals(0, alarmClock.getCount()) ;
+        assertEquals(2, callback.getCount()) ;
+        alarmClock.release() ;
+    }
+
+    @Test public void alarm_05()
+    {
+        AlarmClock alarmClock = new AlarmClock() ;
+        assertEquals(0, alarmClock.getCount()) ;
         Pingback<?> ping1 = alarmClock.add(callback, 100) ;
         assertEquals(1, alarmClock.getCount()) ;
         alarmClock.reset(ping1, 2000) ;
         assertEquals(1, alarmClock.getCount()) ;
         sleep(100) ;
         assertEquals(1, alarmClock.getCount()) ;
+        alarmClock.release() ;
     }
     
-    @Test public void alarm_05()
+    @Test public void alarm_06()
     {
         AlarmClock alarmClock = new AlarmClock() ;
         assertEquals(0, alarmClock.getCount()) ;
@@ -92,8 +130,10 @@ public class TestAlarmClock extends Base
         assertEquals(2, alarmClock.getCount()) ;
         alarmClock.reset(ping1, 2000) ;
         assertEquals(2, alarmClock.getCount()) ;
-        sleep(200) ;    // ping2 goes off.
+        sleep(200) ;    // just ping2 goes off.
+        assertEquals(1, callback.getCount()) ;
         assertEquals(1, alarmClock.getCount()) ;
+        alarmClock.release() ;
     }
     
 }


Reply via email to