Tuesday, December 10, 2013

It is a common use case to create an activity which returns a particular state for a specific amount of time and then revert back to its original state. For example you want to suspend a particular user on your website for say, 60 seconds (maybe because he’s submitting a form too fast – a strategy a lot of forms support). There are many such use cases possible especially when that application is using huge amount of cache. One way to do it would be with database which is not only highly in-efficient but way too cumbersome. If we could create a data structure that could retain its state for a specific time and then revert back, it would be killer.

I would present such a Boolean data structure that could be used to validate a condition for a specific time and then it would revert back to its original status.

One of the important design decisions has been to make this data structure immutable. One instance would represent just one state. Also, in this implementation I have used constructors rather than static factory method to return state objects, but nothing stops us from having a static factory method for our state objects.

Lets look at our class now:








public class AutoRevertingBoolean {



  //the present status

  private final boolean present;

  

  //This is the default status and this is what

  // the object would be reverted to. Since this is boolean

  //it can be either true/fase, but why this property

  //is important would be explained in subsequent posts.

  private final boolean revertTo;

  

  //the time till which the present state would

  //be preserved before reverting back

  private final long waitInMillisBeforeReverting;

  

  //time that preserves the invocation time

  //of this data structure

  private long time = 0;



  /**

   * Constructor that creates the state object but the users

   * would need to explicitly start the ticker by invoking

   * the {@link #startMeasuring()} method

   @param present

   @param revertTo

   @param waitInMillisBeforeReverting long time in milliseconds

   */

  public AutoRevertingBoolean(final boolean present, final boolean revertTo,

      final long waitInMillisBeforeReverting) {

    this.present = present;

    this.revertTo = revertTo;

    this.waitInMillisBeforeReverting = waitInMillisBeforeReverting;

  }



  /**

   * Constructor that also starts the ticker as soon as this

   * object is created.

   @param present boolean

   @param revertTo boolean 

   @param waitInMillisBeforeReverting long time in milliseconds

   @param startNow

   */

  public AutoRevertingBoolean(final boolean present, final boolean revertTo,

      final long waitInMillisBeforeReverting, final boolean startNow) {

    this(present, revertTo, waitInMillisBeforeReverting);

    this.startMeasuring();

  }



  /**

   * Returns the present state of the object

   @return boolean Will return the present state if the 

   * specified time has not elapsed or else would return the

   * default state of the object. 

   */

  public boolean get() {

    return System.currentTimeMillis() < time + waitInMillisBeforeReverting ? present

        : revertTo;

  }



  /**

   * starts the timer for this data structure

   */

  public void startMeasuring() {

    if(!(time > ))

      time = System.currentTimeMillis();

  }



  public static void main(String[] args) {



    AutoRevertingBoolean obj = new AutoRevertingBoolean(true, false, 3000);

    //need to explicitly call this for the constructor that we have used.

    obj.startMeasuring();

    foo(obj);

    obj = new AutoRevertingBoolean(true, false, 5000,true);

    //need not explicitly start measuring the time

    foo(obj);

  }



  private static void foo(AutoRevertingBoolean obj) {

    System.out.println("Starting.....");

    long startTime = System.currentTimeMillis();

    for (int i = 0; i < Integer.MAX_VALUE; i++) {

      if (!obj.get())

        break;

    }

    System.out.println("Done in:" (System.currentTimeMillis() - startTime)+" milliseconds.");

  }



}




The code is pretty self-explanatory. The main method gives away its usage pattern. There are several ways to extend this data structure and as we move forward we would try to improve and evolve this data structure.

No comments:

Post a Comment