[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]