[Schmitzm-commits] r2011 - in trunk/schmitzm-core/src/main/java/de/schmitzm: lang regex
scm-commit at wald.intevation.org
scm-commit at wald.intevation.org
Sat May 26 22:06:33 CEST 2012
Author: alfonx
Date: 2012-05-26 22:06:33 +0200 (Sat, 26 May 2012)
New Revision: 2011
Added:
trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LimitedConcurrentHashMap.java
trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedConcurrentHashMap.java
Modified:
trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedHashMap.java
trunk/schmitzm-core/src/main/java/de/schmitzm/regex/RegexCache.java
Log:
Created a TimedConcurrentHashMap and a LimitedConcurrentHashMap and used it everywhere in Immobrain
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LimitedConcurrentHashMap.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LimitedConcurrentHashMap.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LimitedConcurrentHashMap.java 2012-05-26 20:06:33 UTC (rev 2011)
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Tzeggai - additional utility classes
+ ******************************************************************************/
+package de.schmitzm.lang;
+
+import java.util.Map;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+
+import de.schmitzm.data.event.AbstractObjectTraceable;
+import de.schmitzm.data.event.GeneralObjectChangeEvent;
+import de.schmitzm.data.event.Invoker;
+import de.schmitzm.data.event.ObjectChangeEvent;
+import de.schmitzm.data.event.ObjectEvent;
+import de.schmitzm.data.event.ObjectListener;
+import de.schmitzm.data.event.ObjectTraceable;
+
+/**
+ * This class represents a {@link ConcurrentHashMap} which is limited to a number of
+ * elements. When the maximum number of elements is exceeded, the "oldest"
+ * element is removed.<br>
+ *
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ * (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LimitedConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> implements
+ ObjectTraceable {
+ private static final long serialVersionUID = -565382699338290630L;
+
+ /**
+ * Defines which element is removed when the maximum number of elements is
+ * exceeded.
+ */
+ public enum TRUNC_METHOD {
+ /**
+ * The oldest element in the map (with the oldest {@code put(.)}-call)
+ * is removed.
+ */
+ OLDEST_PUT,
+ /**
+ * The element with the oldest accessed (oldest {@code get(.)}-call) is
+ * removed.
+ */
+ OLDEST_GET
+ }
+
+ /**
+ * Defines the behavior to truncate the map when the maximum number of
+ * elements is exceeded.
+ */
+ protected TRUNC_METHOD truncMethod = null;
+ /** Holds the maximum count of elements, the map can hold. */
+ protected int maxLoad = 0;
+ /** Holds the keys of the map in the order of age. */
+ protected Vector<K> oldestKeys = new Vector<K>();
+
+ // Einfache Implementierung von ObjectTraceable, um die Methoden der
+ // Listener-Verwaltung nicht doppelt implementieren zu muessen
+ private AbstractObjectTraceable objectTraceableProxy = new AbstractObjectTraceable() {
+ };
+
+ /**
+ * Creates an empty map using the {@link TRUNC_METHOD#OLDEST_GET} method to
+ * remove objects when map load is exceeded
+ *
+ * @param maxLoad
+ * max. number of elements the map can hold
+ */
+ public LimitedConcurrentHashMap(int maxLoad) {
+ this(maxLoad, TRUNC_METHOD.OLDEST_GET);
+ }
+
+ /**
+ * Creates an empty map.
+ *
+ * @param maxLoad
+ * max. number of elements the map can hold
+ * @param truncMethod
+ * method applied if the maximum map load is exceeded
+ */
+ public LimitedConcurrentHashMap(int maxLoad, TRUNC_METHOD truncMethod) {
+ super(maxLoad);
+ this.truncMethod = truncMethod;
+ setMaxLoad(maxLoad);
+ }
+
+ /**
+ * Returns the maximum number of elements, the map can hold.
+ */
+ public int getMaxLoad() {
+ return maxLoad;
+ }
+
+ /**
+ * Sets the maximum number of elements, the map can hold. If this number is
+ * exceeded, the oldest element is removed.
+ *
+ * @param maxLoad
+ * maximum number of elements, the map can hold
+ * @see TRUNC_METHOD
+ */
+ public void setMaxLoad(int maxLoad) {
+ this.maxLoad = maxLoad;
+ truncate();
+ }
+
+ /**
+ * Returns the behavior when truncating surplus elements.
+ */
+ public TRUNC_METHOD getTruncMethod() {
+ return this.truncMethod;
+ }
+
+ /**
+ * Removes the oldest element from the map until the maximum element count
+ * is reached.
+ */
+ protected void truncate() {
+ while (size() > maxLoad) {
+ // determine the oldest element key (and remove it)
+ K oldestKey = oldestKeys.remove(0);
+ // remove element from map
+ remove(oldestKey);
+ }
+ }
+
+ /**
+ * Von Stefan Tzeggai nachgepflegt: Bestimmt nicht optimal, aber hauptsache nicht ganz am LImited-Algorithmus
+ * vorbei.
+ */
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ for (K key : m.keySet()) {
+ put(key, m.get(key));
+ }
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // /////////////// Ueberschreiben von Vector ///////////////////
+ // /////////////////////////////////////////////////////////////////
+ /**
+ * Adds an element to the map and removes all surplus elements. An
+ * {@link ObjectChangeEvent} is initiated if the map changes.
+ *
+ * @param key
+ * element key
+ * @param value
+ * element value
+ * @return the former value mapped to {@code key} ({@code null} if there was
+ * no such element)
+ */
+ @Override
+ public V put(K key, V value) {
+ // int oldSize = size();
+ V oldValue = super.put(key, value);
+
+ // truncate the map before updating the oldest list, so that
+ // the new element is ignored in this truncate
+ truncate();
+
+ // update the "oldest" list
+ switch (truncMethod) {
+ // OLDEST_PUT: the new element is the youngest, so add the key of the
+ // new element at the end of the oldest list
+ case OLDEST_PUT:
+ oldestKeys.add(key);
+ break;
+ // MS-01.sc: Adding the new element to the top of the oldest-list causes
+ // that
+ // it might be removed immediately on the next put/truncate!
+ // Although this would be consequent, this is not practical.
+ // Instead we put the new element at the end of the oldest-list
+ // so that the element stays in the map at least "for a while".
+ // // OLDEST_GET: the new element is not yet accessed by get, so add the
+ // key
+ // // at the front of the oldest list
+ // case OLDEST_GET: oldestKeys.add(0,key);
+ // break;
+ // OLDEST_GET: to keep the new element in the map at least
+ // "for a while",
+ // it is added at the end of the oldest-list (like OLDEST_PUT)
+ case OLDEST_GET:
+ oldestKeys.add(key);
+ break;
+ // MS-01.ec
+ }
+
+ // fire an event if the map has changed
+ if (oldValue != value)
+ fireEvent(new ObjectChangeEvent(new Invoker(this), oldValue, value));
+
+ return oldValue;
+ }
+
+ /**
+ * Returns an element of the map.
+ *
+ * @param key
+ * element key
+ */
+ @Override
+ public V get(Object key) {
+ V value = super.get(key);
+
+ // update the oldest list if the truncate method is OLDEST_GET
+ if (oldestKeys.contains(key)
+ && TRUNC_METHOD.OLDEST_GET.equals(truncMethod)) {
+ oldestKeys.remove(key); // remove from current position
+ oldestKeys.add((K) key); // add to the end
+ }
+
+ return value;
+ }
+
+ /**
+ * Removes an element from the map and fires an {@link ObjectChangeEvent},
+ * if the map has changed.
+ *
+ * @param key
+ * element key
+ * @return the former value mapped to {@code key} ({@code null} if there was
+ * no such element)
+ */
+ @Override
+ public V remove(Object key) {
+ // remove element from map
+ V oldValue = super.remove(key);
+ // remove key from oldest list
+ oldestKeys.remove(key);
+
+ // fire change event if the list has changed
+ if (oldValue != null)
+ fireEvent(new ObjectChangeEvent(new Invoker(this), oldValue, null));
+
+ return oldValue;
+ }
+
+ /**
+ * Clears the map and fires an {@link GeneralObjectChangeEvent} if the list
+ * changes.
+ */
+ @Override
+ public void clear() {
+ if (isEmpty())
+ return;
+ // clear the map
+ super.clear();
+ // clear the oldest list
+ oldestKeys.clear();
+
+ fireEvent(new GeneralObjectChangeEvent(this));
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // ////////// Implementierung von ObjectTraceable //////////////
+ // /////////////////////////////////////////////////////////////////
+ /**
+ * Adds a listener to the map, which is informed on map changes.
+ */
+ public void addObjectListener(ObjectListener listener) {
+ this.objectTraceableProxy.addObjectListener(listener);
+ }
+
+ /**
+ * Removes a listener from the map.
+ */
+ public void removeObjectListener(ObjectListener listener) {
+ this.objectTraceableProxy.removeObjectListener(listener);
+ }
+
+ /**
+ * Checks, whether a listener is already connected to the map.
+ */
+ public boolean containsObjectListener(ObjectListener l) {
+ return this.objectTraceableProxy.containsObjectListener(l);
+ }
+
+ /**
+ * Returns all listener of a special type.
+ *
+ * @param type
+ * kind of listener (filter)
+ */
+ public ObjectListener[] getObjectListener(Class type) {
+ return this.objectTraceableProxy.getObjectListener(type);
+ }
+
+ /**
+ * Fires an event to all connected listeners.
+ */
+ public void fireEvent(ObjectEvent e) {
+ this.objectTraceableProxy.fireEvent(e);
+ }
+
+ /**
+ * Fires an event to all listeners of a special type.
+ */
+ public void fireEvent(ObjectEvent e, Class c) {
+ this.objectTraceableProxy.fireEvent(e, c);
+ }
+
+}
Property changes on: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/LimitedConcurrentHashMap.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedConcurrentHashMap.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedConcurrentHashMap.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedConcurrentHashMap.java 2012-05-26 20:06:33 UTC (rev 2011)
@@ -0,0 +1,129 @@
+package de.schmitzm.lang;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.swing.Timer;
+
+/**
+ * Erweiterung der {@link LimitedHashMap}. Erlaubt es in Millisekunden anzugeben, wie lange ein Eintrag gültig ist.
+ * Diese Klasse ist eine Kopie von {@link TimedHashMap}, extended aber nicht {@link HashMap}, sondern
+ * {@link ConcurrentHashMap}.
+ */
+public class TimedConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
+
+ private static final long serialVersionUID = -175821101775531256L;
+
+ private final int timeout;
+
+ HashMap<K, Long> inputTimes = new HashMap<K, Long>();
+
+ Timer cleanTask;
+
+ /**
+ * Erweiterung der {@link LimitedHashMap}. Erlaubt es in Millisekunden anzugeben, wie lange ein Eintrag gültig ist.
+ *
+ * @param timeout
+ * Anz. ms die Einträge gültig sind.
+ */
+ public TimedConcurrentHashMap(Number timeout) {
+ this.timeout = timeout.intValue();
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ final Long now = Long.valueOf(System.currentTimeMillis());
+ super.putAll(m);
+ for (K k : m.keySet()) {
+ inputTimes.put(k, now);
+ }
+ }
+
+ @Override
+ public V remove(Object key) {
+ inputTimes.remove(key);
+ return super.remove(key);
+ }
+
+ @Override
+ synchronized public V put(K key, V value) {
+
+ if (timeout > 0) {
+
+ // Timeour ms Nach dem letzten put die komplette hashmap leeren.
+ if (cleanTask != null) {
+ cleanTask.stop();
+ }
+
+ cleanTask = new Timer(timeout + 1, new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ clear();
+ inputTimes.clear();
+ if (cleanTask != null) {
+ cleanTask.stop();
+ cleanTask = null;
+ }
+ }
+
+ });
+ cleanTask.setInitialDelay(timeout);
+ cleanTask.setRepeats(false);
+ cleanTask.start();
+
+ inputTimes.put(key, Long.valueOf(System.currentTimeMillis()));
+ return super.put(key, value);
+ } else
+ return null;
+ }
+
+ @Override
+ public V get(Object key) {
+
+ // Bei einem Timeout von 0 wird der Wert nie gespeichert
+ if (timeout == 0)
+ return null;
+
+ V v = super.get(key);
+ if (v != null) {
+ Long inputTime = inputTimes.get(key);
+ // ??? Wie kann inputTime null sein? Aber ich hatte hier schon Ex,
+ // es geht?!
+ if (inputTime == null) {
+ inputTime = System.currentTimeMillis();
+ inputTimes.put((K) key, inputTime);
+ }
+ if ((System.currentTimeMillis() - inputTime) >= timeout) {
+ remove(key);
+ inputTimes.remove(key);
+ return null;
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Liefert das eingestelte Timeout
+ *
+ * @return
+ */
+ public int getTimeout() {
+ return timeout;
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return get(key) != null;
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ if (cleanTask != null)
+ cleanTask.stop();
+ }
+}
Property changes on: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedConcurrentHashMap.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedHashMap.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedHashMap.java 2012-05-26 19:28:30 UTC (rev 2010)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/lang/TimedHashMap.java 2012-05-26 20:06:33 UTC (rev 2011)
@@ -12,6 +12,8 @@
*/
public class TimedHashMap<K, V> extends HashMap<K, V> {
+ private static final long serialVersionUID = -1758211041775531256L;
+
private final int timeout;
HashMap<K, Long> inputTimes = new HashMap<K, Long>();
@@ -19,7 +21,7 @@
Timer cleanTask;
/**
- * Erweiterung der {@link LimitedHashMap}. Erlaubt es in Millisekunden anzugeben, wie lange ein Eintrag gültig ist.
+ * Erweiterung der {@link HashMap}. Erlaubt es in Millisekunden anzugeben, wie lange ein Eintrag gültig ist.
*
* @param timeout
* Anz. ms die Einträge gültig sind.
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/regex/RegexCache.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/regex/RegexCache.java 2012-05-26 19:28:30 UTC (rev 2010)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/regex/RegexCache.java 2012-05-26 20:06:33 UTC (rev 2011)
@@ -1,6 +1,5 @@
package de.schmitzm.regex;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -8,8 +7,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import de.schmitzm.lang.LimitedHashMap;
-import de.schmitzm.lang.LimitedHashMap.TRUNC_METHOD;
+import de.schmitzm.lang.LimitedConcurrentHashMap;
+import de.schmitzm.lang.LimitedConcurrentHashMap.TRUNC_METHOD;
/**
* Cached compilierte Pattern und auch Ergebnisse von RegExes. Use the matchers methods to obtain cached result and add
@@ -48,8 +47,9 @@
return singletonInstance != null ? singletonInstance : new RegexCache();
}
- private final LimitedHashMap<Pattern, LimitedHashMap<String, MyMatchResult>> matchers = new LimitedHashMap<Pattern, LimitedHashMap<String, MyMatchResult>>(
- CACHE_VALUES_TO_RESULT_SIZE, LimitedHashMap.TRUNC_METHOD.OLDEST_GET);
+ private final LimitedConcurrentHashMap<Pattern, LimitedConcurrentHashMap<String, MyMatchResult>> matchers = new LimitedConcurrentHashMap<Pattern, LimitedConcurrentHashMap<String, MyMatchResult>>(
+ CACHE_VALUES_TO_RESULT_SIZE, LimitedConcurrentHashMap.TRUNC_METHOD.OLDEST_GET);
+
private final HashMap<String, Pattern> patterns = new HashMap<String, Pattern>();
private RegexCache() {
@@ -88,12 +88,12 @@
}
}
-// final static Map<String, ThreadLocal<Matcher>> matchersCachedThreadLocalPerRegex = Collections
-// .synchronizedMap(new LimitedHashMap<String, ThreadLocal<Matcher>>(10000, TRUNC_METHOD.OLDEST_GET));
+ // final static Map<String, ThreadLocal<Matcher>> matchersCachedThreadLocalPerRegex = Collections
+ // .synchronizedMap(new LimitedHashMap<String, ThreadLocal<Matcher>>(10000, TRUNC_METHOD.OLDEST_GET));
- final static Map<String, ThreadLocal<Matcher>> matchersCachedThreadLocalPerRegex = new ConcurrentHashMap<String, ThreadLocal<Matcher>>(10000);
+ final static Map<String, ThreadLocal<Matcher>> matchersCachedThreadLocalPerRegex = new ConcurrentHashMap<String, ThreadLocal<Matcher>>(
+ 10000);
-
/**
* Diese Methode ist gedacht um die Erstellung von Matcher-Objekten in der JVM zu reduzieren. Es für bis zu 10000
* RegEx ein Cache verwaltet. Jeder dieser Caches ist ein ThreadLocal-Cache von Matchern. Somit liefert diese Methde
@@ -122,8 +122,7 @@
return threadLocal.get().reset(text);
}
-
-
+
/**
* Diese Methode ist gedacht um die Erstellung von Matcher-Objekten in der JVM zu reduzieren. Es für bis zu 10000
* RegEx ein Cache verwaltet. Jeder dieser Caches ist ein ThreadLocal-Cache von Matchern. Somit liefert diese Methde
@@ -131,30 +130,29 @@
* Die Matcher werden für die Regex gecached. Wird ein Matcher für eine gecachte Regex mit einem anderen TEXT
* angeforderd, wird zuerst {@link Matcher#reset(CharSequence)} ausgeführt.
*/
-// public Matcher getMatcher(final String regex, final String text) {
-// ThreadLocal<Matcher> threadLocal = matchersCachedThreadLocalPerRegex.get(regex);
-//
-// synchronized (regex) {
-//
-// if (threadLocal == null) {
-//
-// threadLocal = new ThreadLocal<Matcher>() {
-//
-// @Override
-// protected Matcher initialValue() {
-// return getPattern(regex).matcher(text);
-// }
-// };
-// matchersCachedThreadLocalPerRegex.put(regex, threadLocal);
-// }
-//
-// }
-//
-// return threadLocal.get().reset(text);
-
-// return getPattern(regex).matcher(text);
-// }
+ // public Matcher getMatcher(final String regex, final String text) {
+ // ThreadLocal<Matcher> threadLocal = matchersCachedThreadLocalPerRegex.get(regex);
+ //
+ // synchronized (regex) {
+ //
+ // if (threadLocal == null) {
+ //
+ // threadLocal = new ThreadLocal<Matcher>() {
+ //
+ // @Override
+ // protected Matcher initialValue() {
+ // return getPattern(regex).matcher(text);
+ // }
+ // };
+ // matchersCachedThreadLocalPerRegex.put(regex, threadLocal);
+ // }
+ //
+ // }
+ //
+ // return threadLocal.get().reset(text);
+ // return getPattern(regex).matcher(text);
+ // }
/**
* Will throw java exceptions when pattern won't compile.
@@ -176,12 +174,12 @@
final Pattern pattern = getPattern(regex);
- LimitedHashMap<String, MyMatchResult> m;
+ LimitedConcurrentHashMap<String, MyMatchResult> m;
synchronized (matchers) {
m = matchers.get(pattern);
if (m == null) {
- matchers.put(pattern, m = new LimitedHashMap<String, MyMatchResult>(CACHE_VALUES_TO_RESULT_SIZE,
- TRUNC_METHOD.OLDEST_GET));
+ matchers.put(pattern, m = new LimitedConcurrentHashMap<String, MyMatchResult>(
+ CACHE_VALUES_TO_RESULT_SIZE, TRUNC_METHOD.OLDEST_GET));
}
}
More information about the Schmitzm-commits
mailing list