Author: jdonnerstag
Date: Sat Dec 20 11:34:16 2008
New Revision: 728333

URL: http://svn.apache.org/viewvc?rev=728333&view=rev
Log:
wicket-1908: ResourceNameIterator problem with files with undescore in name

Added:
    
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/collections/ConcurrentHashSet.java
Modified:
    
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/locator/ResourceNameIterator.java

Added: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/collections/ConcurrentHashSet.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/collections/ConcurrentHashSet.java?rev=728333&view=auto
==============================================================================
--- 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/collections/ConcurrentHashSet.java
 (added)
+++ 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/collections/ConcurrentHashSet.java
 Sat Dec 20 11:34:16 2008
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.util.collections;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class implements the <tt>Set</tt> interface, backed by a 
ConcurrentHashMap instance.
+ * 
+ * @author Matt Tucker
+ * @param <E>
+ */
+public class ConcurrentHashSet<E> extends AbstractSet<E>
+       implements
+               Set<E>,
+               Cloneable,
+               java.io.Serializable
+{
+       /** */
+       private static final long serialVersionUID = 1L;
+
+       private transient ConcurrentHashMap<E, Object> map;
+
+       // Dummy value to associate with an Object in the backing Map
+       private static final Object PRESENT = new Object();
+
+       /**
+        * Constructs a new, empty set; the backing <tt>ConcurrentHashMap</tt> 
instance has default
+        * initial capacity (16) and load factor (0.75).
+        */
+       public ConcurrentHashSet()
+       {
+               map = new ConcurrentHashMap<E, Object>();
+       }
+
+       /**
+        * Constructs a new set containing the elements in the specified 
collection. The
+        * <tt>ConcurrentHashMap</tt> is created with default load factor 
(0.75) and an initial capacity
+        * sufficient to contain the elements in the specified collection.
+        * 
+        * @param c
+        *            the collection whose elements are to be placed into this 
set.
+        * @throws NullPointerException
+        *             if the specified collection is null.
+        */
+       public ConcurrentHashSet(Collection<? extends E> c)
+       {
+               map = new ConcurrentHashMap<E, Object>(Math.max((int)(c.size() 
/ .75f) + 1, 16));
+               addAll(c);
+       }
+
+       /**
+        * Constructs a new, empty set; the backing <tt>ConcurrentHashMap</tt> 
instance has the
+        * specified initial capacity and the specified load factor.
+        * 
+        * @param initialCapacity
+        *            the initial capacity of the hash map.
+        * @param loadFactor
+        *            the load factor of the hash map.
+        * @throws IllegalArgumentException
+        *             if the initial capacity is less than zero, or if the 
load factor is nonpositive.
+        */
+       public ConcurrentHashSet(int initialCapacity, float loadFactor)
+       {
+               map = new ConcurrentHashMap<E, Object>(initialCapacity, 
loadFactor, 16);
+       }
+
+       /**
+        * Constructs a new, empty set; the backing <tt>HashMap</tt> instance 
has the specified initial
+        * capacity and default load factor, which is <tt>0.75</tt>.
+        * 
+        * @param initialCapacity
+        *            the initial capacity of the hash table.
+        * @throws IllegalArgumentException
+        *             if the initial capacity is less than zero.
+        */
+       public ConcurrentHashSet(int initialCapacity)
+       {
+               map = new ConcurrentHashMap<E, Object>(initialCapacity);
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#iterator()
+        */
+       @Override
+       public Iterator<E> iterator()
+       {
+               return map.keySet().iterator();
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#size()
+        */
+       @Override
+       public int size()
+       {
+               return map.size();
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#isEmpty()
+        */
+       @Override
+       public boolean isEmpty()
+       {
+               return map.isEmpty();
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#contains(java.lang.Object)
+        */
+       @Override
+       public boolean contains(Object o)
+       {
+               return map.containsKey(o);
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#add(java.lang.Object)
+        */
+       @Override
+       public boolean add(E o)
+       {
+               return map.put(o, PRESENT) == null;
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#remove(java.lang.Object)
+        */
+       @Override
+       public boolean remove(Object o)
+       {
+               return map.remove(o) == PRESENT;
+       }
+
+       /**
+        * 
+        * @see java.util.AbstractCollection#clear()
+        */
+       @Override
+       public void clear()
+       {
+               map.clear();
+       }
+
+       /**
+        * 
+        * @see java.lang.Object#clone()
+        */
+       @SuppressWarnings("unchecked")
+       @Override
+       public Object clone()
+       {
+               try
+               {
+                       ConcurrentHashSet<E> newSet = 
(ConcurrentHashSet<E>)super.clone();
+                       newSet.map.putAll(map);
+                       return newSet;
+               }
+               catch (CloneNotSupportedException e)
+               {
+                       throw new InternalError();
+               }
+       }
+
+       /**
+        * 
+        * @param s
+        * @throws java.io.IOException
+        */
+       private void writeObject(java.io.ObjectOutputStream s) throws 
java.io.IOException
+       {
+               s.defaultWriteObject();
+               s.writeInt(map.size());
+
+               for (Iterator<E> i = map.keySet().iterator(); i.hasNext();)
+               {
+                       s.writeObject(i.next());
+               }
+       }
+
+       /**
+        * Re-constitute the <tt>HashSet</tt> instance from a stream.
+        * 
+        * @param inputStream
+        * @throws ClassNotFoundException
+        * @throws IOException
+        */
+       private void readObject(ObjectInputStream inputStream) throws 
ClassNotFoundException,
+               IOException
+       {
+               inputStream.defaultReadObject();
+
+               map = new ConcurrentHashMap<E, Object>();
+
+               int size = inputStream.readInt();
+               for (int i = 0; i < size; i++)
+               {
+                       E e = (E)inputStream.readObject();
+                       map.put(e, PRESENT);
+               }
+       }
+}
\ No newline at end of file

Modified: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/locator/ResourceNameIterator.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/locator/ResourceNameIterator.java?rev=728333&r1=728332&r2=728333&view=diff
==============================================================================
--- 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/locator/ResourceNameIterator.java
 (original)
+++ 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/locator/ResourceNameIterator.java
 Sat Dec 20 11:34:16 2008
@@ -17,7 +17,6 @@
 package org.apache.wicket.util.resource.locator;
 
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Set;
@@ -25,6 +24,7 @@
 import java.util.regex.Pattern;
 
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.util.collections.ConcurrentHashSet;
 import org.apache.wicket.util.string.Strings;
 
 /**
@@ -54,7 +54,7 @@
  */
 public class ResourceNameIterator implements Iterator<String>
 {
-       private static final Pattern LOCALE_PATTERN = 
Pattern.compile("_[a-zA-Z]{2}($|(?=_))");
+       private static final Pattern LOCALE_PATTERN = 
Pattern.compile("_([a-z]{2})(_([A-Z]{2})(_([^_]+))?)?$");
 
        // The locale to search for the resource file
        private final Locale locale;
@@ -70,10 +70,10 @@
        // The latest exact Locale used
        private Locale currentLocale;
 
-       private final Set<String> isoCountries = new HashSet<String>(
+       private final static Set<String> isoCountries = new 
ConcurrentHashSet<String>(
                Arrays.asList(Locale.getISOCountries()));
 
-       private final Set<String> isoLanguages = new HashSet<String>(
+       private final static Set<String> isoLanguages = new 
ConcurrentHashSet<String>(
                Arrays.asList(Locale.getISOLanguages()));
 
        /**
@@ -102,66 +102,59 @@
                        this.extensions = extensions;
                }
 
-               Matcher matcher = LOCALE_PATTERN.matcher(path);
+               String filename = Strings.lastPathComponent(path, '/');
+               Matcher matcher = LOCALE_PATTERN.matcher(filename);
                if (matcher.find())
                {
-                       String language = null;
-                       String country = null;
-                       String variant = null;
-                       int firstValidLocalePatternFragment = -1;
-                       do
-                       {
-                               String s = matcher.group().substring(1, 3);
-                               if (Character.isLowerCase(s.charAt(0)))
-                               {
-                                       if (isoLanguages.contains(s))
-                                       {
-                                               language = s;
-                                               firstValidLocalePatternFragment 
= matcher.start();
-                                               break;
-                                       }
-                               }
-                       }
-                       while (matcher.find());
+                       String language = matcher.group(1);
+                       String country = matcher.group(3);
+                       String variant = matcher.group(5);
 
                        // did we find a language?
                        if (language != null)
                        {
-                               // check for country
-                               if (matcher.find())
+                               if (isoLanguages.contains(language) == false)
                                {
-                                       do
-                                       {
-                                               String s = 
matcher.group().substring(1, 3);
-                                               if 
(Character.isUpperCase(s.charAt(0)))
-                                               {
-                                                       if 
(isoCountries.contains(s))
-                                                       {
-                                                               country = s;
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                                       while (matcher.find());
+                                       language = null;
+                                       country = null;
+                                       variant = null;
                                }
-                               if (country != null)
+                       }
+
+                       // did we find a country?
+                       if ((language != null) && (country != null))
+                       {
+                               if (isoCountries.contains(country) == false)
                                {
-                                       // country found... just get the rest 
of the string for any variant
-                                       if (matcher.find())
-                                       {
-                                               variant = 
path.substring(matcher.start());
-                                       }
+                                       country = null;
+                                       variant = null;
                                }
-                               path = path.substring(0, 
firstValidLocalePatternFragment);
+                       }
+
+                       if (language != null)
+                       {
+                               path = path.substring(0, path.length() - 
filename.length() + matcher.start());
                                localeIterator = new 
LocaleResourceNameIterator(path, new Locale(language,
                                        country != null ? country : "", variant 
!= null ? variant : ""));
-                       } // else skip the whole thing... probably user 
specific underscores used
-               }
+                       }
+               } // else skip the whole thing... probably user specific 
underscores used
 
                styleIterator = new StyleAndVariationResourceNameIterator(path, 
style, null);
        }
 
        /**
+        * 
+        * @param language
+        * @param country
+        * @param variant
+        * @return Locale
+        */
+       private Locale newLocale(String language, String country, String 
variant)
+       {
+               return new Locale(language, country != null ? country : "", 
variant != null ? variant : "");
+       }
+
+       /**
         * Get the exact Locale which has been used for the latest resource 
path.
         * 
         * @return current Locale


Reply via email to