OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 61 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
61 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.utils.cc;
15
 
16
import org.openconcerto.utils.CompareUtils;
17
 
18
import java.util.AbstractMap;
19
import java.util.AbstractSet;
20
import java.util.Collections;
21
import java.util.HashMap;
22
import java.util.Iterator;
23
import java.util.Map;
24
import java.util.Set;
25
 
26
import net.jcip.annotations.ThreadSafe;
27
 
28
/**
29
 * A thread-safe map in which all mutative operations (put, remove, and so on) are implemented by
30
 * making a fresh copy of the underlying map. The instance of the underlying map can be customized
31
 * with {@link #copy(Map)}. The underlying immutable map is available with {@link #getImmutable()}.
32
 *
33
 * @author Sylvain
34
 *
35
 * @param <K> the type of keys maintained by this map
36
 * @param <V> the type of mapped values
37
 */
38
@ThreadSafe
39
public class CopyOnWriteMap<K, V> extends AbstractMap<K, V> {
40
 
41
    private Map<K, V> immutable;
42
    private Set<Entry<K, V>> entrySet = null;
43
 
44
    public CopyOnWriteMap() {
45
        this.immutable = Collections.emptyMap();
46
    }
47
 
48
    public CopyOnWriteMap(final Map<K, V> m) {
49
        this.immutable = Collections.unmodifiableMap(copy(m));
50
    }
51
 
52
    /**
53
     * Create a copy of the passed map.
54
     *
55
     * @param src the map to copy, not <code>null</code>.
56
     * @return a shallow copy of <code>src</code>.
57
     */
58
    public Map<K, V> copy(Map<? extends K, ? extends V> src) {
59
        return new HashMap<K, V>(src);
60
    }
61
 
62
    // write
63
 
64
    @Override
65
    public synchronized V put(final K key, final V value) {
66
        final Map<K, V> copy = copy(this.immutable);
67
        final V res = copy.put(key, value);
68
        this.immutable = Collections.unmodifiableMap(copy);
69
        return res;
70
    }
71
 
72
    @Override
73
    public synchronized V remove(final Object key) {
74
        final Map<K, V> copy = copy(this.immutable);
75
        final V res = copy.remove(key);
76
        this.immutable = Collections.unmodifiableMap(copy);
77
        return res;
78
    }
79
 
80
    @Override
81
    public synchronized void putAll(final Map<? extends K, ? extends V> m) {
82
        final Map<K, V> copy = copy(this.immutable);
83
        copy.putAll(m);
84
        this.immutable = Collections.unmodifiableMap(copy);
85
    }
86
 
87
    @Override
88
    public synchronized void clear() {
89
        this.immutable = Collections.emptyMap();
90
    }
91
 
92
    // read
93
 
94
    public synchronized final Map<K, V> getImmutable() {
95
        return this.immutable;
96
    }
97
 
98
    @Override
182 ilm 99
    public int size() {
100
        return this.getImmutable().size();
61 ilm 101
    }
102
 
103
    @Override
182 ilm 104
    public boolean isEmpty() {
105
        return this.getImmutable().isEmpty();
61 ilm 106
    }
107
 
108
    @Override
182 ilm 109
    public boolean containsKey(final Object key) {
110
        return this.getImmutable().containsKey(key);
61 ilm 111
    }
112
 
113
    @Override
182 ilm 114
    public boolean containsValue(final Object value) {
115
        return this.getImmutable().containsValue(value);
61 ilm 116
    }
117
 
118
    @Override
182 ilm 119
    public V get(final Object key) {
120
        return this.getImmutable().get(key);
61 ilm 121
    }
122
 
123
    @Override
124
    public synchronized Set<Entry<K, V>> entrySet() {
125
        if (this.entrySet == null)
126
            this.entrySet = new EntrySet();
127
        return this.entrySet;
128
    }
129
 
130
    private final class EntrySet extends AbstractSet<Entry<K, V>> {
131
        public Iterator<Entry<K, V>> iterator() {
132
            return new Iterator<Entry<K, V>>() {
133
                private final Iterator<Entry<K, V>> delegate = CopyOnWriteMap.this.immutable.entrySet().iterator();
134
                private Entry<K, V> current = null;
135
 
136
                @Override
137
                public boolean hasNext() {
138
                    return this.delegate.hasNext();
139
                }
140
 
141
                @Override
142
                public Entry<K, V> next() {
143
                    return (this.current = this.delegate.next());
144
                }
145
 
146
                @Override
147
                public void remove() {
148
                    if (this.current == null)
149
                        throw new IllegalStateException();
150
                    EntrySet.this.remove(this.current);
151
                }
152
            };
153
        }
154
 
155
        public boolean contains(Object o) {
156
            if (!(o instanceof Entry))
157
                return false;
158
            final Entry<?, ?> e = (Entry<?, ?>) o;
159
            return CompareUtils.equals(e.getValue(), get(e.getKey()));
160
        }
161
 
162
        public boolean remove(Object o) {
163
            if (!(o instanceof Entry))
164
                return false;
165
            return CopyOnWriteMap.this.remove(((Entry<?, ?>) o).getKey()) != null;
166
        }
167
 
168
        public int size() {
169
            return CopyOnWriteMap.this.size();
170
        }
171
 
172
        public void clear() {
173
            CopyOnWriteMap.this.clear();
174
        }
175
    }
176
 
177
    // equals
178
 
179
    @Override
182 ilm 180
    public boolean equals(final Object o) {
181
        return this.getImmutable().equals(o);
61 ilm 182
    }
183
 
184
    @Override
182 ilm 185
    public int hashCode() {
186
        return this.getImmutable().hashCode();
61 ilm 187
    }
188
}