com.google.gwt.storage.client.StorageMap Maven / Gradle / Ivy
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.storage.client;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Exposes the local/session {@link Storage} as a standard {@link Map
* Map<String, String>}.
*
*
* Experimental API: This API is still under development
* and is subject to change.
*
*
*
* The following characteristics are associated with this Map:
*
*
* - Mutable - All 'write' methods ({@link #put(String, String)},
* {@link #putAll(Map)}, {@link #remove(Object)}, {@link #clear()},
* {@link Entry#setValue(Object)}) operate as intended;
* - remove() on Iterators - All remove() operations on available
* Iterators (from {@link #keySet()}, {@link #entrySet()} and {@link #values()})
* operate as intended;
* - No
null
values and keys - The Storage doesn't
* accept keys or values which are null
;
* - JavaScriptException instead of NullPointerException - Some Map
* (or other Collection) methods mandate the use of a
* {@link NullPointerException} if some argument is
null
(e.g.
* {@link #remove(Object)} remove(null)). this Map emits
* {@link com.google.gwt.core.client.JavaScriptException}s instead;
* - String values and keys - All keys and values in this Map are
* String types.
*
*/
public class StorageMap extends AbstractMap {
/*
* Represents a Map.Entry to a Storage item
*/
private class StorageEntry implements Map.Entry {
private final String key;
public StorageEntry(String key) {
this.key = key;
}
@Override
@SuppressWarnings("rawtypes")
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (obj == this) {
return true;
} else if (!(obj instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry) obj;
return eq(key, e.getKey()) && eq(getValue(), e.getValue());
}
public String getKey() {
return key;
}
public String getValue() {
return storage.getItem(key);
}
@Override
public int hashCode() {
String value = getValue();
return (key == null ? 0 : key.hashCode())
^ (value == null ? 0 : value.hashCode());
}
public String setValue(String value) {
String oldValue = storage.getItem(key);
storage.setItem(key, value);
return oldValue;
}
}
/*
* Represents an Iterator over all Storage items
*/
private class StorageEntryIterator implements Iterator<
Map.Entry> {
private int index = -1;
private boolean removed = false;
public boolean hasNext() {
return index < size() - 1;
}
public Map.Entry next() {
if (hasNext()) {
index++;
removed = false;
return new StorageEntry(storage.key(index));
}
throw new NoSuchElementException();
}
public void remove() {
if (index >= 0 && index < size()) {
if (removed) {
throw new IllegalStateException(
"Cannot remove() Entry - already removed!");
}
storage.removeItem(storage.key(index));
removed = true;
index--;
} else {
throw new IllegalStateException(
"Cannot remove() Entry - index=" + index + ", size=" + size());
}
}
}
/*
* Represents a Set over all Storage items
*/
private class StorageEntrySet extends AbstractSet> {
@Override
public void clear() {
StorageMap.this.clear();
}
@SuppressWarnings("rawtypes")
@Override
public boolean contains(Object o) {
if (o == null || !(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry) o;
Object key = e.getKey();
return key != null && containsKey(key) && eq(get(key), e.getValue());
}
@Override
public Iterator> iterator() {
return new StorageEntryIterator();
}
@SuppressWarnings("rawtypes")
@Override
public boolean remove(Object o) {
if (o == null || !(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry) o;
if (e.getKey() == null) {
return false;
}
String key = e.getKey().toString();
String value = storage.getItem(key);
if (eq(value, e.getValue())) {
return StorageMap.this.remove(key) != null;
}
return false;
}
@Override
public int size() {
return StorageMap.this.size();
}
}
private Storage storage;
private StorageEntrySet entrySet;
/**
* Creates the Map with the specified Storage as data provider.
*
* @param storage a local/session Storage instance obtained by either
* {@link Storage#getLocalStorageIfSupported()} or
* {@link Storage#getSessionStorageIfSupported()}.
*/
public StorageMap(Storage storage) {
assert storage != null : "storage cannot be null";
this.storage = storage;
}
/**
* Removes all items from the Storage.
*
* @see Storage#clear()
*/
@Override
public void clear() {
storage.clear();
}
/**
* Returns true
if the Storage contains the specified key,
* false
otherwise.
*/
@Override
public boolean containsKey(Object key) {
return storage.getItem(key.toString()) != null;
}
/**
* Returns true
if the Storage contains the specified value,
* false
otherwise (or if the specified key is null
* ).
*/
@Override
public boolean containsValue(Object value) {
int s = size();
for (int i = 0; i < s; i++) {
if (value.equals(storage.getItem(storage.key(i)))) {
return true;
}
}
return false;
}
/**
* Returns a Set containing all entries of the Storage.
*/
@Override
public Set> entrySet() {
if (entrySet == null) {
entrySet = new StorageEntrySet();
}
return entrySet;
}
/**
* Returns the value associated with the specified key in the Storage.
*
* @param key the key identifying the value
* @see Storage#getItem(String)
*/
@Override
public String get(Object key) {
if (key == null) {
return null;
}
return storage.getItem(key.toString());
}
/**
* Adds (or overwrites) a new key/value pair in the Storage.
*
* @param key the key identifying the value (not null
)
* @param value the value associated with the key (not null
)
* @see Storage#setItem(String, String)
*/
@Override
public String put(String key, String value) {
if (key == null || value == null) {
throw new IllegalArgumentException("Key and value cannot be null!");
}
String old = storage.getItem(key);
storage.setItem(key, value);
return old;
}
/**
* Removes the key/value pair from the Storage.
*
* @param key the key identifying the item to remove
* @return the value associated with the key - null
if the key
* was not present in the Storage
* @see Storage#removeItem(String)
*/
@Override
public String remove(Object key) {
String k = key.toString();
String old = storage.getItem(k);
storage.removeItem(k);
return old;
}
/**
* Returns the number of items in the Storage.
*
* @return the number of items
* @see Storage#getLength()
*/
@Override
public int size() {
return storage.getLength();
}
private boolean eq(Object a, Object b) {
if (a == b) {
return true;
}
if (a == null) {
return false;
}
return a.equals(b);
}
}