001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Sam
047: */
048:
049: package com.caucho.portal.generic;
050:
051: import java.util.*;
052: import java.util.logging.Logger;
053:
054: public class StoreUpdateMap<K, V> implements Map<K, V> {
055: static protected final Logger log = Logger
056: .getLogger(StoreUpdateMap.class.getName());
057:
058: private Map<K, K> _nameLinkMap;
059: private Map<K, K> _reverseNameLinkMap;
060: private Map<K, V> _storeMapUnlinked;
061: private Map<K, V> _storeMap;
062: private Map<K, V> _defaultMap;
063: private Set<K> _names;
064: private V _deletedValue;
065:
066: private Set<K> _keySet;
067: private boolean _keySetModifiable;
068: private Map<K, V> _updateMapUnlinked;
069: private Map<K, V> _updateMap;
070:
071: void start(Map<K, K> nameLinkMap, Map<K, K> reverseNameLinkMap,
072: Map<K, V> defaultMap, Map<K, V> storeMap, Set<K> names,
073: V deletedValue) {
074: if (_defaultMap != null || _storeMap != null)
075: throw new IllegalStateException("missing finish()?");
076:
077: _nameLinkMap = nameLinkMap;
078: _reverseNameLinkMap = reverseNameLinkMap;
079:
080: if (nameLinkMap != null) {
081: _defaultMap = new KeyLinkMap<K, V>(defaultMap,
082: _nameLinkMap, _reverseNameLinkMap);
083: _storeMapUnlinked = storeMap;
084: _storeMap = new KeyLinkMap<K, V>(storeMap, _nameLinkMap,
085: _reverseNameLinkMap);
086: } else {
087: _defaultMap = defaultMap;
088: _storeMapUnlinked = storeMap;
089: _storeMap = storeMap;
090: }
091:
092: _names = names;
093: _deletedValue = deletedValue;
094: }
095:
096: void finish() {
097: _updateMap = null;
098: _updateMapUnlinked = null;
099: _keySet = null;
100: _keySetModifiable = false;
101:
102: _nameLinkMap = null;
103: _defaultMap = null;
104: _storeMapUnlinked = null;
105: _storeMap = null;
106: _names = null;
107: }
108:
109: Map<K, V> getStoreMap() {
110: return _storeMapUnlinked;
111: }
112:
113: Map<K, V> getUpdateMap() {
114: return _updateMapUnlinked;
115: }
116:
117: private Set<K> getKeySet(boolean modifiable) {
118:
119: if (!modifiable) {
120: if (_keySet != null)
121: return _keySet;
122:
123: while (true) {
124: Set<K> keySet = _names;
125:
126: if (_defaultMap != null) {
127: if (keySet != null)
128: break;
129: else
130: keySet = _defaultMap.keySet();
131: }
132:
133: if (_storeMap != null) {
134: if (keySet != null)
135: break;
136: else
137: keySet = _storeMap.keySet();
138: }
139:
140: if (_updateMap != null) {
141: if (keySet != null)
142: break;
143: else
144: keySet = _updateMap.keySet();
145: }
146: }
147: }
148:
149: if (_keySetModifiable)
150: return _keySet;
151:
152: _keySet = new HashSet<K>();
153: _keySetModifiable = true;
154:
155: if (_names != null) {
156: Iterator<K> iter = _names.iterator();
157:
158: while (iter.hasNext()) {
159: K key = iter.next();
160:
161: if ((_storeMap != null && _storeMap.containsKey(key))
162: || (_defaultMap != null && _defaultMap
163: .containsKey(key))) {
164: _keySet.add(key);
165: }
166: }
167: } else {
168: if (_defaultMap != null)
169: _keySet.addAll(_defaultMap.keySet());
170:
171: if (_storeMap != null)
172: _keySet.addAll(_storeMap.keySet());
173: }
174:
175: return _keySet;
176: }
177:
178: public int size() {
179: return getKeySet(false).size();
180: }
181:
182: public boolean isEmpty() {
183: return getKeySet(false).isEmpty();
184: }
185:
186: public boolean containsKey(Object key) {
187: return getKeySet(false).contains(key);
188: }
189:
190: public V get(Object key) {
191: if (!getKeySet(false).contains(key))
192: return null;
193:
194: if (_updateMap != null && _updateMap.containsKey(key)) {
195: V v = _updateMap.get(key);
196:
197: return v;
198: } else if (_storeMap != null && _storeMap.containsKey(key))
199: return _storeMap.get(key);
200: else if (_defaultMap != null)
201: return _defaultMap.get(key);
202: else
203: return null;
204: }
205:
206: public Set<K> keySet() {
207: return getKeySet(false);
208: }
209:
210: public boolean containsValue(Object v) {
211: Iterator<K> iter = _keySet.iterator();
212:
213: while (iter.hasNext()) {
214: K key = iter.next();
215: V value = get(key);
216:
217: if (value == null) {
218: if (v == null)
219: return true;
220: } else {
221: if (value.equals(v))
222: return true;
223: }
224: }
225:
226: return false;
227: }
228:
229: public Collection<V> values() {
230: LinkedList<V> values = new LinkedList<V>();
231:
232: Iterator<K> iter = getKeySet(false).iterator();
233:
234: while (iter.hasNext()) {
235: K key = iter.next();
236: V value = get(key);
237:
238: values.add(value);
239: }
240:
241: return values;
242: }
243:
244: public Set<Map.Entry<K, V>> entrySet() {
245: // XXX: better implemented as custom class extending AbstractSet
246: LinkedHashMap<K, V> map = new LinkedHashMap<K, V>();
247:
248: Iterator<K> iter = getKeySet(false).iterator();
249:
250: while (iter.hasNext()) {
251: K key = iter.next();
252: V value = get(key);
253:
254: map.put(key, value);
255: }
256:
257: return map.entrySet();
258: }
259:
260: private void makeUpdateMap() {
261: if (_updateMap == null) {
262: _updateMapUnlinked = new LinkedHashMap<K, V>();
263: if (_nameLinkMap != null)
264: _updateMap = new KeyLinkMap<K, V>(_updateMapUnlinked,
265: _nameLinkMap, _reverseNameLinkMap);
266: else
267: _updateMap = _updateMapUnlinked;
268: }
269: }
270:
271: public V put(K key, V value) {
272: if (_names != null && !_names.contains(key))
273: throw new IllegalArgumentException("attribute name `" + key
274: + "' not allowed");
275:
276: makeUpdateMap();
277:
278: Set<K> keySet = getKeySet(false);
279:
280: if (!keySet.contains(key)) {
281: if (keySet != _updateMap.keySet())
282: keySet = getKeySet(true);
283:
284: if (value != _deletedValue)
285: keySet.add(key);
286: }
287:
288: V oldValue = _updateMap.put(key, value);
289:
290: if (oldValue == _deletedValue)
291: oldValue = null;
292:
293: return oldValue;
294: }
295:
296: public void putAll(Map<? extends K, ? extends V> srcMap) {
297: Iterator<? extends Entry<? extends K, ? extends V>> iter = srcMap
298: .entrySet().iterator();
299:
300: while (iter.hasNext()) {
301: Map.Entry<? extends K, ? extends V> entry = iter.next();
302: put(entry.getKey(), entry.getValue());
303: }
304: }
305:
306: public V remove(Object key) {
307: Set<K> keySet = getKeySet(false);
308:
309: V oldValue = null;
310:
311: if (keySet.contains(key)) {
312: oldValue = put((K) key, _deletedValue);
313: getKeySet(true).remove(key);
314: }
315:
316: return oldValue;
317: }
318:
319: public void clear() {
320: Iterator<K> iter = getKeySet(true).iterator();
321:
322: while (iter.hasNext()) {
323: K key = iter.next();
324:
325: if (_storeMap != null && _storeMap.containsKey(key))
326: put(key, _deletedValue);
327: else if (_updateMap != null)
328: _updateMap.remove(key);
329:
330: iter.remove();
331: }
332: }
333: }
|