blob: 1c20129a774f20aeb96391fe1f4248ee367459dd [file] [log] [blame]
/*
* Copyright 2007 Sascha Weinreuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.plugins.xsltDebugger;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.util.EventDispatcher;
import com.intellij.xdebugger.XSourcePosition;
import org.intellij.plugins.xsltDebugger.impl.XsltBreakpointHandler;
import org.intellij.plugins.xsltDebugger.impl.XsltDebugProcess;
import org.intellij.plugins.xsltDebugger.rt.engine.Breakpoint;
import org.intellij.plugins.xsltDebugger.rt.engine.BreakpointManager;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.DebuggerStoppedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.rmi.RemoteException;
import java.util.EventListener;
/**
* This is the main place that interacts with the debugged XSLT processor. Waits until the processor
* hits a breakpoint, resumes execution, etc.
*/
public class XsltDebuggerSession implements Disposable {
private static final Key<XsltDebuggerSession> DEBUGGER_SESSION = Key.create("DEBUGGER_SESSION");
private final Project myProject;
private final ProcessHandler myProcess;
private final Debugger myClient;
private final EventDispatcher<Listener> myEventDispatcher = EventDispatcher.create(Listener.class);
private Breakpoint myTempBreakpoint;
private volatile Debugger.State myState;
private boolean myClosed;
private XsltDebuggerSession(Project project, ProcessHandler process, Debugger client) {
myProject = project;
myProcess = process;
myClient = client;
Disposer.register(XsltDebugProcess.getInstance(process), this);
}
public void start() {
myClient.start();
myState = Debugger.State.RUNNING;
final BreakpointManager breakpointManager = myClient.getBreakpointManager();
final Listener multicaster = myEventDispatcher.getMulticaster();
try {
if (!myClient.waitForDebuggee()) {
multicaster.debuggerStopped();
return;
}
myState = Debugger.State.SUSPENDED;
do {
if (myState == Debugger.State.SUSPENDED) {
if (myTempBreakpoint != null) {
breakpointManager.removeBreakpoint(myTempBreakpoint);
myTempBreakpoint = null;
}
multicaster.debuggerSuspended();
} else if (myState == Debugger.State.RUNNING) {
multicaster.debuggerResumed();
} else if (myState == Debugger.State.STOPPED) {
break;
}
}
while ((myState = myClient.waitForStateChange(myState)) != null);
multicaster.debuggerStopped();
} catch (DebuggerStoppedException e) {
multicaster.debuggerStopped();
} catch (RuntimeException e) {
if (e.getCause() instanceof RemoteException) {
if (e.getCause().getCause() instanceof SocketException) {
multicaster.debuggerStopped();
return;
}
}
throw e;
} finally {
myState = Debugger.State.STOPPED;
close();
}
}
public void addListener(Listener listener) {
myEventDispatcher.addListener(listener);
}
public void removeListener(Listener listener) {
myEventDispatcher.removeListener(listener);
}
public Debugger getClient() {
return myClient;
}
public Debugger.State getCurrentState() {
return myState;
}
public void pause() {
myClient.pause();
}
public void resume() {
myClient.resume();
}
public void stop() {
try {
myClient.stop(false);
} catch (DebuggerStoppedException ignore) {
}
}
public void stepOver() {
myClient.step();
}
public void stepInto() {
myClient.stepInto();
}
public boolean canRunTo(final XSourcePosition position) {
return XsltBreakpointHandler.getActualLineNumber(myProject, position) != -1;
}
public void runTo(final PsiFile file, final XSourcePosition position) {
assert myTempBreakpoint == null;
final int lineNumber = XsltBreakpointHandler.getActualLineNumber(myProject, position);
final String uri = XsltBreakpointHandler.getFileURL(file.getVirtualFile());
myTempBreakpoint = myClient.getBreakpointManager().setBreakpoint(uri, lineNumber);
resume();
}
@Nullable
public static Editor openLocation(Project project, @NotNull String uri, int lineNumber) {
try {
final VirtualFile file = VfsUtil.findFileByURL(new URI(uri).toURL());
final OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, lineNumber, 0);
descriptor.navigate(true);
return FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
} catch (MalformedURLException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
} catch (URISyntaxException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
}
public synchronized void close() {
if (myClosed) return;
myClosed = true;
try {
myClient.stop(true);
} catch (DebuggerStoppedException e) {
// OK
} finally {
myProcess.destroyProcess();
}
}
@Override
public void dispose() {
detach(myProcess);
}
@NotNull
public static XsltDebuggerSession create(Project project, @NotNull ProcessHandler process, Debugger client) {
final XsltDebuggerSession session = new XsltDebuggerSession(project, process, client);
process.putUserData(DEBUGGER_SESSION, session);
return session;
}
public static XsltDebuggerSession getInstance(@NotNull ProcessHandler process) {
return process.getUserData(DEBUGGER_SESSION);
}
public static void detach(ProcessHandler processHandler) {
processHandler.putUserData(DEBUGGER_SESSION, null);
}
public interface Listener extends EventListener {
void debuggerSuspended();
void debuggerResumed();
void debuggerStopped();
}
}