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