/*******************************************************************************
* Copyright © 2006, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.runtime.java.eglx.lang;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.eclipse.edt.javart.Constants;
import org.eclipse.edt.javart.messages.Message;
import eglx.lang.AnyException;
import eglx.lang.DynamicAccessException;
import eglx.lang.OrderingKind;
/**
*
*/
public class EDictionary extends EAny implements eglx.lang.EDictionary {
private static final long serialVersionUID = Constants.SERIAL_VERSION_UID;
/**
* The map containing the dictionary values. It maps String keys to AnyRef objects, and iterates the values in the
* specified order (insertion, key or unspecified order).
*/
private Map<String, Object> map;
/** Whether the keys are case sensitive or not. */
private boolean caseSensitive;
/** The order that the dictionary will iterate its values in. */
private OrderingKind order;
/**
* Constructor
*/
public EDictionary() {
this(false, OrderingKind.none);
}
/**
* Constructor
*/
public EDictionary(boolean caseSensitive, OrderingKind order) {
this.caseSensitive = caseSensitive;
this.order = order;
createMap();
}
/**
* Copy constructor
*/
public EDictionary(EDictionary other) throws AnyException {
this(other.caseSensitive, other.order);
insertAll((EDictionary) other);
}
/**
* Return whether the dictionary key comparison is case sensitive
*/
public boolean getCaseSensitive() {
return this.caseSensitive;
}
/**
* Return the enumeration order for the dictionary
*/
public OrderingKind getOrdering() {
return this.order;
}
/**
* Create the map data structure
*/
private void createMap() {
switch (this.order) {
case byInsertion:
this.map = new LinkedHashMap<String, Object>();
break;
case byKey:
this.map = new TreeMap<String, Object>();
break;
default:
this.map = new HashMap<String, Object>();
break;
}
}
/**
* Clear the contents of the dictionary.
*/
public void clear() {
this.map.clear();
}
/**
* Return whether the dictionary contains an entry with a specified key.
* @param key The key
* @return True if so
*/
public boolean containsKey(Object key) {
if (key instanceof String) {
return containsKey( (String)key );
}
return this.map.containsKey(key);
}
/**
* Return whether the dictionary contains a specified value.
*/
public boolean containsValue(Object value) {
return this.map.containsValue(value);
}
/**
* Return the set of entries in the dictionary.
*/
public Set entrySet() {
return this.map.entrySet();
}
/**
* Compare this dictionary to another object
*/
public boolean equals(Object obj) {
// equals must be implemented this way to meet the requirements of
// the Map interface.
return map.equals(obj);
}
/**
* Return the hashcode for this Dictionary Object.
*/
public int hashCode() {
// hashCode must be implemented this way to meet the requirements of
// the Map interface.
return map.hashCode();
}
/**
* Retrieve a value for the specified key.
*/
public Object get(Object key) {
if (!this.caseSensitive && key instanceof String) {
key = ((String) key).toLowerCase();
}
return this.map.get(key);
}
/**
* Return whether the dictionary is empty.
*/
public boolean isEmpty() {
return this.map.isEmpty();
}
/**
* Return a set of keys that exist in the dictionary. It will iterate itself in the preferred order.
*/
public Set keySet() {
return this.map.keySet();
}
/**
* Remove a specified key and its value from the dictionary. Not supported, use removeElement() instead.
*/
public Object remove(Object key) {
throw new UnsupportedOperationException();
}
/**
* Return how many entries are in this dictionary.
*/
public int size() {
return this.map.size();
}
/**
* Return the values that exist in the dictionary. If a value occurs more than once, it will be duplicated in the
* returned collection. The returned collection will iterate itself in the preferred order.
*/
public Collection values() {
return this.map.values();
}
/**
* Return the keys for the contents of the dictionary, in the preferred order.
*/
public String[] getKeyArray() {
String[] keyArray = new String[this.map.size()];
int ii = 0;
for (Iterator iter = this.map.keySet().iterator(); iter.hasNext(); ++ii) {
keyArray[ii] = (String) iter.next();
}
return keyArray;
}
/**
* Return the values for the contents of the dictionary, in the preferred order.
*/
public Object[] getValueArray() {
Object[] valueArray = new Object[this.map.size()];
int ii = 0;
for (Iterator iter = this.map.values().iterator(); iter.hasNext(); ++ii) {
valueArray[ii] = iter.next();
}
return valueArray;
}
/**
* Add an entry to the dictionary
*/
public void insert(String key, Object value) {
if (!this.caseSensitive) {
key = key.toLowerCase();
}
map.put(key, value);
}
/**
* Return whether a given key exists in the dictionary.
*/
public boolean containsKey(String key) {
if (!this.caseSensitive) {
key = key.toLowerCase();
}
return this.map.containsKey(key);
}
/**
* Return a list of the keys (StringItems) that exist in this dictionary in the preferred order.
*/
public List<String> getKeys() throws AnyException {
List<String> keys = new ArrayList<String>();
for (String key : this.map.keySet()) {
keys.add(key);
}
return keys;
}
/**
* Return a list of the values that exist in this dictionary in the preferred order.
*/
public List<Object> getValues() throws AnyException {
List<Object> vals = new ArrayList<Object>();
for (Object value : this.map.values()) {
vals.add(value);
}
return vals;
}
/**
* Insert all the entries another dictionary into this dictionary.
*/
public void insertAll(eglx.lang.EDictionary d) throws AnyException {
// d.insertAll(d) is a NOOP
if (d == this) {
return;
}
String[] newKeys = d.getKeyArray();
Object[] newValues = d.getValueArray();
for (int ii = 0; ii < newKeys.length; ++ii) {
insert(newKeys[ii], newValues[ii]);
}
}
/**
* Remove the entry with a specified key from the dictionary
*/
@Override
public void removeElement(String key) throws AnyException {
if (!this.caseSensitive) {
key = key.toLowerCase();
}
int originalSize = map.size();
this.map.remove(key);
if ( originalSize == map.size() )
{
// Since the size is unchanged, there was no value with that key.
DynamicAccessException dax = new DynamicAccessException();
dax.key = key;
throw dax.fillInMessage( Message.DYNAMIC_ACCESS_FAILED, key, "dictionary" );
}
}
/**
* Removes all the entries in the dictionary
*/
public void removeAll() {
this.map.clear();
}
/**
* Returns a clone of this object.
*/
public Object clone() throws CloneNotSupportedException {
EDictionary theClone = (EDictionary) super.clone();
// clone the map
switch (this.order) {
case byInsertion:
theClone.map = new LinkedHashMap<String, Object>(this.map.size());
break;
case byKey:
theClone.map = new TreeMap<String, Object>();
break;
default:
theClone.map = new HashMap<String, Object>(this.map.size());
break;
}
for (Iterator<Map.Entry<String, Object>> iter = this.map.entrySet().iterator(); iter.hasNext();) {
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) iter.next();
Object value = entry.getValue();
if (value instanceof AnyValue) {
value = ((AnyValue) value).clone();
}
theClone.map.put(entry.getKey(), value);
}
return theClone;
}
@Override
public Object put(String key, Object value) {
if (!this.caseSensitive) {
key = key.toLowerCase();
}
this.map.put(key, value);
return value;
}
public Object ezeGet(String name) throws AnyException {
if (!this.caseSensitive) {
name = name.toLowerCase();
}
Object value = map.get( name );
if ( value == null && !map.containsKey( name ) )
{
DynamicAccessException dax = new DynamicAccessException();
dax.key = name;
throw dax.fillInMessage( Message.DYNAMIC_ACCESS_FAILED, name, "dictionary" );
}
return value;
}
@Override
public void ezeSet(String name, Object value) {
put(name, value);
}
@Override
public void putAll(Map<? extends String, ? extends Object> map) {
this.map.putAll(map);
}
}