package com.mobilesorcery.sdk.html5.debug.jsdt; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptLineBreakpoint; import org.eclipse.wst.jsdt.debug.core.jsdi.Location; import org.eclipse.wst.jsdt.debug.core.jsdi.event.EventQueue; import org.eclipse.wst.jsdt.debug.core.jsdi.event.EventSet; import org.eclipse.wst.jsdt.debug.core.jsdi.request.EventRequest; import org.json.simple.JSONObject; import com.mobilesorcery.sdk.core.CoreMoSyncPlugin; import com.mobilesorcery.sdk.core.Pair; import com.mobilesorcery.sdk.core.Util; import com.mobilesorcery.sdk.html5.Html5Plugin; import com.mobilesorcery.sdk.html5.debug.JSODDSupport; import com.mobilesorcery.sdk.html5.debug.ReloadVirtualMachine; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadBreakpointEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadDebuggerStatementEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadExceptionEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadScriptEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadStepEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadSuspendEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadThreadEnterEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.events.ReloadThreadExitEvent; import com.mobilesorcery.sdk.html5.debug.jsdt.requests.ReloadBreakpointRequest; import com.mobilesorcery.sdk.html5.debug.jsdt.requests.ReloadDebuggerStatementRequest; import com.mobilesorcery.sdk.html5.debug.jsdt.requests.ReloadExceptionRequest; import com.mobilesorcery.sdk.html5.debug.jsdt.requests.ReloadScriptLoadRequest; import com.mobilesorcery.sdk.html5.debug.jsdt.requests.ReloadStepRequest; import com.mobilesorcery.sdk.html5.debug.jsdt.requests.ReloadSuspendRequest; import com.mobilesorcery.sdk.html5.live.JSODDServer; public class ReloadEventQueue implements EventQueue { public static final String CUSTOM_EVENT = "custom-event"; public static final String THREAD_ENTER = "thread-enter"; public static final String THREAD_EXIT = "thread-exit"; private final ReloadVirtualMachine vm; private final ReloadEventRequestManager requests; private final LinkedBlockingQueue<Pair<String, Object>> internalQueue = new LinkedBlockingQueue<Pair<String, Object>>(); public ReloadEventQueue(ReloadVirtualMachine vm, ReloadEventRequestManager requests) { this.vm = vm; this.requests = requests; } @Override public EventSet remove() { return remove(-1); } @Override public EventSet remove(int timeout) { try { // TODO: EVENTS SHOULD BE PURE JSON!? Pair<String, Object> event = timeout > 0 ? internalQueue.poll( timeout, TimeUnit.MILLISECONDS) : internalQueue.take(); if (event.first == null) { internalQueue.clear(); } else { return handleEvent(event.first, event.second); } } catch (Exception e) { CoreMoSyncPlugin.getDefault().log(e); } return null; } private EventSet handleEvent(String commandName, Object commandObj) { if (CoreMoSyncPlugin.getDefault().isDebugging()) { CoreMoSyncPlugin.trace("Event {0}", commandName); } ReloadEventSet eventSet = new ReloadEventSet(vm); ReloadVirtualMachine targetVM = extractVM(commandObj); if (targetVM == this.vm) { List bpRequests = requests.breakpointRequests(); List stepRequests = requests.stepRequests(); List suspendRequests = requests.suspendRequests(); List exceptionRequests = requests.exceptionRequests(); List scriptLoadRequests = requests.scriptLoadRequests(); List threadExitRequests = requests.threadExitRequests(); List threadEnterRequests = requests.threadEnterRequests(); List debuggerStatementRequests = requests.debuggerStatementRequests(); if ("report-breakpoint".equals(commandName)) { ReloadThreadReference thread = extractThread(commandObj); // Breakpoint! JSONObject command = (JSONObject) commandObj; String fileName = (String) command.get("file"); Long line = (Long) command.get("line"); boolean isSuspendedByDebugger = command.containsKey("suspended") && (Boolean) command.get("suspended"); boolean isStepping = isSuspendedByDebugger || command.containsKey("step") && (Boolean) command.get("step"); boolean isException = "exception".equals(command.get("type")); boolean isScriptLoad = "load".equals(command.get("type")); boolean isDebuggerStatement = "debugger".equals(command.get("type")); if (fileName != null && line != null) { IFile file = ResourcesPlugin.getWorkspace().getRoot() .getFile(new Path(fileName)); Location location = new SimpleLocation(vm, file, line.intValue()); IProject project = file.getProject(); IJavaScriptLineBreakpoint bp = JSODDSupport.findBreakPoint( new Path(fileName), line.intValue()); for (Object bpRequestObj : bpRequests) { ReloadBreakpointRequest bpRequest = (ReloadBreakpointRequest) bpRequestObj; Location bpLocation = bpRequest.location(); if (!isStepping && !isException && sameLocation(bpLocation, bp)) { eventSet.add(new ReloadBreakpointEvent(vm, thread, bpLocation, bpRequest)); } } for (Object stepRequestObj : stepRequests) { ReloadStepRequest stepRequest = (ReloadStepRequest) stepRequestObj; eventSet.add(new ReloadStepEvent(vm, thread, location, stepRequest)); } if (isSuspendedByDebugger) { for (Object suspendRequestObj : suspendRequests) { ReloadSuspendRequest suspendRequest = (ReloadSuspendRequest) suspendRequestObj; eventSet.add(new ReloadSuspendEvent(vm, thread, location, suspendRequest)); } } else if (isException) { for (Object exceptionRequestObj : exceptionRequests) { ReloadExceptionRequest exceptionRequest = (ReloadExceptionRequest) exceptionRequestObj; String message = (String) command.get("message"); eventSet.add(new ReloadExceptionEvent(vm, thread, location, message, exceptionRequest)); } } else if (isScriptLoad) { for (Object scriptLoadRequestObj : scriptLoadRequests) { // For some reason, the project should not be in this path!? ReloadScriptLoadRequest scriptLoadRequest = (ReloadScriptLoadRequest) scriptLoadRequestObj; SimpleScriptReference script = new SimpleScriptReference(vm, file.getProjectRelativePath()); eventSet.add(new ReloadScriptEvent(targetVM, thread, script, scriptLoadRequest)); } } else if (isDebuggerStatement) { for (Object debuggerStatementRequestObj : debuggerStatementRequests) { // For some reason, the project should not be in this path!? ReloadDebuggerStatementRequest debuggerStatementRequest = (ReloadDebuggerStatementRequest) debuggerStatementRequestObj; eventSet.add(new ReloadDebuggerStatementEvent(targetVM, thread, location, debuggerStatementRequest)); } } } if (!eventSet.isEmpty()) { thread.markSuspended(!isStepping && !isException && !isSuspendedByDebugger); } } else if (THREAD_ENTER.equals(commandName)) { ReloadThreadReference thread = (ReloadThreadReference) commandObj; for (Object threadEnterRequest : threadEnterRequests) { eventSet.add(new ReloadThreadEnterEvent(targetVM, thread, null, (EventRequest) threadEnterRequest)); } } else if (THREAD_EXIT.equals(commandName)) { ReloadThreadReference thread = (ReloadThreadReference) commandObj; for (Object threadExitRequest : threadExitRequests) { eventSet.add(new ReloadThreadExitEvent(targetVM, thread, null, (EventRequest) threadExitRequest)); } } else if (CUSTOM_EVENT.equals(commandName)) { ReloadEvent event = (ReloadEvent) commandObj; eventSet.add(event); } } if (CoreMoSyncPlugin.getDefault().isDebugging() && !eventSet.isEmpty()) { CoreMoSyncPlugin.trace("Event set: {0}", eventSet); } return eventSet; } private ReloadVirtualMachine extractVM(Object commandObj) { if (commandObj instanceof ReloadEvent) { return (ReloadVirtualMachine) ((ReloadEvent) commandObj) .virtualMachine(); } else { ReloadThreadReference thread = extractThread(commandObj); return (ReloadVirtualMachine) (thread == null ? null : thread.virtualMachine()); } } private ReloadThreadReference extractThread(Object commandObj) { if (commandObj instanceof JSONObject) { Integer sessionId = JSODDServer .extractSessionId((JSONObject) commandObj); if (sessionId != null) { return Html5Plugin.getDefault().getReloadServer() .getThread(sessionId); } } else if (commandObj instanceof ReloadThreadReference) { return (ReloadThreadReference) commandObj; } return null; } private boolean sameLocation(Location location, IJavaScriptLineBreakpoint bp) { if (bp == null || !(location instanceof SimpleLocation)) { return false; } try { if (bp.getLineNumber() == location.lineNumber()) { IPath path1 = ((SimpleScriptReference) location .scriptReference()).getFile().getFullPath(); IPath path2 = new Path(bp.getScriptPath()); return Util.equals(path1, path2); } } catch (CoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } public void received(String command, Object data) { if (CoreMoSyncPlugin.getDefault().isDebugging()) { CoreMoSyncPlugin.trace("Received event {0}", command); } internalQueue.offer(new Pair<String, Object>(command, data)); } public void close() { internalQueue.offer(new Pair<String, Object>(null, null)); //internalQueue.clear(); } }