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 }