/* 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.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.eclipse.dltk.rhino.dbgp.LazyInitScope; import org.mozilla.javascript.Context; import org.mozilla.javascript.NativeJavaArray; import org.mozilla.javascript.Scriptable; import com.servoy.j2db.IApplication; import com.servoy.j2db.IBasicFormManager; import com.servoy.j2db.IFormController; import com.servoy.j2db.util.Debug; /** * This class handles dynamic creation/compilation of a 'form' and methods when asked for<br> * Normally this is a prototype of the top level scope (== solution scope) * * @author jblok */ public class CreationalPrototype extends DefaultScope implements LazyInitScope { private volatile IApplication application; public CreationalPrototype(Scriptable parent, IApplication application) { super(parent); this.application = application; setLocked(true); } @Override public void destroy() { super.destroy(); application = null; } /** * @see org.mozilla.javascript.ScriptableObject#getDefaultValue(java.lang.Class) */ @Override public Object getDefaultValue(Class typeHint) { StringBuffer sb = new StringBuffer(); sb.append("CreationalPrototype["); //$NON-NLS-1$ Object[] objects = getIds(); for (Object element : objects) { sb.append(element); sb.append(","); //$NON-NLS-1$ } if (objects.length > 0) sb.setCharAt(sb.length() - 1, ']'); else sb.append("]"); //$NON-NLS-1$ return sb.toString(); } /** * @see com.servoy.j2db.scripting.DefaultScope#getIds() */ @Override public Object[] getIds() { ArrayList<String> al = new ArrayList<String>(); al.add("allnames"); //$NON-NLS-1$ al.add("length"); //$NON-NLS-1$ IBasicFormManager fm = application.getFormManager(); Iterator<String> it = fm.getPossibleFormNames(); while (it.hasNext()) { al.add(it.next()); } return al.toArray(); } /** * @see org.eclipse.dltk.rhino.dbgp.LazyInitScope#getInitializedIds() */ public Object[] getInitializedIds() { ArrayList<String> al = new ArrayList<String>(); al.add("allnames"); //$NON-NLS-1$ al.add("length"); //$NON-NLS-1$ IBasicFormManager fm = application.getFormManager(); if (fm == null) return new Object[0]; Iterator<String> it = fm.getPossibleFormNames(); while (it.hasNext()) { String form = it.next(); Object o = super.get(form, this); if (o != null && o != Scriptable.NOT_FOUND) { if (o instanceof FormScope) { IFormController fp = ((FormScope)o).getFormController(); if (!fp.isShowingData()) continue; } al.add(form); } } return al.toArray(); } @Override public Object get(java.lang.String name, Scriptable start) { if ("allnames".equals(name)) //$NON-NLS-1$ { ArrayList<String> al = new ArrayList<String>(); IBasicFormManager fm = application.getFormManager(); if (fm == null) throw new IllegalStateException( "Trying to access forms after client was shut down? This JS code was probably running decoupled from client shut down but at the same time."); // should never happen during normal operation; see case 251716 Iterator<String> it = fm.getPossibleFormNames(); while (it.hasNext()) { al.add(it.next()); } Context.enter(); try { return new NativeJavaArray(this, al.toArray()); } finally { Context.exit(); } } Object o = super.get(name, start); if ((o == null || o == Scriptable.NOT_FOUND)) { IBasicFormManager fm = application.getFormManager(); if (fm == null) throw new IllegalStateException( "Trying to access forms after client was shut down? This JS code was probably running decoupled from client shut down but at the same time."); // should never happen during normal operation; see case 251716 if (!fm.isPossibleForm(name)) { return o; } Context.enter(); try { Debug.trace("CreationalPrototype:get " + name + " scope " + start); //$NON-NLS-1$ //$NON-NLS-2$ if (!application.isEventDispatchThread()) { Debug.log("Form " + name + " is not created because it is CreationalPrototype.get(formname) is called outside of the event thread"); //$NON-NLS-1$ //$NON-NLS-2$ return "<Form " + name + " not loaded yet>"; //$NON-NLS-1$ //$NON-NLS-2$ } IFormController fp = fm.leaseFormPanel(name); if (fp != null) { fp.initForJSUsage(this);//This registers the object in this scopes, this must called before anything else! (to prevent repeative calls/lookups here) o = super.get(name, this);//re-get } if (o == null) o = Scriptable.NOT_FOUND; } finally { Context.exit(); } } if (o instanceof FormScope) { IFormController fp = ((FormScope)o).getFormController(); fp.setView(fp.getView()); fp.executeOnLoadMethod(); try { if (!fp.isShowingData()) { if (fp.wantEmptyFoundSet()) { if (fp.getFormModel() != null) fp.getFormModel().clear(); } else { fp.loadAllRecordsImpl(true); } } } catch (Exception ex) { Debug.error(ex); application.handleException(application.getI18NMessage("servoy.formPanel.error.formData"), ex); //$NON-NLS-1$ } } return o; } public void removeFormPanel(IFormController fp) { String name = fp.getName(); Object o = allVars.remove(name); if (o != null) { Iterator<Entry<Integer, Object>> it = allIndex.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Object> entry = it.next(); if (entry.getValue() == o) { Integer key = entry.getKey(); allIndex.remove(key); Integer nextKey = new Integer(key.intValue() + 1); o = allIndex.remove(nextKey); while (o != null) { allIndex.put(key, o); key = nextKey; nextKey = new Integer(key.intValue() + 1); o = allIndex.remove(nextKey); } break; } } } } }