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 every time this class is used.
038    */
039    public final class ThreadLocalCalendar
040    {
041    public ThreadLocalCalendar()
042      { }
043    /*
044    Each get/set into the threadlocal must be seperately by each thread (the
045    initialValue() method is good for auto-assigning a new value but we
046    may need to assign a custom calendar value per thread, so we can't use
047    initialValue()
048    */
049    private static final ThreadLocal tlcal = new ThreadLocal();
050    
051    public Calendar get()
052      {
053      return (Calendar) tlcal.get();
054      }
055    
056    public void set(Calendar cal)
057      {
058      tlcal.set(cal);
059      }
060    
061    public boolean isNull()
062      {
063      return tlcal.get() == null;
064      }
065    
066    public static void main (String args[]) throws Exception
067      { 
068      final ThreadLocalCalendar cal1 = new ThreadLocalCalendar();
069      
070      Thread t1 = new TestThread(false, cal1);
071      Thread t2 = new TestThread(false, cal1);
072      t1.start();
073      t2.start();
074      
075      for (int n = 0; n < 100; n++) {
076        new TestThread(true, cal1).start();
077        }
078      }
079    
080    static class TestThread extends Thread
081      {
082      boolean timing_only = false;
083      ThreadLocalCalendar cal;
084      TestThread(boolean timing_only, ThreadLocalCalendar cal) {
085        this.timing_only = timing_only;
086        this.cal = cal;
087        }
088        
089      public void run()
090        {
091        //warm up
092        if (cal.isNull()) {
093          cal.set(Calendar.getInstance());
094          }
095    
096        Watch w = new NanoWatch();
097        w.start();
098        if (cal.isNull()) {
099          cal.set(Calendar.getInstance());
100          }
101        Calendar c = cal.get();
102        w.stop();
103        
104        NumberFormat nf = NumberFormat.getNumberInstance();
105        nf.setMinimumFractionDigits(2);
106        nf.setMaximumFractionDigits(2);
107        nf.setMinimumIntegerDigits(2);
108      
109        if (timing_only)
110          System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]");
111        else
112          System.out.println("[" + nf.format(w.getTime() / 1000000.00D) + " ms]" + Thread.currentThread() + "/Calendar-ID:[" + System.identityHashCode(c) + "] "+ c);
113        }
114      }
115    }