[Comments inline.  Sorry for the delay, JavaOne last week and away for
the weekend.]

"Henning P. Schmiedehausen" <[EMAIL PROTECTED]> writes:

> Daniel Rall <[EMAIL PROTECTED]> writes:
> >The existing SequencedHashtable iterator() method provides this
> >functionality.
> 
> >> In my application, I first used an Hashtable and an ArrayList in
> >> parallel which I replaced easily with the SequencedHashtable, once I
> >> added the keyList() method. I'm not that sure about keySet() and I
> >> really wanted access to the List to be sure about the sequence.
> 
> >Will iterator() do the trick?  If it does, can you suggest an
> 
> Unfortunately not. Especially as obj.keyList() gives an
> java.util.Collection compatible object which makes it usable in
> Velocity foreach while the SequencedHashtable is not.
> 
> ( I have code like this:
> 
> class foo
> {
>         SequencedHashtable st = new SequencedHashtable();
> 
>         public List getList()
>         {
>                 return this.st.keyList();
>         }
> }
> 
> class baz implements VelocityScreen
> {
> 
>         public void doBuildTemplate(RunData d, Context c)
>         {
>                 foo f = new foo();
>                 c.put("foo", foo);
>         }
> }
> 
> baz.vm:
> 
>         foreach($blqx in $foo.List)
>         {
>                 display_something($blqx);
>         }
> 
> Which works nicely. If I just return the "st" object above in foo,
> then the whole iteration stuff will not work (because Velocity sees
> the "Map" interface, gets the values().iterator() and then goes
> completely in the wrong direction.
> 
> I was thinking about implementing the Collections interface for
> SequencedHashtable and now I understand the somewhat cryptic comment
> "Implementing the List interface is not possible due to a instance
> method name clash.  Java does not support method renaming." :
> 
> Collections:
> 
> boolean remove(Object o)
> 
> Map:
> 
> Object remove(Object o)
> 
> Jeez, what did the guy smoke that designed these classes?

I don't know, but he needs to share.  ;P

I'm sure it was because the Hashtable API has been around since Java
1.0, and the Collections API wasn't introduced until 1.2.

> So, no, I'm afraid I need my keyList() method. ;-) The iterator simply
> will not cut it.

I agree.  Can we call it keySequence()--or just plain sequence()--
instead of keyList()?

> >alternate name which would make its purpose more clear (so that users
> >need not scan the existing JavaDoc)?  I was originally trying to avoid
> >providing direct access to the underlying List (but am not married to
> >the idea).
> 
> If I could get a Collections interface, I wouldn't be either. How
> about the attached SequencedHashtable. ==:-) 

I appreciate you providing such a thorough example, but this would
break backwards compatibility by moving SequencedHashtable from the
Map to Collection interface.  Though the sequence is a nice by-product
of the implementation, I consider SequencedHashtable to intrinsically
be a Map implementation.

> (If you like it, I would check it into the CVS with some more
> comments. The SequencedHashtable and its child is, as far as I can
> see, nowhere used in the Turbine itself, but I would guess that it is
> used by Applications and I would be interested, if people actually use
> the Map interface (if yes, then this change would be a bad idea).)

They are not used in Turbine proper, but are used in Helm
(extensively) and Scarab.

> package org.apache.turbine.util;
> 
> /* ====================================================================
>  * The Apache Software License, Version 1.1
>  *
>  * Copyright (c) 2001 The Apache Software Foundation.  All rights
>  * reserved.
>  *
>  * Redistribution and use in source and binary forms, with or without
>  * modification, are permitted provided that the following conditions
>  * are met:
>  *
>  * 1. Redistributions of source code must retain the above copyright
>  *    notice, this list of conditions and the following disclaimer.
>  *
>  * 2. Redistributions in binary form must reproduce the above copyright
>  *    notice, this list of conditions and the following disclaimer in
>  *    the documentation and/or other materials provided with the
>  *    distribution.
>  *
>  * 3. The end-user documentation included with the redistribution,
>  *    if any, must include the following acknowledgment:
>  *       "This product includes software developed by the
>  *        Apache Software Foundation (http://www.apache.org/)."
>  *    Alternately, this acknowledgment may appear in the software itself,
>  *    if and wherever such third-party acknowledgments normally appear.
>  *
>  * 4. The names "Apache" and "Apache Software Foundation" and 
>  *    "Apache Turbine" must not be used to endorse or promote products 
>  *    derived from this software without prior written permission. For 
>  *    written permission, please contact [EMAIL PROTECTED]
>  *
>  * 5. Products derived from this software may not be called "Apache",
>  *    "Apache Turbine", nor may "Apache" appear in their name, without 
>  *    prior written permission of the Apache Software Foundation.
>  *
>  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>  * SUCH DAMAGE.
>  * ====================================================================
>  *
>  * This software consists of voluntary contributions made by many
>  * individuals on behalf of the Apache Software Foundation.  For more
>  * information on the Apache Software Foundation, please see
>  * <http://www.apache.org/>.
>  */
> 
> import java.util.Collection;
> import java.util.Hashtable;
> import java.util.Iterator;
> import java.util.List;
> import java.util.LinkedList;
> import java.util.Map;
> import java.util.Set;
> 
> /**
>  * A {@link java.util.Hashtable} whose keys are sequenced.  The
>  * sequencing of the keys allow easy access to the values in the order
>  * which they were added in.  This class is thread safe.
>  * <p>
>  * Implementing the List interface is not possible due to a instance
>  * method name clash.  Java does not support method renaming.
>  * <p>
>  * A slightly more complex implementation and interface could involve
>  * the use of a list of <code>Map.Entry</code> objects.
>  *
>  * @author <a href="mailto:[EMAIL PROTECTED]";>Daniel Rall</a>
>  * @author <a href="mailto:[EMAIL PROTECTED]";>Henning P. Schmiedehausen</a>
>  * @version $Id: SequencedHashtable.java,v 1.4 2001/05/20 02:38:52 dlr Exp $
>  */
> 
> public class SequencedHashtable extends LinkedList
> {
>     /**
>      * Indicator for an unknown index.
>      */
> 
>     private static final int UNKNOWN_INDEX = -1;
> 
>     /**
>      * The table for the keys.
>      */
> 
>     private Hashtable keyMap;
> 
>     /**
>      * Creates a new instance with default storage.
>      */
> 
>     public SequencedHashtable ()
>     {
>         keyMap = new Hashtable();
>     }
> 
>     /**
>      * Creates a new instance with the specified storage.
>      *
>      * @param size The storage to allocate up front.
>      */
> 
>     public SequencedHashtable (int size)
>     {
>         keyMap = new Hashtable(size);
>     }
> 
>     /**
>      * Clears all elements.
>      */
> 
>     public synchronized void clear ()
>     {
>         super.clear();
>         keyMap.clear();
>     }
> 
>     /**
>      * Creates a shallow copy of this object, preserving the internal
>      * structure by copying only references.  The keys, values, and
>      * sequence are not <code>clone()</code>'d.
>      *
>      * @return A clone of this instance.
>      */
> 
>     public synchronized Object clone ()
>     {
>         SequencedHashtable seqList = (SequencedHashtable)super.clone();
>         seqList.keyMap = (Hashtable)keyMap.clone();
>         return seqList;
>     }
> 
>     /**
>      * Stores the provided key/value pair.  Freshens the sequence of existing
>      * elements.
>      *
>      * @param key   The key to the provided value.
>      * @param value The value to store.
>      * @return      The previous value for the specified key, or
>      *              <code>null</code> if none.
>      */
> 
>     public synchronized Object put (Object key, Object value)
>     {
>         Object prevValue = this.keyMap.put(key, value);
>         freshenSequence(key, prevValue);
>         return prevValue;
>     }
> 
>     /**
>      * Freshens the sequence of the element <code>value</code> if
>      * <code>value</code> is not <code>null</code>.
>      *
>      * @param key   The key whose sequence to freshen.
>      * @param value The value whose existance to check before removing the old
>      *              key sequence.
>      */
> 
>     protected void freshenSequence(Object key, Object value)
>     {
>         if (value != null)
>         {
>             // Freshening existing element's sequence.
>             super.remove(key);
>         }
>         super.add(key);
>     }
> 
>     /**
>      * Stores the provided key/value pairs.
>      *
>      * @param t The key/value pairs to store.
>      */
> 
>     public synchronized void putAll (Map t)
>     {
>         Set set = t.entrySet();
>         for (Iterator iter = set.iterator(); iter.hasNext(); )
>         {
>             Map.Entry e = (Map.Entry)iter.next();
>             put(e.getKey(), e.getValue());
>         }
>     }
> 
>     /**
>      * Removes the element at the specified index.
>      *
>      * @param index The index of the object to remove.
>      * @return      The previous value coressponding the <code>key</code>, or
>      *              <code>null</code> if none existed.
>      */
> 
>     public Object remove (int index)
>     {
>         return remove(index, null);
>     }
> 
>     /**
>      * Removes the element with the specified key.
>      *
>      * @param key   The <code>Map</code> key of the object to remove.
>      * @return      The previous value coressponding the <code>key</code>, or
>      *              <code>null</code> if none existed.
>      */
> 
>     public boolean remove (Object key)
>     {
>         Object o = remove(UNKNOWN_INDEX, key);
> 
>         return (o != null);
>     }
> 
>     /**
>      * Removes the element with the specified key or index.
>      *
>      * @param index The index of the object to remove, or
>      *              <code>UNKNOWN_INDEX</code> if not known.
>      * @param key   The <code>Map</code> key of the object to remove.
>      * @return      The previous value coressponding the <code>key</code>, or
>      *              <code>null</code> if none existed.
>      */
> 
>     private final synchronized Object remove (int index, Object key)
>     {
>         Object o = null;
> 
>         if (index == UNKNOWN_INDEX) 
>             index = indexOf(key);
> 
>         if (key == null) 
>             key = super.get(index);
> 
>         if (index != UNKNOWN_INDEX) 
>         {
>             super.remove(index);
>             o = this.keyMap.remove(key); 
>         }
> 
>         return o;
>     }
> 
>     /**
>      * Tests if the specified object is a key in this hashtable
>      *
>      * @param key possible key
>      *
>      * @return <CODE>true</CODE> if and only if the specified object 
>      *          is a key in this hashtable, as determined by the 
>      *          equals method; <CODE>false</CODE> otherwise
>      */
> 
>     public boolean containsKey(Object key)
>     {
>         return contains(key);
>     }
> 
>     public boolean containsValue(Object value)
>     {
>         return this.keyMap.containsValue(value);
>     }
> 
>     public Object get(Object key)
>     {
>         return this.keyMap.get(key);
>     }
> 
>     public Set keySet()
>     {
>         return this.keyMap.keySet();
>     }
> 
>     public Collection values()
>     {
>         return this.keyMap.values();
>     }
> 
>     public Set entrySet()
>     {
>         return this.keyMap.entrySet();
>     }
> 
>     public boolean equals(Object o)
>     {
>         return this.keyMap.entrySet().equals(((Map)o).entrySet());
>     }
> 
>     public int hashCode()
>     {
>         return this.keyMap.hashCode();
>     }
> 
> }
> --- cut --- 
> -- 
> Dipl.-Inf. (Univ.) Henning P. Schmiedehausen       -- Geschaeftsfuehrer
> INTERMETA - Gesellschaft fuer Mehrwertdienste mbH     [EMAIL PROTECTED]
> 
> Am Schwabachgrund 22  Fon.: 09131 / 50654-0   [EMAIL PROTECTED]
> D-91054 Buckenhof     Fax.: 09131 / 50654-20   
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to