/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Blacksmith, Inc. This library 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 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.foundation; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * A pure java implementation of NSDictionary that implements Map for greater * java interoperability. * * @author michael@mpowers.net * @author cgruber@israfil.net * @author $Author: cgruber $ * @version $Revision: 893 $ */ public class NSDictionary extends HashMap implements NSKeyValueCoding { private static final long serialVersionUID = -5043903788052328633L; public static final NSDictionary EmptyDictionary = new NSDictionary<>(); /** * Default constructor produces an empty dictionary. */ public NSDictionary() { super(); } /** * Constructor produces an empty dictionary with an initial capacity. */ public NSDictionary(int initialCapacity) { super(initialCapacity); } /** * Produces a dictionary that contains one key referencing one value. */ public NSDictionary(K key, V value) { super(); put(key, value); } /** * Produces a dictionary containing the specified keys and values. An * IllegalArgumentException is thrown if the arrays are not of the same length. */ public NSDictionary(V[] objects, K[] keys) { super(); if (keys.length != objects.length) { throw new IllegalArgumentException("Array lengths do not match."); } for (int i = 0; i < keys.length; i++) { put(keys[i], objects[i]); } } /** * Produces a dictionary that is a copy of the specified map (or dictionary). */ public NSDictionary(Map aMap) { super(aMap); } /** * Returns a count of the key-value pairs in this dictionary. */ public int count() { return size(); } /** * Returns an NSArray containing all keys in this dictionary. */ public NSArray allKeys() { return new NSArray<>(keySet()); } /** * Returns an NSArray containing all keys that reference the specified value. */ public NSArray allKeysForObject(V value) { NSMutableArray result = new NSMutableArray<>(); Map.Entry entry; Iterator> it = entrySet().iterator(); while (it.hasNext()) { entry = (Map.Entry) it.next(); // handle null values if ((value == null) && (entry.getValue() == null) || (value.equals(entry.getValue()))) { // if match, add to result set result.addObject(entry.getKey()); } } return result; } /** * Returns an NSArray containing all values in this dictionary. */ public NSArray allValues() { return new NSArray<>(values()); } /** * Returns whether the specified dictionary has the same or equivalent key-value * pairs as this dictionary. */ public boolean isEqualToDictionary(NSDictionary aDictionary) { return equals(aDictionary); } /** * Returns an array of objects for the specified array of keys. If a key isn't * found, the marker parameter will be placed in the corresponding index(es) in * the returned array. */ public NSArray objectsForKeys(NSArray anArray, V aMarker) { NSMutableArray result = new NSMutableArray<>(); if (anArray == null) return result; V value; Enumeration enumeration = anArray.objectEnumerator(); while (enumeration.hasMoreElements()) { value = objectForKey(enumeration.nextElement()); if (value == null) { value = aMarker; } result.addObject(value); } return result; } /** * Returns an enumeration over the keys in this dictionary. */ public java.util.Enumeration keyEnumerator() { return new java.util.Enumeration<>() { Iterator it = NSDictionary.this.keySet().iterator(); public boolean hasMoreElements() { return it.hasNext(); } public K nextElement() { return it.next(); } }; } /** * Returns an enumeration over the values in this dictionary. */ public java.util.Enumeration objectEnumerator() { return new java.util.Enumeration<>() { Iterator it = NSDictionary.this.values().iterator(); public boolean hasMoreElements() { return it.hasNext(); } public V nextElement() { return it.next(); } }; } /** * Returns the value for the specified key, or null if the key is not found. */ public V objectForKey(K aKey) { return get(aKey); } // interface NSKeyValueCoding @SuppressWarnings("unchecked") @Override public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this ); Object result = objectForKey((K) aKey); if (result == null) result = NSKeyValueCodingSupport.valueForKey(this, aKey); return result; } @SuppressWarnings("unchecked") @Override public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : " // + aValue + "->" + this ); put((K)aKey, (V)aValue); // FIXME: technically cheating since this is a read-only class } @SuppressWarnings("unchecked") @Override public Object storedValueForKey(String aKey) { Object result = objectForKey((K) aKey); if (result == null) result = NSKeyValueCodingSupport.storedValueForKey(this, aKey); return result; } @SuppressWarnings("unchecked") @Override public void takeStoredValueForKey(Object aValue, String aKey) { put((K)aKey, (V)aValue); // FIXME: technically cheating since this is a read-only class } @Override public Object handleQueryWithUnboundKey(String aKey) { return NSKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey); } @Override public void handleTakeValueForUnboundKey(Object aValue, String aKey) { NSKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey); } @Override public void unableToSetNullForKey(String aKey) { NSKeyValueCodingSupport.unableToSetNullForKey(this, aKey); } public Object validateTakeValueForKeyPath(Object aValue, String aKey) { throw new RuntimeException("Not implemented yet."); } @SuppressWarnings("unchecked") @Override public String toString() { StringBuffer buf = new StringBuffer(); Enumeration enumeration = keyEnumerator(); buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DICTIONARY]); while (enumeration.hasMoreElements()) { if (buf.length() == 1) buf.append(' '); Object k = enumeration.nextElement(); buf.append(NSPropertyListSerialization.stringForPropertyList(k)); buf.append(" = "); k = objectForKey((K) k); buf.append(NSPropertyListSerialization.stringForPropertyList(k)); buf.append("; "); } buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DICTIONARY]); return buf.toString(); } } /* * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in * eclipse-friendly maven-enabled packages. * * Revision 1.9 2005/05/11 15:21:53 cgruber Change enum to enumeration, since * enum is now a keyword as of Java 5.0 * * A few other comments in the code. * * Revision 1.8 2003/08/05 00:50:14 chochos use NSPropertyListSerialization to * get the tokens to enclose the string description * * Revision 1.7 2003/08/04 20:26:10 chochos use NSPropertyListSerialization * inside toString() * * Revision 1.6 2003/08/04 18:49:38 chochos NSDictionary(Object[], Object[]) was * taking the parameters in the wrong order; for compatibility with Apple's * NSDictionary, objects comes first, then keys. * * Revision 1.5 2003/08/04 18:26:19 chochos fixed opening '{' * * Revision 1.4 2003/01/28 22:11:30 mpowers Now implements NSKeyValueCoding. * * Revision 1.3 2002/06/30 17:58:06 mpowers Add a capacity constructor and * static empty dictionary: thanks cgruber. * * Revision 1.2 2001/02/23 23:43:41 mpowers Removed ill-advised this. * * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers Contributing wotonomy. * * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */