001/*
002 * Copyright c 2018 Rusi Popov, MDA Tools.net All rights reserved.
003 *
004 * This program and the accompanying materials are made available under the terms of the
005 * Eclipse Public License v2.0 which accompanies this distribution, and is available at
006 * http://www.eclipse.org/legal/epl-v20.html
007 */
008package net.mdatools.modelant.core.util.map;
009
010import java.util.Collection;
011import java.util.HashMap;
012import java.util.HashSet;
013import java.util.Map;
014import java.util.Set;
015
016/**
017 * This class is a composite Map implementation, so that when creating a
018 * new map form another, this implementation does not copy the original,
019 * but any access is delegated to the wrapped one.
020 * @author Rusi Popov (popovr@mdatools.net)
021 */
022public class CompositeMap<K,V> implements Map<K,V> {
023
024  private final Map<K,V> wrapped;
025
026  /**
027   * Any local changes
028   */
029  private final Map<K,V> local = new HashMap<>();
030
031  /**
032   *
033   */
034  public CompositeMap(Map<K,V> wrapped) {
035    this.wrapped = wrapped;
036  }
037
038  /**
039   * @see java.util.Map#clear()
040   */
041  public void clear() {
042    wrapped.clear();
043    local.clear();
044  }
045
046  /**
047   * @see java.util.Map#containsKey(java.lang.Object)
048   */
049  public boolean containsKey(Object key) {
050    return local.containsKey( key ) || wrapped.containsKey( key );
051  }
052
053  /**
054   * @see java.util.Map#containsValue(java.lang.Object)
055   */
056  public boolean containsValue(Object value) {
057    return local.containsValue( value ) || wrapped.containsValue( value );
058  }
059
060  /**
061   * @see java.util.Map#get(java.lang.Object)
062   */
063  public V get(Object key) {
064    V result;
065
066    if ( local.containsKey( key ) ) { // handles key-to-null local bindings
067      result = local.get( key );
068    } else {
069      result = wrapped.get( key );
070    }
071    return result;
072  }
073
074  /**
075   * @see java.util.Map#entrySet()
076   */
077  public Set entrySet() {
078    Set result = new HashSet();
079    result.addAll( wrapped.entrySet() );
080    result.addAll( local.entrySet() );
081    return result;
082  }
083
084  /**
085   * @see java.util.Map#keySet()
086   */
087  public Set keySet() {
088    Set result = new HashSet();
089    result.addAll( wrapped.keySet() );
090    result.addAll( local.keySet() );
091    return result;
092  }
093
094  /**
095   * @see java.util.Map#values()
096   */
097  public Collection values() {
098    Set result = new HashSet();
099    result.addAll( wrapped.values() );
100    result.addAll( local.values() );
101    return result;
102  }
103
104  /**
105   * @see java.util.Map#isEmpty()
106   */
107  public boolean isEmpty() {
108    return local.isEmpty() && wrapped.isEmpty();
109  }
110
111  /**
112   * @see java.util.Map#put(java.lang.Object, java.lang.Object)
113   */
114  public V put(K key, V value) {
115    return local.put( key, value );
116  }
117
118  /**
119   * @see java.util.Map#putAll(java.util.Map)
120   */
121  public void putAll(Map m) {
122    local.putAll( m );
123  }
124
125  /**
126   * @see java.util.Map#remove(java.lang.Object)
127   */
128  public V remove(Object key) {
129    V result;
130
131    if (  local.containsKey( key )) {
132      result = local.remove( key );
133    } else {
134      result = wrapped.remove( key );
135    }
136    return result;
137  }
138
139  /**
140   * @see java.util.Map#size()
141   */
142  public int size() {
143    return local.size() + wrapped.size();
144  }
145
146  /**
147   * @see java.lang.Object#toString()
148   */
149  public String toString() {
150    Map local;
151
152    local = new HashMap(this);
153    return local.toString();
154  }
155}