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 date format instances.  This class is
013    intended for servlets/molly pages. Instead of static get/set methods,
014    this class must be instantiated and the instance methods used to get/set
015    the calendar object. This allows multiple instances of this class in the
016    webapp, with each instance being able to get/set a separate calendar. [If
017    the methods in this class were static, then only 1 calendar could be
018    get/set per thread].
019    <p>
020    <font color=red><b>Each thread must remember to individually create a
021    separate calendar instance and store it via the set method</b></font>. The
022    usage idiom is:
023    <blockquote>
024    <pre>
025    <font color=blue>
026    //WebApp has a map of ThreadLocalDateFormat's and also a instance variable
027    //pointing to a default ThreadLocalDateFormat
028    ThreadLocalDateFormat mydf = WebApp.getThreadLocalDateFormat("foo");
029    </font><font color=red>
030    if (mydf.isNull())  {
031      mydf.set(DateFormat.getInstance());
032      }
033    </font><font color=blue>
034    DateFormat df = mydf.get();
035    </font>
036    </pre>
037    </blockquote>
038    Note, the lines in red are always needed anywhere/anytime this class is used.
039    */
040    public final class ThreadLocalDateFormat
041    {
042    public ThreadLocalDateFormat()
043      { }
044    /*
045    Each get/set into the threadlocal must be seperately by each thread (the
046    initialValue() method is good for auto-assigning a new value but we
047    may need to assign a custom calendar value per thread, so we can't use
048    initialValue()
049    */
050    private static final ThreadLocal tldf = new ThreadLocal();
051    
052    public DateFormat get()
053      {
054      return (DateFormat) tldf.get();
055      }
056    
057    public void set(DateFormat df)
058      {
059      tldf.set(df);
060      }
061    
062    public boolean isNull()
063      {
064      return tldf.get() == null;
065      }
066    
067    public static void main (String args[]) throws Exception
068      { 
069      final ThreadLocalDateFormat df1 = new ThreadLocalDateFormat();
070      
071      Thread t1 = new TestThread(false, df1);
072      Thread t2 = new TestThread(false, df1);
073      t1.start();
074      t2.start();
075      
076      for (int n = 0; n < 100; n++) {
077        new TestThread(true, df1).start();
078        }
079      }
080    
081    static class TestThread extends Thread
082      {
083      boolean timing_only = false;
084      ThreadLocalDateFormat df;
085      TestThread(boolean timing_only, ThreadLocalDateFormat df) {
086        this.timing_only = timing_only;
087        this.df = df;
088        }
089        
090      public void run()
091        {
092        //warm-up
093        if (df.isNull()) {
094          df.set(DateFormat.getInstance());
095          }
096    
097        Watch w = new NanoWatch();
098        w.start();
099        if (df.isNull()) {
100          df.set(DateFormat.getInstance());
101          }
102        DateFormat c = df.get();
103        w.stop();
104        
105        NumberFormat nf = NumberFormat.getNumberInstance();
106        nf.setMinimumFractionDigits(2);
107        nf.setMaximumFractionDigits(2);
108        nf.setMinimumIntegerDigits(2);
109      
110        if (timing_only)
111          System.out.println("[" + nf.format(w.getTime() / 1000000.00D) 
112            + " ms]");
113        else
114          System.out.println("[" + nf.format(w.getTime() / 1000000.00D) 
115            + " ms]" + Thread.currentThread() 
116            + "/DateFormat-ID:[" + System.identityHashCode(c) 
117            + "] "+ c);
118        }
119      }
120    }