/*
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.scripting;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.javascript.CharSequenceBuffer;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.JavaMembers;
import org.mozilla.javascript.NativeDate;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.WrapFactory;
import com.servoy.j2db.FormController;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.dataprocessing.IDataSet;
import com.servoy.j2db.dataprocessing.JSDataSet;
import com.servoy.j2db.dataprocessing.ValueFactory.DbIdentValue;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.UUID;
/**
* @author jcompagner
*
*/
public final class ServoyWrapFactory extends WrapFactory
{
private final IApplication application;
/**
* @param application
*/
public ServoyWrapFactory(IApplication application)
{
this.application = application;
setJavaPrimitiveWrap(false);
}
/**
* @see org.mozilla.javascript.WrapFactory#wrap(org.mozilla.javascript.Context, org.mozilla.javascript.Scriptable, java.lang.Object, java.lang.Class)
*/
@Override
public Object wrap(Context cx, Scriptable scope, Object obj, Class staticType)
{
if (obj == null || obj == Undefined.instance || obj instanceof Scriptable || obj instanceof String || obj instanceof CharSequenceBuffer ||
obj instanceof Number || obj instanceof Boolean)
{
return obj;
}
if (obj instanceof Date)
{
return cx.newObject(scope, "Date", new Object[] { new Double(NativeDate.convertToUTCMillisFromJava(((Date)obj).getTime())) });
}
if (obj instanceof DbIdentValue || obj instanceof UUID)
{
return new NativeJavaObject(scope, obj, ScriptObjectRegistry.getJavaMembers(obj.getClass(), null));
}
if (cx != null)
{
if (obj instanceof JSConvertedMap< ? , ? >)
{
Scriptable newObject = null;
JSConvertedMap< ? , ? > map = (JSConvertedMap< ? , ? >)obj;
if (map.getConstructorName() != null)
{
newObject = cx.newObject(scope, map.getConstructorName());
}
else
{
newObject = cx.newObject(scope);
}
Iterator< ? > iterator = map.entrySet().iterator();
while (iterator.hasNext())
{
Map.Entry< ? , ? > next = (Entry< ? , ? >)iterator.next();
Object key = next.getKey();
Object value = next.getValue();
if (value != null)
{
value = wrap(cx, newObject, value, value.getClass());
}
if (key instanceof Integer)
{
newObject.put(((Integer)key).intValue(), newObject, value);
}
else if (key instanceof String)
{
newObject.put((String)key, newObject, value);
}
else
{
Debug.error("Try to create a JSConvertedMap->NativeObject with a key that isnt a string or integer:" + key + " for value: " + value); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return newObject;
}
if (obj.getClass() == JSONObject.class)
{
JSONObject json = (JSONObject)obj;
Scriptable newObject = cx.newObject(scope);
Iterator<String> iterator = json.keys();
while (iterator.hasNext())
{
String key = iterator.next();
Object value = null;
try
{
value = json.get(key);
}
catch (JSONException e)
{
Debug.error(e);
}
if (value != null)
{
value = wrap(cx, newObject, value, value.getClass());
}
newObject.put(key, newObject, value);
}
return newObject;
}
if (obj.getClass() == JSONArray.class)
{
JSONArray array = (JSONArray)obj;
Scriptable newObject = cx.newObject(scope, "Array");
for (int i = 0; i < array.length(); i++)
{
Object value = null;
try
{
value = array.get(i);
}
catch (JSONException e)
{
Debug.error(e);
}
if (value != null)
{
value = wrap(cx, newObject, value, value.getClass());
}
newObject.put(i, newObject, value);
}
return newObject;
}
}
if (obj instanceof IDataSet)
{
return new JSDataSet(application, (IDataSet)obj);
}
if (obj instanceof FormController)
{
throw new IllegalArgumentException(
"Bad practice: FormController cant be wrapped to javascript (for example not usable as argument in Scheduler plugin)"); //$NON-NLS-1$
}
// if it is a none primitive array
if (obj.getClass().isArray() && !obj.getClass().getComponentType().isPrimitive())
{
// then convert the array to a NativeArray, first convert all the elements of the array itself.
Object[] source = (Object[])obj;
Object[] array = new Object[source.length];
for (int i = 0; i < source.length; i++)
{
Object src = source[i];
array[i] = wrap(cx, scope, src, src != null ? src.getClass() : null);
}
return cx.newArray(scope, array);
}
return super.wrap(cx, scope, obj, staticType);
}
/*
* (non-Javadoc)
*
* @see org.mozilla.javascript.WrapFactory#wrapAsJavaObject(org.mozilla.javascript.Context, org.mozilla.javascript.Scriptable, java.lang.Object,
* java.lang.Class)
*/
@Override
public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class< ? > staticType)
{
JavaMembers members = javaObject != null ? ScriptObjectRegistry.getJavaMembers(javaObject.getClass(), scope) : ScriptObjectRegistry.getJavaMembers(
staticType, scope);
if (members != null)
{
return new NativeJavaObject(scope, javaObject, members);
}
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
}
}