Author: ivaynberg
Date: Mon Jun 16 08:42:19 2008
New Revision: 668201

URL: http://svn.apache.org/viewvc?rev=668201&view=rev
Log:
WICKET-1667, WICKET-1697: localizer memory leak fixes

Modified:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/Localizer.java

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Localizer.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Localizer.java?rev=668201&r1=668200&r2=668201&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/Localizer.java 
(original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Localizer.java Mon Jun 
16 08:42:19 2008
@@ -16,12 +16,16 @@
  */
 package org.apache.wicket;
 
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import org.apache.wicket.markup.repeater.AbstractRepeater;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.resource.loader.IStringResourceLoader;
 import org.apache.wicket.settings.IResourceSettings;
@@ -57,6 +61,8 @@
        /** Cache properties */
        private Map<String, String> cache = newCache();
 
+       private final ClassMetaDatabase metaDatabase = new ClassMetaDatabase();
+
        /**
         * Create the utils instance class backed by the configuration 
information contained within the
         * supplied application object.
@@ -331,11 +337,26 @@
                        Component<?> cursor = component;
                        while (cursor != null)
                        {
-                               
buffer.append("-").append(cursor.getClass().getName());
-                               buffer.append(":").append(cursor.getId());
-                               cursor = cursor.getParent();
+                               
buffer.append("-").append(metaDatabase.id(cursor.getClass()));
+
                                if (cursor instanceof Page)
+                               {
                                        break;
+                               }
+
+                               if (cursor.getParent() != null && 
!(cursor.getParent() instanceof AbstractRepeater))
+                               {
+                                       /*
+                                        * only append component id if parent 
is not a repeater because
+                                        * 
+                                        * (a) these ids are irrelevant when 
generating resource cache keys
+                                        * 
+                                        * (b) they cause a lot of redundant 
keys to be generated
+                                        */
+                                       
buffer.append(":").append(cursor.getId());
+                               }
+                               cursor = cursor.getParent();
+
                        }
 
                        buffer.append("-").append(component.getLocale());
@@ -399,4 +420,57 @@
        {
                return new ConcurrentHashMap<String, String>();
        }
+
+       /**
+        * Database that maps class names to an integer id. This is used to 
make localizer keys shorter
+        * because sometimes they can contain a large number of class names.
+        * 
+        * @author igor.vaynberg
+        */
+       private static class ClassMetaDatabase
+       {
+               private final Map<String, Long> nameToId = new HashMap<String, 
Long>();
+               private final ReadWriteLock nameToIdLock = new 
ReentrantReadWriteLock();
+               private long nameCounter = 0;
+
+               /**
+                * Returns a unique id that represents this class' name. This 
can be used for compressing
+                * class names. Notice this id should not be used across 
cluster nodes.
+                * 
+                * @param clazz
+                * @return long id of class name
+                */
+               public long id(Class<?> clazz)
+               {
+                       final String name = clazz.getName();
+                       nameToIdLock.readLock().lock();
+                       try
+                       {
+                               Long id = nameToId.get(name);
+                               if (id == null)
+                               {
+                                       nameToIdLock.readLock().unlock();
+                                       nameToIdLock.writeLock().lock();
+                                       try
+                                       {
+                                               nameToId.put(name, nameCounter);
+                                               id = nameCounter;
+                                               nameCounter++;
+                                       }
+                                       finally
+                                       {
+                                               nameToIdLock.readLock().lock();
+                                               
nameToIdLock.writeLock().unlock();
+                                       }
+                               }
+                               return id;
+                       }
+                       finally
+                       {
+                               nameToIdLock.readLock().unlock();
+                       }
+               }
+       }
+
+
 }
\ No newline at end of file


Reply via email to