/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.util;
import java.util.AbstractMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Map interface wrapper on JSONObject.
*
* @author rgansevles
*
*/
public class JSONWrapperMap<T> extends AbstractMap<String, T>
{
// original source, will be cleared when json object is touched
protected String source;
// json object based on source
private JSONObject json; // NOTE: never use this field directly when possibly making changes, always call getJson() to keep source in sync!
public JSONWrapperMap(String source)
{
this.source = source;
}
public JSONWrapperMap(JSONObject json)
{
this.json = json;
}
/**
* Method to get the json object in a lazy way, postpone parsing of the json if possible.
*
* @return
*/
protected JSONObject getJson()
{
if (json == null && source != null)
{
try
{
json = new ServoyJSONObject(source, true);
}
catch (JSONException e)
{
throw new RuntimeException(e);
}
}
// clear source, it may be outdated when json changes
source = null;
return json;
}
@Override
public Set<String> keySet()
{
Set<String> set = new HashSet<String>(size());
Iterator<String> keys = getJson().keys();
while (keys.hasNext())
{
set.add(keys.next());
}
return set;
}
@Override
public Set<java.util.Map.Entry<String, T>> entrySet()
{
Set<java.util.Map.Entry<String, T>> set = new HashSet<java.util.Map.Entry<String, T>>();
Iterator<String> keys = getJson().keys();
while (keys.hasNext())
{
set.add((java.util.Map.Entry<String, T>)new JSONWrapperMapEntry(keys.next(), getJson()));
}
return set;
}
@Override
public boolean containsKey(Object key)
{
if (key instanceof String)
{
return getJson().has((String)key);
}
return false;
}
protected Object toJava(Object o)
{
return ServoyJSONObject.toJava(o);
}
@Override
public T get(Object key)
{
if (key instanceof String)
{
return (T)toJava(getJson().opt((String)key));
}
return null;
}
@Override
public T remove(Object key)
{
if (key instanceof String)
{
return (T)toJava(getJson().remove((String)key));
}
return null;
}
@Override
public T put(String key, T value)
{
try
{
Object old = getJson().opt(key);
getJson().put(key, value);
return (T)toJava(old);
}
catch (JSONException e)
{
throw new RuntimeException(e);
}
}
@Override
public int size()
{
return getJson().length();
}
@Override
public String toString()
{
if (source == null)
{
// source is touched
source = ServoyJSONObject.toString(getJson(), true, true, true);
}
return source;
}
public class JSONWrapperMapEntry implements Entry<String, Object>
{
private final String key;
private final JSONObject json;
public JSONWrapperMapEntry(String key, JSONObject json)
{
this.key = key;
this.json = json;
}
public String getKey()
{
return key;
}
public Object getValue()
{
if (json.has(key))
{
try
{
return toJava(json.get(key));
}
catch (JSONException e)
{
throw new RuntimeException(e);
}
}
return null;
}
public Object setValue(Object value)
{
try
{
return toJava(json.put(key, value));
}
catch (JSONException e)
{
throw new RuntimeException(e);
}
}
}
/**
* merge 2 maps into 1, map2 overrides values in map1
*
* @param map1
* @param map2
* @return
*/
public static <T> JSONWrapperMap< ? > mergeMaps(JSONWrapperMap< ? extends T> map1, JSONWrapperMap< ? extends T> map2)
{
if (map1 == null)
{
return map2;
}
if (map2 == null)
{
return map1;
}
JSONWrapperMap<T> merged = new JSONWrapperMap<T>(new JSONObject());
for (String key2 : map2.keySet())
{
T val1 = map2.get(key2);
if (map1.containsKey(key2))
{
Object val2 = map1.get(key2);
if (val1 instanceof JSONWrapperMap && val2 instanceof JSONWrapperMap)
{
merged.put(key2, (T)mergeMaps((JSONWrapperMap< ? >)val1, (JSONWrapperMap< ? >)val2));
continue;
}
}
merged.put(key2, val1);
}
for (String key1 : map1.keySet())
{
if (!map2.containsKey(key1))
{
merged.put(key1, map1.get(key1));
}
}
return merged;
}
}