001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.util;
007    
008    import java.util.*;
009    import java.text.*;
010    
011    /** 
012    Useful to store thread-local calendar instances.  This class is intended
013    for servlets/molly pages. Instead of static get/set methods, this class
014    must be instantiated and the instance methods used to get/set the calendar
015    object. This allows multiple instances of this class in the webapp, with
016    each instance being able to get/set a seperate calendar. [If the methods in
017    this class were static, then only 1 calendar could be get/set per thread].
018    <p>
019    <font color=red><b>Each thread must remember to individually create a seperate
020    calendar instance and store it via the set method</b></font>. The usage idiom
021    is:
022    <blockquote>
023    <pre>
024    <font color=blue>
025    //WebApp has a map of ThreadLocalCalendars and also a instance variable
026    //with a default ThreadLocalCalendar
027    ThreadLocalCalendar mycal = WebApp.getThreadLocalCalendar("foo");
028    </font><font color=red>
029    if (mycal.isNull())  {
030      mycal.set(Calendar.getInstance());
031      }
032    </font><font color=blue>
033    Calendar cal = mycal.get();
034    </font>
035    </pre>
036    </blockquote>
037    Note, the lines in red are always needed anywhere/anytime this class is used.
038    (note, it just so happens that the {@link Calendar#getInstance} returns (at
039    least for now) a new object every time it is called, else which is why it is
040    being used in the example above, else we would have to manually create a new
041    Calendar instance instead).
042    
043    */
044    public final class ThreadLocalCalendar
045    {
046    public ThreadLocalCalendar()
047      { }
048    /*
049    Each get/set into the threadlocal must be seperately by each thread (the
050    initialValue() method is good for auto-assigning a new value but we
051    may need to assign a custom calendar value per thread, so we can't use
052    initialValue()
053    */
054    private final ThreadLocal tlcal = new ThreadLocal();
055    
056    public Calendar get()
057      {
058      return (Calendar) tlcal.get();
059      }
060    
061    public void set(Calendar cal)
062      {
063      tlcal.set(cal);
064      }
065    
066    public boolean isNull()
067      {
068      return tlcal.get() == null;
069      }
070    
071    public static void main (String args[]) throws Exception
072      { 
073      final ThreadLocalCalendar cal1 = new ThreadLocalCalendar();
074      
075      Thread t1 = new TestThread(false, cal1);
076      Thread t2 = new TestThread(false, cal1);
077      t1.start();
078      t2.start();
079      
080      for (int n = 0; n < 100; n++) {
081        new TestThread(true, cal1).start();
082        }
083      }
084    
085    static class TestThread extends Thread
086      {
087      boolean timing_only = false;
088      ThreadLocalCalendar cal;
089      TestThread(boolean timing_only, ThreadLocalCalendar cal) {
090        this.timing_only = timing_only;
091        this.cal = cal;
092        }
093        
094      public void run()
095        {
096        //warm up
097        if (cal.isNull()) {
098          cal.set(Calendar.getInstance());
099          }
100    
101        Watch w = new NanoWatch();
102        w.start();
103        if (cal.isNull()) {
104          cal.set(Calendar.getInstance());
105          }
106        Calendar c = cal.get();
107        w.stop();
108        
109        NumberFormat nf = NumberFormat.getNumberInstance();
110        nf.setMinimumFractionDigits(2);
111        nf.setMaximumFractionDigits(2);
112        nf.setMinimumIntegerDigits(2);
113      
114        if (timing_only)
115          System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]");
116        else
117          System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]" + Thread.currentThread() + "/Calendar-ID:[" + System.identityHashCode(c) + "] "+ c);
118        }
119      }
120    }