/******************************************************************************* * * Copyright (c) 2004-2010 Oracle Corporation. * * 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: * * Kohsuke Kawaguchi * * *******************************************************************************/ package hudson.util; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.converters.collections.TreeMapConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * {@link Map} that has copy-on-write semantics. * * <p> This class is suitable where highly concurrent access is needed, yet the * write operation is relatively uncommon. * * @author Kohsuke Kawaguchi */ public abstract class CopyOnWriteMap<K, V> implements Map<K, V> { protected volatile Map<K, V> core; /** * Read-only view of {@link #core}. */ private volatile Map<K, V> view; protected CopyOnWriteMap(Map<K, V> core) { update(core); } protected CopyOnWriteMap() { update(Collections.<K, V>emptyMap()); } protected void update(Map<K, V> m) { core = m; view = Collections.unmodifiableMap(core); } public int size() { return core.size(); } public boolean isEmpty() { return core.isEmpty(); } public boolean containsKey(Object key) { return core.containsKey(key); } public boolean containsValue(Object value) { return core.containsValue(value); } public V get(Object key) { return core.get(key); } public synchronized V put(K key, V value) { Map<K, V> m = copy(); V r = m.put(key, value); update(m); return r; } public synchronized V remove(Object key) { Map<K, V> m = copy(); V r = m.remove(key); update(m); return r; } public synchronized void putAll(Map<? extends K, ? extends V> t) { Map<K, V> m = copy(); m.putAll(t); update(m); } protected abstract Map<K, V> copy(); public synchronized void clear() { update(Collections.<K, V>emptyMap()); } /** * This method will return a read-only {@link Set}. */ public Set<K> keySet() { return view.keySet(); } /** * This method will return a read-only {@link Collection}. */ public Collection<V> values() { return view.values(); } /** * This method will return a read-only {@link Set}. */ public Set<Entry<K, V>> entrySet() { return view.entrySet(); } /** * {@link CopyOnWriteMap} backed by {@link HashMap}. */ public static final class Hash<K, V> extends CopyOnWriteMap<K, V> { public Hash(Map<K, V> core) { super(new LinkedHashMap<K, V>(core)); } public Hash() { } protected Map<K, V> copy() { return new LinkedHashMap<K, V>(core); } public static class ConverterImpl extends MapConverter { public ConverterImpl(Mapper mapper) { super(mapper); } @Override public boolean canConvert(Class type) { return type == Hash.class; } @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { return new Hash((Map) super.unmarshal(reader, context)); } @Override public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { super.marshal(((Hash) source).core, writer, context); } } } /** * {@link CopyOnWriteMap} backed by {@link TreeMap}. */ public static final class Tree<K, V> extends CopyOnWriteMap<K, V> { private final Comparator<K> comparator; public Tree(Map<K, V> core, Comparator<K> comparator) { this(comparator); putAll(core); } public Tree(Comparator<K> comparator) { super(new TreeMap<K, V>(comparator)); this.comparator = comparator; } public Tree() { this(null); } protected Map<K, V> copy() { TreeMap<K, V> m = new TreeMap<K, V>(comparator); m.putAll(core); return m; } @Override public synchronized void clear() { update(new TreeMap<K, V>(comparator)); } public static class ConverterImpl extends TreeMapConverter { public ConverterImpl(Mapper mapper) { super(mapper); } @Override public boolean canConvert(Class type) { return type == Tree.class; } @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { TreeMap tm = (TreeMap) super.unmarshal(reader, context); return new Tree(tm, tm.comparator()); } @Override public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { super.marshal(((Tree) source).core, writer, context); } } } }