/* * Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org * Use is subject to license terms. See license.txt. */ // TODO javadoc - remove this comment only when the class and all non-public // methods and fields are documented package org.beanfabrics.model; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import org.beanfabrics.event.OptionsEvent; import org.beanfabrics.event.OptionsListener; /** * Note: * <ul> * <li>keys must be unique</li> * <li>keys can be null</li> * <li>values must be unique</li> * <li>values must not be null</li> * </ul> * * @param <K> the key type used in this options. * @author Michael Karneim TODO introduce an interface for this implementation. */ public class Options<K> { private final Map<K, String> map = new LinkedHashMap<K, String>(); private final List<String> values = new ArrayList<String>(); private final CopyOnWriteArrayList<OptionsListener> optionsListeners = new CopyOnWriteArrayList<OptionsListener>(); public Map<K, String> toMap() { return new LinkedHashMap<K, String>(map); } public void clear() { boolean isEmpty = this.isEmpty(); if (!isEmpty) { map.clear(); values.clear(); this.fireChanged(); } } public boolean containsKey(Object key) { return map.containsKey(key); } public boolean containsValue(Object value) { return map.containsValue(value); } public String get(Object key) { return map.get(key); } public K getKey(String value) { if (value == null) { throw new IllegalArgumentException("value==null"); } for (K key : map.keySet()) { String val = map.get(key); if (value.equals(val)) { return key; } } throw new NoSuchElementException("value='" + value + "' not found"); } public boolean isEmpty() { return map.isEmpty(); } public Set<K> keySet() { return new LinkedHashSet<K>(map.keySet()); } public String put(K key, String value) { if (value == null) { throw new IllegalArgumentException("value==null"); } boolean noChange = equals(map.get(key), value); if (noChange) { return value; } if (values.contains(value)) { throw new IllegalArgumentException("duplicate value='" + value + "' "); } String result = map.put(key, value); values.add(value); if (result != null) { values.remove(result); } this.fireChanged(); return result; } public void putAll(Options other) { this.putAll(other.map); } public void putAll(Map<K, String> aMap) { LinkedHashMap<K, String> tmp = new LinkedHashMap<K, String>(this.map); for (Map.Entry<K, String> entry : aMap.entrySet()) { if (entry.getValue() == null) { throw new IllegalArgumentException("value for entry with key='" + entry.getKey() + "' is null"); } tmp.put(entry.getKey(), entry.getValue()); } Collection<String> tmpValues = tmp.values(); Set<String> tmpValuesSet = new LinkedHashSet<String>(tmpValues); if (tmpValues.size() != tmpValuesSet.size()) { // some value(s) are duplicates throw new IllegalArgumentException("some values are duplicates"); } this.map.clear(); this.map.putAll(tmp); this.values.clear(); this.values.addAll(tmpValuesSet); this.fireChanged(); } public String remove(Object key) { String result = map.remove(key); if (result != null) { values.remove(result); this.fireChanged(); } return result; } public Set<String> removeAll(Set<K> keys) { LinkedHashSet<String> result = new LinkedHashSet<String>(); for (K key : keys) { String removed = map.remove(key); if (removed != null) { result.add(removed); } } if (!values.isEmpty()) { values.removeAll(result); this.fireChanged(); } return result; } public int size() { return map.size(); } public Set<String> values() { return new LinkedHashSet<String>(this.values); } public String[] getValues() { return (String[])values.toArray(new String[values.size()]); } public int indexOf(String value) { return this.values.indexOf(value); } public String getValue(int index) { return this.values.get(index); } public void addOptionsListener(OptionsListener l) { if (l == null) { throw new IllegalArgumentException("l must not be null."); } optionsListeners.add(l); } public void removeOptionsListener(OptionsListener l) { if (l == null) { throw new IllegalArgumentException("l must not be null."); } optionsListeners.remove(l); } protected void fireChanged() { OptionsEvent evt = new OptionsEvent(this); for (OptionsListener l : optionsListeners) { l.changed(evt); } } protected static boolean equals(Object a, Object b) { return (a == null && b == null) || (a != null && a.equals(b)); } public static <T> Options<T> create(T... values) { Options<T> result = new Options<T>(); for (T value : values) { result.put(value, String.valueOf(value)); } return result; } }