Revision: 682
          http://stripes.svn.sourceforge.net/stripes/?rev=682&view=rev
Author:   bengunter
Date:     2007-12-12 15:43:26 -0800 (Wed, 12 Dec 2007)

Log Message:
-----------
Added thread local caching of Formatter instances and a test to make sure it's 
working.

Modified Paths:
--------------
    
trunk/stripes/src/net/sourceforge/stripes/format/DefaultFormatterFactory.java
    
trunk/tests/src/net/sourceforge/stripes/format/DefaultFormatterFactoryTest.java

Modified: 
trunk/stripes/src/net/sourceforge/stripes/format/DefaultFormatterFactory.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/format/DefaultFormatterFactory.java   
    2007-12-12 19:18:51 UTC (rev 681)
+++ 
trunk/stripes/src/net/sourceforge/stripes/format/DefaultFormatterFactory.java   
    2007-12-12 23:43:26 UTC (rev 682)
@@ -44,6 +44,22 @@
     private Map<Class<?>, Class<? extends Formatter<?>>> classCache = 
Collections
             .synchronizedMap(new HashMap<Class<?>, Class<? extends 
Formatter<?>>>());
 
+    /** Thread local cache of formatter instances. */
+    private ThreadLocal<Map<Class<? extends Formatter<?>>, Formatter<?>>> 
instanceCache = new ThreadLocal<Map<Class<? extends Formatter<?>>, 
Formatter<?>>>() {
+        @Override
+        protected Map<Class<? extends Formatter<?>>, Formatter<?>> 
initialValue() {
+            return new HashMap<Class<? extends Formatter<?>>, Formatter<?>>();
+        }
+    };
+
+    /** Thread local flag that, if true, causes the instance cache to be reset 
in each thread. */
+    private ThreadLocal<Boolean> clearInstanceCache = new 
ThreadLocal<Boolean>() {
+        @Override
+        protected Boolean initialValue() {
+            return false;
+        }
+    };
+
     /** Stores a reference to the Configuration passed in at initialization 
time. */
     private Configuration configuration;
 
@@ -80,15 +96,21 @@
      * @param formatterClass the implementation class that will handle the 
formatting
      */
     public void add(Class<?> targetType, Class<? extends Formatter<?>> 
formatterClass) {
+        this.formatters.put(targetType, formatterClass);
         if (classCache.size() > 0)
             clearCache();
-        this.formatters.put(targetType, formatterClass);
     }
 
     /** Clear the class and instance caches. This is called by [EMAIL 
PROTECTED] #add(Class, Class)}. */
-    protected void clearCache() {
+    protected synchronized void clearCache() {
         log.debug("Clearing formatter cache");
         classCache.clear();
+        clearInstanceCache = new ThreadLocal<Boolean>() {
+            @Override
+            protected Boolean initialValue() {
+                return true;
+            }
+        };
     }
 
     /**
@@ -223,8 +245,21 @@
     public Formatter<?> getInstance(Class<? extends Formatter<?>> clazz,
             String formatType, String formatPattern, Locale locale)
             throws Exception {
-        // TODO: add thread local caching of formatter classes
-        Formatter<?> formatter = clazz.newInstance();
+        // If the reset flag is turned on, then clear the cache and turn the 
flag off
+        if (clearInstanceCache.get()) {
+            log.debug("Clearing formatter instance cache for thread ",
+                    Thread.currentThread().getName());
+            instanceCache.get().clear();
+            clearInstanceCache.set(false);
+        }
+
+        // Look for an instance in the cache. If none is found then create one 
and cache it.
+        Formatter<?> formatter = instanceCache.get().get(clazz);
+        if (formatter == null) {
+            formatter = clazz.newInstance();
+            log.debug("Caching instance of formatter ", clazz);
+            instanceCache.get().put(clazz, formatter);
+        }
         formatter.setFormatType(formatType);
         formatter.setFormatPattern(formatPattern);
         formatter.setLocale(locale);

Modified: 
trunk/tests/src/net/sourceforge/stripes/format/DefaultFormatterFactoryTest.java
===================================================================
--- 
trunk/tests/src/net/sourceforge/stripes/format/DefaultFormatterFactoryTest.java 
    2007-12-12 19:18:51 UTC (rev 681)
+++ 
trunk/tests/src/net/sourceforge/stripes/format/DefaultFormatterFactoryTest.java 
    2007-12-12 23:43:26 UTC (rev 682)
@@ -148,13 +148,43 @@
         Assert.assertEquals(YFormatter.class, formatter.getClass());
     }
 
-    public static void main(String[] args) throws Exception {
-        DefaultFormatterFactoryTest test = new DefaultFormatterFactoryTest();
-        test.testFormatterSuperclass();
-        test.testFormatterInterface();
-        test.testNullFormatterIsNeverBestMatch();
-        test.testFormatterSuperclassImplementsInterface();
-        test.testFormatterForInterfaceSuperclass();
+    @Test(groups = "fast")
+    public void testFormatterInstanceCaching() throws Exception {
+        DefaultFormatterFactory factory = new DefaultFormatterFactory();
+        factory.init(new DefaultConfiguration());
+
+        Locale locale = Locale.getDefault();
+        Formatter<?> first, second;
+
+        // register some formatters
+        factory.add(X.class, XFormatter.class);
+        factory.add(Y.class, YFormatter.class);
+        factory.add(Z.class, ZFormatter.class);
+
+        // get each twice in succession and compare the references to make 
sure it's the same object
+        first = factory.getFormatter(SuperclassImplementsX.class, locale, 
null, null);
+        second = factory.getFormatter(SuperclassImplementsX.class, locale, 
null, null);
+        Assert.assertTrue(first == second);
+        first = factory.getFormatter(SuperclassImplementsY.class, locale, 
null, null);
+        second = factory.getFormatter(SuperclassImplementsY.class, locale, 
null, null);
+        Assert.assertTrue(first == second);
+        first = factory.getFormatter(SuperclassImplementsZ.class, locale, 
null, null);
+        second = factory.getFormatter(SuperclassImplementsZ.class, locale, 
null, null);
+        Assert.assertTrue(first == second);
+
+        // do it again but force a cache clear between gets
+        first = factory.getFormatter(SuperclassImplementsX.class, locale, 
null, null);
+        factory.add(X.class, XFormatter.class);
+        second = factory.getFormatter(SuperclassImplementsX.class, locale, 
null, null);
+        Assert.assertFalse(first == second);
+        first = factory.getFormatter(SuperclassImplementsY.class, locale, 
null, null);
+        factory.add(Y.class, YFormatter.class);
+        second = factory.getFormatter(SuperclassImplementsY.class, locale, 
null, null);
+        Assert.assertFalse(first == second);
+        first = factory.getFormatter(SuperclassImplementsZ.class, locale, 
null, null);
+        factory.add(Z.class, ZFormatter.class);
+        second = factory.getFormatter(SuperclassImplementsZ.class, locale, 
null, null);
+        Assert.assertFalse(first == second);
     }
 
     public void testFormatterForInterfaceSuperclass() throws Exception {


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to