1 /*
2  * JBoss, Home of Professional Open Source.
3  * Copyright 2014 Red Hat, Inc., and individual contributors
4  * as indicated by the @author tags.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */

18
19 package io.undertow.util;
20
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.concurrent.ConcurrentMap;
27
28 /**
29  * A basic copy on write map. It simply delegates to an underlying map, that is swapped out
30  * every time the map is updated.
31  *
32  * Note: this is not a secure map. It should not be used in situations where the map is populated
33  * from user input.
34  *
35  * @author Stuart Douglas
36  */

37 public class CopyOnWriteMap<K,V> implements ConcurrentMap<K, V> {
38
39     private volatile Map<K, V> delegate = Collections.emptyMap();
40
41     public CopyOnWriteMap() {
42     }
43
44     public CopyOnWriteMap(Map<K, V> existing) {
45         this.delegate = new HashMap<>(existing);
46     }
47
48     @Override
49     public synchronized V putIfAbsent(K key, V value) {
50         final Map<K, V> delegate = this.delegate;
51         V existing = delegate.get(key);
52         if(existing != null) {
53             return existing;
54         }
55         putInternal(key, value);
56         return null;
57     }
58
59     @Override
60     public synchronized boolean remove(Object key, Object value) {
61         final Map<K, V> delegate = this.delegate;
62         V existing = delegate.get(key);
63         if(existing.equals(value)) {
64             removeInternal(key);
65             return true;
66         }
67         return false;
68     }
69
70     @Override
71     public synchronized boolean replace(K key, V oldValue, V newValue) {
72         final Map<K, V> delegate = this.delegate;
73         V existing = delegate.get(key);
74         if(existing.equals(oldValue)) {
75             putInternal(key, newValue);
76             return true;
77         }
78         return false;
79     }
80
81     @Override
82     public synchronized V replace(K key, V value) {
83         final Map<K, V> delegate = this.delegate;
84         V existing = delegate.get(key);
85         if(existing != null) {
86             putInternal(key, value);
87             return existing;
88         }
89         return null;
90     }
91
92     @Override
93     public int size() {
94         return delegate.size();
95     }
96
97     @Override
98     public boolean isEmpty() {
99         return delegate.isEmpty();
100     }
101
102     @Override
103     public boolean containsKey(Object key) {
104         return delegate.containsKey(key);
105     }
106
107     @Override
108     public boolean containsValue(Object value) {
109         return delegate.containsValue(value);
110     }
111
112     @Override
113     public V get(Object key) {
114         return delegate.get(key);
115     }
116
117     @Override
118     public synchronized V put(K key, V value) {
119         return putInternal(key, value);
120     }
121
122     @Override
123     public synchronized V remove(Object key) {
124         return removeInternal(key);
125     }
126
127     @Override
128     public synchronized void putAll(Map<? extends K, ? extends V> m) {
129         final Map<K, V> delegate = new HashMap<>(this.delegate);
130         for(Entry<? extends K, ? extends V> e : m.entrySet()) {
131             delegate.put(e.getKey(), e.getValue());
132         }
133         this.delegate = delegate;
134     }
135
136     @Override
137     public synchronized void clear() {
138         delegate = Collections.emptyMap();
139     }
140
141     @Override
142     public Set<K> keySet() {
143         return delegate.keySet();
144     }
145
146     @Override
147     public Collection<V> values() {
148         return delegate.values();
149     }
150
151     @Override
152     public Set<Entry<K, V>> entrySet() {
153         return delegate.entrySet();
154     }
155
156     //must be called under lock
157     private V putInternal(final K key, final V value) {
158         final Map<K, V> delegate = new HashMap<>(this.delegate);
159         V existing = delegate.put(key, value);
160         this.delegate = delegate;
161         return existing;
162     }
163
164     public V removeInternal(final Object key) {
165         final Map<K, V> delegate = new HashMap<>(this.delegate);
166         V existing = delegate.remove(key);
167         this.delegate = delegate;
168         return existing;
169     }
170 }
171