All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prompto.debug.ProcessDebugger Maven / Gradle / Ivy

The newest version!
package prompto.debug;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import prompto.debug.stack.IStack;
import prompto.debug.stack.IStackFrame;
import prompto.debug.stack.LeanStack;
import prompto.debug.variable.IVariable;
import prompto.debug.worker.IWorker;
import prompto.debug.worker.LeanWorker;
import prompto.parser.ICodeSection;
import prompto.parser.ISection;
import prompto.runtime.Context;
import prompto.utils.Logger;

public class ProcessDebugger implements IDebugger {

	private static Logger logger = new Logger();

	static ProcessDebugger instance = null;
	
	public static ProcessDebugger getInstance() {
		return instance;
	}
	
	public static ProcessDebugger createInstance(Context context) {
		if(instance!=null)
			throw new IllegalStateException("An instance already exists!");
		instance = new ProcessDebugger(context);
		return instance;
	}
	
	public static void reset() {
		instance = null;
	}

	
	Map debuggers = new HashMap<>();
	ProcessStatus processStatus = ProcessStatus.PROCESS_STARTING;
	IDebugEventListener listener;
	Context context;
	
	private ProcessDebugger(Context context) {
		this.context = context;
	}
	
	public void setProcessStatus(ProcessStatus status) {
		this.processStatus = status;
	}
	
	@Override
	public ProcessStatus getProcessStatus() {
		return processStatus;
	}
	
	public void register(Thread thread, WorkerDebugger debugger) {
		DebuggedWorker debugged = DebuggedWorker.wrap(thread);
		debuggers.put(debugged, debugger);
	}
	
	public void unregister(Thread thread) {
		DebuggedWorker debugged = DebuggedWorker.wrap(thread);
		debuggers.remove(debugged);
	}

	@Override
	public void setListener(IDebugEventListener listener) {
		this.listener = listener;
	}

	@Override
	public void installBreakpoint(ISection section) {
		if(context==null)
			throw new RuntimeException("No context to search from!");
		ICodeSection instance = context.locateCodeSection(section);
		if(instance!=null) {
			logger.debug(()->"Found section " + instance.toString());
			instance.getSection().setAsBreakpoint(section.isBreakpoint());
		} else
			logger.debug(()->"Could not find section " + section.toString());
		
	}

	@Override
	public boolean isTerminated() {
		return processStatus==ProcessStatus.PROCESS_TERMINATED;
	}

	@Override
	public boolean canTerminate() {
		return !isTerminated();
	}

	@Override
	public void terminate() {
		notifyTerminated();
	}

	@Override
	public void notifyTerminated() {
		if(!isTerminated()) {
			setProcessStatus(ProcessStatus.PROCESS_TERMINATED);
			if(listener!=null)
				listener.onProcessTerminatedEvent();
		}
	}

	@Override
	public Collection getWorkers() {
		return debuggers.keySet();
	}

	@Override
	public WorkerStatus getWorkerStatus(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return WorkerStatus.WORKER_UNREACHABLE;
		} else
			return debugger.getWorkerStatus();
	}

	@Override
	public IStack getWorkerStack(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return new LeanStack();
		} else
			return debugger.getStack();
	}

	@Override
	public int getLineInFile(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return -1;
		} else
			return debugger.getLineInFile();	
	}
	
	@Override
	public int getLineInMethod(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return -1;
		} else
			return debugger.getLineInMethod();	
	}

	@Override
	public boolean isStepping(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.isStepping();	
	}

	@Override
	public boolean isSuspended(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.isSuspended();	
	}

	@Override
	public boolean canResume(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.canResume();	
	}

	@Override
	public boolean canSuspend(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.canSuspend();	
	}

	@Override
	public boolean canStepInto(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.canStepInto();	
	}

	@Override
	public boolean canStepOver(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.canStepOver();	
	}

	@Override
	public boolean canStepOut(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return false;
		} else
			return debugger.canStepOut();	
	}

	@Override
	public void suspend(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null)
			logger.warn(()->"Invalid worker: " + worker);
		else
			debugger.suspend(); 
	}

	@Override
	public void resume(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null)
			logger.warn(()->"Invalid worker: " + worker);
		else
			debugger.resume(); 
	}
	
	
	@Override
	public void terminate(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null)
			logger.warn(()->"Invalid worker: " + worker);
		else
			debugger.terminate(); 
	}

	@Override
	public void stepInto(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null)
			logger.warn(()->"Invalid worker: " + worker);
		else
			debugger.stepInto(); 
	}

	@Override
	public void stepOut(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null)
			logger.warn(()->"Invalid worker: " + worker);
		else
			debugger.stepOut(); 
	}

	@Override
	public void stepOver(IWorker worker) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null)
			logger.warn(()->"Invalid worker: " + worker);
		else
			debugger.stepOver(); 
	}

	@Override
	public Collection getVariables(IWorker worker, IStackFrame frame) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return Collections.emptyList();
		} else
			return debugger.getVariables(frame);
	}
	
	
	@Override
	public IVariable getVariable(IWorker worker, IStackFrame frame, String variableName) {
		IWorkerDebugger debugger = debuggers.get(worker);
		if(debugger==null) {
			logger.warn(()->"Invalid worker: " + worker);
			return null;
		} else
			return debugger.getVariable(frame, variableName);
	}
	
	public static class DebuggedWorker extends LeanWorker {

		public static DebuggedWorker wrap(Thread thread) {
			return new DebuggedWorker(thread);
		}

		public static IWorker parse(String workerId) {
			try {
				long id = Long.parseLong(workerId);
				return new DebuggedWorker(id);
			} catch(NumberFormatException e) {
				// gracefully handle special case for testing
				if("only".equals(workerId)) {
					Set workers = ProcessDebugger.getInstance().debuggers.keySet();
					if(workers.size()==1)
						return workers.iterator().next();
				}
				return null;
			}
		}

		long threadId;
		
		public DebuggedWorker(long threadId) {
			this.threadId = threadId;
			this.workerId = String.valueOf(threadId);
		}
		
		public DebuggedWorker(Thread thread) {
			this.threadId = thread.getId();
			this.workerId = String.valueOf(threadId);
			this.name = thread.getName();
			this.workerStatus = WorkerStatus.valueOf(thread.getState());
		}
		
		@Override
		public boolean equals(Object obj) {
			return obj instanceof DebuggedWorker && equals((DebuggedWorker)obj);
		}

		public boolean equals(DebuggedWorker obj) {
			return this.threadId == obj.threadId;
		}
		
		@Override
		public int hashCode() {
			return Long.hashCode(this.threadId);
		}
		
	}



}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy