package jetbrains.mps.debugger.java.runtime.engine; /*Generated by MPS */ import jetbrains.mps.debugger.java.runtime.engine.requests.IRequestManager; import jetbrains.mps.logging.Logger; import org.apache.log4j.LogManager; import java.util.Map; import jetbrains.mps.debugger.java.runtime.engine.requests.Requestor; import java.util.Set; import com.sun.jdi.request.EventRequest; import com.intellij.util.containers.HashMap; import com.sun.jdi.request.EventRequestManager; import jetbrains.mps.debugger.java.runtime.engine.events.EventsProcessor; import java.util.List; import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import org.jetbrains.annotations.Nullable; import jetbrains.mps.debugger.java.runtime.engine.concurrent.ManagerThread; import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.HashSet; import com.sun.jdi.request.InvalidRequestStateException; import com.sun.jdi.InternalException; import com.sun.jdi.request.BreakpointRequest; import jetbrains.mps.debugger.java.runtime.breakpoints.JavaBreakpoint; import com.sun.jdi.Location; import com.sun.jdi.request.MethodEntryRequest; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.MethodExitRequest; import com.sun.jdi.request.AccessWatchpointRequest; import com.sun.jdi.Field; import com.sun.jdi.request.ModificationWatchpointRequest; import com.sun.jdi.request.ExceptionRequest; import com.sun.jdi.request.StepRequest; import com.sun.jdi.ThreadReference; import jetbrains.mps.debugger.java.runtime.engine.requests.StepRequestor; import jetbrains.mps.debugger.java.runtime.engine.requests.ClassPrepareRequestor; import com.sun.jdi.request.ClassPrepareRequest; import jetbrains.mps.internal.collections.runtime.IVisitor; import com.sun.jdi.event.ClassPrepareEvent; import com.sun.jdi.ClassType; import com.sun.jdi.InterfaceType; import jetbrains.mps.debug.api.BreakpointManagerComponent; import jetbrains.mps.debug.api.breakpoints.IBreakpoint; public class RequestManager implements IRequestManager { private static final Logger LOG = Logger.wrap(LogManager.getLogger(RequestManager.class)); private static final Object REQUESTOR = new Object(); private static final Object CLASS_NAME = new Object(); private final Map<Requestor, Set<EventRequest>> myRequestorToBelongedRequests = new HashMap<Requestor, Set<EventRequest>>(); private EventRequestManager myEventRequestManager; private EventsProcessor myDebugEventsProcessor; private final RequestManager.MyDebugProcessListener myDebugProcessListener = new RequestManager.MyDebugProcessListener(); private final Map<Requestor, String> myInvalidRequestsAndWarnings = new HashMap<Requestor, String>(); private final List<_FunctionTypes._void_P0_E0> myWarningsListeners = ListSequence.fromList(new ArrayList<_FunctionTypes._void_P0_E0>()); public RequestManager(EventsProcessor processor) { myDebugEventsProcessor = processor; myDebugEventsProcessor.addDebugProcessListener(myDebugProcessListener); } public EventRequestManager getVMRequestManager() { return myEventRequestManager; } @Nullable public Requestor findRequestor(EventRequest request) { ManagerThread.assertIsMangerThread(); return (request != null ? (Requestor) request.getProperty(REQUESTOR) : null); } @NotNull public Set<EventRequest> findRequests(Requestor requestor) { ManagerThread.assertIsMangerThread(); if (!(myRequestorToBelongedRequests.containsKey(requestor))) { return Collections.emptySet(); } return new HashSet<EventRequest>(myRequestorToBelongedRequests.get(requestor)); } private void registerRequestInternal(final Requestor requestor, final EventRequest request) { registerRequest(requestor, request); request.putProperty(REQUESTOR, requestor); } private void registerRequest(Requestor requestor, EventRequest request) { Set<EventRequest> reqSet = myRequestorToBelongedRequests.get(requestor); if (reqSet == null) { reqSet = new HashSet<EventRequest>(); myRequestorToBelongedRequests.put(requestor, reqSet); } reqSet.add(request); } public void deleteRequests(Requestor requestor) { ManagerThread.assertIsMangerThread(); if (!(myDebugEventsProcessor.isAttached())) { return; } final Set<EventRequest> requests = myRequestorToBelongedRequests.remove(requestor); if (requests == null) { return; } for (final EventRequest request : requests) { try { final Requestor targetRequestor = (Requestor) request.getProperty(REQUESTOR); if (targetRequestor != requestor) { // the same request may be assigned to more than one requestor, but // there is only one 'targetRequestor' for each request, so if target requestor and requestor being processed are different, // should clear also the mapping targetRequestor->request final Set<EventRequest> allTargetRequestorRequests = myRequestorToBelongedRequests.get(targetRequestor); if (allTargetRequestorRequests != null) { allTargetRequestorRequests.remove(request); if (allTargetRequestorRequests.size() == 0) { myRequestorToBelongedRequests.remove(targetRequestor); } } } myEventRequestManager.deleteEventRequest(request); } catch (InvalidRequestStateException ignored) { // request is already deleted } catch (InternalException e) { LOG.error(e); } } } public BreakpointRequest createBreakpointRequest(JavaBreakpoint requestor, Location location) { // ------------------- requests creation ManagerThread.assertIsMangerThread(); BreakpointRequest request = myEventRequestManager.createBreakpointRequest(location); initRequest(requestor, request); return request; } public MethodEntryRequest createMethodEntryRequest(JavaBreakpoint requestor, ReferenceType type) { ManagerThread.assertIsMangerThread(); MethodEntryRequest request = myEventRequestManager.createMethodEntryRequest(); request.addClassFilter(type); initRequest(requestor, request); return request; } public MethodExitRequest createMethodExitRequest(JavaBreakpoint requestor, ReferenceType type) { ManagerThread.assertIsMangerThread(); MethodExitRequest request = myEventRequestManager.createMethodExitRequest(); request.addClassFilter(type); initRequest(requestor, request); return request; } public AccessWatchpointRequest createFieldAccessRequest(JavaBreakpoint requestor, Field field) { ManagerThread.assertIsMangerThread(); AccessWatchpointRequest request = myEventRequestManager.createAccessWatchpointRequest(field); initRequest(requestor, request); return request; } public ModificationWatchpointRequest createFieldModificationRequest(JavaBreakpoint requestor, Field field) { ManagerThread.assertIsMangerThread(); ModificationWatchpointRequest request = myEventRequestManager.createModificationWatchpointRequest(field); initRequest(requestor, request); return request; } public ExceptionRequest createExceptionRequest(JavaBreakpoint requestor, ReferenceType reference) { ManagerThread.assertIsMangerThread(); ExceptionRequest request = myEventRequestManager.createExceptionRequest(reference, true, true); initRequest(requestor, request); return request; } private void initRequest(JavaBreakpoint requestor, EventRequest req) { int suspendPolicy = requestor.getSuspendPolicy(); if (suspendPolicy == EventRequest.SUSPEND_NONE) { suspendPolicy = EventRequest.SUSPEND_ALL; } // we suspend all, do smth and then resume req.setSuspendPolicy(suspendPolicy); registerRequestInternal(requestor, req); } public void deleteStepRequests() { ManagerThread.assertIsMangerThread(); // todo what are these step requests to delete? List<StepRequest> stepRequests = myEventRequestManager.stepRequests(); if (stepRequests.size() > 0) { List<StepRequest> toDelete = new ArrayList<StepRequest>(stepRequests.size()); for (StepRequest request : stepRequests) { ThreadReference threadReference = request.thread(); // on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN) { toDelete.add(request); } } // removing from requestor maps for (StepRequest stepRequest : toDelete) { Requestor requestor = findRequestor(stepRequest); if (requestor != null) { Set<EventRequest> requestSet = myRequestorToBelongedRequests.get(requestor); requestSet.remove(stepRequest); if (requestSet.isEmpty()) { myRequestorToBelongedRequests.remove(requestor); } } } myEventRequestManager.deleteEventRequests(toDelete); } } public StepRequest createStepRequest(StepRequestor requestor, int stepType, ThreadReference stepThread, int suspendPolicy) { deleteStepRequests(); StepRequest stepRequest = myEventRequestManager.createStepRequest(stepThread, StepRequest.STEP_LINE, stepType); stepRequest.setSuspendPolicy(suspendPolicy); registerRequestInternal(requestor, stepRequest); return stepRequest; } public void callbackOnPrepareClasses(ClassPrepareRequestor requestor, String classOrPatternToBeLoaded) { // todo: some other types of requests; later // ------------------- ~requests creation // by classname ManagerThread.assertIsMangerThread(); ClassPrepareRequest classPrepareRequest = createClassPrepareRequest(requestor, classOrPatternToBeLoaded); classPrepareRequest.enable(); } private ClassPrepareRequest createClassPrepareRequest(ClassPrepareRequestor requestor, String className) { ClassPrepareRequest classPrepareRequest = myEventRequestManager.createClassPrepareRequest(); classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); classPrepareRequest.addClassFilter(className); classPrepareRequest.putProperty(CLASS_NAME, className); registerRequestInternal(requestor, classPrepareRequest); return classPrepareRequest; } public void enableRequest(EventRequest request) { // currently does no much more than request.enable() ManagerThread.assertIsMangerThread(); LOG.assertLog(findRequestor(request) != null, "Assertion failed."); request.enable(); } public void setInvalid(Requestor requestor, String message) { ManagerThread.assertIsMangerThread(); myInvalidRequestsAndWarnings.put(requestor, message); ListSequence.fromList(myWarningsListeners).visitAll(new IVisitor<_FunctionTypes._void_P0_E0>() { public void visit(_FunctionTypes._void_P0_E0 it) { it.invoke(); } }); } @Nullable public String getWarning(Requestor requestor) { ManagerThread.assertIsMangerThread(); return myInvalidRequestsAndWarnings.get(requestor); } public void addWarningsListener(_FunctionTypes._void_P0_E0 listener) { ListSequence.fromList(myWarningsListeners).addElement(listener); } public void removeWarningsListener(_FunctionTypes._void_P0_E0 listener) { ListSequence.fromList(myWarningsListeners).removeElement(listener); } public void processClassPrepared(final ClassPrepareEvent event) { if (!(myDebugEventsProcessor.isAttached())) { return; } final ReferenceType refType = event.referenceType(); if (refType instanceof ClassType || refType instanceof InterfaceType) { ClassPrepareRequestor requestor = (ClassPrepareRequestor) event.request().getProperty(REQUESTOR); if (requestor != null) { requestor.processClassPrepare(myDebugEventsProcessor, refType); } } } public static void createClassPrepareRequests(final JavaBreakpoint breakpoint) { VMEventsProcessorManagerComponent.getInstance(breakpoint.getProject()).performAllDebugProcessesAction(new _FunctionTypes._void_P1_E0<EventsProcessor>() { public void invoke(EventsProcessor processor) { if (processor.isAttached()) { breakpoint.createClassPrepareRequest(processor); } } }); } public static void removeClassPrepareRequests(final JavaBreakpoint breakpoint) { VMEventsProcessorManagerComponent.getInstance(breakpoint.getProject()).performAllDebugProcessesAction(new _FunctionTypes._void_P1_E0<EventsProcessor>() { public void invoke(EventsProcessor processor) { if (processor.isAttached()) { processor.getRequestManager().deleteRequests(breakpoint); } } }); } public class MyDebugProcessListener extends DebugProcessAdapter { public MyDebugProcessListener() { } @Override public void processDetached(@NotNull EventsProcessor process, boolean closedByUser) { myEventRequestManager = null; myRequestorToBelongedRequests.clear(); } @Override public void processAttached(@NotNull EventsProcessor process) { myEventRequestManager = myDebugEventsProcessor.getVirtualMachine().eventRequestManager(); // invoke later, so that requests are for sure created only _after_ 'processAttached()' methods of other listeneres are executed process.schedule(new _FunctionTypes._void_P0_E0() { public void invoke() { BreakpointManagerComponent breakpointManager = myDebugEventsProcessor.getBreakpointManager(); for (IBreakpoint breakpoint : breakpointManager.getAllIBreakpoints()) { if (breakpoint instanceof JavaBreakpoint) { ((JavaBreakpoint) breakpoint).createClassPrepareRequest(myDebugEventsProcessor); } } } }); } } }