/*******************************************************************************
* Copyright (c) 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
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Jan S. Rellermeyer, IBM Research - initial API and implementation
*******************************************************************************/
package org.eclipse.concierge;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface ConciergeCollections {
public static class MultiMap<K, V> implements Map<K, List<V>> {
protected final HashMap<K, List<V>> map;
protected final LinkedHashSet<V> allValues = new LinkedHashSet<V>();
private final Comparator<V> comp;
boolean dirty = false;
public MultiMap() {
this.map = new HashMap<K, List<V>>();
this.comp = null;
}
public MultiMap(final int initialSize) {
this.map = new HashMap<K, List<V>>(initialSize);
this.comp = null;
}
public MultiMap(final MultiMap<K, ? extends V> existing) {
this();
insertMap(existing);
}
public MultiMap(final Comparator<V> comp) {
map = new HashMap<K, List<V>>();
this.comp = comp;
}
HashMap<K, List<V>> getFlatMap() {
return map;
}
public void insert(final K key, final V value) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<V>();
map.put(key, list);
}
list.add(value);
if (comp != null) {
Collections.sort(list, comp);
}
if (!dirty) {
allValues.add(value);
}
}
public void insertEmpty(final K key) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<V>();
map.put(key, list);
}
}
public void insertUnique(final K key, final V value) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<V>();
map.put(key, list);
}
if (!list.contains(value)) {
list.add(value);
if (comp != null) {
Collections.sort(list, comp);
}
if (!dirty) {
allValues.add(value);
}
}
}
public void insertAll(final K key,
final Collection<? extends V> values) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<V>();
map.put(key, list);
}
list.addAll(values);
if (comp != null) {
Collections.sort(list, comp);
}
if (!dirty) {
allValues.addAll(values);
}
}
public void insertMap(final MultiMap<K, ? extends V> existing) {
for (final K key : existing.keySet()) {
final List<? extends V> vals = existing.get(key);
insertAll(key, vals);
}
}
public List<V> get(final Object key) {
return map.get(key);
}
public int indexOf(final K key, final V value) {
final List<V> list = get(key);
return list == null ? -1 : list.indexOf(value);
}
public boolean remove(final Object key, final Object value) {
final List<V> list = get(key);
if (list != null) {
final boolean result = list.remove(value);
if (result) {
dirty = true;
}
return result;
}
return false;
}
public List<V> remove(final Object key) {
final List<V> values = map.remove(key);
if (values == null) {
return null;
}
dirty = true;
return values;
}
public List<V> lookup(final K key) {
final List<V> result = get(key);
return result == null ? Collections.<V> emptyList() : result;
}
protected void redoAllValues() {
allValues.clear();
for (final List<V> valueList : values()) {
allValues.addAll(valueList);
}
dirty = false;
}
public List<V> getAllValues() {
if (dirty) {
redoAllValues();
}
return new ArrayList<V>(allValues);
}
public void removeAll(final K[] keys, final V value) {
for (int i = 0; i < keys.length; i++) {
final List<V> list = get(keys[i]);
if (list != null) {
list.remove(value);
}
}
dirty = true;
}
public Set<K> keySet() {
return new KeySet();
}
public String toString() {
return "MultiMap " + map.toString();
}
private final class KeySet extends AbstractSet<K> {
private final Set<K> keySet;
protected KeySet() {
keySet = map.keySet();
}
public Iterator<K> iterator() {
final Iterator<K> inner = keySet.iterator();
return new Iterator<K>() {
private K element;
public boolean hasNext() {
return inner.hasNext();
}
public K next() {
element = inner.next();
return element;
}
public void remove() {
MultiMap.this.remove(element);
}
};
}
public int size() {
return map.size();
}
public boolean contains(final Object key) {
return containsKey(key);
}
public boolean remove(final Object key) {
final boolean result = MultiMap.this.remove(key) != null;
if (result) {
dirty = true;
}
return result;
}
public void clear() {
MultiMap.this.clear();
allValues.clear();
dirty = false;
}
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean containsKey(final Object key) {
return map.containsKey(key);
}
public boolean containsValue(final Object value) {
if (dirty) {
redoAllValues();
}
return allValues.contains(value);
}
public List<V> put(final K key, final List<V> value) {
throw new UnsupportedOperationException("put");
}
public void putAll(final Map<? extends K, ? extends List<V>> m) {
throw new UnsupportedOperationException("putAll");
}
public void clear() {
map.clear();
allValues.clear();
dirty = false;
}
public Collection<List<V>> values() {
return map.values();
}
public Set<java.util.Map.Entry<K, List<V>>> entrySet() {
return map.entrySet();
}
}
public static class Tuple<T1, T2> {
private final T1 former;
private final T2 latter;
public Tuple(final T1 former, final T2 latter) {
this.former = former;
this.latter = latter;
}
public T1 getFormer() {
return former;
}
public T2 getLatter() {
return latter;
}
@Override
public String toString() {
return "<" + former + ", " + latter + ">";
}
}
public static class ParseResult
extends Tuple<HashMap<String, String>, HashMap<String, Object>> {
public ParseResult(final HashMap<String, String> directives,
final HashMap<String, Object> attributes) {
super(directives, attributes);
}
public HashMap<String, String> getDirectives() {
return getFormer();
}
public HashMap<String, Object> getAttributes() {
return getLatter();
}
}
static class RemoveOnlyMap<K, V> extends HashMap<K, V> {
/**
*
*/
private static final long serialVersionUID = -3743325895136799794L;
private boolean sealed;
@Override
public V put(final K key, final V value) {
if (sealed) {
throw new UnsupportedOperationException("put");
}
return super.put(key, value);
}
public void putAll(final Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException("putAll");
}
void seal() {
sealed = true;
}
}
static class RemoveOnlyList<E> extends ArrayList<E> {
/**
*
*/
private static final long serialVersionUID = -2126964539821583131L;
public RemoveOnlyList(final Collection<? extends E> result) {
super(result);
}
public boolean add(final Object o) {
throw new UnsupportedOperationException("add");
}
public boolean addAll(final Collection<? extends E> c) {
throw new UnsupportedOperationException("addAll");
}
}
static class DeltaTrackingRemoveOnlyList<E> extends RemoveOnlyList<E> {
private final ArrayList<E> removed = new ArrayList<E>();
/**
*
*/
private static final long serialVersionUID = 2467542232248099702L;
public DeltaTrackingRemoveOnlyList(final Collection<E> result) {
super(result);
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(final Object o) {
final boolean modified = super.remove(o);
if (modified) {
removed.add((E) o);
}
return modified;
}
@Override
public boolean removeAll(final Collection<?> c) {
boolean modified = false;
for (final Object o : c) {
modified |= remove(o);
}
return modified;
}
@Override
public boolean retainAll(final Collection<?> c) {
boolean modified = false;
for (final E e : this) {
if (!c.contains(e)) {
remove(e);
modified = true;
}
}
return modified;
}
public List<E> getRemoved() {
return removed;
}
}
}