package er.extensions.foundation;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSCoder;
import com.webobjects.foundation.NSData;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSPropertyListSerialization;
/**
* Adds {@link java.util.Map} functionality to NSMutableDictionary and has
* helpers to en- and decode from database field.
* <code>ERPrototype name = mutableDictionary</code>
* @param <V>
*/
public class ERXMutableDictionary<K,V> extends NSMutableDictionary<K,V> {
public static final long serialVersionUID = 8091318522043166356L;
public static NSData toBlob(NSDictionary<?,?> d) {
try (ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout)) {
oos.writeObject(d);
NSData sp = new NSData(bout.toByteArray());
return sp;
}
catch (IOException e) {
// shouldn't ever happen, as we only write to memory
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
public static NSData toBlob(ERXMutableDictionary<?,?> dict) {
return toBlob((NSDictionary<?,?>) dict);
}
@SuppressWarnings("unchecked")
public static NSDictionary fromBlob(NSData d) {
try (ByteArrayInputStream bis = new ByteArrayInputStream(d.bytes()); ObjectInputStream ois = new ERXMappingObjectStream(bis)) {
NSDictionary<?,?> dd = (NSDictionary<?,?>) ois.readObject();
return dd;
}
catch (IOException e) {
// shouldn't ever happen, as we only read from memory
throw NSForwardException._runtimeExceptionForThrowable(e);
}
catch (ClassNotFoundException e) {
// might happen, but it doesn't help us much to know it
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
@SuppressWarnings("unchecked")
public static NSDictionary fromPropertyList(String plist) {
NSDictionary<Object,Object> dict = (NSDictionary) NSPropertyListSerialization.propertyListFromString(plist);
return new ERXMutableDictionary<Object,Object>(dict);
}
public static String toPropertyList(NSDictionary<?,?> dict) {
String plist = NSPropertyListSerialization.stringFromPropertyList(dict);
return plist;
}
public String toPropertyList() {
String plist = NSPropertyListSerialization.stringFromPropertyList(this);
return plist;
}
public NSData toBlob() {
return toBlob(this);
}
public ERXMutableDictionary(NSDictionary<? extends K, ? extends V> d) {
super(d);
}
public ERXMutableDictionary() {
super();
}
@Override
public Object clone() {
return new ERXMutableDictionary<K,V>(this);
}
/**
* return the string value of an object for key
*
* @param key
* the key which is linked to the object
* @return if objectForKey return a non null value this method returns the
* toString value from the object
*/
public String stringObjectForKey(K key) {
Object o = objectForKey(key);
return o == null ? null : o.toString();
}
/**
* @param key
*/
public Boolean booleanObjectForKey(K key) {
Object o = objectForKey(key);
return o == null ? null : ERXValueUtilities.booleanValue(o) ? Boolean.TRUE : Boolean.FALSE;
}
/**
* Simple thread safe wrapper. May or may not be correct, but it doesn't
* matter as you will never, *ever* call this directly, but call <code>
* ERXMutableDictionary.synchronizedDictionary();
* </code>
* instead and we will fix all the bugs in due time.
*
* @author ak
*
*/
public static class ThreadSafeDictionary<K,V> extends ERXMutableDictionary<K,V> {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
public ThreadSafeDictionary(NSMutableDictionary<? extends K, ? extends V> dictionary) {
super(dictionary);
}
@Override
public synchronized void addEntriesFromDictionary(NSDictionary<? extends K, ? extends V> otherDictionary) {
super.addEntriesFromDictionary(otherDictionary);
}
@Override
public synchronized NSDictionary<K,V> immutableClone() {
return super.immutableClone();
}
@Override
public synchronized NSMutableDictionary<K,V> mutableClone() {
return super.mutableClone();
}
@Override
public synchronized void removeAllObjects() {
super.removeAllObjects();
}
@Override
public synchronized V removeObjectForKey(Object key) {
return super.removeObjectForKey(key);
}
@Override
public synchronized void removeObjectsForKeys(NSArray<? extends K> keys) {
super.removeObjectsForKeys(keys);
}
@Override
public synchronized void setDictionary(NSDictionary<? extends K, ? extends V> otherDictionary) {
super.setDictionary(otherDictionary);
}
@Override
public synchronized void setObjectForKey(V object, K key) {
super.setObjectForKey(object, key);
}
@Override
public synchronized void takeValueForKey(Object value, String key) {
super.takeValueForKey(value, key);
}
@Override
protected synchronized void _clearDeletionsAndCollisions() {
super._clearDeletionsAndCollisions();
}
@Override
protected synchronized void _ensureCapacity(int capacity) {
super._ensureCapacity(capacity);
}
@Override
protected synchronized void _initializeDictionary() {
super._initializeDictionary();
}
@Override
public synchronized int _shallowHashCode() {
return super._shallowHashCode();
}
@Override
public synchronized NSArray<K> allKeys() {
return super.allKeys();
}
@Override
public synchronized NSArray<K> allKeysForObject(Object object) {
return super.allKeysForObject(object);
}
@Override
@SuppressWarnings("unchecked")
public synchronized Class classForCoder() {
return super.classForCoder();
}
@Override
public synchronized int count() {
return super.count();
}
@Override
public synchronized void encodeWithCoder(NSCoder coder) {
super.encodeWithCoder(coder);
}
@Override
public synchronized boolean equals(Object object) {
return super.equals(object);
}
@Override
public synchronized int hashCode() {
return super.hashCode();
}
@Override
public synchronized HashMap<K,V> hashMap() {
Object keys[] = keysNoCopy();
int c = keys.length;
HashMap<K,V> map = new HashMap<K,V>(c <= 0 ? 1 : c);
for (int i = 0; i < c; i++) {
map.put((K)keys[i], objectForKey(keys[i]));
}
return map;
}
@Override
public synchronized Hashtable<K,V> hashtable() {
return super.hashtable();
}
@Override
public synchronized boolean isEqualToDictionary(NSDictionary<?, ?> otherDictionary) {
return super.isEqualToDictionary(otherDictionary);
}
@Override
public synchronized Enumeration<K> keyEnumerator() {
return super.keyEnumerator();
}
@Override
public synchronized Object[] keysNoCopy() {
return super.keysNoCopy();
}
@Override
public synchronized Enumeration<V> objectEnumerator() {
return super.objectEnumerator();
}
@Override
public synchronized V objectForKey(Object key) {
return super.objectForKey(key);
}
@Override
public synchronized NSArray<V> objectsForKeys(NSArray<? extends K> keys, V notFoundMarker) {
return super.objectsForKeys(keys, notFoundMarker);
}
@Override
public synchronized Object[] objectsNoCopy() {
return super.objectsNoCopy();
}
@Override
public synchronized void takeValueForKeyPath(Object value, String keyPath) {
super.takeValueForKeyPath(value, keyPath);
}
@Override
public synchronized String toString() {
return super.toString();
}
@Override
public synchronized Object valueForKey(String key) {
return super.valueForKey(key);
}
@Override
public synchronized Object valueForKeyPath(String keyPath) {
return super.valueForKeyPath(keyPath);
}
}
/**
* Returns a thread-safe mutable wrapper for the given mutable dictionary.
*
* @param dict
* the dictionary to make thread-safe
* @return a thread-safe wrapper around the given dictionary
*/
public static <T,U> NSMutableDictionary<T,U> synchronizedDictionary(NSMutableDictionary<? extends T, ? extends U> dict) {
return new ThreadSafeDictionary<T,U>(dict);
}
/**
* Returns a new thread-safe mutable dictionary.
* @param <U>
*
* @return a new thread-safe mutable dictionary
*/
public static <T,U> NSMutableDictionary<T,U> synchronizedDictionary() {
return synchronizedDictionary(new ERXMutableDictionary<T,U>());
}
/**
* Returns either a new thread-safe dictionary, or just
* returns dict if the dictionary is not mutable.
*
* @param dict
* the dictionary to make thread-safe
* @return a thread-safe dictionary
*/
public static <T,U> NSDictionary<T,U> synchronizedDictionary(NSDictionary<? extends T, ? extends U> dict) {
if (!(dict instanceof NSMutableDictionary)) {
return (NSDictionary<T, U>) dict;
}
return synchronizedDictionary((NSMutableDictionary<T, U>) dict);
}
}