/*
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.debug;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import org.eclipse.dltk.rhino.dbgp.DBGPDebugFrame;
import org.eclipse.dltk.rhino.dbgp.DBGPDebugger;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.debug.DebugFrame;
import org.mozilla.javascript.debug.DebuggableScript;
import org.sablo.websocket.CurrentWindow;
import com.servoy.j2db.IServiceProvider;
import com.servoy.j2db.J2DBGlobals;
import com.servoy.j2db.server.ngclient.NGClient;
import com.servoy.j2db.server.ngclient.eventthread.NGClientWebsocketSessionWindows;
/**
* @author jcompagner
*/
public class ServoyDebugger extends DBGPDebugger
{
private static class ProfileInfo
{
private ServoyDebugFrame first;
private final Stack<ServoyDebugFrame> current = new Stack<ServoyDebugFrame>();
private final HashMap<ServoyDebugFrame, ArrayList<ServoyDebugFrame>> map = new HashMap<ServoyDebugFrame, ArrayList<ServoyDebugFrame>>();
/**
* @param servoyDebugFrame
*/
public void push(ServoyDebugFrame servoyDebugFrame)
{
if (!current.isEmpty())
{
ServoyDebugFrame top = current.peek();
ArrayList<ServoyDebugFrame> calllist = map.get(top);
if (calllist == null)
{
calllist = new ArrayList<ServoyDebugFrame>();
map.put(top, calllist);
}
calllist.add(servoyDebugFrame);
}
else
{
first = servoyDebugFrame;
map.clear();
}
this.current.push(servoyDebugFrame);
}
public ServoyDebugFrame peek()
{
if (current.empty()) return null;
return current.peek();
}
public boolean pop(ServoyDebugFrame frame)
{
if (current.pop() != frame)
{
System.err.println("shouldnt happen!!");
}
return current.isEmpty();
}
public ProfileData getProfileData()
{
return getProfileData(first);
}
private ProfileData getProfileData(ServoyDebugFrame frame)
{
ProfileData profileData = frame.getProfileData();
ArrayList<ServoyDebugFrame> arrayList = map.get(frame);
if (arrayList != null)
{
for (ServoyDebugFrame servoyDebugFrame : arrayList)
{
profileData.addChild(getProfileData(servoyDebugFrame));
}
}
return profileData;
}
}
private final ThreadLocal<ProfileInfo> profileInfo = new ThreadLocal<ProfileInfo>();
private final List<IProfileListener> profilelisteners;
/**
* @param socket
* @param file
* @param string
* @param ct
* @param profilelisteners
* @throws IOException
*/
public ServoyDebugger(Socket socket, String file, String string, Context ct, List<IProfileListener> profilelisteners) throws IOException
{
super(socket, file, string, ct);
this.profilelisteners = profilelisteners;
}
/**
* @see org.eclipse.dltk.rhino.dbgp.DBGPDebugger#getFrame(org.mozilla.javascript.Context, org.mozilla.javascript.debug.DebuggableScript)
*/
@Override
public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript)
{
final IServiceProvider client = J2DBGlobals.getServiceProvider();
if (profilelisteners.size() > 0)
{
ProfileInfo info = profileInfo.get();
return new ServoyDebugFrame(cx, fnOrScript, this, info != null ? info.peek() : null);
}
return new DBGPDebugFrame(cx, fnOrScript, this)
{
@Override
public Object eval(String value)
{
if (client != null && J2DBGlobals.getServiceProvider() == null)
{
J2DBGlobals.setServiceProvider(client);
}
boolean reset = false;
try
{
if (client instanceof NGClient && !CurrentWindow.exists())
{
// make sure that for an NGClient the current window is set.
CurrentWindow.set(new NGClientWebsocketSessionWindows(((NGClient)client).getWebsocketSession()));
reset = true;
}
return super.eval(value);
}
finally
{
if (reset) CurrentWindow.set(null);
}
}
};
}
public void onenter(ServoyDebugFrame servoyDebugFrame)
{
ProfileInfo info = profileInfo.get();
if (info == null)
{
info = new ProfileInfo();
profileInfo.set(info);
}
info.push(servoyDebugFrame);
}
/**
* @param servoyDebugFrame
*/
public void onexit(ServoyDebugFrame servoyDebugFrame)
{
if (profileInfo.get().pop(servoyDebugFrame))
{
// last call
for (IProfileListener listener : profilelisteners)
{
listener.addProfileData(profileInfo.get().getProfileData());
}
profileInfo.remove();
}
}
}