[Schmitzm-commits] r941 - in trunk: . src/schmitzm/lang src_junit/schmitzm/lang

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Jul 22 12:20:11 CEST 2010


Author: mojays
Date: 2010-07-22 12:20:09 +0200 (Thu, 22 Jul 2010)
New Revision: 941

Added:
   trunk/src/schmitzm/lang/LimitedHashMap.java
   trunk/src_junit/schmitzm/lang/LimitedHashMapTest.java
Modified:
   trunk/build.xml
   trunk/src/schmitzm/lang/LangUtil.java
   trunk/src/schmitzm/lang/LimitedVector.java
Log:
build.xml: updated on new target folder
LangUtil: new helper methods for string/object connect
LimitedVector: java doc updated
LimitedHashMap: new class analogous to LimitedVector
LimitedHashMapTest: new junit test for LimitedHashMap

Modified: trunk/build.xml
===================================================================
--- trunk/build.xml	2010-07-21 18:07:39 UTC (rev 940)
+++ trunk/build.xml	2010-07-22 10:20:09 UTC (rev 941)
@@ -3,7 +3,7 @@
            dependencies)!!
 
      Option "jar"     -> a JAR from the existing binaries expected in folder
-                         "classes" plus a ZIP of the JAR
+                         "targes/classes" plus a ZIP of the JAR
      Option "src"     -> a ZIP of the source code in folder "src"
      Option "javadoc" -> a JavaDoc in folder "javadoc" plus a ZIP of
                          this folder
@@ -40,7 +40,7 @@
 	<property name="FILE.SRC.ZIP"     value="${DEST.DIR}/${PROJECT.PREFIX}-src.zip"/>
 	
 	<!-- Source and Destination for JAR file -->
-	<property name="DIR.CLASSES"      value="classes"/>
+	<property name="DIR.CLASSES"      value="target/classes"/>
     <property name="FILE.JAR"         value="${DEST.DIR}/${PROJECT.PREFIX}.jar"/>
 	<property name="FILE.JAR.ZIP"     value="${FILE.JAR}.zip"/>
 	

Modified: trunk/src/schmitzm/lang/LangUtil.java
===================================================================
--- trunk/src/schmitzm/lang/LangUtil.java	2010-07-21 18:07:39 UTC (rev 940)
+++ trunk/src/schmitzm/lang/LangUtil.java	2010-07-22 10:20:09 UTC (rev 941)
@@ -90,21 +90,59 @@
 	 * @return
 	 */
 	public static String listString(String delim, String... strList) {
-	  StringBuffer resultStr = new StringBuffer();
-	  for (int i=0; i<strList.length; i++) {
-	    // ignore item if it it null or empty
-	    if ( strList[i] == null || "".equals(strList[i].trim()) )
-	      continue;
-	    // append delimiter (if necessary)
-	    if ( resultStr.length() > 0 && delim != null )
-	      resultStr.append(delim);
-	    // append string
-	    resultStr.append(strList[i].trim());
-	  }
-	  return resultStr.toString();
+//	  StringBuffer resultStr = new StringBuffer();
+//	  for (int i=0; i<strList.length; i++) {
+//	    // ignore item if it it null or empty
+//	    if ( strList[i] == null || "".equals(strList[i].trim()) )
+//	      continue;
+//	    // append delimiter (if necessary)
+//	    if ( resultStr.length() > 0 && delim != null )
+//	      resultStr.append(delim);
+//	    // append string
+//	    resultStr.append(strList[i].trim());
+//	  }
+//	  return resultStr.toString();
+	  return listObjects(delim, true, (Object[])strList);
 	}
 
-	/**
+    /**
+     * Haengt Objekte (als String) aneinander, getrennt durch Trennzeichen. 
+     * @param delim   Trennzeichen (kann {@code null} sein)
+     * @param ignoreNulls bestimmt, ob {@code null}-Elemente (und leere Strings)
+     *                    ignoriert werden
+     * @param objList Liste von Objekten
+     * @return
+     */
+    public static String listObjects(String delim, boolean ignoreNulls, Object... objList) {
+      StringBuffer resultStr = new StringBuffer();
+      for (int i=0; i<objList.length; i++) {
+        // ignore item if it is null or empty
+        if ( ignoreNulls && (objList[i] == null || objList[i] instanceof String && "".equals(((String)objList[i]).trim()) ) )
+          continue;
+        // append delimiter (if necessary)
+        if ( resultStr.length() > 0 && delim != null )
+          resultStr.append(delim);
+        // append string
+        String str = (objList[i] == null) ? "null" : objList[i].toString(); 
+        resultStr.append(str.trim());
+      }
+      return resultStr.toString();
+    }
+
+    /**
+     * Haengt Objekte (als String) aneinander, getrennt durch Trennzeichen. 
+     * @param delim   Trennzeichen (kann {@code null} sein)
+     * @param ignoreNulls bestimmt, ob {@code null}-Elemente (und leere Strings)
+     *                    ignoriert werden
+     * @param objList Liste von Objekten
+     * @return
+     */
+    public static String listObjects(String delim, boolean ignoreNulls, Collection<?> values) {
+      Object[] objArray = values.toArray();
+      return listObjects(delim,ignoreNulls,objArray);
+    }
+    
+    /**
 	 * Prueft, ob ein {@link Enum} ein spezielles Feld besitzt.
 	 * 
 	 * @param enumClass

Added: trunk/src/schmitzm/lang/LimitedHashMap.java
===================================================================
--- trunk/src/schmitzm/lang/LimitedHashMap.java	2010-07-21 18:07:39 UTC (rev 940)
+++ trunk/src/schmitzm/lang/LimitedHashMap.java	2010-07-22 10:20:09 UTC (rev 941)
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * 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 schmitzm.lang;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Vector;
+
+import schmitzm.data.event.AbstractObjectTraceable;
+import schmitzm.data.event.GeneralObjectChangeEvent;
+import schmitzm.data.event.Invoker;
+import schmitzm.data.event.ObjectChangeEvent;
+import schmitzm.data.event.ObjectEvent;
+import schmitzm.data.event.ObjectListener;
+import schmitzm.data.event.ObjectTraceable;
+
+/**
+ * This class represents a {@link HashMap} 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 LimitedHashMap<K,V> extends HashMap<K,V> implements ObjectTraceable {
+  
+  /**
+   * 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.
+   * @param maxLoad max. number of elements the map can hold
+   * @param truncMethod method applied if the maximum map load is exeeced 
+   */
+  public LimitedHashMap(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 );
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  /////////////////   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;
+      // 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;
+    }
+    
+    // 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);
+  }
+
+}

Modified: trunk/src/schmitzm/lang/LimitedVector.java
===================================================================
--- trunk/src/schmitzm/lang/LimitedVector.java	2010-07-21 18:07:39 UTC (rev 940)
+++ trunk/src/schmitzm/lang/LimitedVector.java	2010-07-22 10:20:09 UTC (rev 941)
@@ -90,7 +90,7 @@
   }
 
   /**
-   * Loescht solange das letzte Element der Liste, bis die maximale Anzahl
+   * Loescht solange das erste Element der Liste, bis die maximale Anzahl
    * an Elementen erreicht ist.
    */
   protected void truncate() {

Added: trunk/src_junit/schmitzm/lang/LimitedHashMapTest.java
===================================================================
--- trunk/src_junit/schmitzm/lang/LimitedHashMapTest.java	2010-07-21 18:07:39 UTC (rev 940)
+++ trunk/src_junit/schmitzm/lang/LimitedHashMapTest.java	2010-07-22 10:20:09 UTC (rev 941)
@@ -0,0 +1,107 @@
+package schmitzm.lang;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.filter.text.cql2.CQLException;
+import org.jfree.chart.ChartFrame;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.AxisState;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.NumberTick;
+import org.jfree.chart.axis.NumberTickUnit;
+import org.jfree.chart.axis.TickUnits;
+import org.jfree.chart.axis.ValueTick;
+import org.jfree.ui.RectangleEdge;
+import org.jfree.ui.TextAnchor;
+import org.junit.Test;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+
+import schmitzm.geotools.io.GeoImportUtil;
+import schmitzm.io.IOUtil;
+import schmitzm.jfree.chart.style.ChartAxisStyle;
+import schmitzm.jfree.chart.style.ChartLabelStyle;
+import schmitzm.jfree.chart.style.ChartRendererStyle;
+import schmitzm.jfree.chart.style.ChartType;
+import schmitzm.jfree.table.AggregationFunction;
+
+public class LimitedHashMapTest {
+  private static Logger log = Logger.getLogger(LimitedHashMapTest.class);
+  /** If tests are run on a system with head, we may theoretically open dialgs, frames etc. **/
+  boolean INTERACTIVE = !GraphicsEnvironment.isHeadless();
+	
+
+  @Test
+  public void testLimitedHashMap() throws IOException, InterruptedException {
+    LimitedHashMap<Integer, String> lhm = new LimitedHashMap<Integer, String>(5, LimitedHashMap.TRUNC_METHOD.OLDEST_GET);
+
+    // Initialisierung pruefen
+    assertEquals("Map muss leer sein.", 0, lhm.size());
+    assertEquals("Oldest list muss leer sein.", 0, lhm.oldestKeys.size());
+
+    // Elemente einfuegen bis Map voll ist
+    for (int i=1; i<=lhm.getMaxLoad(); i++) {
+      lhm.put(i, "Element "+i);
+      assertEquals("Map muss "+i+" Elemente haben.", i, lhm.size());
+      assertEquals("Oldest list "+i+" Elemente haben.", i, lhm.oldestKeys.size());
+    }
+    debugLimitedHashMap(lhm);
+
+    // Weiteres Element hinzufuegen
+    lhm.put(6, "Element "+6);
+    debugLimitedHashMap(lhm);
+    // Map muss weiterhin 5 Elemente haben
+    assertEquals("Map muss 5 Elemente haben.", 5, lhm.size());
+    assertEquals("Oldest list 5 Elemente haben.", 5, lhm.oldestKeys.size());
+    switch ( lhm.getTruncMethod() ) {
+      case OLDEST_PUT:
+        // 1 muesste geloescht worden sein
+        assertEquals("Erstes Element in Oldest-List muss 2 sein.", 2, (int)lhm.oldestKeys.firstElement());
+        // 6 muesste letztes Element sein
+        assertEquals("Letztes Element in Oldest-List muss 6 sein.", 6, (int)lhm.oldestKeys.lastElement());
+        // 5 muesste vorletztes Element sein
+        assertEquals("Vorletztes Element in Oldest-List muss 5 sein.", 5, (int)lhm.oldestKeys.elementAt(lhm.size()-2));
+        break;
+      case OLDEST_GET:
+        // 5 muesste geloescht worden sein
+        assertEquals("Erstes Element in Oldest-List muss 6 sein.", 6, (int)lhm.oldestKeys.firstElement());
+        // 6 muesste letztes Element sein
+        assertEquals("Letztes Element in Oldest-List muss 1 sein.", 1, (int)lhm.oldestKeys.lastElement());
+        // 4 muesste vorletztes Element sein
+        assertEquals("Vorletztes Element in Oldest-List muss 2 sein.", 2, (int)lhm.oldestKeys.elementAt(lhm.size()-2));
+        break;
+    }
+    
+    lhm.get(7); // noch nicht drin, nichts darf sich aendern
+    debugLimitedHashMap(lhm);
+    lhm.get(6); // 6 muss ans Ende der Oldest-List rutschen
+    debugLimitedHashMap(lhm);
+    
+    
+    lhm.put(7, "Element "+7);
+    debugLimitedHashMap(lhm);
+  }
+  
+  private void debugLimitedHashMap(LimitedHashMap<?, ?> lhm) {
+    System.out.println("Elemente:   "+LangUtil.listObjects(", ", false, lhm.values()));
+    System.out.println("OldestList: "+LangUtil.listObjects(", ", false, lhm.oldestKeys));
+  }
+
+}



More information about the Schmitzm-commits mailing list