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 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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