/* 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 org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; import com.servoy.j2db.IApplication; import com.servoy.j2db.IFormController; import com.servoy.j2db.persistence.ScriptVariable; import com.servoy.j2db.plugins.ClientPluginAccessProvider; import com.servoy.j2db.plugins.IClientPluginAccess; /** * Function definition, use to retrieve form and method name from a javascript Function object * * This class should be used to hold on to function objects in plugins that are later called by using the method * {@link #executeSync(IClientPluginAccess, Object[])} which is a short cut to {@link IClientPluginAccess#executeMethod(String, String, Object[], boolean)} * */ public class FunctionDefinition { private String contextName; // form name or sopes.scopeName private String methodName; public FunctionDefinition() // for bean xml serialization { } /** * Create FunctionDefinition from method string. * @param methodString formname.methodname or globals.methodname or scopes.scopename.methodname * @since 5.0 */ public FunctionDefinition(String methodString) { if (methodString != null) { String[] split = methodString.split("\\."); //$NON-NLS-1$ if (split.length == 1) { // global method methodName = split[0]; contextName = ScriptVariable.SCOPES_DOT_PREFIX + ScriptVariable.GLOBAL_SCOPE; } else if (split.length <= 3) { if (split.length == 2 && ScriptVariable.GLOBAL_SCOPE.equals(split[0])) { contextName = ScriptVariable.SCOPES_DOT_PREFIX + ScriptVariable.GLOBAL_SCOPE; } else if (split.length == 3 && ScriptVariable.SCOPES.equals(split[0])) { contextName = ScriptVariable.SCOPES_DOT_PREFIX + split[1]; } else { // form method if (split.length == 3) { contextName = split[1]; } else { contextName = split[0]; } } methodName = split[split.length - 1]; } } } /** * Create FunctionDefinition from context and method name. * @param contextName form name or scopes.scopename * @param methodName * @since 6.1 */ public FunctionDefinition(String contextName, String methodName) { this.contextName = contextName == null ? ScriptVariable.SCOPES_DOT_PREFIX + ScriptVariable.GLOBAL_SCOPE : contextName; this.methodName = methodName; } public FunctionDefinition(Function f) { if (f == null) { throw new IllegalArgumentException("Method/Function is null"); //$NON-NLS-1$ } Object scopeNameObj = f.get("_scopename_", f); //$NON-NLS-1$ if (scopeNameObj == null || scopeNameObj.equals(Scriptable.NOT_FOUND)) { Object formNameObj = f.getParentScope().get("_formname_", f.getParentScope()); //$NON-NLS-1$ if (formNameObj == null || formNameObj.equals(Scriptable.NOT_FOUND)) { this.contextName = ScriptVariable.SCOPES_DOT_PREFIX + ScriptVariable.GLOBAL_SCOPE; } else { this.contextName = formNameObj.toString(); } } else { this.contextName = ScriptVariable.SCOPES_DOT_PREFIX + scopeNameObj.toString(); } Object methodNameObj = f.get("_methodname_", f); //$NON-NLS-1$ this.methodName = (methodNameObj == null || methodNameObj.equals(Scriptable.NOT_FOUND)) ? null : methodNameObj.toString(); if (this.methodName == null) { throw new IllegalArgumentException("Method/Function is not a servoy method"); //$NON-NLS-1$ } } /** * Get the scope name of this FunctionDefinition when the context is defined for a global method. * Otherwise returns null. * @since 6.1 */ public String getScopeName() { return contextName.startsWith(ScriptVariable.SCOPES_DOT_PREFIX) ? contextName.substring(ScriptVariable.SCOPES_DOT_PREFIX.length()) : null; } /** * Get the context of this function definition. * <p>The context name is either the form name or scopes.scopeName. * @since 6.1 */ public String getContextName() { return contextName; } /** * Set the context of this function definition. * <p>The context name is either the form name or scopes.scopeName. * @since 6.1 */ public void setContextName(String contextName) { this.contextName = contextName; } /** * @deprecated see {@link #getContextName()}. */ @Deprecated public String getFormName() { return contextName.startsWith(ScriptVariable.SCOPES_DOT_PREFIX) ? null : contextName; } /** * @deprecated see {@link #setContextName(String)}. */ @Deprecated public void setFormName(String formName) { this.contextName = formName == null ? ScriptVariable.SCOPES_DOT_PREFIX + ScriptVariable.GLOBAL_SCOPE : formName; } /** * Get the method name of this function definition. */ public String getMethodName() { return methodName; } /** * Set the method name of this function definition. */ public void setMethodName(String methodName) { this.methodName = methodName; } /** * Get the method name plus scope. */ public String toMethodString() { return contextName + '.' + methodName; } public enum Exist { NO_SOLUTION, METHOD_NOT_FOUND, METHOD_FOUND, FORM_NOT_FOUND; } /** * Test if the given methodName or formName do exist. Will return one of the {@link Exist} enums. * @since 5.2 */ public Exist exists(IClientPluginAccess access) { final Exist[] retVal = new Exist[] { Exist.METHOD_NOT_FOUND }; if (access instanceof ClientPluginAccessProvider) { final IApplication application = ((ClientPluginAccessProvider)access).getApplication(); application.invokeAndWait(new Runnable() { public void run() { if (application.getSolution() != null) { if (contextName.startsWith(ScriptVariable.SCOPES_DOT_PREFIX)) { GlobalScope gs = application.getScriptEngine().getScopesScope().getGlobalScope( contextName.substring(ScriptVariable.SCOPES_DOT_PREFIX.length())); if (gs != null && gs.get(methodName) instanceof Function) { retVal[0] = Exist.METHOD_FOUND; } } else { IFormController fp = application.getFormManager().leaseFormPanel(contextName); if (fp == null) { retVal[0] = Exist.FORM_NOT_FOUND; } else if (fp.getFormScope().get(methodName, fp.getFormScope()) instanceof Function) { retVal[0] = Exist.METHOD_FOUND; } } } else { retVal[0] = Exist.NO_SOLUTION; } } }); } return retVal[0]; } /** * @deprecated see {@link #executeAsync(IClientPluginAccess, Object[])}and {@link #executeSync(IClientPluginAccess, Object[]) */ @Deprecated public Object execute(IClientPluginAccess access, Object[] arguments, boolean async) { return exec(access, arguments, async); } /** * Helper method that calls the {@link IClientPluginAccess#executeMethod(String, String, Object[], boolean)} for you with the right formname/context and * method name. And exception that {@link IClientPluginAccess#executeMethod(String, String, Object[], boolean)} will throw will be catched and {@link IClientPluginAccess#handleException(String, Exception)} * will be called with the Exception object. If you want the exception object call {@link IClientPluginAccess#executeMethod(String, String, Object[], boolean)} directly. * <b>The method is called asynchronously in the user-interface thread. * * @param access The IClientPluginAccess object to call * @param arguments The arguments to give to the method calls */ public void executeAsync(IClientPluginAccess access, Object[] arguments) { exec(access, arguments, true); } /** * Helper method that calls the {@link IClientPluginAccess#executeMethod(String, String, Object[], boolean)} for you with the right formname/context and * method name. * * @param access The IClientPluginAccess object to call * @param arguments The arguments to give to the method calls * * @return The object that the method returns. */ public Object executeSync(IClientPluginAccess access, Object[] arguments) { return exec(access, arguments, false); } @SuppressWarnings("nls") private Object exec(IClientPluginAccess access, Object[] arguments, boolean async) { try { return access.executeMethod(contextName, methodName, arguments, async); } catch (Exception e) { access.handleException( "Failed to execute the method of context " + contextName + " and name " + methodName + " on the solution " + access.getSolutionName(), e); } return null; } @Override public String toString() { return "Function(" + toMethodString() + ')'; //$NON-NLS-1$ } }