Author: fhanik Date: Mon May 22 16:29:40 2006 New Revision: 408787 URL: http://svn.apache.org/viewvc?rev=408787&view=rev Log: Refactored, all methods in a replicated map are common except the one that chooses the backup node.
Modified: tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java Modified: tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java URL: http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java?rev=408787&r1=408786&r2=408787&view=diff ============================================================================== --- tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java (original) +++ tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java Mon May 22 16:29:40 2006 @@ -23,13 +23,19 @@ import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelListener; +import org.apache.catalina.tribes.Heartbeat; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.group.Response; @@ -39,9 +45,6 @@ import org.apache.catalina.tribes.membership.MemberImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.catalina.tribes.Heartbeat; -import java.util.HashMap; -import org.apache.catalina.tribes.group.*; /** * <p>Title: </p> @@ -253,6 +256,7 @@ */ public void replicate(Object key, boolean complete) { MapEntry entry = (MapEntry)super.get(key); + if ( !entry.isSerializable() ) return; if (entry != null && entry.isPrimary() && entry.getBackupNodes()!= null && entry.getBackupNodes().length > 0) { Object value = entry.getValue(); //check to see if we need to replicate this object isDirty()||complete @@ -368,7 +372,7 @@ //backup request if (mapmsg.getMsgType() == mapmsg.MSG_RETRIEVE_BACKUP) { MapEntry entry = (MapEntry)super.get(mapmsg.getKey()); - if (entry == null)return null; + if (entry == null || (!entry.isSerializable()) )return null; mapmsg.setValue( (Serializable) entry.getValue()); return mapmsg; } @@ -381,9 +385,11 @@ while (i.hasNext()) { Map.Entry e = (Map.Entry) i.next(); MapEntry entry = (MapEntry) e.getValue(); - MapMessage me = new MapMessage(mapContextName, MapMessage.MSG_PROXY, - false, (Serializable) entry.getKey(), null,null, entry.getBackupNodes()); - list.add(me); + if ( entry.isSerializable() ) { + MapMessage me = new MapMessage(mapContextName, MapMessage.MSG_PROXY, + false, (Serializable) entry.getKey(), null, null, entry.getBackupNodes()); + list.add(me); + } } mapmsg.setValue(list); return mapmsg; @@ -606,6 +612,79 @@ // METHODS TO OVERRIDE //------------------------------------------------------------------------------ + /** + * Removes an object from this map, it will also remove it from + * + * @param key Object + * @return Object + */ + public Object remove(Object key) { + MapEntry entry = (MapEntry)super.remove(key); + + try { + MapMessage msg = new MapMessage(getMapContextName(),MapMessage.MSG_REMOVE,false,(Serializable)key,null,null,null); + getChannel().send(getMapMembers(), msg,getChannelSendOptions()); + } catch ( ChannelException x ) { + log.error("Unable to replicate out data for a LazyReplicatedMap.remove operation",x); + } + return entry!=null?entry.getValue():null; + } + + public Object get(Object key) { + MapEntry entry = (MapEntry)super.get(key); + if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" entry:"+entry); + if ( entry == null ) return null; + if ( !entry.isPrimary() ) { + //if the message is not primary, we need to retrieve the latest value + try { + Member[] backup = null; + MapMessage msg = null; + if ( !entry.isBackup() ) { + //make sure we don't retrieve from ourselves + msg = new MapMessage(getMapContextName(), MapMessage.MSG_RETRIEVE_BACKUP, false, + (Serializable) key, null, null, null); + Response[] resp = getRpcChannel().send(entry.getBackupNodes(),msg, this.getRpcChannel().FIRST_REPLY, Channel.SEND_OPTIONS_DEFAULT, getRpcTimeout()); + if (resp == null || resp.length == 0) { + //no responses + log.warn("Unable to retrieve remote object for key:" + key); + return null; + } + msg = (MapMessage) resp[0].getMessage(); + msg.deserialize(getExternalLoaders()); + backup = entry.getBackupNodes(); + if ( entry.getValue() instanceof ReplicatedMapEntry ) { + ReplicatedMapEntry val = (ReplicatedMapEntry)entry.getValue(); + val.setOwner(getMapOwner()); + } + if ( msg.getValue()!=null ) entry.setValue(msg.getValue()); + } + if (entry.isBackup()) { + //select a new backup node + backup = publishEntryInfo(key, entry.getValue()); + } else if ( entry.isProxy() ) { + //invalidate the previous primary + msg = new MapMessage(getMapContextName(),MapMessage.MSG_PROXY,false,(Serializable)key,null,null,backup); + Member[] dest = getMapMembersExcl(backup); + if ( dest!=null && dest.length >0) { + getChannel().send(dest, msg, getChannelSendOptions()); + } + } + + entry.setBackupNodes(backup); + entry.setBackup(false); + entry.setProxy(false); + + + } catch (Exception x) { + log.error("Unable to replicate out data for a LazyReplicatedMap.get operation", x); + return null; + } + } + if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" result:"+entry.getValue()); + return entry.getValue(); + } + + protected void printMap(String header) { try { System.out.println("\nDEBUG MAP:"+header); @@ -626,6 +705,150 @@ ignore.printStackTrace(); } } + + /** + * Returns true if the key has an entry in the map. + * The entry can be a proxy or a backup entry, invoking <code>get(key)</code> + * will make this entry primary for the group + * @param key Object + * @return boolean + */ + public boolean containsKey(Object key) { + return super.containsKey(key); + } + + + public Object put(Object key, Object value) { + MapEntry entry = new MapEntry(key,value); + entry.setBackup(false); + entry.setProxy(false); + + Object old = null; + + //make sure that any old values get removed + if ( containsKey(key) ) old = remove(key); + try { + Member[] backup = publishEntryInfo(key, value); + entry.setBackupNodes(backup); + } catch (ChannelException x) { + log.error("Unable to replicate out data for a LazyReplicatedMap.put operation", x); + } + super.put(key,entry); + return old; + } + + + /** + * Copies all values from one map to this instance + * @param m Map + */ + public void putAll(Map m) { + Iterator i = m.entrySet().iterator(); + while ( i.hasNext() ) { + Map.Entry entry = (Map.Entry)i.next(); + put(entry.getKey(),entry.getValue()); + } + } + + public void clear() { + //only delete active keys + Iterator keys = keySet().iterator(); + while ( keys.hasNext() ) remove(keys.next()); + } + + public boolean containsValue(Object value) { + if ( value == null ) { + return super.containsValue(value); + } else { + Iterator i = super.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry e = (Map.Entry) i.next(); + MapEntry entry = (MapEntry) e.getValue(); + if (entry.isPrimary() && value.equals(entry.getValue())) return true; + }//while + return false; + }//end if + } + + public Object clone() { + throw new UnsupportedOperationException("This operation is not valid on a replicated map"); + } + + /** + * Returns the entire contents of the map + * Map.Entry.getValue() will return a LazyReplicatedMap.MapEntry object containing all the information + * about the object. + * @return Set + */ + public Set entrySetFull() { + return super.entrySet(); + } + + public Set keySetFull() { + return super.keySet(); + } + + public int sizeFull() { + return super.size(); + } + + public Set entrySet() { + LinkedHashSet set = new LinkedHashSet(super.size()); + Iterator i = super.entrySet().iterator(); + while ( i.hasNext() ) { + Map.Entry e = (Map.Entry)i.next(); + MapEntry entry = (MapEntry)e.getValue(); + if ( entry.isPrimary() ) set.add(entry); + } + return Collections.unmodifiableSet(set); + } + + public Set keySet() { + //todo implement + //should only return keys where this is active. + LinkedHashSet set = new LinkedHashSet(super.size()); + Iterator i = super.entrySet().iterator(); + while ( i.hasNext() ) { + Map.Entry e = (Map.Entry)i.next(); + MapEntry entry = (MapEntry)e.getValue(); + if ( entry.isPrimary() ) set.add(entry.getKey()); + } + return Collections.unmodifiableSet(set); + } + + + public int size() { + //todo, implement a counter variable instead + //only count active members in this node + int counter = 0; + Iterator i = super.entrySet().iterator(); + while ( i.hasNext() ) { + Map.Entry e = (Map.Entry)i.next(); + MapEntry entry = (MapEntry)e.getValue(); + if ( entry.isPrimary() && entry.getValue()!=null ) counter++; + } + return counter; + } + + protected boolean removeEldestEntry(Map.Entry eldest) { + return false; + } + + public boolean isEmpty() { + return size()==0; + } + + public Collection values() { + ArrayList values = new ArrayList(super.size()); + Iterator i = super.entrySet().iterator(); + while ( i.hasNext() ) { + Map.Entry e = (Map.Entry)i.next(); + MapEntry entry = (MapEntry)e.getValue(); + if ( entry.isPrimary() && entry.getValue()!=null) values.add(entry.getValue()); + } + return Collections.unmodifiableCollection(values); + } + //------------------------------------------------------------------------------ // Map Entry class Modified: tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java URL: http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java?rev=408787&r1=408786&r2=408787&view=diff ============================================================================== --- tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java (original) +++ tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java Mon May 22 16:29:40 2006 @@ -16,20 +16,13 @@ package org.apache.catalina.tribes.tipis; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; -import org.apache.catalina.tribes.group.*; +import org.apache.catalina.tribes.group.RpcCallback; /** * A smart implementation of a stateful replicated map. uses primary/secondary backup strategy. @@ -125,6 +118,7 @@ * @throws ChannelException */ protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException { + if (! (key instanceof Serializable && value instanceof Serializable) ) return new Member[0]; Member[] members = getMapMembers(); int firstIdx = getNextBackupIndex(); int nextIdx = firstIdx; @@ -175,224 +169,6 @@ return backup; } - public Object get(Object key) { - MapEntry entry = (MapEntry)super.get(key); - if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" entry:"+entry); - if ( entry == null ) return null; - if ( !entry.isPrimary() ) { - //if the message is not primary, we need to retrieve the latest value - try { - Member[] backup = null; - MapMessage msg = null; - if ( !entry.isBackup() ) { - //make sure we don't retrieve from ourselves - msg = new MapMessage(getMapContextName(), MapMessage.MSG_RETRIEVE_BACKUP, false, - (Serializable) key, null, null, null); - Response[] resp = getRpcChannel().send(entry.getBackupNodes(),msg, this.getRpcChannel().FIRST_REPLY, Channel.SEND_OPTIONS_DEFAULT, getRpcTimeout()); - if (resp == null || resp.length == 0) { - //no responses - log.warn("Unable to retrieve remote object for key:" + key); - return null; - } - msg = (MapMessage) resp[0].getMessage(); - msg.deserialize(getExternalLoaders()); - backup = entry.getBackupNodes(); - if ( entry.getValue() instanceof ReplicatedMapEntry ) { - ReplicatedMapEntry val = (ReplicatedMapEntry)entry.getValue(); - val.setOwner(getMapOwner()); - } - if ( msg.getValue()!=null ) entry.setValue(msg.getValue()); - } - if (entry.isBackup()) { - //select a new backup node - backup = publishEntryInfo(key, entry.getValue()); - } else if ( entry.isProxy() ) { - //invalidate the previous primary - msg = new MapMessage(getMapContextName(),MapMessage.MSG_PROXY,false,(Serializable)key,null,null,backup); - Member[] dest = getMapMembersExcl(backup); - if ( dest!=null && dest.length >0) { - getChannel().send(dest, msg, getChannelSendOptions()); - } - } - - entry.setBackupNodes(backup); - entry.setBackup(false); - entry.setProxy(false); - - - } catch (Exception x) { - log.error("Unable to replicate out data for a LazyReplicatedMap.get operation", x); - return null; - } - } - if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" result:"+entry.getValue()); - return entry.getValue(); - } - - /** - * Returns true if the key has an entry in the map. - * The entry can be a proxy or a backup entry, invoking <code>get(key)</code> - * will make this entry primary for the group - * @param key Object - * @return boolean - */ - public boolean containsKey(Object key) { - return super.containsKey(key); - } - - - public Object put(Object key, Object value) { - if ( !(key instanceof Serializable) ) throw new IllegalArgumentException("Key is not serializable:"+key.getClass().getName()); - if ( value == null ) return remove(key); - if ( !(value instanceof Serializable) ) throw new IllegalArgumentException("Value is not serializable:"+value.getClass().getName()); - - MapEntry entry = new MapEntry((Serializable)key,(Serializable)value); - entry.setBackup(false); - entry.setProxy(false); - - Object old = null; - - //make sure that any old values get removed - if ( containsKey(key) ) old = remove(key); - try { - Member[] backup = publishEntryInfo(key, value); - entry.setBackupNodes(backup); - } catch (ChannelException x) { - log.error("Unable to replicate out data for a LazyReplicatedMap.put operation", x); - } - super.put(key,entry); - return old; - } - - - /** - * Copies all values from one map to this instance - * @param m Map - */ - public void putAll(Map m) { - Iterator i = m.entrySet().iterator(); - while ( i.hasNext() ) { - Map.Entry entry = (Map.Entry)i.next(); - put(entry.getKey(),entry.getValue()); - } - } - - /** - * Removes an object from this map, it will also remove it from - * - * @param key Object - * @return Object - */ - public Object remove(Object key) { - MapEntry entry = (MapEntry)super.remove(key); - - try { - MapMessage msg = new MapMessage(getMapContextName(),MapMessage.MSG_REMOVE,false,(Serializable)key,null,null,null); - getChannel().send(getMapMembers(), msg,getChannelSendOptions()); - } catch ( ChannelException x ) { - log.error("Unable to replicate out data for a LazyReplicatedMap.remove operation",x); - } - return entry!=null?entry.getValue():null; - } - - public void clear() { - //only delete active keys - Iterator keys = keySet().iterator(); - while ( keys.hasNext() ) remove(keys.next()); - } - - public boolean containsValue(Object value) { - if ( value == null ) { - return super.containsValue(value); - } else { - Iterator i = super.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = (Map.Entry) i.next(); - MapEntry entry = (MapEntry) e.getValue(); - if (entry.isPrimary() && value.equals(entry.getValue())) return true; - }//while - return false; - }//end if - } - - public Object clone() { - throw new UnsupportedOperationException("This operation is not valid on a replicated map"); - } - - /** - * Returns the entire contents of the map - * Map.Entry.getValue() will return a LazyReplicatedMap.MapEntry object containing all the information - * about the object. - * @return Set - */ - public Set entrySetFull() { - return super.entrySet(); - } - - public Set keySetFull() { - return super.keySet(); - } - - public int sizeFull() { - return super.size(); - } - - public Set entrySet() { - LinkedHashSet set = new LinkedHashSet(super.size()); - Iterator i = super.entrySet().iterator(); - while ( i.hasNext() ) { - Map.Entry e = (Map.Entry)i.next(); - MapEntry entry = (MapEntry)e.getValue(); - if ( entry.isPrimary() ) set.add(entry); - } - return Collections.unmodifiableSet(set); - } - - public Set keySet() { - //todo implement - //should only return keys where this is active. - LinkedHashSet set = new LinkedHashSet(super.size()); - Iterator i = super.entrySet().iterator(); - while ( i.hasNext() ) { - Map.Entry e = (Map.Entry)i.next(); - MapEntry entry = (MapEntry)e.getValue(); - if ( entry.isPrimary() ) set.add(entry.getKey()); - } - return Collections.unmodifiableSet(set); - } - - - public int size() { - //todo, implement a counter variable instead - //only count active members in this node - int counter = 0; - Iterator i = super.entrySet().iterator(); - while ( i.hasNext() ) { - Map.Entry e = (Map.Entry)i.next(); - MapEntry entry = (MapEntry)e.getValue(); - if ( entry.isPrimary() && entry.getValue()!=null ) counter++; - } - return counter; - } - - protected boolean removeEldestEntry(Map.Entry eldest) { - return false; - } - - public boolean isEmpty() { - return size()==0; - } - - public Collection values() { - ArrayList values = new ArrayList(super.size()); - Iterator i = super.entrySet().iterator(); - while ( i.hasNext() ) { - Map.Entry e = (Map.Entry)i.next(); - MapEntry entry = (MapEntry)e.getValue(); - if ( entry.isPrimary() && entry.getValue()!=null) values.add(entry.getValue()); - } - return Collections.unmodifiableCollection(values); - } Modified: tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java URL: http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java?rev=408787&r1=408786&r2=408787&view=diff ============================================================================== --- tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java (original) +++ tomcat/container/tc5.5.x/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java Mon May 22 16:29:40 2006 @@ -16,13 +16,6 @@ package org.apache.catalina.tribes.tipis; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; @@ -106,6 +99,7 @@ * @throws ChannelException */ protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException { + if (! (key instanceof Serializable && value instanceof Serializable) ) return new Member[0]; //select a backup node Member[] backup = getMapMembers(); @@ -118,167 +112,6 @@ getChannel().send(getMapMembers(), msg, getChannelSendOptions()); return backup; - } - - public Object get(Object key) { - MapEntry entry = (MapEntry)super.get(key); - if (entry == null) { - return null; - } - return entry.getValue(); - } - - /** - * Returns true if the key has an entry in the map. - * The entry can be a proxy or a backup entry, invoking <code>get(key)</code> - * will make this entry primary for the group - * @param key Object - * @return boolean - */ - public boolean containsKey(Object key) { - return super.containsKey(key); - } - - public Object put(Object key, Object value) { - if (! (key instanceof Serializable))throw new IllegalArgumentException("Key is not serializable:" +key.getClass().getName()); - if (value == null)return remove(key); - if (! (value instanceof Serializable))throw new IllegalArgumentException("Value is not serializable:" +value.getClass().getName()); - - MapEntry entry = new MapEntry( (Serializable) key, (Serializable) value); - entry.setBackup(false); - entry.setProxy(false); - - Object old = null; - - //make sure that any old values get removed - if (containsKey(key)) old = remove(key); - try { - Member[] backup = publishEntryInfo(key, value); - entry.setBackupNodes(backup); - } catch (ChannelException x) { - log.error("Unable to replicate out data for a LazyReplicatedMap.put operation", x); - } - super.put(key, entry); - return old; - } - - /** - * Copies all values from one map to this instance - * @param m Map - * @todo send one bulk message - */ - public void putAll(Map m) { - Iterator i = m.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry entry = (Map.Entry) i.next(); - put(entry.getKey(), entry.getValue()); - } - } - - /** - * Removes an object from this map, it will also remove it from - * - * @param key Object - * @return Object - */ - public Object remove(Object key) { - MapEntry entry = (MapEntry)super.remove(key); - MapMessage msg = new MapMessage(getMapContextName(), MapMessage.MSG_REMOVE, false, (Serializable) key, null, null, null); - try { - getChannel().send(getMapMembers(), msg, Channel.SEND_OPTIONS_DEFAULT); - } catch (ChannelException x) { - log.error("Unable to replicate out data for a LazyReplicatedMap.remove operation", x); - } - return entry != null ? entry.getValue() : null; - } - - public void clear() { - //only delete active keys - Iterator keys = keySet().iterator(); - while (keys.hasNext()) remove(keys.next()); - } - - public boolean containsValue(Object value) { - if (value == null) { - return super.containsValue(value); - } else { - Iterator i = super.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = (Map.Entry) i.next(); - MapEntry entry = (MapEntry) e.getValue(); - if ( value.equals(entry.getValue()) ) return true; - } //while - return false; - } //end if - } - - public Object clone() { - throw new UnsupportedOperationException("This operation is not valid on a replicated map"); - } - - /** - * Returns the entire contents of the map - * Map.Entry.getValue() will return a LazyReplicatedMap.MapEntry object containing all the information - * about the object. - * @return Set - */ - public Set entrySetFull() { - return super.entrySet(); - } - - public Set keySetFull() { - return super.keySet(); - } - - public Set entrySet() { - LinkedHashSet set = new LinkedHashSet(super.size()); - Iterator i = super.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = (Map.Entry) i.next(); - MapEntry entry = (MapEntry) e.getValue(); - if (entry.isPrimary()) set.add(entry.getValue()); - } - return Collections.unmodifiableSet(set); - } - - public Set keySet() { - //todo implement - //should only return keys where this is active. - LinkedHashSet set = new LinkedHashSet(super.size()); - Iterator i = super.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = (Map.Entry) i.next(); - MapEntry entry = (MapEntry) e.getValue(); - if (entry.isPrimary()) set.add(entry.getKey()); - } - return Collections.unmodifiableSet(set); - } - - public int sizeFull() { - return super.size(); - } - - public int size() { - return super.size(); - } - - protected boolean removeEldestEntry(Map.Entry eldest) { - return false; - } - - public boolean isEmpty() { - return size() == 0; - } - - public Collection values() { - ArrayList values = new ArrayList(super.size()); - Iterator i = super.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = (Map.Entry) i.next(); - MapEntry entry = (MapEntry) e.getValue(); - values.add(entry); - } - return Collections.unmodifiableCollection(values); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]