package edu.stanford.rt.credential; import java.util.*; /** * @author Ninghui Li, Sandra Qiu
* * OrderedMap maintains a map from key to values and the ordering * of the keys. * */ public class OrderedMap { /** key type */ private Class keyClass; /** value type */ private Class valueClass; /** map for the key-value pairs */ private HashMap dataMap; /** also stores the keys as they are added to the list, * so that we can remember the ordering of the keys. */ private ArrayList keyList; /** whether this map is editable */ private boolean editable; /** defualt map capacity */ private static final int DEFAULT_SIZE = 10; /** * Constructor for OrderedMap. * * Constructs a OrderedMap object with size default to 10. * Both key and value are of Object type. */ public OrderedMap() { this(DEFAULT_SIZE, Object.class, Object.class); } /** * Constructor for OrderedMap. * Constructs a OrderedMap object with given size. * Both key and value are of Object type. */ public OrderedMap(int size) { this(size, Object.class, Object.class); } /** * Constructor for OrderedMap. * Constructs a OrderedMap object with size default to 10. * The key and value type are specified by the given keyClass and * valueClass, respectively. */ public OrderedMap(Class keyClass, Class valueClass) { this(DEFAULT_SIZE, keyClass, valueClass); } /** * Constructor for OrderedMap. * Constructs a OrderedMap object with given size. * The key and value type are specified by the given keyClass and * valueClass, respectively. */ public OrderedMap(int size, Class keyClass, Class valueClass) { this.keyClass = keyClass; this.valueClass = valueClass; this.dataMap = new HashMap(size); this.keyList = new ArrayList(size); this.editable = true; } /** * Method constainsKey. * Returns true if there is a mapping for the given key. * @param key * @return boolean */ public synchronized boolean constainsKey(Object key) { return dataMap.containsKey(key); } /** * Method put. * Add a new key-value mapping entry to the map. * Exception is thrown if the map is not editable, the key is null, * or the given key or value's type does not match the specified * key type or value type. Exception will also be thrown if trying * to add duplicated key-value pair. * @param key * @param value * @throws DomainSpecException */ public synchronized void put(Object key, Object value) throws DomainSpecException { if (!editable) throw new DomainSpecException("Adding to unmodifiable map"); if (key == null) throw new DomainSpecException("Wrong key value: null."); if (!keyClass.isInstance(key)) throw new DomainSpecException("Wrong key type"); if (value != null && !valueClass.isInstance(value)) throw new DomainSpecException("Wrong value type"); myPut(key, value); } private void myPut(Object key, Object value) throws DomainSpecException { //RTUtil.debugInfo("myPut() > key = " + key.toString()); if (dataMap.get(key) != null) { //RTUtil.debugInfo("myPut() > " + dataMap.get(key).toString()); throw new DomainSpecException("Duplicate mapping"); } dataMap.put(key, value); keyList.add(key); } /** Copies all the mapping entries to this map, perserving the original ordering of the entries. Exception is thrown when the key type or value type of the given map does not match that of this map, or when duplicated entries are detected. */ public synchronized void putAll(OrderedMap map) throws DomainSpecException { if (!this.keyClass.equals(map.getKeyClass()) || !this.valueClass.equals(map.getValueClass())) { throw new DomainSpecException("Illegal key/value type."); } Iterator it = map.keyIterator(); while (it.hasNext()) { Object key = it.next(); Object value = map.get(key); myPut(key, value); } // Do not call setUneditable mothod here! } /** marks this map as uneditable. */ public synchronized void setUneditable() { editable = false; } /** Returns true if the map is editable. */ public boolean isEditable() { return editable; } /** Returns the size of this map */ public synchronized int size() { return keyList.size(); } /** Returns iterator to the list of keys in the map.*/ public synchronized Iterator keyIterator() { return keyList.iterator(); } /** Returns the value for the given key and returns null if there is no mapping for the given key . Exception is thrown when the type of given key does not match the specified key type of this map. */ public Object get(Object key) throws DomainSpecException { if (!keyClass.isInstance(key)) throw new DomainSpecException("Wrong key type"); return dataMap.get(key); } /** Returns an unmodifiable view of all the keys. */ public synchronized List keyList() { // returns a unmodifiable version of the keys return Collections.unmodifiableList(keyList); } /** Returns an unmodifiable view of this map. */ public synchronized Map valueMap() { return Collections.unmodifiableMap(dataMap); } /** Returns the key type. */ public Class getKeyClass() { return keyClass; } /** Returns the value type */ public Class getValueClass() { return valueClass; } }