/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2014 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.server.ngclient.property.types;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.mozilla.javascript.NativeFunction;
import org.mozilla.javascript.Scriptable;
import org.sablo.specification.PropertyDescription;
import org.sablo.specification.property.IBrowserConverterContext;
import org.sablo.specification.property.IConvertedPropertyType;
import org.sablo.specification.property.types.FunctionPropertyType;
import org.sablo.util.ValueReference;
import org.sablo.websocket.utils.DataConversion;
import org.sablo.websocket.utils.JSONUtils;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.persistence.Form;
import com.servoy.j2db.persistence.ISupportChilds;
import com.servoy.j2db.persistence.ScriptMethod;
import com.servoy.j2db.persistence.ScriptVariable;
import com.servoy.j2db.persistence.Solution;
import com.servoy.j2db.persistence.TableNode;
import com.servoy.j2db.scripting.FormScope;
import com.servoy.j2db.scripting.GlobalScope;
import com.servoy.j2db.scripting.ScriptVariableScope;
import com.servoy.j2db.scripting.solutionmodel.IJSParent;
import com.servoy.j2db.scripting.solutionmodel.JSBaseContainer;
import com.servoy.j2db.scripting.solutionmodel.JSForm;
import com.servoy.j2db.scripting.solutionmodel.JSMethod;
import com.servoy.j2db.scripting.solutionmodel.JSWebComponent;
import com.servoy.j2db.server.ngclient.FormElementContext;
import com.servoy.j2db.server.ngclient.property.types.NGConversions.IFormElementToTemplateJSON;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.IRhinoDesignConverter;
import com.servoy.j2db.util.SecuritySupport;
import com.servoy.j2db.util.Settings;
import com.servoy.j2db.util.Utils;
/**
* @author lvostinar
*
*/
public class ServoyFunctionPropertyType extends FunctionPropertyType
implements IConvertedPropertyType<Object>, IFormElementToTemplateJSON<Object, Object>, IRhinoDesignConverter
{
public static final ServoyFunctionPropertyType INSTANCE = new ServoyFunctionPropertyType();
private ServoyFunctionPropertyType()
{
}
@Override
public Object fromJSON(Object newValue, Object previousValue, PropertyDescription pd, IBrowserConverterContext dataConverterContext,
ValueReference<Boolean> returnValueAdjustedIncommingValue)
{
if (newValue instanceof JSONObject)
{
Map<String, Object> value = new HashMap<String, Object>();
Iterator<String> it = ((JSONObject)newValue).keys();
while (it.hasNext())
{
String key = it.next();
try
{
value.put(key, ((JSONObject)newValue).get(key));
}
catch (JSONException ex)
{
Debug.error(ex);
}
}
return value;
}
return newValue;
}
@Override
public JSONWriter toJSON(JSONWriter writer, String key, Object object, PropertyDescription pd, DataConversion clientConversion,
IBrowserConverterContext dataConverterContext) throws JSONException
{
Map<String, Object> map = new HashMap<>();
try
{
if (object instanceof String)
{
addScriptToMap((String)object, map);
}
else if (object instanceof NativeFunction)
{
NativeFunction function = (NativeFunction)object;
String functionName = function.getFunctionName();
Scriptable parentScope = function.getParentScope();
while (parentScope != null && !(parentScope instanceof ScriptVariableScope))
{
parentScope = parentScope.getParentScope();
}
if (parentScope instanceof FormScope && ((FormScope)parentScope).getFormController() != null)
{
String formName = ((FormScope)parentScope).getFormController().getName();
map.put("script", SecuritySupport.encrypt(Settings.getInstance(), "forms." + formName + "." + functionName + "()"));
map.put("formname", SecuritySupport.encrypt(Settings.getInstance(), formName));
}
else if (parentScope instanceof GlobalScope)
{
map.put("script",
SecuritySupport.encrypt(Settings.getInstance(), "scopes." + ((GlobalScope)parentScope).getScopeName() + "." + functionName + "()"));
}
}
else if (object instanceof Map)
{
map = new HashMap<String, Object>((Map<String, Object>)object);
if (map.get("script") instanceof String) addScriptToMap((String)map.get("script"), map);
}
}
catch (Exception ex)
{
Debug.error(ex);
}
return JSONUtils.toBrowserJSONFullValue(writer, key, map.size() == 0 ? null : map, null, clientConversion, null);
}
private void addScriptToMap(String script, Map<String, Object> map) throws Exception
{
if (script.startsWith(ScriptVariable.SCOPES_DOT_PREFIX) || script.startsWith(ScriptVariable.GLOBALS_DOT_PREFIX))
{
// scope method
map.put("script", SecuritySupport.encrypt(Settings.getInstance(), script + "()"));
}
else if (script.startsWith("entity."))
{
String formName = script.substring(7, script.indexOf('.', 7));
map.put("script", SecuritySupport.encrypt(Settings.getInstance(), script + "()"));
map.put("formname", SecuritySupport.encrypt(Settings.getInstance(), formName));
}
else if (script.contains("."))
{
// form method: formname.formmethod
String formName = script.substring(0, script.indexOf('.'));
map.put("script", SecuritySupport.encrypt(Settings.getInstance(), "forms." + script + "()"));
map.put("formname", SecuritySupport.encrypt(Settings.getInstance(), formName));
}
else
{
Debug.log("Can't create a function callback for " + script);
}
}
@Override
public JSONWriter toTemplateJSONValue(JSONWriter writer, String key, Object formElementValue, PropertyDescription pd,
DataConversion browserConversionMarkers, FormElementContext formElementContext) throws JSONException
{
if (formElementValue != null && formElementContext != null)
{
String[] components = formElementValue.toString().split("-"); //$NON-NLS-1$
if (components.length == 5)
{
String scriptString = null;
// this is a uuid
ScriptMethod sm = formElementContext.getFlattenedSolution().getScriptMethod(formElementValue.toString());
if (sm != null)
{
ISupportChilds parent = sm.getParent();
if (parent instanceof Solution)
{
scriptString = "scopes." + sm.getScopeName() + "." + sm.getName();
}
else if (parent instanceof Form)
{
scriptString = ((Form)parent).getName() + "." + sm.getName();
}
else if (parent instanceof TableNode)
{
scriptString = "entity." + formElementContext.getFormElement().getForm().getName() + "." + sm.getName();
}
}
else Debug.log("can't find a scriptmethod for: " + formElementValue);
return toJSON(writer, key, scriptString, pd, browserConversionMarkers, null);
}
}
return toJSON(writer, key, formElementValue, pd, browserConversionMarkers, null);
}
@Override
public Object fromRhinoToDesignValue(Object value, PropertyDescription pd, IApplication application, JSWebComponent webComponent)
{
if (value instanceof JSMethod)
{
return new Integer(JSBaseContainer.getMethodId(application, webComponent.getBaseComponent(false), ((JSMethod)value).getScriptMethod()));
}
return value;
}
@Override
public Object fromDesignToRhinoValue(Object value, PropertyDescription pd, IApplication application, JSWebComponent webComponent)
{
IJSParent< ? > jsParent = webComponent.getJSParent();
while (!(jsParent instanceof JSForm) && (jsParent != null))
{
jsParent = jsParent.getJSParent();
}
return JSForm.getEventHandler(application, webComponent.getBaseComponent(false), Utils.getAsInteger(value), jsParent, pd.getName());
}
}