/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2011 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.headlessclient.eventthread; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.wicket.Application; import org.apache.wicket.IClusterable; import org.apache.wicket.Page; import org.apache.wicket.RequestCycle; import org.apache.wicket.Session; import org.mozilla.javascript.Function; import com.servoy.j2db.IServiceProvider; import com.servoy.j2db.J2DBGlobals; import com.servoy.j2db.server.headlessclient.ServoyRequestCycle; import com.servoy.j2db.server.headlessclient.WebClient; import com.servoy.j2db.server.headlessclient.WebClientSession; import com.servoy.j2db.util.Debug; /** * An implementation of {@link Event} that executes {@link Function} when {@link #execute()} is called. * Will set and reset all the wicket thread locals from the creation thread (the http thread) to the execution thread. * * @author jcompagner * * @since 6.1 */ public final class WicketEvent extends Event { private final RequestCycle requestCycle; private final Session session; private final Application application; private volatile boolean wasSuspended; private final List<IClusterable> dirtyObjectsList; private final List<Page> touchedPages; private volatile Thread httpThread; private final IServiceProvider serviceProvider; private volatile List<Runnable> events; private final WebClient client; private final List<Page> pagesToRelease; /** * @param f * @param scope * @param thisObject * @param args * @param focusEvent * @param throwException * @param scriptEngine TODO */ public WicketEvent(WebClient client, Runnable runnable) { super(runnable); this.client = client; requestCycle = RequestCycle.get(); session = Session.get(); serviceProvider = J2DBGlobals.getServiceProvider(); application = Application.get(); dirtyObjectsList = session.getDirtyObjectsList(); touchedPages = session.getTouchedPages(); httpThread = Thread.currentThread(); pagesToRelease = ((WebClientSession)session).getPagesToRelease(); if (pagesToRelease.size() > 0) { Debug.error("there are already locked pages for the wicket event, expect to be 0 " + pagesToRelease); } } /** * @param last */ public void updateHttpThread(Event last) { if (last instanceof WicketEvent) { httpThread = ((WicketEvent)last).httpThread; } } /* * (non-Javadoc) * * @see com.servoy.j2db.server.headlessclient.IExecuteEvent#execute() */ @Override public final void execute() { try { ServoyRequestCycle.set(requestCycle); Session.set(session); Application.set(application); J2DBGlobals.setServiceProvider(serviceProvider); // if somehow there where already locked pages copy them over to the current execute thread. // so that this thread has them as there own lock. if (pagesToRelease.size() > 0) { List<Page> toReleasePages = ((WebClientSession)session).getPagesToRelease(); toReleasePages.addAll(pagesToRelease); } session.moveUsedPage(httpThread, Thread.currentThread()); super.execute(); } finally { // store the current request events of the client that are // created in this thread on this event object. (see addEvent) // but only if it was never suspended. if it was suspended then on this event no http thread is waiting any more on. if (!wasSuspended) { setEvents(client.getRequestEvents()); } cleanup(); } } /** * */ private void cleanup() { List<IClusterable> lst = session.getDirtyObjectsList(); for (IClusterable dirtyObject : lst) { if (!dirtyObjectsList.contains(dirtyObject)) { dirtyObjectsList.add(dirtyObject); } } lst.clear(); List<Page> pages = session.getTouchedPages(); for (Page page : pages) { if (!touchedPages.contains(page)) { touchedPages.add(page); } } pages.clear(); // copy over the current owned pages to the http threads list so that it owns and will release it. List<Page> toReleasePages = ((WebClientSession)session).getPagesToRelease(); for (Page page : toReleasePages) { if (!pagesToRelease.contains(page)) { pagesToRelease.add(page); } } toReleasePages.clear(); session.moveUsedPage(Thread.currentThread(), httpThread); } /** * */ @Override public void willSuspend() { // store the current request events of the client that are // created in this thread on this event object. (see addEvent) // but only if it was never suspended. if it was suspended then on this event no http thread is waiting any more on. if (!wasSuspended) { setEvents(client.getRequestEvents()); } cleanup(); super.willSuspend(); wasSuspended = true; } /* * (non-Javadoc) * * @see com.servoy.j2db.server.headlessclient.eventthread.Event#willResume() */ @Override public void willResume() { super.willResume(); // when resuming move all used pages back to this thread. // the httpThread should be updated session.moveUsedPage(httpThread, Thread.currentThread()); } /* * (non-Javadoc) * * @see com.servoy.j2db.server.headlessclient.eventthread.Event#executeInBackground() */ @Override public void executeInBackground() { cleanup(); super.executeInBackground(); } /** * @return */ public List<Runnable> getEvents() { List<Runnable> retval = events; events = null; return retval == null ? Collections.<Runnable> emptyList() : retval; } public void setEvents(List<Runnable> requestEvents) { if (events != null) { Debug.error(new IllegalStateException("events set twice!")); events = new ArrayList<Runnable>(events); events.addAll(requestEvents); } else { events = requestEvents; } } }