<commit_before>/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2009 The eXist Project
 *  http://exist-db.org
 *  
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  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 Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *  
 *  $Id:$
 */
package org.exist.debuggee;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.exist.debuggee.dbgp.packets.AbstractCommandContinuation;
import org.exist.debuggee.dbgp.packets.Command;
import org.exist.debuggee.dbgp.packets.Init;
import org.exist.debugger.model.Breakpoint;
import org.exist.dom.QName;
import org.exist.xquery.CompiledXQuery;
import org.exist.xquery.Expression;
import org.exist.xquery.TerminatedException;
import org.exist.xquery.Variable;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;

/**
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 *
 */
public class DebuggeeJointImpl implements DebuggeeJoint, Status {
	
    private final static Logger LOG = Logger.getLogger(DebuggeeJoint.class);

    private Map<String, String> features = new HashMap<String, String>(DebuggeeImpl.SET_GET_FEATURES);
	
	private Expression firstExpression = null;
	
	private List<Expression> stack = new ArrayList<Expression>();
	private int stackDepth = 0;
	
	private CommandContinuation command = null;
	
	private int breakpointNo = 0;
	//<fileName, Map<line, breakpoint>>
	private Map<String, Map<Integer, Breakpoint>> filesBreakpoints = 
		new HashMap<String, Map<Integer, Breakpoint>>();
	
	//id, breakpoint
	private Map<Integer, Breakpoint> breakpoints = new HashMap<Integer, Breakpoint>();

	private CompiledXQuery compiledXQuery;
	
	public DebuggeeJointImpl() {
	}
	
	protected void setCompiledScript(CompiledXQuery compiledXQuery) {
		this.compiledXQuery = compiledXQuery;
		stack.add(null);
	}

	public void stackEnter(Expression expr) {
		if (LOG.isDebugEnabled())
			LOG.debug("stackEnter " + expr.getLine() + " expr = "+ expr.toString());
		
		stack.add(expr);
		stackDepth++;
		
	}
	
	public void stackLeave(Expression expr) {
		if (LOG.isDebugEnabled())
			LOG.debug("stackLeave " + expr.getLine() + " expr = "+ expr.toString());
		
		stack.remove(stack.size()-1);
		stackDepth--;
		
		if (command.is(CommandContinuation.STEP_OUT) 
				&& command.getCallStackDepth() > stackDepth
				&& command.isStatus(RUNNING)) {
			command.setStatus(BREAK);
		}
	}

	/* (non-Javadoc)
	 * @see org.exist.debuggee.DebuggeeJoint#expressionStart(org.exist.xquery.Expression)
	 */
	public void expressionStart(Expression expr) throws TerminatedException {
		if (LOG.isDebugEnabled())
			LOG.debug("expressionStart " + expr.getLine() + " expr = "+ expr.toString());
		
		if (compiledXQuery == null)
			return;
		
		if (firstExpression == null)
			firstExpression = expr;
		
		stack.set(stackDepth, expr);
		
		String fileName = Command.getFileuri(expr.getSource());
		Integer lineNo = expr.getLine();

		Map<Integer, Breakpoint> fileBreakpoints = null;

		while (true) {
			//didn't receive any command, wait for any 
			if (command == null ||
					//the status is break, wait for changes
					command.isStatus(BREAK)) {
				waitCommand();
				continue;
			}

			//wait for connection
			if (command.is(CommandContinuation.INIT) && command.isStatus(STARTING)) {
				Init init = (Init)command;
				init.getSession().setAttribute("joint", this);
				init.setFileURI(compiledXQuery.getSource());
				
				//break on first line
				command.setStatus(BREAK);
			}
			
			//disconnected
			if (compiledXQuery == null)
				return;
			
			//stop command, terminate
			if (command.is(CommandContinuation.STOP) && !command.isStatus(STOPPED)) {
				command.setStatus(STOPPED);
	            throw new TerminatedException(expr.getLine(), expr.getColumn(), "Debuggee STOP command.");
			}

			//step-into is done
			if (command.is(CommandContinuation.STEP_INTO) && command.isStatus(RUNNING)) {
				command.setStatus(BREAK);

			//step-over should stop on same call's stack depth
			} else if (command.is(CommandContinuation.STEP_OVER)  
					&& command.getCallStackDepth() == stackDepth
					&& command.isStatus(RUNNING)) {
				command.setStatus(BREAK);

			}
			
			//checking breakpoints
			synchronized (breakpoints) {
				if (filesBreakpoints.containsKey(fileName)) {
					fileBreakpoints = filesBreakpoints.get(fileName);
					
					if (fileBreakpoints.containsKey(lineNo)) {
						Breakpoint breakpoint = fileBreakpoints.get(lineNo);
						
						if (breakpoint.getState() && breakpoint.getType().equals(Breakpoint.TYPE_LINE)) {
							command.setStatus(BREAK);
						}
					}
				}
			}
			
			//RUS command with status RUNNING can be break only on breakpoints
			if (command.getType() >= CommandContinuation.RUN && command.isStatus(RUNNING)) {
				break;

			//any continuation command with status RUNNING
			} else if (command.getType() >= CommandContinuation.RUN && command.isStatus(STARTING)) {
				command.setStatus(RUNNING);
				break;
			}
			
			waitCommand();
		}
	}

	/* (non-Javadoc)
	 * @see org.exist.debuggee.DebuggeeJoint#expressionEnd(org.exist.xquery.Expression)
	 */
	public void expressionEnd(Expression expr) {
		if (LOG.isDebugEnabled())
			LOG.debug("expressionEnd expr = "+expr.toString());

		if (firstExpression == expr) {
			firstExpression = null;
			
			command.setStatus(STOPPED);
			
			sessionClosed(true);
		}
		
	}
	
	private synchronized void waitCommand() {
		notifyAll();
		try {
			wait();
		} catch (InterruptedException e) {
			//UNDERSTAND: what to do?
		}
	}

	/* (non-Javadoc)
	 * @see org.exist.debuggee.DebuggeeJoint#getContext()
	 */
	public XQueryContext getContext() {
		return compiledXQuery.getContext();
	}

	public void reset() {
		firstExpression = null;
		
		stack = new ArrayList<Expression>();
		stackDepth = 0;
		
		command = null;
		
		breakpointNo = 0;
		filesBreakpoints = new HashMap<String, Map<Integer, Breakpoint>>();
		
		breakpoints = new HashMap<Integer, Breakpoint>();
	}

	public synchronized void continuation(CommandContinuation command) {
		if (firstExpression == null && !command.is(CommandContinuation.INIT))
			command.setStatus(STOPPED);
		
		else
			command.setStatus(STARTING);

		((AbstractCommandContinuation)command).setCallStackDepth(stackDepth);
		
		this.command = command;

		notifyAll();
	}
	
	public boolean featureSet(String name, String value) {
		if (features.containsKey(name)) {
			features.put(name, value);
			
			return true;
		}
		
		return false;
	}

	public String featureGet(String name) {
		if (DebuggeeImpl.GET_FEATURES.containsKey(name))
			return DebuggeeImpl.GET_FEATURES.get(name);
		
		return features.get(name);
	}
	<commit_msg>[bugfix] debuggee can't process next command with out finish previous one<commit_after>/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2009 The eXist Project
 *  http://exist-db.org
 *  
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  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 Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *  
 *  $Id:$
 */
package org.exist.debuggee;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.apache.log4j.Logger;
import org.exist.debuggee.dbgp.packets.AbstractCommandContinuation;
import org.exist.debuggee.dbgp.packets.Command;
import org.exist.debuggee.dbgp.packets.Init;
import org.exist.debugger.model.Breakpoint;
import org.exist.dom.QName;
import org.exist.xquery.CompiledXQuery;
import org.exist.xquery.Expression;
import org.exist.xquery.TerminatedException;
import org.exist.xquery.Variable;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;

/**
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 *
 */
public class DebuggeeJointImpl implements DebuggeeJoint, Status {
	
    private final static Logger LOG = Logger.getLogger(DebuggeeJoint.class);

    private Map<String, String> features = new HashMap<String, String>(DebuggeeImpl.SET_GET_FEATURES);
	
	private Expression firstExpression = null;
	
	private List<Expression> stack = new ArrayList<Expression>();
	private int stackDepth = 0;
	
	private CommandContinuation command = null;
	private Stack<CommandContinuation> commands = new Stack<CommandContinuation>();
	
	private int breakpointNo = 0;
	//<fileName, Map<line, breakpoint>>
	private Map<String, Map<Integer, Breakpoint>> filesBreakpoints = 
		new HashMap<String, Map<Integer, Breakpoint>>();
	
	//id, breakpoint
	private Map<Integer, Breakpoint> breakpoints = new HashMap<Integer, Breakpoint>();

	private CompiledXQuery compiledXQuery;
	
	public DebuggeeJointImpl() {
	}
	
	protected void setCompiledScript(CompiledXQuery compiledXQuery) {
		this.compiledXQuery = compiledXQuery;
		stack.add(null);
	}

	public void stackEnter(Expression expr) {
		if (LOG.isDebugEnabled())
			LOG.debug("stackEnter " + expr.getLine() + " expr = "+ expr.toString());
		
		stack.add(expr);
		stackDepth++;
		
	}
	
	public void stackLeave(Expression expr) {
		if (LOG.isDebugEnabled())
			LOG.debug("stackLeave " + expr.getLine() + " expr = "+ expr.toString());
		
		stack.remove(stack.size()-1);
		stackDepth--;
		
		if (command.is(CommandContinuation.STEP_OUT) 
				&& command.getCallStackDepth() > stackDepth
				&& command.isStatus(RUNNING)) {
			command.setStatus(BREAK);
		}
	}

	/* (non-Javadoc)
	 * @see org.exist.debuggee.DebuggeeJoint#expressionStart(org.exist.xquery.Expression)
	 */
	public void expressionStart(Expression expr) throws TerminatedException {
		if (LOG.isDebugEnabled())
			LOG.debug("expressionStart " + expr.getLine() + " expr = "+ expr.toString());
		
		if (compiledXQuery == null)
			return;
		
		if (firstExpression == null)
			firstExpression = expr;
		
		stack.set(stackDepth, expr);
		
		String fileName = Command.getFileuri(expr.getSource());
		Integer lineNo = expr.getLine();

		Map<Integer, Breakpoint> fileBreakpoints = null;

		while (true) {
			//didn't receive any command, wait for any 
			if (command == null ||
					//the status is break, wait for changes
					command.isStatus(BREAK)) {
				waitCommand();
				continue;
			}

			//wait for connection
			if (command.is(CommandContinuation.INIT) && command.isStatus(STARTING)) {
				Init init = (Init)command;
				init.getSession().setAttribute("joint", this);
				init.setFileURI(compiledXQuery.getSource());
				
				//break on first line
				command.setStatus(BREAK);
			}
			
			//disconnected
			if (compiledXQuery == null)
				return;
			
			//stop command, terminate
			if (command.is(CommandContinuation.STOP) && !command.isStatus(STOPPED)) {
				command.setStatus(STOPPED);
	            throw new TerminatedException(expr.getLine(), expr.getColumn(), "Debuggee STOP command.");
			}

			//step-into is done
			if (command.is(CommandContinuation.STEP_INTO) && command.isStatus(RUNNING)) {
				command.setStatus(BREAK);

			//step-over should stop on same call's stack depth
			} else if (command.is(CommandContinuation.STEP_OVER)  
					&& command.getCallStackDepth() == stackDepth
					&& command.isStatus(RUNNING)) {
				command.setStatus(BREAK);

			}
			
			//checking breakpoints
			synchronized (breakpoints) {
				if (filesBreakpoints.containsKey(fileName)) {
					fileBreakpoints = filesBreakpoints.get(fileName);
					
					if (fileBreakpoints.containsKey(lineNo)) {
						Breakpoint breakpoint = fileBreakpoints.get(lineNo);
						
						if (breakpoint.getState() && breakpoint.getType().equals(Breakpoint.TYPE_LINE)) {
							command.setStatus(BREAK);
						}
					}
				}
			}
			
			//RUS command with status RUNNING can be break only on breakpoints
			if (command.getType() >= CommandContinuation.RUN && command.isStatus(RUNNING)) {
				break;

			//any continuation command with status RUNNING
			} else if (command.getType() >= CommandContinuation.RUN && command.isStatus(STARTING)) {
				command.setStatus(RUNNING);
				break;
			}
			
			waitCommand();
		}
	}

	/* (non-Javadoc)
	 * @see org.exist.debuggee.DebuggeeJoint#expressionEnd(org.exist.xquery.Expression)
	 */
	public void expressionEnd(Expression expr) {
		if (LOG.isDebugEnabled())
			LOG.debug("expressionEnd expr = "+expr.toString());

		if (firstExpression == expr) {
			firstExpression = null;
			
			command.setStatus(STOPPED);
			
			sessionClosed(true);
		}
		
	}
	
	private synchronized void waitCommand() {
		if (command.isStatus(BREAK) && commands.size() != 0) {
			command = commands.pop();
			
			((AbstractCommandContinuation)command).setCallStackDepth(stackDepth);
			
			return;
		}
			
			
		notifyAll();
		try {
			wait();
		} catch (InterruptedException e) {
			//UNDERSTAND: what to do?
		}
	}

	/* (non-Javadoc)
	 * @see org.exist.debuggee.DebuggeeJoint#getContext()
	 */
	public XQueryContext getContext() {
		return compiledXQuery.getContext();
	}

	public void reset() {
		firstExpression = null;
		
		stack = new ArrayList<Expression>();
		stackDepth = 0;
		
		command = null;
		
		breakpointNo = 0;
		filesBreakpoints = new HashMap<String, Map<Integer, Breakpoint>>();
		
		breakpoints = new HashMap<Integer, Breakpoint>();
	}

	public synchronized void continuation(CommandContinuation command) {
		if (firstExpression == null && !command.is(CommandContinuation.INIT))
			command.setStatus(STOPPED);
		
		else
			command.setStatus(STARTING);

		if (this.command == null || this.command.isStatus(STOPPED)) {
			((AbstractCommandContinuation)command).setCallStackDepth(stackDepth);
		
			this.command = command;
		} else {
			commands.add(command);
		}

		notifyAll();
	}
	
	public boolean featureSet(String name, String value) {
		if (features.containsKey(name)) {
			features.put(name, value);
			
			return true;
		}
		
		return false;
	}

	public String featureGet(String name) {
		if (DebuggeeImpl.GET_FEATURES.containsKey(name))
			return DebuggeeImpl.GET_FEATURES.get(name);
		
		return features.get(name);
	}
	
{'fraction_non_alphanumeric': 0.11867884564469156, 'fraction_numerical': 0.002581413820492454, 'mean_word_length': 3.8071905822462617, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4939774', 'n_tokens_mistral': 5393, 'n_tokens_neox': 4564, 'n_words': 1103}