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 006package fc.util; 007 008import java.util.*; 009import java.text.*; 010 011/** 012Useful to store thread-local calendar instances. This class is intended 013for servlets/molly pages. Instead of static get/set methods, this class 014must be instantiated and the instance methods used to get/set the calendar 015object. This allows multiple instances of this class in the webapp, with 016each instance being able to get/set a seperate calendar. [If the methods in 017this 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 020calendar instance and store it via the set method</b></font>. The usage idiom 021is: 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 027ThreadLocalCalendar mycal = WebApp.getThreadLocalCalendar("foo"); 028</font><font color=red> 029if (mycal.isNull()) { 030 mycal.set(Calendar.getInstance()); 031 } 032</font><font color=blue> 033Calendar cal = mycal.get(); 034</font> 035</pre> 036</blockquote> 037Note, 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 039least for now) a new object every time it is called, else which is why it is 040being used in the example above, else we would have to manually create a new 041Calendar instance instead). 042 043*/ 044public final class ThreadLocalCalendar 045{ 046public ThreadLocalCalendar() 047 { } 048/* 049Each get/set into the threadlocal must be seperately by each thread (the 050initialValue() method is good for auto-assigning a new value but we 051may need to assign a custom calendar value per thread, so we can't use 052initialValue() 053*/ 054private final ThreadLocal tlcal = new ThreadLocal(); 055 056public Calendar get() 057 { 058 return (Calendar) tlcal.get(); 059 } 060 061public void set(Calendar cal) 062 { 063 tlcal.set(cal); 064 } 065 066public boolean isNull() 067 { 068 return tlcal.get() == null; 069 } 070 071public 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 085static 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}