xslt debugger initial commit

This commit is contained in:
Sascha Weinreuter
2011-05-24 11:05:50 +02:00
parent 0bdca1d96d
commit d1f0c5fcfc
85 changed files with 8292 additions and 0 deletions
+2
View File
@@ -100,6 +100,8 @@
<module fileurl="file://$PROJECT_DIR$/xml/openapi/xml-openapi.iml" filepath="$PROJECT_DIR$/xml/openapi/xml-openapi.iml" group="xml" />
<module fileurl="file://$PROJECT_DIR$/plugins/xpath/xpath.iml" filepath="$PROJECT_DIR$/plugins/xpath/xpath.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/xpath/xslt-rt/xslt-rt.iml" filepath="$PROJECT_DIR$/plugins/xpath/xslt-rt/xslt-rt.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/xslt-debugger/xslt-debugger.iml" filepath="$PROJECT_DIR$/plugins/xslt-debugger/xslt-debugger.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/xslt-debugger/rt/xslt-debugger-rt.iml" filepath="$PROJECT_DIR$/plugins/xslt-debugger/rt/xslt-debugger-rt.iml" group="plugins" />
</modules>
</component>
</project>
+1
View File
@@ -77,6 +77,7 @@
<orderEntry type="module" module-name="IntelliLang-javaee" />
<orderEntry type="module" module-name="IntelliLang-xml" />
<orderEntry type="module" module-name="xpath" />
<orderEntry type="module" module-name="xslt-debugger" />
<orderEntry type="module" module-name="tasks-core" />
<orderEntry type="module" module-name="jira-connector" />
<orderEntry type="module" module-name="tasks-api" />
+8
View File
@@ -0,0 +1,8 @@
#idea.home=C:\\Programme\\IntelliJ Selena
idea.home=C:\\work\\Programme\\IntelliJ 10
idea.plugins.home=${idea.home}/plugins
xpathview.src.home=../xpath
compile.debug=true
compile.optimize=true
+198
View File
@@ -0,0 +1,198 @@
<project default="rebuild" name="xslt-debugger">
<property file="build.properties"/>
<dirname file="${ant.file}" property="project.dir"/>
<property name="src.dir" value="${project.dir}/src"/>
<property name="src.rt.dir" value="${project.dir}/rt/src"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="build.classes.rt.dir" value="${build.dir}/rt/classes"/>
<path id="classpath.uidesigner">
<fileset dir="${idea.home}">
<include name="lib/*.jar"/>
<include name="redist/*.jar"/>
</fileset>
</path>
<taskdef name="javac2" classname="com.intellij.ant.Javac2">
<classpath refid="classpath.uidesigner"/>
</taskdef>
<taskdef name="jflex" classname="JFlex.anttask.JFlexTask">
<classpath location="${idea.home}/tools/jflex/lib/JFlex.jar"/>
</taskdef>
<path id="idea.classpath">
<fileset dir="${idea.home}">
<include name="lib/*.jar"/>
<include name="redist/*.jar"/>
</fileset>
</path>
<path id="rt.classpath">
<fileset dir="${idea.home}/lib">
<include name="trove4j.jar" />
</fileset>
<fileset dir="rt/lib">
<include name="*.jar"/>
</fileset>
</path>
<property name="xpathview.plugin.home" value="${idea.plugins.home}/xpath"/>
<target name="init">
<condition property="xpathview.src.available">
<available file="${xpathview.src.home}/build.xml"/>
</condition>
</target>
<target name="xpathview.compile" depends="init" if="xpathview.src.available">
<echo message="Building XPathView from source: ${xpathview.src.home}"/>
<property name="build.xpathview.dir" value="${build.dir}/xpathview"/>
<mkdir dir="${build.xpathview.dir}"/>
<ant dir="${xpathview.src.home}" target="jar">
<property name="build.dir" value="${build.xpathview.dir}"/>
</ant>
<path id="xpathview.classpath">
<fileset dir="${build.xpathview.dir}">
<include name="xpath-lang/*.jar"/>
<include name="*.jar"/>
</fileset>
</path>
<path id="xpathview.rt.classpath">
<fileset dir="${build.xpathview.dir}">
<include name="xpath-lang/xslt-rt/*.jar"/>
</fileset>
</path>
</target>
<target name="xpathview.binary" depends="init" unless="xpathview.src.available">
<available file="${xpathview.plugin.home}/lib/xpath.jar" property="xpathview.binary.available"/>
<available file="${xpathview.plugin.home}/lib/xpath-view.jar" property="xpathview.binary.available"/>
<fail unless="xpathview.binary.available">
The XPathView plugin is required to build the XSLT-Debugger. Please set the property "xpathview.plugin.home" to
point to the installation of the plugin in IntelliJ IDEA.
</fail>
<path id="xpathview.classpath">
<fileset dir="${xpathview.plugin.home}">
<include name="lib/*.jar"/>
</fileset>
</path>
<path id="xpathview.rt.classpath">
<fileset dir="${xpathview.plugin.home}">
<include name="lib/rt/*.jar"/>
</fileset>
</path>
</target>
<target name="compile" depends="init, xpathview.compile, xpathview.binary">
<mkdir dir="${build.classes.dir}"/>
<mkdir dir="${build.classes.rt.dir}"/>
<javac2 srcdir="${src.rt.dir}" destdir="${build.classes.rt.dir}" source="1.5" target="1.5" debug="${compile.debug}"
optimize="${compile.optimize}">
<classpath refid="rt.classpath"/>
<classpath refid="xpathview.rt.classpath"/>
<exclude name="com/**/*"/>
</javac2>
<javac2 srcdir="${src.dir}" destdir="${build.classes.dir}" source="1.5" target="1.5" debug="${compile.debug}"
optimize="${compile.optimize}">
<classpath refid="idea.classpath"/>
<classpath refid="xpathview.classpath"/>
<classpath location="${build.classes.rt.dir}"/>
<exclude name="com/**/*"/>
<exclude name="Main.java"/>
</javac2>
<rmic base="${build.classes.rt.dir}">
<include name="**/remote/Remote*Impl.class"/>
<include name="**/remote/DebuggerServer.class"/>
</rmic>
<jar destfile="${build.dir}/rmi-stubs.jar">
<fileset dir="${build.classes.rt.dir}">
<include name="**/remote/Remote*Impl_*.class"/>
<include name="**/remote/DebuggerServer_*.class"/>
</fileset>
</jar>
</target>
<target name="build" depends="compile" description="Build project"/>
<target name="jar" depends="build">
<jar file="${build.dir}/xslt-debugger.jar" compress="false">
<zipfileset dir="${build.classes.dir}">
<include name="**/*"/>
</zipfileset>
<zipfileset dir=".">
<include name="META-INF/*.xml"/>
</zipfileset>
<zipfileset dir="${src.dir}">
<include name="**/*.xml"/>
<include name="**/*.png"/>
</zipfileset>
</jar>
<mkdir dir="${build.dir}/rt"/>
<jar file="${build.dir}/xslt-debugger-engine.jar" compress="false">
<zipfileset dir="${build.classes.rt.dir}">
<include name="**/*"/>
</zipfileset>
<zipfileset dir="${src.rt.dir}">
<include name="**/*.xml"/>
<include name="**/*.png"/>
</zipfileset>
</jar>
</target>
<target name="rebuild" depends="clean, jar" description="Clean and rebuild"/>
<target name="clean">
<delete dir="build"/>
</target>
<target name="dist" depends="rebuild" description="Build distribution ZIP">
<mkdir dir="dist"/>
<zip file="dist/xslt-debugger.zip">
<zipfileset dir="build" prefix="xslt-debugger/lib">
<include name="*.jar"/>
</zipfileset>
<zipfileset dir="rt/lib" prefix="xslt-debugger/lib/rt">
<include name="saxon*"/>
<include name="xalan.jar"/>
<include name="serializer.jar"/>
</zipfileset>
<zipfileset dir="doc" prefix="xslt-debugger/help">
<include name="help.jar"/>
</zipfileset>
<zipfileset dir="." prefix="xslt-debugger">
<include name="LICENSE"/>
</zipfileset>
</zip>
<zip file="dist/xslt-debugger_src.zip">
<zipfileset dir="." prefix="xslt-debugger">
<include name="src/**/*"/>
<include name="rt/src/**/*"/>
<include name="rt/*.iml"/>
<include name="*.iml"/>
<include name="*.ipr"/>
<include name="META-INF/*.xml"/>
<include name="build.xml"/>
<include name="build.properties"/>
<include name="LICENSE"/>
<include name="readme-project.txt"/>
</zipfileset>
</zip>
</target>
</project>
Binary file not shown.
@@ -0,0 +1,148 @@
<html>
<head>
<title>SAXON: Conditions of Use</title>
</head>
<body leftmargin="150" bgcolor="#ddeeff"><font face="Arial, Helvetica, sans-serif">
<div align=right><a href="index.html">SAXON home page</a></div>
<h1><big><font color="#FF0080">SAXON: Conditions of Use</font></big></h1>
<h2>Saxon</h2>
<p>The contents of the downloaded file (saxon.zip), with the exception of the
&AElig;lfred parser (see below),
are subject to the Mozilla Public License Version 1.0
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
<a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a></p>
<p>Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied.
See the License for the specific language governing rights and limitations under the License.
<p>
<p>The Original Code of SAXON comprises all those components which are not explicitly attributed
to other parties. It does not include the &AElig;lfred parser, which is redistributed under
the licence described below.</p>
<p>The Initial Developer of the Original Code was Michael Kay.
Individual modules identified as being created by James Clark, David Megginson, or John Cowan include
separate IPR notices. All Rights Reserved.</p>
<p>
<small><i>Until January 2001 Michael Kay worked for International Computers Limited (ICL, now part
of Fujitsu), and from February 2001 to January 2004 he worked for Software AG. These two companies
both sponsored the development of Saxon and authorised its release under this license, but are not
themselves parties to the license. Michael Kay now runs his own company, Saxonica, which has taken
over all responsibility for Saxon development and support.</i></small>
</p>
<p>
<small><i>For reasons of continuity,
the icl.com domain name is retained in package names and namespace URIs with the tacit
consent of ICL, but this should not be taken to imply any ongoing ICL involvement.</small>
</i></p>
<p>If you produce a product that includes or requires SAXON, please refer to it as
&quot;The SAXON XSLT Processor from Michael Kay&quot;, and include the URL of the
home page, which is at
<a HREF="http://saxon.sourceforge.net/">http://saxon.sourceforge.net/</a>.</p>
<p>There is no guarantee of technical support, though I am usually able to answer enquiries
within a few days. Please subscribe to the mailing list available at
<a href="http://lists.sourceforge.net/lists/listinfo/saxon-help"/>
http://lists.sourceforge.net/lists/listinfo/saxon-help</a> and raise any enquiries there.
Also check the Saxon project pages on sourceforge for details of known errors; all bugs are
listed there as soon as I have sufficient evidence to describe the nature of the problem.</p>
<hr>
<h2>&AElig;lfred</h2>
<p>Included in the Saxon distribution is a modified version of the &AElig;lfred XML parser
originally developed by David Megginson at Microstar (no longer in existence).
I have taken the relevant part of
<A href="mailto:david-b@pacbell.net">David Brownell</a>'s
<a href="http://home.pacbell.net/david-b/xml/">&AElig;lfred2</a> distribution, repackaged it,
and fixed a few bugs. All changes are clearly documented in the source code.</p>
<p>This is distributed under the terms of Microstar's terms and conditions, which are as follows:</p>
<table>
<tr>
<td width=100></td>
<td>
<p>AElfred, Version 1.2<br>
Microstar's Java-Based XML Parser<br>
Copyright (c) 1997, 1998 by Microstar Software Ltd.<br>
Home Page: http://www.microstar.com/XML/</p>
<p>AElfred is free for both commercial and non-commercial use and
redistribution, provided that Microstar's copyright and disclaimer are
retained intact. You are free to modify AElfred for your own use and
to redistribute AElfred with your modifications, provided that the
modifications are clearly documented.</p>
<p><u>DISCLAIMER</u></p>
<p>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. Please use it AT
YOUR OWN RISK.</p>
</td>
<td width=100></td>
</tr>
</table>
<p>David Brownell added the following statement: </p>
<code><pre>
/*
* Copyright (c) 1999-2000 by David Brownell. All Rights Reserved.
*
* This program is open source software; you may use, copy, modify, and
* redistribute it under the terms of the LICENSE with which it was
* originally distributed.
*
* 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
* LICENSE for more details.
*/
</pre>
</code>
<p>The version included with Saxon is David Brownell's code of 26 Feb 2000,
modified as follows:</p>
<ul>
<li>Changed the package name to com.icl.saxon.aelfred to prevent any accidental confusion with the
original Microstar code or with David Brownell's version.
</li>
<li>Fixed several bugs: (1) a bug in namespace handling (where an attribute xxx:name precedes the xmlns:xxx
declaration) (2) poor diagnostics when end of file occurs prematurely
</li>
<li>Subsetting the code to include only the XML non-validating parser and SAX driver, with appropriate
changes to the setFeature() and getFeature() methods.
</li>
<li>Some further changes made by David Brownell up to June 2001 have been incorporated.</li>
</ul>
<hr>
<p align="center">Michael H. Kay<br>
<a href="http://www.saxonica.com/">Saxonica Limited</a><br>
22 June 2005</p>
</font>
</body>
</html>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,58 @@
/*
* Copyright 2002-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.rt;
import org.intellij.plugins.xslt.run.rt.XSLTMain;
import org.intellij.plugins.xslt.run.rt.XSLTRunner;
import org.intellij.plugins.xsltDebugger.rt.engine.local.saxon.SaxonSupport;
import org.intellij.plugins.xsltDebugger.rt.engine.local.saxon9.Saxon9Support;
import org.intellij.plugins.xsltDebugger.rt.engine.local.xalan.XalanSupport;
import org.intellij.plugins.xsltDebugger.rt.engine.remote.DebuggerServer;
import javax.xml.transform.*;
import java.rmi.RemoteException;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.11.2007
*/
public class XSLTDebuggerMain implements XSLTMain {
public TransformerFactory createTransformerFactory() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
final String type = System.getProperty("xslt.transformer.type");
if ("xalan".equalsIgnoreCase(type)) {
return XalanSupport.createTransformerFactory();
} else if ("saxon".equalsIgnoreCase(type)) {
return SaxonSupport.createTransformerFactory();
} else if ("saxon9".equalsIgnoreCase(type)) {
return Saxon9Support.createTransformerFactory();
} else if (type != null) {
throw new UnsupportedOperationException("Unsupported Transformer type '" + type + "'");
}
return XalanSupport.prepareFactory(XSLTRunner.createTransformerFactoryStatic());
}
public void start(Transformer transformer, Source source, Result result) throws TransformerException {
try {
DebuggerServer.create(transformer, source, result, Integer.getInteger("xslt.debugger.port"));
} catch (RemoteException e) {
throw new TransformerException(e.getMessage(), e.getCause());
}
}
}
@@ -0,0 +1,48 @@
/*
* 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.rt.engine;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 29.05.2007
*/
public interface Breakpoint {
String getUri();
int getLine();
boolean isEnabled();
void setEnabled(boolean enabled);
String getCondition();
void setCondition(String expr);
String getLogMessage();
void setLogMessage(String expr);
String getTraceMessage();
void setTraceMessage(String expr);
boolean isSuspend();
void setSuspend(boolean suspend);
}
@@ -0,0 +1,39 @@
/*
* 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.rt.engine;
import java.io.File;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.05.2007
*/
public interface BreakpointManager {
Breakpoint setBreakpoint(File file, int line);
Breakpoint setBreakpoint(String uri, int line);
void removeBreakpoint(Breakpoint bp);
void removeBreakpoint(String uri, int line);
List<Breakpoint> getBreakpoints();
Breakpoint getBreakpoint(String uri, int lineNumber);
}
@@ -0,0 +1,103 @@
/*
* 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.rt.engine;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.05.2007
*/
public interface Debugger extends Watchable {
enum State {
CREATED, RUNNING, SUSPENDED, STOPPED
}
State getState();
boolean start();
void stop(boolean force);
void step();
void stepInto();
void resume();
void pause();
boolean isStopped();
StyleFrame getCurrentFrame();
SourceFrame getSourceFrame();
Value eval(String expr) throws EvaluationException;
List<Variable> getGlobalVariables();
BreakpointManager getBreakpointManager();
OutputEventQueue getEventQueue();
boolean waitForDebuggee();
State waitForStateChange(State state);
interface Locatable {
String getURI();
int getLineNumber();
}
interface Frame<T extends Frame> extends Locatable {
T getNext();
T getPrevious();
}
interface StyleFrame extends Frame<StyleFrame> {
String getInstruction();
Value eval(String expr) throws EvaluationException;
List<Variable> getVariables();
}
interface SourceFrame extends Frame<SourceFrame> {
String getXPath();
}
interface Variable extends Locatable {
enum Kind {VARIABLE, PARAMETER, EXPRESSION}
boolean isGlobal();
Kind getKind();
String getName();
Value getValue();
}
class EvaluationException extends Exception {
public EvaluationException(String message) {
super(message);
}
}
}
@@ -0,0 +1,25 @@
/*
* 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.rt.engine;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 24.05.2007
*/
public class DebuggerStoppedException extends RuntimeException {
}
@@ -0,0 +1,116 @@
/*
* Copyright 2002-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.rt.engine;
import java.io.Serializable;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 08.06.2007
*/
public interface OutputEventQueue {
int START_DOCUMENT = 0;
int END_DOCUMENT = 99;
int START_ELEMENT = 1;
int END_ELEMENT = 2;
int ATTRIBUTE = 3;
int CHARACTERS = 4;
int COMMENT = 5;
int PI = 6;
int TRACE_POINT = 20;
void setEnabled(boolean b);
List<NodeEvent> getEvents();
final class NodeEvent implements Serializable {
public static final class QName implements Serializable {
public String myPrefix;
public String myLocalName;
public String myURI;
public QName(String prefix, String localName, String URI) {
myPrefix = prefix;
myLocalName = localName;
myURI = URI;
}
public QName(String qName, String uri) {
myURI = uri;
final String[] parts = qName.split(":");
if (parts.length == 2) {
myPrefix = parts[0];
myLocalName = parts[1];
} else {
myPrefix = null;
myLocalName = parts[0];
}
}
public QName(String name) {
myLocalName = name;
myPrefix = null;
myURI = null;
}
public String getQName() {
return myPrefix != null && myPrefix.length() > 0 ? myPrefix + ":" + myLocalName : myLocalName;
}
}
private final int myType;
public String myValue;
public QName myQName;
public String myURI;
private int myLineNumber;
public NodeEvent(int type, QName qName, String value) {
myType = type;
myQName = qName;
myValue = value;
}
public int getType() {
return myType;
}
public QName getQName() {
return myQName;
}
public String getValue() {
return myValue;
}
public void setLocation(String uri, int lineNumber) {
myURI = uri;
myLineNumber = lineNumber;
}
public int getLineNumber() {
return myLineNumber;
}
public String getURI() {
return myURI;
}
}
}
@@ -0,0 +1,105 @@
/*
* 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.rt.engine;
import java.io.Serializable;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 31.05.2007
*/
public interface Value extends Serializable {
interface Type extends Serializable {
String getName();
}
enum XPathType implements Type {
BOOLEAN, NUMBER, STRING, NODESET, OBJECT, UNKNOWN;
public String getName() {
return name().toLowerCase();
}
}
final class ObjectType implements Type {
private final String myName;
public ObjectType(String name) {
myName = name;
}
public String getName() {
return myName;
}
}
Object getValue();
Type getType();
class NodeSet implements Serializable {
public final String myStringValue;
private final List<Node> myNodes;
public NodeSet(String stringValue, List<Node> nodes) {
myStringValue = stringValue;
myNodes = nodes;
}
public List<Node> getNodes() {
return myNodes;
}
@Override
public String toString() {
return myStringValue;
}
}
class Node implements Serializable, Debugger.Locatable {
public final String myURI;
public final int myLineNumber;
public final String myXPath;
public final String myStringValue;
public Node(String URI, int lineNumber, String XPath, String stringValue) {
myURI = URI;
myLineNumber = lineNumber;
myXPath = XPath;
myStringValue = stringValue;
}
public String getURI() {
return myURI;
}
public int getLineNumber() {
return myLineNumber;
}
public String toString() {
return "Node{" +
"myURI='" + myURI + '\'' +
", myLineNumber=" + myLineNumber +
", myXPath='" + myXPath + '\'' +
", myStringValue='" + myStringValue + '\'' +
'}';
}
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* 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.rt.engine;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 09.05.11
*/
public interface Watchable {
boolean ping();
}
@@ -0,0 +1,62 @@
/*
* 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.rt.engine.local;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger.Frame;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 02.06.2007
*/
public abstract class AbstractFrame<F extends Frame> implements Frame<F> {
private final F myPrev;
private F myNext;
private boolean myValid = true;
public AbstractFrame(F prev) {
myPrev = prev;
if (prev != null) {
((AbstractFrame)prev).myNext = this;
}
}
public void invalidate() {
assert myValid;
assert myNext == null;
if (myPrev != null) {
((AbstractFrame)myPrev).myNext = null;
}
myValid = false;
}
public F getNext() {
assert myValid;
return myNext;
}
public F getPrevious() {
assert myValid;
return myPrev;
}
public boolean isValid() {
return myValid;
}
}
@@ -0,0 +1,114 @@
/*
* 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.rt.engine.local;
import org.intellij.plugins.xsltDebugger.rt.engine.Breakpoint;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 29.05.2007
*/
class BreakpointImpl implements Breakpoint {
private final String myUri;
private final int myLine;
private boolean myEnabled;
private String myCondition;
private String myLogMsg;
private String myTraceMsg;
private boolean mySuspend;
public BreakpointImpl(String uri, int line) {
myUri = uri;
myLine = line;
myEnabled = true;
}
public void setEnabled(boolean b) {
myEnabled = b;
}
public void setCondition(String expr) {
myCondition = expr;
}
public void setLogMessage(String expr) {
myLogMsg = expr;
}
public String getTraceMessage() {
return myTraceMsg;
}
public void setTraceMessage(String expr) {
myTraceMsg = expr;
}
public boolean isSuspend() {
return mySuspend;
}
public void setSuspend(boolean suspend) {
mySuspend = suspend;
}
public String getCondition() {
return myCondition;
}
public String getLogMessage() {
return myLogMsg;
}
public String getUri() {
return myUri;
}
public int getLine() {
return myLine;
}
public boolean isEnabled() {
return myEnabled;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final BreakpointImpl that = (BreakpointImpl)o;
if (myLine != that.myLine) return false;
return myUri.equals(that.myUri);
}
public int hashCode() {
int result;
result = myUri.hashCode();
result = 31 * result + myLine;
return result;
}
public String toString() {
return "Breakpoint{" +
"myUri='" + myUri + '\'' +
", myLine=" + myLine +
", myEnabled=" + myEnabled +
'}';
}
}
@@ -0,0 +1,107 @@
/*
* 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.rt.engine.local;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TIntObjectProcedure;
import org.intellij.plugins.xsltDebugger.rt.engine.Breakpoint;
import org.intellij.plugins.xsltDebugger.rt.engine.BreakpointManager;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 19.05.2007
*/
public class BreakpointManagerImpl implements BreakpointManager {
private final TIntObjectHashMap<Map<String, Breakpoint>> myBreakpoints =
new TIntObjectHashMap<Map<String, Breakpoint>>();
public Breakpoint setBreakpoint(File file, int line) {
return setBreakpoint(file.toURI().toASCIIString(), line);
}
public synchronized void removeBreakpoint(String uri, int line) {
final Map<String, Breakpoint> s = myBreakpoints.get(line);
if (s != null) {
s.remove(normalizeUri(uri));
}
}
public synchronized List<Breakpoint> getBreakpoints() {
final ArrayList<Breakpoint> breakpoints = new ArrayList<Breakpoint>();
myBreakpoints.forEachEntry(new TIntObjectProcedure<Map<String, Breakpoint>>() {
public boolean execute(int i, Map<String, Breakpoint> map) {
breakpoints.addAll(map.values());
return true;
}
});
return breakpoints;
}
public void removeBreakpoint(Breakpoint bp) {
removeBreakpoint(bp.getUri(), bp.getLine());
}
public synchronized Breakpoint setBreakpoint(String uri, int line) {
assert line > 0 : "No line number for breakpoint in file " + uri;
uri = normalizeUri(uri);
final Map<String, Breakpoint> s = myBreakpoints.get(line);
final BreakpointImpl bp = new BreakpointImpl(uri, line);
if (s == null) {
final HashMap<String, Breakpoint> map = new HashMap<String, Breakpoint>();
map.put(uri, bp);
myBreakpoints.put(line, map);
} else {
s.put(uri, bp);
}
return bp;
}
private static String normalizeUri(String uri) {
// hmm, this code sucks, but seems to be a good guess to ensure the same format of
// strings (file:/C:/... vs, file:///C:/...) on both sides...
try {
try {
uri = uri.replaceAll(" ", "%20");
return new File(new URI(uri)).toURI().toASCIIString();
} catch (IllegalArgumentException e) {
return new URI(uri).normalize().toASCIIString();
}
} catch (URISyntaxException e) {
System.err.println("Failed to parse <" + uri + ">: " + e);
return uri;
}
}
public synchronized boolean isBreakpoint(String uri, int lineNumber) {
final Breakpoint breakpoint = getBreakpoint(uri, lineNumber);
return breakpoint != null && breakpoint.isEnabled();
}
public synchronized Breakpoint getBreakpoint(String uri, int lineNumber) {
final Map<String, Breakpoint> s = myBreakpoints.get(lineNumber);
if (s != null) {
return s.get(normalizeUri(uri));
}
return null;
}
}
@@ -0,0 +1,408 @@
/*
* 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.rt.engine.local;
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.intellij.plugins.xsltDebugger.rt.engine.local.saxon.SaxonSupport;
import org.intellij.plugins.xsltDebugger.rt.engine.local.saxon9.Saxon9Support;
import org.intellij.plugins.xsltDebugger.rt.engine.local.xalan.XalanSupport;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 19.05.2007
*/
public class LocalDebugger implements Debugger {
private final Thread myThread;
private final BreakpointManager myBreakpointManager;
private final OutputEventQueueImpl myEventQueue;
private volatile Condition myCurrentStopCondition;
private final Object theLock = new Object();
private volatile State myState = State.CREATED;
private final LinkedList<StyleFrame> myFrames = new LinkedList<StyleFrame>();
private final LinkedList<SourceFrame> mySourceFrames = new LinkedList<SourceFrame>();
public LocalDebugger(final Transformer transformer, final Source source, final Result result) {
prepareTransformer(transformer);
myBreakpointManager = new BreakpointManagerImpl();
myEventQueue = new OutputEventQueueImpl(this);
myThread = new Thread(new Runnable() {
public void run() {
try {
synchronized (theLock) {
myState = State.RUNNING;
theLock.notifyAll();
}
transformer.transform(source, result);
stopped();
} catch (DebuggerStoppedException e) {
// OK
} catch (TransformerException e) {
// TODO: log, pass to client
e.printStackTrace();
stopped();
}
}
});
}
protected void prepareTransformer(Transformer transformer) {
try {
if (Saxon9Support.init(transformer, this)) {
return;
}
} catch (NoClassDefFoundError e1) {
// ignore
}
try {
if (SaxonSupport.init(transformer, this)) {
return;
}
} catch (NoClassDefFoundError e) {
// ignore
}
try {
if (XalanSupport.init(transformer, this)) {
return;
}
} catch (NoClassDefFoundError e1) {
// ignore
}
throw new UnsupportedOperationException("Unsupported Transformer: " + transformer.getClass().getName());
}
private void suspendAndWait() throws DebuggerStoppedException {
try {
synchronized (theLock) {
myCurrentStopCondition = null;
myState = State.SUSPENDED;
theLock.notifyAll();
do {
theLock.wait();
}
while (myState == State.SUSPENDED);
if (myState == State.STOPPED) {
throw new DebuggerStoppedException();
}
}
} catch (InterruptedException e) {
throw new DebuggerStoppedException();
}
}
public void resume() throws DebuggerStoppedException {
synchronized (theLock) {
if (myState == State.STOPPED) {
throw new DebuggerStoppedException();
} else if (myState != State.SUSPENDED) {
throw new IllegalStateException();
}
myState = State.RUNNING;
theLock.notifyAll();
}
}
public void pause() {
synchronized (theLock) {
if (myState == State.STOPPED) {
throw new DebuggerStoppedException();
} else if (myState != State.RUNNING) {
throw new IllegalStateException();
}
myCurrentStopCondition = Condition.TRUE;
}
}
public void stopped() {
assert Thread.currentThread() == myThread;
stop0();
}
private void stop0() {
synchronized (theLock) {
myState = State.STOPPED;
theLock.notifyAll();
}
}
public State getState() {
synchronized (theLock) {
return myState;
}
}
@SuppressWarnings({ "deprecation" })
public void stop(boolean force) {
stop0();
myThread.interrupt();
if (!force) {
return;
}
try {
myThread.join(1000);
if (myThread.isAlive()) {
myThread.stop();
}
} catch (InterruptedException e) {
//
}
}
public State waitForStateChange(State state) {
try {
synchronized (theLock) {
if (myState == State.STOPPED) {
return State.STOPPED;
}
while (myState == state) {
theLock.wait();
}
return myState;
}
} catch (InterruptedException e) {
return null;
}
}
public boolean waitForDebuggee() {
try {
synchronized (theLock) {
while (myState == State.RUNNING) {
theLock.wait();
}
return myState != State.STOPPED;
}
} catch (InterruptedException e) {
return false;
}
}
public boolean isStopped() {
synchronized (theLock) {
return myState == State.STOPPED;
}
}
public boolean start() {
assert myState == State.CREATED : "Already started";
myThread.start();
try {
synchronized (theLock) {
while (myState == State.CREATED) {
theLock.wait();
}
}
return true;
} catch (InterruptedException e) {
//
}
return false;
}
public void enter(StyleFrame frame) {
assert Thread.currentThread() == myThread;
myFrames.addFirst(frame);
final String uri = frame.getURI();
final StyleFrame previous = frame.getPrevious();
if (previous != null && previous.getLineNumber() == frame.getLineNumber() && uri != null && uri.equals(previous.getURI())) {
if (frame.getInstruction().equals(previous.getInstruction())) {
System.err.println(
"WARN: Same instruction <" + frame.getInstruction() + "> on line " + frame.getLineNumber() + " encountered more than once");
}
}
if (isStopped()) {
throw new DebuggerStoppedException();
} else if (myCurrentStopCondition != null && myCurrentStopCondition.value()) {
suspendAndWait();
} else {
final int lineNumber = frame.getLineNumber();
final Breakpoint breakpoint = myBreakpointManager.getBreakpoint(uri, lineNumber);
if (breakpoint != null && breakpoint.isEnabled()) {
// do not evaluate a log or condition bp more than once on the same line
if (previous == null || previous.getLineNumber() != lineNumber) {
final String condition = breakpoint.getCondition();
try {
if (evalCondition(condition)) {
final String logMessage = breakpoint.getLogMessage();
final String traceMessage = breakpoint.getTraceMessage();
if (logBreakpoint(frame, logMessage, traceMessage) || breakpoint.isSuspend()) {
suspendAndWait();
}
}
} catch (EvaluationException e) {
// TODO: send to IDEA
System.err.println("[" + lineNumber + "]: Failed to evaluate expression: " + condition + " -- " + e.getMessage());
breakpoint.setEnabled(false);
}
}
}
}
}
private boolean evalCondition(String condition) throws EvaluationException {
if (condition != null && condition.length() > 0) {
if (!"true".equals(eval("boolean(" + condition + ")").getValue().toString())) {
return false;
}
}
return true;
}
private boolean logBreakpoint(StyleFrame frame, String logMessage, String traceMessage) throws EvaluationException {
if (logMessage != null) {
final String uri = frame.getURI();
final String pos = uri.substring(uri.lastIndexOf('/') + 1) + ":" + frame.getLineNumber();
System.out.println("[" + pos + "]: " + (logMessage.length() > 0 ? eval(logMessage).getValue().toString() : "<no message>"));
if (traceMessage != null) {
myEventQueue.trace(makeTraceMessage(traceMessage));
}
return false;
} else if (traceMessage != null) {
myEventQueue.trace(makeTraceMessage(traceMessage));
return false;
}
return true;
}
private String makeTraceMessage(String traceMessage) throws EvaluationException {
if (traceMessage.length() > 0) {
return eval(traceMessage).getValue().toString();
} else {
return null;
}
}
public void leave() {
assert Thread.currentThread() == myThread;
if (isStopped()) {
throw new DebuggerStoppedException();
// } else if (myBreakpointManager.isBreakpoint(uri, lineNumber)) {
// suspendAndWait();
// } else if (myCurrentStopCondition != null && myCurrentStopCondition.value()) {
// suspendAndWait();
}
((AbstractFrame)myFrames.removeFirst()).invalidate();
}
public void step() {
final int targetSize = myFrames.size();
myCurrentStopCondition = new Condition() {
public boolean value() {
return myFrames.size() <= targetSize;
}
};
resume();
}
public void stepInto() {
myCurrentStopCondition = Condition.TRUE;
resume();
}
public org.intellij.plugins.xsltDebugger.rt.engine.Value eval(String expr) throws EvaluationException {
final StyleFrame frame = getCurrentFrame();
if (frame == null) {
throw new EvaluationException("No frame available");
}
return frame.eval(expr);
}
public StyleFrame getCurrentFrame() {
return myFrames.size() > 0 ? myFrames.getFirst() : null;
}
public SourceFrame getSourceFrame() {
return mySourceFrames.size() > 0 ? mySourceFrames.getFirst() : null;
}
public List<Debugger.Variable> getGlobalVariables() {
final List<Variable> vars = getCurrentFrame().getVariables();
for (Iterator<Variable> it = vars.iterator(); it.hasNext(); ) {
Variable var = it.next();
if (!var.isGlobal()) {
it.remove();
}
}
return vars;
}
public BreakpointManager getBreakpointManager() {
return myBreakpointManager;
}
public void pushSource(SourceFrame sourceFrame) {
mySourceFrames.addFirst(sourceFrame);
}
public void popSource() {
((AbstractFrame)mySourceFrames.removeFirst()).invalidate();
}
interface Condition {
Condition TRUE = new Condition() {
public boolean value() {
return true;
}
};
boolean value();
}
public OutputEventQueueImpl getEventQueue() {
return myEventQueue;
}
public boolean ping() {
System.out.println(".");
return true;
}
}
@@ -0,0 +1,106 @@
/*
* Copyright 2002-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.rt.engine.local;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 08.06.2007
*/
public class OutputEventQueueImpl implements OutputEventQueue {
private final Debugger myDebugger;
private final List<NodeEvent> myEvents = new ArrayList<NodeEvent>();
private boolean myEnabled = true;
public OutputEventQueueImpl(Debugger debugger) {
myDebugger = debugger;
}
public void startDocument() {
if (myEnabled) {
myEvents.add(new NodeEvent(START_DOCUMENT, null, null));
}
}
public void endDocument() {
if (myEnabled) {
myEvents.add(new NodeEvent(END_DOCUMENT, null, null));
}
}
public void startElement(String prefix, String localName, String uri) {
addEvent(new NodeEvent(OutputEventQueue.START_ELEMENT, new NodeEvent.QName(prefix, localName, uri), null));
}
public void attribute(String prefix, String localName, String uri, String value) {
addEvent(new NodeEvent(ATTRIBUTE, new NodeEvent.QName(prefix, localName, uri), value));
}
public void endElement() {
addEvent(new NodeEvent(END_ELEMENT, null, null));
}
public void characters(String s) {
addEvent(new NodeEvent(CHARACTERS, null, s));
}
public void comment(String s) {
addEvent(new NodeEvent(COMMENT, null, s));
}
public void pi(String target, String data) {
addEvent(new NodeEvent(PI, new NodeEvent.QName(target), data));
}
public void trace(String text) {
addEvent(new NodeEvent(TRACE_POINT, null, text));
}
public void setEnabled(boolean b) {
myEnabled = b;
}
public boolean isEnabled() {
return myEnabled;
}
private void addEvent(NodeEvent event) {
if (myEnabled) {
final Debugger.StyleFrame frame = myDebugger.getCurrentFrame();
if (frame != null) {
event.setLocation(frame.getURI(), frame.getLineNumber());
}
myEvents.add(event);
}
}
public List<NodeEvent> getEvents() {
try {
return new ArrayList<NodeEvent>(myEvents);
} finally {
myEvents.clear();
}
}
}
@@ -0,0 +1,24 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import java.util.Comparator;
public final class VariableComparator implements Comparator<Debugger.Variable> {
public static final VariableComparator INSTANCE = new VariableComparator();
private VariableComparator() {
}
public int compare(Debugger.Variable o1, Debugger.Variable o2) {
final boolean og = o2.isGlobal();
final boolean g = o1.isGlobal();
if (og && !g) {
return 1;
} else if (!og && g) {
return -1;
} else {
return o1.getName().compareTo(o2.getName());
}
}
}
@@ -0,0 +1,85 @@
/*
* 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.rt.engine.local;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.05.2007
*/
public class VariableImpl implements Debugger.Variable {
private final boolean myGlobal;
private final Kind myKind;
private final String myRealname;
private final Value myValue;
private final String myUri;
private final int myLineNumber;
public VariableImpl(String realname, Value value, boolean global, Kind kind, String uri, int lineNumber) {
myValue = value;
myRealname = realname;
myGlobal = global;
myKind = kind;
myUri = uri;
myLineNumber = lineNumber;
}
public String getURI() {
return myUri;
}
public int getLineNumber() {
return myLineNumber;
}
public String getName() {
return myRealname;
}
public Value getValue() {
return myValue;
}
public boolean isGlobal() {
return myGlobal;
}
public Kind getKind() {
return myKind;
}
@Override
public String toString() {
return (myGlobal ? "global:" : "") + "{" + myKind + ":" + myRealname + "=" + myValue + "}";
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final VariableImpl that = (VariableImpl)o;
return myRealname.equals(that.myRealname);
}
public int hashCode() {
return myRealname.hashCode();
}
}
@@ -0,0 +1,44 @@
/*
* 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.rt.engine.local.saxon;
import com.icl.saxon.om.NodeInfo;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.local.AbstractFrame;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 02.06.2007
*/
class AbstractSaxonFrame<F extends Debugger.Frame, N extends NodeInfo> extends AbstractFrame<F> {
protected final N myElement;
protected AbstractSaxonFrame(F prev, N element) {
super(prev);
myElement = element;
}
public int getLineNumber() {
return myElement.getLineNumber();
}
public String getURI() {
final String uri = myElement.getSystemId();
return uri != null ? uri.replaceAll(" ", "%20") : null;
}
}
@@ -0,0 +1,269 @@
/*
* 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.rt.engine.local.saxon;
import com.icl.saxon.Bindery;
import com.icl.saxon.Binding;
import com.icl.saxon.Context;
import com.icl.saxon.expr.*;
import com.icl.saxon.om.*;
import com.icl.saxon.output.GeneralOutputter;
import com.icl.saxon.style.ExpressionContext;
import com.icl.saxon.style.StyleElement;
import com.icl.saxon.style.XSLGeneralVariable;
import com.icl.saxon.style.XSLParam;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableComparator;
import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableImpl;
import org.w3c.dom.Node;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.05.2007
*/
class SaxonFrameImpl extends AbstractSaxonFrame<Debugger.StyleFrame, StyleElement> implements Debugger.StyleFrame {
private static Field fGeneralUseAllowed;
static {
try {
fGeneralUseAllowed = SingletonNodeSet.class.getDeclaredField("generalUseAllowed");
fGeneralUseAllowed.setAccessible(true);
} catch (NoSuchFieldException e) {
fGeneralUseAllowed = null;
System.err.println("Failed to get field com.icl.saxon.expr.SingletonNodeSet.generalUseAllowed - incompatible Saxon version?");
e.printStackTrace();
}
}
private final Context myContext;
private final int myFrameId;
SaxonFrameImpl(Debugger.StyleFrame prev, Context context, StyleElement element) {
super(prev, element);
myContext = context;
myFrameId = context.getBindery().getFrameId();
}
public String getInstruction() {
return myElement.getDisplayName();
}
public List<Debugger.Variable> getVariables() {
assert isValid();
final ArrayList<Debugger.Variable> variables = new ArrayList<Debugger.Variable>();
final Enumeration[] variableNames = myElement.getVariableNames();
this.addVariables(myElement, variables, variableNames[0], true);
this.addVariables(myElement, variables, variableNames[1], false);
Collections.sort(variables, VariableComparator.INSTANCE);
return variables;
}
public Value eval(String expr) throws Debugger.EvaluationException {
assert isValid();
try {
// trick to avoid exception when evaluating variable references on xsl:template frames
final MyDummyElement dummy = new MyDummyElement(myElement);
final Expression expression = Expression.make(expr, dummy.getStaticContext());
return convertValue(expression.evaluate(myContext));
} catch (XPathException e) {
throw new Debugger.EvaluationException(e.getMessage());
}
}
private Value convertValue(com.icl.saxon.expr.Value v) throws XPathException {
return MyValue.create(v, myContext);
}
void addVariables(StyleElement element, ArrayList<Debugger.Variable> variables, Enumeration enumeration, boolean isGlobal) {
final Context context = myContext;
final StaticContext ctx = context.getStaticContext();
final NamePool pool = element.getNamePool();
final Bindery bindery = context.getBindery();
while (enumeration.hasMoreElements()) {
String name = (String)enumeration.nextElement();
try {
final String[] parts = name.split("\\^");
final String realname = parts[1];
final int fingerprint = ctx != null ? ctx.getFingerprint(realname, false) : pool.getFingerprint(parts[0], realname);
final Binding binding = element.getVariableBinding(fingerprint);
final Debugger.Variable.Kind kind =
binding instanceof XSLParam ? Debugger.Variable.Kind.PARAMETER : Debugger.Variable.Kind.VARIABLE;
final com.icl.saxon.expr.Value value = bindery.getValue(binding, myFrameId);
if (binding instanceof XSLGeneralVariable) {
final XSLGeneralVariable v = (XSLGeneralVariable)binding;
final String id = v.getSystemId();
variables.add(new VariableImpl(realname, convertValue(value), isGlobal, kind, id != null ? id.replaceAll(" ", "%20") : null,
v.getLineNumber()));
} else {
variables.add(new VariableImpl(realname, convertValue(value), isGlobal, kind, null, -1));
}
} catch (XPathException e) {
// this should never happen I guess...
e.printStackTrace();
}
}
}
private static class MyValue implements Value {
private final Object myValue;
private final Type myType;
public MyValue(Object value, String type) {
myValue = value;
myType = new ObjectType(type);
}
public MyValue(Object value, int type) {
myValue = value;
myType = mapType(type);
}
public Object getValue() {
return myValue;
}
public Type getType() {
return myType;
}
private static Type mapType(int type) {
switch (type) {
case com.icl.saxon.expr.Value.BOOLEAN:
return XPathType.BOOLEAN;
case com.icl.saxon.expr.Value.NODESET:
return XPathType.NODESET;
case com.icl.saxon.expr.Value.NUMBER:
return XPathType.NUMBER;
case com.icl.saxon.expr.Value.STRING:
return XPathType.STRING;
case com.icl.saxon.expr.Value.OBJECT:
return XPathType.OBJECT;
default:
return XPathType.UNKNOWN;
}
}
public static Value create(com.icl.saxon.expr.Value v, Context context) throws XPathException {
if (v instanceof NodeSetValue) {
if (v instanceof FragmentValue) {
final FragmentValue value = (FragmentValue)v;
final boolean b = value.isGeneralUseAllowed();
try {
if (!b) value.allowGeneralUse();
final DocumentInfo node = value.getRootNode();
final GeneralOutputter outputter = new GeneralOutputter(node.getNamePool());
final StringWriter writer = new StringWriter();
final Properties props = new Properties();
props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
outputter.setOutputDestination(props, new StreamResult(writer));
node.copy(outputter);
return new MyValue(writer.toString(), v.getDataType());
} catch (TransformerException e) {
return new MyValue(v.asString(), v.getDataType());
} finally {
if (!b && fGeneralUseAllowed != null) {
resetGeneralUseAllowed(value);
}
}
} else if (v instanceof TextFragmentValue) {
// this really is just a string
return new MyValue(v.asString(), com.icl.saxon.expr.Value.STRING);
}
final List<Node> list = new ArrayList<Node>();
final NodeEnumeration nodeEnumeration = ((NodeSetValue)v).enumerate();
while (nodeEnumeration.hasMoreElements()) {
final NodeInfo node = nodeEnumeration.nextElement();
final String path = Navigator.getPath(node);
final String id = node.getSystemId();
if (id != null) {
try {
list.add(new Node(new URI(id.replaceAll(" ", "%20")).normalize().toASCIIString(), node.getLineNumber(), path,
node.getStringValue()));
} catch (URISyntaxException e) {
e.printStackTrace();
list.add(new Node(id, node.getLineNumber(), path, node.getStringValue()));
}
} else {
list.add(new Node(null, -1, path, node.getStringValue()));
}
}
return new MyValue(new NodeSet(v.asString(), list), v.getDataType());
} else if (v instanceof ObjectValue) {
final Object o = ((ObjectValue)v).getObject();
return new MyValue(o, o != null ? o.getClass().getName() : "null");
} else {
return new MyValue(v.evaluateAsString(context), v.getDataType());
}
}
}
private static void resetGeneralUseAllowed(FragmentValue value) {
try {
fGeneralUseAllowed.set(value, false);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static class MyDummyElement extends StyleElement {
private final StyleElement myElement;
public MyDummyElement(StyleElement element) {
myElement = element;
substituteFor(element);
}
public void prepareAttributes() throws TransformerConfigurationException {
}
public void process(Context context) throws TransformerException {
}
public StaticContext getStaticContext() {
return new ExpressionContext(this);
}
@Override
public Node getPreviousSibling() {
return myElement.getPreviousSibling();
}
}
}
@@ -0,0 +1,36 @@
/*
* 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.rt.engine.local.saxon;
import com.icl.saxon.om.Navigator;
import com.icl.saxon.om.NodeInfo;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 03.06.2007
*/
class SaxonSourceFrame extends AbstractSaxonFrame<Debugger.SourceFrame, NodeInfo> implements Debugger.SourceFrame {
public SaxonSourceFrame(Debugger.SourceFrame prev, NodeInfo element) {
super(prev, element);
}
public String getXPath() {
return Navigator.getPath(myElement);
}
}
@@ -0,0 +1,30 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.saxon;
import com.icl.saxon.Controller;
import com.icl.saxon.TransformerFactoryImpl;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 12.01.2009
*/
public class SaxonSupport {
public static boolean init(Transformer transformer, LocalDebugger dbg) {
if (transformer instanceof Controller) {
System.out.println("SAXON");
final Controller controller = (Controller)transformer;
controller.setLineNumbering(true);
controller.addTraceListener(new SaxonTraceListener(dbg, controller));
return true;
}
return false;
}
public static TransformerFactory createTransformerFactory() {
return new TransformerFactoryImpl();
}
}
@@ -0,0 +1,242 @@
/*
* 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.rt.engine.local.saxon;
import com.icl.saxon.Context;
import com.icl.saxon.Controller;
import com.icl.saxon.Mode;
import com.icl.saxon.NodeHandler;
import com.icl.saxon.om.NamePool;
import com.icl.saxon.om.Navigator;
import com.icl.saxon.om.NodeInfo;
import com.icl.saxon.output.Emitter;
import com.icl.saxon.output.GeneralOutputter;
import com.icl.saxon.style.StyleElement;
import com.icl.saxon.trace.TraceListener;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import org.intellij.plugins.xsltDebugger.rt.engine.local.OutputEventQueueImpl;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerException;
import java.lang.reflect.Field;
import java.util.Properties;
/**
* A Simple trace listener that writes messages to System.err
*/
public class SaxonTraceListener implements TraceListener {
private static final boolean TRACE = "true".equals(System.getProperty("xslt.debugger.trace", "false"));
private String indent = "";
private final LocalDebugger myDebugger;
private final Controller myController;
private boolean myIsInitialized;
public SaxonTraceListener(LocalDebugger debugger, Controller controller) {
myDebugger = debugger;
myController = controller;
}
/**
* Called at start
*/
public void open() {
myDebugger.getEventQueue().startDocument();
if (TRACE) {
trace("<trace>");
}
}
private static void trace(String s) {
if (TRACE) {
System.err.println(s);
}
}
/**
* Called at end
*/
public void close() {
myDebugger.getEventQueue().endDocument();
// myDebugger.stopped();
if (TRACE) {
trace("</trace>");
}
}
/**
* Called for all top level elements
*/
public void toplevel(NodeInfo element) {
if (!myIsInitialized) {
myIsInitialized = true;
final Properties properties = myController.getOutputProperties();
final String method = properties.getProperty(OutputKeys.METHOD);
if (method == null || "xml".equals(method) || "html".equals(method)) {
try {
final Emitter emitter = myController.getOutputter().getEmitter();
final GeneralOutputter outputter = new TracingOutputter(emitter, myController.getNamePool());
final Field fOutputter = Controller.class.getDeclaredField("currentOutputter");
fOutputter.setAccessible(true);
fOutputter.set(myController, outputter);
} catch (Exception e1) {
System.err.println("Failed to change output emitter");
e1.printStackTrace();
}
}
}
if (TRACE) {
StyleElement e = (StyleElement)element;
trace("<Top-level element=\"" + e.getDisplayName() + "\" line=\"" + e.getLineNumber() +
"\" file=\"" + e.getSystemId() + "\" precedence=\"" + e.getPrecedence() + "\"/>");
}
}
/**
* Called when a node of the source tree gets processed
*/
public void enterSource(NodeHandler handler, Context context) {
NodeInfo curr = context.getContextNodeInfo();
final String path = Navigator.getPath(curr);
if (TRACE) {
trace(indent + "<Source node=\"" + path
+ "\" line=\"" + curr.getLineNumber()
+ "\" mode=\"" + getModeName(context) + "\">");
indent += " ";
}
myDebugger.pushSource(new SaxonSourceFrame(myDebugger.getSourceFrame(), curr));
}
/**
* Called after a node of the source tree got processed
*/
public void leaveSource(NodeHandler handler, Context context) {
if (TRACE) {
indent = indent.substring(0, indent.length() - 1);
trace(indent + "</Source><!-- " +
Navigator.getPath(context.getContextNodeInfo()) + " -->");
}
myDebugger.popSource();
}
/**
* Called when an element of the stylesheet gets processed
*/
public void enter(NodeInfo element, Context context) {
if (element.getNodeType() == NodeInfo.ELEMENT) {
if (TRACE) {
trace(indent + "<Instruction element=\"" + element.getDisplayName() + "\" line=\"" + element.getLineNumber() + "\">");
indent += " ";
}
myDebugger.enter(new SaxonFrameImpl(myDebugger.getCurrentFrame(), context, (StyleElement)element));
}
}
/**
* Called after an element of the stylesheet got processed
*/
public void leave(NodeInfo element, Context context) {
if (element.getNodeType() == NodeInfo.ELEMENT) {
// final int lineNumber = element.getLineNumber();
// final String uri = element.getSystemId();
myDebugger.leave();
if (TRACE) {
indent = indent.substring(0, indent.length() - 1);
trace(indent + "</Instruction> <!-- " +
element.getDisplayName() + " -->");
}
}
}
static String getModeName(Context context) {
Mode mode = context.getMode();
if (mode == null) return "#none";
int nameCode = mode.getNameCode();
if (nameCode == -1) {
return "#default";
} else {
return context.getController().getNamePool().getDisplayName(nameCode);
}
}
private final class TracingOutputter extends GeneralOutputter {
private final NamePool myNamePool;
private final OutputEventQueueImpl myEventQueue;
public TracingOutputter(Emitter emitter, NamePool namePool) {
super(namePool);
this.emitter = emitter;
myNamePool = namePool;
myEventQueue = myDebugger.getEventQueue();
}
public void writeAttribute(int nameCode, String value, boolean noEscape) throws TransformerException {
if (myEventQueue.isEnabled()) {
final String localName = myNamePool.getLocalName(nameCode);
final String prefix = myNamePool.getPrefix(nameCode);
myEventQueue.attribute(prefix, localName, myNamePool.getURI(nameCode), value);
}
super.writeAttribute(nameCode, value, noEscape);
}
public void writeComment(String comment) throws TransformerException {
myEventQueue.comment(comment);
super.writeComment(comment);
}
public void writeContent(char[] chars, int start, int length) throws TransformerException {
myEventQueue.characters(new String(chars, start, length));
super.writeContent(chars, start, length);
}
public void writeContent(StringBuffer chars, int start, int len) throws TransformerException {
myEventQueue.characters(chars.substring(start, start + len));
super.writeContent(chars, start, len);
}
public void writeEndTag(int nameCode) throws TransformerException {
myEventQueue.endElement();
super.writeEndTag(nameCode);
}
public void writePI(String target, String data) throws TransformerException {
myEventQueue.pi(target, data);
super.writePI(target, data);
}
public void writeStartTag(int nameCode) throws TransformerException {
if (myEventQueue.isEnabled()) {
final String localName = myNamePool.getLocalName(nameCode);
final String prefix = myNamePool.getPrefix(nameCode);
myEventQueue.startElement(prefix, localName, myNamePool.getURI(nameCode));
}
super.writeStartTag(nameCode);
}
}
}
@@ -0,0 +1,30 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.saxon9;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.local.AbstractFrame;
import javax.xml.transform.Source;
import javax.xml.transform.SourceLocator;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 04.05.11
*/
class AbstractSaxon9Frame<F extends Debugger.Frame, N extends Source> extends AbstractFrame<F> {
protected final N myElement;
protected AbstractSaxon9Frame(F prev, N element) {
super(prev);
myElement = element;
}
public int getLineNumber() {
return ((SourceLocator)myElement).getLineNumber();
}
public String getURI() {
final String uri = myElement.getSystemId();
return uri != null ? uri.replaceAll(" ", "%20") : null;
}
}
@@ -0,0 +1,38 @@
/*
* 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.rt.engine.local.saxon9;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.tree.util.Navigator;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 02.06.2007
*/
class Saxon9SourceFrame<N extends NodeInfo> extends AbstractSaxon9Frame<Debugger.SourceFrame, N> implements Debugger.SourceFrame {
protected Saxon9SourceFrame(Debugger.SourceFrame prev, N element) {
super(prev, element);
}
public String getXPath() {
return Navigator.getPath(myElement);
}
}
@@ -0,0 +1,98 @@
/*
* 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.rt.engine.local.saxon9;
import net.sf.saxon.expr.StackFrame;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.expr.instruct.SlotManager;
import net.sf.saxon.om.ValueRepresentation;
import net.sf.saxon.style.StyleElement;
import net.sf.saxon.trans.XPathException;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableImpl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 02.06.2007
*/
class Saxon9StyleFrame<N extends StyleElement> extends AbstractSaxon9Frame<Debugger.StyleFrame, N> implements Debugger.StyleFrame {
private final XPathContext myXPathContext;
private final StackFrame myStackFrame;
protected Saxon9StyleFrame(Debugger.StyleFrame prev, N element, XPathContext xPathContext) {
super(prev, element);
myXPathContext = xPathContext;
myStackFrame = myXPathContext.getStackFrame();
}
public String getInstruction() {
return myElement.getDisplayName();
}
public Value eval(String expr) throws Debugger.EvaluationException {
return null;
}
public List<Debugger.Variable> getVariables() {
final ArrayList<Debugger.Variable> variables = new ArrayList<Debugger.Variable>();
XPathContext context = myXPathContext;
while (context != null) {
final StackFrame frame = context.getStackFrame();
final SlotManager map = frame.getStackFrameMap();
final int numberOfVariables = map.getNumberOfVariables();
System.out.println("numberOfVariables = " + numberOfVariables);
for (int i = 0; i < numberOfVariables; i++) {
final ValueRepresentation valueRepresentation = context.evaluateLocalVariable(i);
System.out.println("valueRepresentation = " + valueRepresentation);
}
final ValueRepresentation[] values = frame.getStackFrameValues();
System.out.println("values = " + Arrays.toString(values));
for (int i = 0, valuesLength = values.length; i < valuesLength; i++) {
final ValueRepresentation value = values[i];
variables.add(new VariableImpl(map.getVariableMap().get(i).getDisplayName(), new Value() {
public Object getValue() {
try {
return value.getStringValue();
} catch (XPathException e) {
return " - error: " + e.getMessage() + " - ";
}
}
public Type getType() {
return XPathType.UNKNOWN;
}
}, false, Debugger.Variable.Kind.VARIABLE, "", -1));
}
context = context.getCaller();
System.out.println("context = " + context);
}
return variables;
}
}
@@ -0,0 +1,72 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.saxon9;
import net.sf.saxon.Controller;
import net.sf.saxon.TransformerFactoryImpl;
import net.sf.saxon.event.PipelineConfiguration;
import net.sf.saxon.event.ProxyReceiver;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.expr.instruct.Debugger;
import net.sf.saxon.expr.instruct.SlotManager;
import net.sf.saxon.lib.FeatureKeys;
import net.sf.saxon.lib.SerializerFactory;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.serialize.CharacterMapExpander;
import net.sf.saxon.serialize.Emitter;
import net.sf.saxon.trans.XPathException;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import java.util.Properties;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 12.01.2009
*/
public class Saxon9Support {
public static boolean init(Transformer transformer, final LocalDebugger dbg) {
if (transformer instanceof Controller) {
System.out.println("SAXON 9");
final Controller controller = (Controller)transformer;
((Saxon9TraceListener)controller.getConfiguration().getTraceListener()).setDebugger(dbg);
controller.getConfiguration().setLineNumbering(true);
controller.getConfiguration().setCompileWithTracing(true);
controller.getConfiguration().setMultiThreading(false);
controller.getConfiguration().setSerializerFactory(new SerializerFactory(controller.getConfiguration()) {
@Override
protected Receiver createXMLSerializer(Emitter emitter,
Properties props,
PipelineConfiguration pipe,
CharacterMapExpander characterMapExpander,
ProxyReceiver normalizer) throws XPathException {
return super.createXMLSerializer(emitter, props, pipe, characterMapExpander, normalizer);
}
@Override
protected Emitter newXMLEmitter() {
return new TracingOutputter(dbg.getEventQueue(), super.newXMLEmitter());
}
});
controller.getConfiguration().setDebugger(new Debugger() {
public SlotManager makeSlotManager() {
return new SlotManager() {
@Override
public int allocateSlotNumber(StructuredQName qName) {
System.out.println("qName = " + qName);
return super.allocateSlotNumber(qName);
}
};
}
});
return true;
}
return false;
}
public static TransformerFactory createTransformerFactory() {
final TransformerFactoryImpl factory = new TransformerFactoryImpl();
factory.setAttribute(FeatureKeys.TRACE_LISTENER, new Saxon9TraceListener());
return factory;
}
}
@@ -0,0 +1,90 @@
/*
* 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.rt.engine.local.saxon9;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.TraceListener;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.style.StyleElement;
import net.sf.saxon.trace.InstructionInfo;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
public class Saxon9TraceListener implements TraceListener {
private static final boolean TRACE = "true".equals(System.getProperty("xslt.debugger.trace", "false"));
private LocalDebugger myDebugger;
public Saxon9TraceListener() {
}
public void setDebugger(LocalDebugger debugger) {
myDebugger = debugger;
}
private static void trace(String s) {
if (TRACE) {
System.err.println(s);
}
}
public void open() {
myDebugger.getEventQueue().startDocument();
if (TRACE) {
trace("<trace>");
}
}
public void close() {
myDebugger.getEventQueue().endDocument();
if (TRACE) {
trace("</trace>");
}
}
public void enter(InstructionInfo instructionInfo, XPathContext xPathContext) {
if (TRACE) {
trace("<" + instructionInfo + ">");
}
if (instructionInfo instanceof StyleElement) {
myDebugger.enter(new Saxon9StyleFrame(myDebugger.getCurrentFrame(), (StyleElement)instructionInfo, xPathContext));
}
}
public void leave(InstructionInfo instructionInfo) {
if (TRACE) {
trace("</>");
}
if (instructionInfo instanceof StyleElement) {
myDebugger.leave();
}
}
public void startCurrentItem(Item item) {
if (item instanceof NodeInfo) {
if (TRACE) {
trace("<" + ((NodeInfo)item).getDisplayName() + ">");
}
myDebugger.pushSource(new Saxon9SourceFrame(myDebugger.getSourceFrame(), (NodeInfo)item));
}
}
public void endCurrentItem(Item item) {
myDebugger.popSource();
}
}
@@ -0,0 +1,124 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.saxon9;
import net.sf.saxon.event.PipelineConfiguration;
import net.sf.saxon.serialize.Emitter;
import net.sf.saxon.trans.XPathException;
import org.intellij.plugins.xsltDebugger.rt.engine.local.OutputEventQueueImpl;
import javax.xml.transform.stream.StreamResult;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Properties;
final class TracingOutputter extends Emitter {
private final OutputEventQueueImpl myEventQueue;
private final Emitter myEmitter;
public TracingOutputter(OutputEventQueueImpl queue, Emitter emitter) {
myEmitter = emitter;
myEventQueue = queue;
}
@Override
public void setPipelineConfiguration(PipelineConfiguration pipe) {
super.setPipelineConfiguration(pipe);
myEmitter.setPipelineConfiguration(pipe);
}
@Override
public void setSystemId(String systemId) {
myEmitter.setSystemId(systemId);
}
@Override
public void setOutputProperties(Properties details) throws XPathException {
myEmitter.setOutputProperties(details);
}
@Override
public void setStreamResult(StreamResult result) throws XPathException {
myEmitter.setStreamResult(result);
}
@Override
public void setWriter(Writer writer) throws XPathException {
myEmitter.setWriter(writer);
}
@Override
public void setOutputStream(OutputStream stream) throws XPathException {
myEmitter.setOutputStream(stream);
}
@Override
public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException {
myEmitter.setUnparsedEntity(name, uri, publicId);
}
public void open() throws XPathException {
myEmitter.open();
}
public void startDocument(int properties) throws XPathException {
myEmitter.startDocument(properties);
}
public void endDocument() throws XPathException {
myEmitter.endDocument();
}
public void namespace(int namespaceCode, int properties) throws XPathException {
myEmitter.namespace(namespaceCode, properties);
}
@Override
public void close() throws XPathException {
myEmitter.close();
}
public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException {
if (myEventQueue.isEnabled()) {
final String localName = namePool.getLocalName(nameCode);
final String prefix = namePool.getPrefix(nameCode);
myEventQueue.startElement(prefix, localName, namePool.getURI(nameCode));
}
myEmitter.startElement(nameCode, typeCode, locationId, properties);
}
public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException {
if (myEventQueue.isEnabled()) {
final String localName = namePool.getLocalName(nameCode);
final String prefix = namePool.getPrefix(nameCode);
myEventQueue.attribute(prefix, localName, namePool.getURI(nameCode), value.toString());
}
myEmitter.attribute(nameCode, typeCode, value, locationId, properties);
}
public void startContent() throws XPathException {
}
public void endElement() throws XPathException {
myEventQueue.endElement();
myEmitter.endElement();
}
public void characters(CharSequence chars, int locationId, int properties) throws XPathException {
myEventQueue.characters(chars.toString());
myEmitter.characters(chars, locationId, properties);
}
public void processingInstruction(String name, CharSequence data, int locationId, int properties) throws XPathException {
myEventQueue.pi(name, data.toString());
myEmitter.processingInstruction(name, data, locationId, properties);
}
public void comment(CharSequence content, int locationId, int properties) throws XPathException {
myEventQueue.comment(content.toString());
myEmitter.comment(content, locationId, properties);
}
public boolean usesTypeAnnotations() {
return false;
}
}
@@ -0,0 +1,397 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.xalan;
import org.apache.xml.serializer.DOMSerializer;
import org.apache.xml.serializer.NamespaceMappings;
import org.apache.xml.serializer.SerializationHandler;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import org.w3c.dom.Node;
import org.xml.sax.*;
import javax.xml.transform.SourceLocator;
import javax.xml.transform.Transformer;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Properties;
import java.util.Vector;
class TracingSerializationHandler implements SerializationHandler {
private final LocalDebugger myDebugger;
private final SerializationHandler mySerializationHandler;
public TracingSerializationHandler(LocalDebugger debugger, SerializationHandler handler) {
myDebugger = debugger;
mySerializationHandler = handler;
// final URL location = SerializationHandler.class.getProtectionDomain().getCodeSource().getLocation();
// System.out.println("location = " + location);
}
private static String calcPrefix(String qname) {
return qname.indexOf(':') == -1 ? "" : qname.split(":")[0];
}
public void setContentHandler(ContentHandler ch) {
mySerializationHandler.setContentHandler(ch);
}
public void close() {
mySerializationHandler.close();
}
public void serialize(Node node) throws IOException {
mySerializationHandler.serialize(node);
}
public boolean setEscaping(boolean escape) throws SAXException {
return mySerializationHandler.setEscaping(escape);
}
public void setIndentAmount(int spaces) {
mySerializationHandler.setIndentAmount(spaces);
}
public void setTransformer(Transformer transformer) {
mySerializationHandler.setTransformer(transformer);
}
public Transformer getTransformer() {
return mySerializationHandler.getTransformer();
}
public void setNamespaceMappings(NamespaceMappings mappings) {
mySerializationHandler.setNamespaceMappings(mappings);
}
public void flushPending() throws SAXException {
mySerializationHandler.flushPending();
}
public void setDTDEntityExpansion(boolean expand) {
mySerializationHandler.setDTDEntityExpansion(expand);
}
public void addAttribute(String uri, String localName, String rawName, String type, String value, boolean XSLAttribute)
throws SAXException {
myDebugger.getEventQueue().attribute(calcPrefix(rawName), localName, uri, value);
mySerializationHandler.addAttribute(uri, localName, rawName, type, value, XSLAttribute);
}
public void addAttribute(String uri, String localName, String rawName, String type, String value) throws SAXException {
myDebugger.getEventQueue().attribute("", localName, uri, value);
mySerializationHandler.addAttribute(uri, localName, rawName, type, value);
}
public void addAttributes(Attributes atts) throws SAXException {
mySerializationHandler.addAttributes(atts);
}
public void addAttribute(String qName, String value) {
mySerializationHandler.addAttribute(qName, value);
}
public void characters(String chars) throws SAXException {
mySerializationHandler.characters(chars);
}
public void characters(Node node) throws SAXException {
mySerializationHandler.characters(node);
}
public void endElement(String elemName) throws SAXException {
mySerializationHandler.endElement(elemName);
}
public void startElement(String uri, String localName, String qName) throws SAXException {
myDebugger.getEventQueue().startElement(calcPrefix(qName), localName, uri);
mySerializationHandler.startElement(uri, localName, qName);
}
public void startElement(String qName) throws SAXException {
mySerializationHandler.startElement(qName);
}
public void namespaceAfterStartElement(String uri, String prefix) throws SAXException {
mySerializationHandler.namespaceAfterStartElement(uri, prefix);
}
public boolean startPrefixMapping(String prefix, String uri, boolean shouldFlush) throws SAXException {
return mySerializationHandler.startPrefixMapping(prefix, uri, shouldFlush);
}
public void entityReference(String entityName) throws SAXException {
mySerializationHandler.entityReference(entityName);
}
public NamespaceMappings getNamespaceMappings() {
return mySerializationHandler.getNamespaceMappings();
}
public String getPrefix(String uri) {
return mySerializationHandler.getPrefix(uri);
}
public String getNamespaceURI(String name, boolean isElement) {
return mySerializationHandler.getNamespaceURI(name, isElement);
}
public String getNamespaceURIFromPrefix(String prefix) {
return mySerializationHandler.getNamespaceURIFromPrefix(prefix);
}
public void setSourceLocator(SourceLocator locator) {
mySerializationHandler.setSourceLocator(locator);
}
public void addUniqueAttribute(String qName, String value, int flags) throws SAXException {
mySerializationHandler.addUniqueAttribute(qName, value, flags);
}
public void addXSLAttribute(String qName, String value, String uri) {
mySerializationHandler.addXSLAttribute(qName, value, uri);
}
public void setDocumentLocator(Locator locator) {
mySerializationHandler.setDocumentLocator(locator);
}
public void startDocument() throws SAXException {
mySerializationHandler.startDocument();
}
public void endDocument() throws SAXException {
mySerializationHandler.endDocument();
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
mySerializationHandler.startPrefixMapping(prefix, uri);
}
public void endPrefixMapping(String prefix) throws SAXException {
mySerializationHandler.endPrefixMapping(prefix);
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
mySerializationHandler.startElement(uri, localName, qName, atts);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
mySerializationHandler.endElement(uri, localName, qName);
}
public void characters(char[] ch, int start, int length) throws SAXException {
mySerializationHandler.characters(ch, start, length);
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
mySerializationHandler.ignorableWhitespace(ch, start, length);
}
public void processingInstruction(String target, String data) throws SAXException {
mySerializationHandler.processingInstruction(target, data);
}
public void skippedEntity(String name) throws SAXException {
mySerializationHandler.skippedEntity(name);
}
public void comment(String comment) throws SAXException {
mySerializationHandler.comment(comment);
}
public void startDTD(String name, String publicId, String systemId) throws SAXException {
mySerializationHandler.startDTD(name, publicId, systemId);
}
public void endDTD() throws SAXException {
mySerializationHandler.endDTD();
}
public void startEntity(String name) throws SAXException {
mySerializationHandler.startEntity(name);
}
public void endEntity(String name) throws SAXException {
mySerializationHandler.endEntity(name);
}
public void startCDATA() throws SAXException {
mySerializationHandler.startCDATA();
}
public void endCDATA() throws SAXException {
mySerializationHandler.endCDATA();
}
public void comment(char[] ch, int start, int length) throws SAXException {
mySerializationHandler.comment(ch, start, length);
}
public String getDoctypePublic() {
return mySerializationHandler.getDoctypePublic();
}
public String getDoctypeSystem() {
return mySerializationHandler.getDoctypeSystem();
}
public String getEncoding() {
return mySerializationHandler.getEncoding();
}
public boolean getIndent() {
return mySerializationHandler.getIndent();
}
public int getIndentAmount() {
return mySerializationHandler.getIndentAmount();
}
public String getMediaType() {
return mySerializationHandler.getMediaType();
}
public boolean getOmitXMLDeclaration() {
return mySerializationHandler.getOmitXMLDeclaration();
}
public String getStandalone() {
return mySerializationHandler.getStandalone();
}
public String getVersion() {
return mySerializationHandler.getVersion();
}
public void setCdataSectionElements(Vector URI_and_localNames) {
mySerializationHandler.setCdataSectionElements(URI_and_localNames);
}
public void setDoctype(String system, String pub) {
mySerializationHandler.setDoctype(system, pub);
}
public void setDoctypePublic(String doctype) {
mySerializationHandler.setDoctypePublic(doctype);
}
public void setDoctypeSystem(String doctype) {
mySerializationHandler.setDoctypeSystem(doctype);
}
public void setEncoding(String encoding) {
mySerializationHandler.setEncoding(encoding);
}
public void setIndent(boolean indent) {
mySerializationHandler.setIndent(indent);
}
public void setMediaType(String mediatype) {
mySerializationHandler.setMediaType(mediatype);
}
public void setOmitXMLDeclaration(boolean b) {
mySerializationHandler.setOmitXMLDeclaration(b);
}
public void setStandalone(String standalone) {
mySerializationHandler.setStandalone(standalone);
}
public void setVersion(String version) {
mySerializationHandler.setVersion(version);
}
public String getOutputProperty(String name) {
return mySerializationHandler.getOutputProperty(name);
}
public String getOutputPropertyDefault(String name) {
return mySerializationHandler.getOutputPropertyDefault(name);
}
public void setOutputProperty(String name, String val) {
mySerializationHandler.setOutputProperty(name, val);
}
public void setOutputPropertyDefault(String name, String val) {
mySerializationHandler.setOutputPropertyDefault(name, val);
}
public void elementDecl(String name, String model) throws SAXException {
mySerializationHandler.elementDecl(name, model);
}
public void attributeDecl(String eName, String aName, String type, String mode, String value) throws SAXException {
mySerializationHandler.attributeDecl(eName, aName, type, mode, value);
}
public void internalEntityDecl(String name, String value) throws SAXException {
mySerializationHandler.internalEntityDecl(name, value);
}
public void externalEntityDecl(String name, String publicId, String systemId) throws SAXException {
mySerializationHandler.externalEntityDecl(name, publicId, systemId);
}
public void notationDecl(String name, String publicId, String systemId) throws SAXException {
mySerializationHandler.notationDecl(name, publicId, systemId);
}
public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
mySerializationHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
}
public void warning(SAXParseException exception) throws SAXException {
mySerializationHandler.warning(exception);
}
public void error(SAXParseException exception) throws SAXException {
mySerializationHandler.error(exception);
}
public void fatalError(SAXParseException exception) throws SAXException {
mySerializationHandler.fatalError(exception);
}
public void setOutputStream(OutputStream output) {
mySerializationHandler.setOutputStream(output);
}
public OutputStream getOutputStream() {
return mySerializationHandler.getOutputStream();
}
public void setWriter(Writer writer) {
mySerializationHandler.setWriter(writer);
}
public Writer getWriter() {
return mySerializationHandler.getWriter();
}
public void setOutputFormat(Properties format) {
mySerializationHandler.setOutputFormat(format);
}
public Properties getOutputFormat() {
return mySerializationHandler.getOutputFormat();
}
public ContentHandler asContentHandler() throws IOException {
return mySerializationHandler.asContentHandler();
}
public DOMSerializer asDOMSerializer() throws IOException {
return mySerializationHandler.asDOMSerializer();
}
public boolean reset() {
return mySerializationHandler.reset();
}
public Object asDOM3Serializer() throws IOException {
return mySerializationHandler.asDOM3Serializer();
}
}
@@ -0,0 +1,80 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.xalan;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xml.dtm.ref.DTMNodeIterator;
import org.apache.xml.serializer.ToXMLStream;
import org.apache.xpath.objects.XNodeSet;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XRTreeFrag;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import javax.xml.transform.SourceLocator;
import javax.xml.transform.TransformerException;
import java.io.StringWriter;
import java.util.ArrayList;
class XObjectValue implements Value {
private String myTypeString;
private Object myValue;
public XObjectValue(XObject value) {
try {
if (value != null) {
myTypeString = value.getTypeString().replaceAll("#", "");
} else {
myTypeString = "undefined";
}
if (value instanceof XNodeSet) {
final ArrayList<Node> nodes = new ArrayList<Node>();
final DTMIterator v = value.mutableNodeset();
for (int i = 0; i < v.getLength(); i++) {
final int p = v.item(i);
final DTM dtm = v.getDTM(p);
if (dtm == null) continue;
final SourceLocator loc = dtm.getSourceLocatorFor(p);
nodes.add(new Node(loc != null ? loc.getSystemId() : null, loc != null ? loc.getLineNumber() : -1, XalanSupport.getPath(dtm, p),
dtm.getStringValue(p).toString()));
}
myValue = new NodeSet(value.str(), nodes);
} else if (value instanceof XRTreeFrag) {
final org.w3c.dom.Node node = ((DTMNodeIterator)value.object()).nextNode();
if (node == null) {
myValue = "";
} else {
try {
final ToXMLStream stream = new ToXMLStream();
final StringWriter writer = new StringWriter();
stream.setWriter(writer);
stream.setOmitXMLDeclaration(true);
stream.serialize(node);
myValue = writer.toString();
} catch (Exception e) {
e.printStackTrace();
myValue = "???";
}
}
} else if (value != null) {
myValue = value.object();
}
} catch (TransformerException e) {
myTypeString = "UNKNOWN";
}
}
public Object getValue() {
return myValue;
}
public Type getType() {
try {
return XPathType.valueOf(myTypeString.toUpperCase());
} catch (IllegalArgumentException e) {
return new ObjectType(myTypeString);
}
}
}
@@ -0,0 +1,182 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.xalan;
import org.apache.xalan.templates.ElemLiteralResult;
import org.apache.xalan.templates.ElemParam;
import org.apache.xalan.templates.ElemTemplateElement;
import org.apache.xalan.templates.ElemVariable;
import org.apache.xalan.trace.TracerEvent;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xml.dtm.ref.DTMNodeProxy;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xml.utils.PrefixResolverDefault;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import org.intellij.plugins.xsltDebugger.rt.engine.local.AbstractFrame;
import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableComparator;
import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableImpl;
import org.w3c.dom.Node;
import javax.xml.transform.TransformerException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
class XalanStyleFrame extends AbstractFrame<Debugger.StyleFrame> implements Debugger.StyleFrame {
private final boolean myWithSourceFrame;
private final TransformerImpl myTransformer;
private final ElemTemplateElement myCurrentElement;
private final XPathContext myContext;
private final int myCurrentNode;
private final int myLineNumber;
private final String myURI;
private final String myInstr;
public XalanStyleFrame(TracerEvent ev, Debugger.StyleFrame currentFrame, boolean withSourceFrame) {
super(currentFrame);
myWithSourceFrame = withSourceFrame;
myInstr = getInstruction(ev.m_styleNode);
myLineNumber = ev.m_styleNode.getLineNumber();
if (ev.m_styleNode.getSystemId() != null) {
myURI = ev.m_styleNode.getSystemId();
} else if (currentFrame != null && currentFrame.getURI() != null) {
myURI = currentFrame.getURI();
} else {
myURI = ev.m_processor.getStylesheet().getSystemId();
}
myTransformer = ev.m_processor;
myCurrentElement = myTransformer.getCurrentElement();
myContext = ev.m_processor.getXPathContext();
myCurrentNode = myContext.getCurrentNode();
}
private void addVariable(ElemVariable variable, boolean global, List<Debugger.Variable> variables) {
final Debugger.Variable.Kind kind = variable instanceof ElemParam ?
Debugger.Variable.Kind.PARAMETER : Debugger.Variable.Kind.VARIABLE;
assert global == variable.getIsTopLevel() : global + " vs. " + variable.getIsTopLevel() + " (" + variable.getName() + ")";
final String name = variable.getName().getLocalName();
try {
final Value value = new XObjectValue(variable.getValue(myTransformer, myCurrentNode));
variables.add(new VariableImpl(name, value, global, kind, variable.getSystemId(), variable.getLineNumber()));
} catch (TransformerException e) {
// TODO
e.printStackTrace();
}
}
public boolean isWithSourceFrame() {
return myWithSourceFrame;
}
public String getInstruction() {
return myInstr;
}
public List<Debugger.Variable> getVariables() {
return collectVariables();
}
private List<Debugger.Variable> collectVariables() {
List<Debugger.Variable> variables = new ArrayList<Debugger.Variable>();
@SuppressWarnings({ "unchecked" })
final Vector<ElemVariable> globals = myTransformer.getStylesheet().getVariablesAndParamsComposed();
for (ElemVariable variable : globals) {
addVariable(variable, true, variables);
}
ElemTemplateElement p = myCurrentElement;
while (p != null) {
ElemTemplateElement s = p;
while ((s = s.getPreviousSiblingElem()) != null) {
if (s instanceof ElemVariable) {
final ElemVariable variable = (ElemVariable)s;
if (variable.getIsTopLevel()) {
continue;
}
addVariable(variable, false, variables);
}
}
p = p.getParentElem();
}
Collections.sort(variables, VariableComparator.INSTANCE);
return variables;
}
public String getURI() {
return myURI;
}
public int getLineNumber() {
return myLineNumber;
}
public Value eval(String expr) throws Debugger.EvaluationException {
try {
final DTMIterator context = myTransformer.getContextNodeList();
final int ctx;
final DTM dtm = context.getDTM(myCurrentNode);
if (dtm.getDocumentRoot(myCurrentNode) == myCurrentNode) {
ctx = dtm.getFirstChild(myCurrentNode);
} else {
ctx = myCurrentNode;
}
final DTMNodeProxy c = new DTMNodeProxy(dtm, ctx);
final PrefixResolver prefixResolver = new PrefixResolverDefault(c) {
public String getNamespaceForPrefix(String prefix, Node context) {
if (context instanceof DTMNodeProxy) {
final DTMNodeProxy proxy = (DTMNodeProxy)context;
final DTM dtm = proxy.getDTM();
int p = proxy.getDTMNodeNumber();
while (p != DTM.NULL) {
int nsNode = dtm.getFirstNamespaceNode(p, true);
while (nsNode != DTM.NULL) {
final String s = dtm.getLocalName(nsNode);
if (s.equals(prefix)) {
return dtm.getNodeValue(nsNode);
}
nsNode = dtm.getNextNamespaceNode(p, nsNode, true);
}
p = dtm.getParent(p);
}
}
return super.getNamespaceForPrefix(prefix, context);
}
};
final XPath xPath = new XPath(expr, myCurrentElement, prefixResolver, XPath.SELECT, myTransformer.getErrorListener());
return new XObjectValue(xPath.execute(myContext, myCurrentNode, myCurrentElement));
} catch (Exception e) {
e.printStackTrace();
final String message = e.getMessage();
throw new Debugger.EvaluationException(message != null ? message : e.getClass().getSimpleName());
}
}
static String getInstruction(ElemTemplateElement node) {
final String name = node.getNodeName();
if (node instanceof ElemLiteralResult) {
return name;
} else if (name != null && name.indexOf(':') == -1) {
return "xsl:" + name;
}
return name;
}
}
@@ -0,0 +1,123 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.xalan;
import org.apache.xalan.processor.TransformerFactoryImpl;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xml.dtm.DTM;
import org.apache.xml.utils.DefaultErrorHandler;
import org.intellij.plugins.xsltDebugger.rt.engine.DebuggerStoppedException;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import org.w3c.dom.Node;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import java.util.TooManyListenersException;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 12.01.2009
*/
public class XalanSupport {
public static boolean init(Transformer transformer, LocalDebugger dbg) {
if (transformer instanceof TransformerImpl) {
try {
System.out.println("XALAN: " +
Class.forName("org.apache.xalan.Version", true, transformer.getClass().getClassLoader()).getMethod("getVersion")
.invoke(null));
final TransformerImpl tr = (TransformerImpl)transformer;
tr.setErrorListener(new DefaultErrorHandler(false) {
@Override
public void fatalError(TransformerException exception) throws TransformerException {
if (!(exception.getCause() instanceof DebuggerStoppedException)) {
super.fatalError(exception);
}
}
});
try {
tr.getTraceManager().addTraceListener(new XalanTraceListener(dbg, tr));
} catch (TooManyListenersException e) {
throw new AssertionError(e);
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
public static TransformerFactory createTransformerFactory() {
final TransformerFactoryImpl factory = new TransformerFactoryImpl();
prepareFactory(factory);
return factory;
}
public static TransformerFactory prepareFactory(TransformerFactory factory) {
try {
factory.setAttribute("http://xml.apache.org/xalan/properties/source-location", Boolean.TRUE);
factory.setAttribute("http://xml.apache.org/xalan/features/optimize", Boolean.FALSE);
} catch (Exception e) {
// ignore
}
return factory;
}
public static String getPath(DTM dtm, int node) {
String pre;
switch (dtm.getNodeType(node)) {
case Node.DOCUMENT_NODE:
return "/";
case Node.ELEMENT_NODE:
pre = getPath(dtm, dtm.getParent(node));
return (pre.equals("/") ? "" : pre) +
"/" + dtm.getNodeName(node) + "[" + getNumberSimple(dtm, node) + "]";
case Node.ATTRIBUTE_NODE:
return getPath(dtm, dtm.getParent(node)) + "/@" + dtm.getNodeNameX(node);
case Node.TEXT_NODE:
pre = getPath(dtm, dtm.getParent(node));
return (pre.equals("/") ? "" : pre) +
"/text()[" + getNumberSimple(dtm, node) + "]";
case Node.COMMENT_NODE:
pre = getPath(dtm, dtm.getParent(node));
return (pre.equals("/") ? "" : pre) +
"/comment()[" + getNumberSimple(dtm, node) + "]";
case Node.PROCESSING_INSTRUCTION_NODE:
pre = getPath(dtm, dtm.getParent(node));
return (pre.equals("/") ? "" : pre) +
"/processing-instruction()[" + getNumberSimple(dtm, node) + "]";
}
return "?";
}
private static int getNumberSimple(DTM dtm, int node) {
final String localName = dtm.getLocalName(node);
String uri = dtm.getNamespaceURI(node);
if (uri == null) uri = "";
final short type = dtm.getNodeType(node);
int i = 1;
int p = node;
while ((p = dtm.getPreviousSibling(p)) != DTM.NULL) {
if (dtm.getNodeType(p) == type) {
switch (type) {
case Node.TEXT_NODE:
case Node.COMMENT_NODE:
case Node.PROCESSING_INSTRUCTION_NODE:
i++;
break;
default:
if (localName.equals(dtm.getLocalName(p)) && uri.equals(dtm.getNamespaceURI(p))) {
i++;
}
}
}
}
return i;
}
}
@@ -0,0 +1,162 @@
package org.intellij.plugins.xsltDebugger.rt.engine.local.xalan;
import org.apache.xalan.trace.GenerateEvent;
import org.apache.xalan.trace.PrintTraceListener;
import org.apache.xalan.trace.TracerEvent;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xml.serializer.SerializerTrace;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.local.AbstractFrame;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import javax.xml.transform.SourceLocator;
import java.io.PrintWriter;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 09.01.2009
*/
public class XalanTraceListener extends PrintTraceListener {
private final LocalDebugger myDebugger;
private final TransformerImpl myTransformer;
private volatile boolean myTracing = false;
private boolean firstTrace = true;
public XalanTraceListener(LocalDebugger localDebugger, TransformerImpl tr) {
super(new PrintWriter(System.out, true));
m_traceElements = false;
m_traceGeneration = false;
m_traceSelection = false;
myDebugger = localDebugger;
myTransformer = tr;
}
@Override
public void trace(TracerEvent ev) {
if (myTracing) return;
myTracing = true; // prevents handling of recursive trace() events
try {
// init
if (firstTrace) {
firstTrace = false;
final SerializationHandler handler = myTransformer.getSerializationHandler();
myTransformer.setSerializationHandler(new TracingSerializationHandler(myDebugger, handler));
}
super.trace(ev);
final DTMIterator iterator = myTransformer.getContextNodeList();
final int node = myTransformer.getMatchedNode();
final Debugger.SourceFrame sourceFrame = myDebugger.getSourceFrame();
final boolean withSource;
if (sourceFrame == null || ((MySourceFrame)sourceFrame).getMatchedNode() != node) {
myDebugger.pushSource(new MySourceFrame(sourceFrame, iterator.getDTM(node), node));
withSource = true;
} else {
withSource = false;
}
myDebugger.enter(new XalanStyleFrame(ev, myDebugger.getCurrentFrame(), withSource));
} finally {
myTracing = false;
}
}
@Override
public void traceEnd(TracerEvent ev) {
if (myTracing) return;
if (myDebugger.getCurrentFrame() == null) {
return;
}
// xsl:choose (and maybe others) don't generate traceEnd()-events
final String instr = XalanStyleFrame.getInstruction(ev.m_styleNode);
if (instr != null) {
while (!instr.equals(myDebugger.getCurrentFrame().getInstruction())) {
leave();
}
}
super.traceEnd(ev);
leave();
}
private void leave() {
if (((XalanStyleFrame)myDebugger.getCurrentFrame()).isWithSourceFrame()) {
myDebugger.popSource();
}
myDebugger.leave();
}
@Override
public void generated(GenerateEvent ev) {
if (!(myTransformer.getSerializationHandler() instanceof TracingSerializationHandler)) {
// internal RTF evaluation, don't care
return;
}
switch (ev.m_eventtype) {
case SerializerTrace.EVENTTYPE_STARTDOCUMENT:
myDebugger.getEventQueue().startDocument();
break;
case SerializerTrace.EVENTTYPE_ENDDOCUMENT:
myDebugger.getEventQueue().endDocument();
break;
case SerializerTrace.EVENTTYPE_ENDELEMENT:
myDebugger.getEventQueue().endElement();
break;
case SerializerTrace.EVENTTYPE_CDATA:
case SerializerTrace.EVENTTYPE_CHARACTERS:
myDebugger.getEventQueue().characters(new String(ev.m_characters, ev.m_start, ev.m_length));
break;
case SerializerTrace.EVENTTYPE_COMMENT:
myDebugger.getEventQueue().comment(ev.m_data);
break;
case SerializerTrace.EVENTTYPE_PI:
myDebugger.getEventQueue().pi(ev.m_name, ev.m_data);
break;
}
}
private static class MySourceFrame extends AbstractFrame<Debugger.SourceFrame> implements Debugger.SourceFrame {
private final String mySystemId;
private final int myLineNumber;
private final int myMatchedNode;
private String myPath;
public MySourceFrame(Debugger.SourceFrame sourceFrame, DTM dtm, int node) {
super(sourceFrame);
final SourceLocator loc = dtm.getSourceLocatorFor(node);
mySystemId = loc.getSystemId();
myLineNumber = loc.getLineNumber();
myPath = XalanSupport.getPath(dtm, node);
myMatchedNode = node;
}
public String getXPath() {
return myPath;
}
public String getURI() {
return mySystemId;
}
public int getLineNumber() {
return myLineNumber;
}
public int getMatchedNode() {
return myMatchedNode;
}
}
}
@@ -0,0 +1,153 @@
/*
* 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.rt.engine.remote;
import com.icl.saxon.TransformerFactoryImpl;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import org.intellij.plugins.xsltDebugger.rt.engine.local.LocalDebugger;
import javax.rmi.PortableRemoteObject;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.05.2007
*/
public class DebuggerServer extends PortableRemoteObject implements RemoteDebugger {
private static final String XSLT_DEBUGGER = "XsltDebugger";
public static final int PORT = 34275;
private final Debugger myDebugger;
private final RemoteBreakpointManagerImpl myBreakpointManager;
private final RemoteEventQueueImpl myEventQueue;
private final int myPort;
private DebuggerServer(Transformer transformer, Source xml, Result out, int port)
throws TransformerConfigurationException, RemoteException {
myPort = port;
myDebugger = new LocalDebugger(transformer, xml, out) {
@Override
public void stop(boolean b) {
try {
super.stop(b);
} finally {
if (b) System.exit(0);
}
}
};
myBreakpointManager = new RemoteBreakpointManagerImpl(myDebugger.getBreakpointManager());
myEventQueue = new RemoteEventQueueImpl(myDebugger.getEventQueue());
}
public static DebuggerServer create(Transformer xsl, Source xml, Result out, int port)
throws TransformerConfigurationException, RemoteException {
final DebuggerServer server = new DebuggerServer(xsl, xml, out, port);
final Registry registry = LocateRegistry.createRegistry(port);
registry.rebind(XSLT_DEBUGGER, server);
return server;
}
public static DebuggerServer create(File f, File x) throws TransformerConfigurationException, RemoteException {
return create(new TransformerFactoryImpl().newTransformer(new StreamSource(f)), new StreamSource(x), new StreamResult(), PORT);
}
public void stop(boolean force) throws RemoteException {
myDebugger.stop(force);
try {
LocateRegistry.getRegistry(myPort).unbind(XSLT_DEBUGGER);
} catch (NotBoundException e) {
// hu?
}
}
public boolean ping() throws RemoteException {
return myDebugger.ping();
}
public Debugger.State waitForStateChange(Debugger.State state) throws RemoteException {
return myDebugger.waitForStateChange(state);
}
public boolean waitForDebuggee() throws RemoteException {
return myDebugger.waitForDebuggee();
}
public boolean start() throws RemoteException {
return myDebugger.start();
}
public void step() throws RemoteException {
myDebugger.step();
}
public void stepInto() throws RemoteException {
myDebugger.stepInto();
}
public void resume() throws RemoteException {
myDebugger.resume();
}
public boolean isStopped() throws RemoteException {
return myDebugger.isStopped();
}
public Frame getCurrentFrame() throws RemoteException {
return RemoteFrameImpl.create(myDebugger.getCurrentFrame());
}
public Frame getSourceFrame() throws RemoteException {
return RemoteFrameImpl.create(myDebugger.getSourceFrame());
}
public Value eval(String expr) throws RemoteException, Debugger.EvaluationException {
return getCurrentFrame().eval(expr);
}
public List<Variable> getGlobalVariables() throws RemoteException {
return RemoteVariableImpl.convert(myDebugger.getGlobalVariables());
}
public RemoteBreakpointManager getBreakpointManager() throws RemoteException {
return myBreakpointManager;
}
public Debugger.State getState() throws RemoteException {
return myDebugger.getState();
}
public void pause() throws RemoteException {
myDebugger.pause();
}
public EventQueue getEventQueue() throws RemoteException {
return myEventQueue;
}
}
@@ -0,0 +1,51 @@
/*
* 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.rt.engine.remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 29.05.2007
*/
public interface RemoteBreakpoint extends Remote {
String getUri() throws RemoteException;
int getLine() throws RemoteException;
boolean isEnabled() throws RemoteException;
void setEnabled(boolean b) throws RemoteException;
String getCondition() throws RemoteException;
void setCondition(String expr) throws RemoteException;
String getLogMessage() throws RemoteException;
void setLogMessage(String expr) throws RemoteException;
String getTraceMessage() throws RemoteException;
void setTraceMessage(String expr) throws RemoteException;
boolean isSuspend() throws RemoteException;
void setSuspend(boolean suspend) throws RemoteException;
}
@@ -0,0 +1,93 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.Breakpoint;
import javax.rmi.PortableRemoteObject;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 29.05.2007
*/
class RemoteBreakpointImpl extends PortableRemoteObject implements RemoteBreakpoint {
private final Breakpoint myBreakpoint;
public RemoteBreakpointImpl(Breakpoint breakpoint) throws RemoteException {
myBreakpoint = breakpoint;
}
public String getUri() throws RemoteException {
return myBreakpoint.getUri();
}
public int getLine() throws RemoteException {
return myBreakpoint.getLine();
}
public boolean isEnabled() throws RemoteException {
return myBreakpoint.isEnabled();
}
public String getCondition() {
return myBreakpoint.getCondition();
}
public String getLogMessage() {
return myBreakpoint.getLogMessage();
}
public void setCondition(String expr) {
myBreakpoint.setCondition(expr);
}
public void setEnabled(boolean enabled) {
myBreakpoint.setEnabled(enabled);
}
public void setLogMessage(String expr) {
myBreakpoint.setLogMessage(expr);
}
public String getTraceMessage() throws RemoteException {
return myBreakpoint.getTraceMessage();
}
public void setTraceMessage(String expr) throws RemoteException {
myBreakpoint.setTraceMessage(expr);
}
public boolean isSuspend() {
return myBreakpoint.isSuspend();
}
public void setSuspend(boolean suspend) {
myBreakpoint.setSuspend(suspend);
}
public static List<RemoteBreakpoint> convert(List<Breakpoint> list) throws RemoteException {
final ArrayList<RemoteBreakpoint> breakpoints = new ArrayList<RemoteBreakpoint>(list.size());
for (Breakpoint breakpoint : list) {
breakpoints.add(new RemoteBreakpointImpl(breakpoint));
}
return breakpoints;
}
}
@@ -0,0 +1,39 @@
/*
* 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.rt.engine.remote;
import java.io.File;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 24.05.2007
*/
public interface RemoteBreakpointManager extends Remote {
RemoteBreakpoint setBreakpoint(File file, int line) throws RemoteException;
RemoteBreakpoint setBreakpoint(String uri, int line) throws RemoteException;
void removeBreakpoint(String uri, int line) throws RemoteException;
List<RemoteBreakpoint> getBreakpoints() throws RemoteException;
RemoteBreakpoint getBreakpoint(String uri, int lineNumber) throws RemoteException;
}
@@ -0,0 +1,58 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.BreakpointManager;
import javax.rmi.PortableRemoteObject;
import java.io.File;
import java.rmi.RemoteException;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 24.05.2007
*/
class RemoteBreakpointManagerImpl extends PortableRemoteObject implements RemoteBreakpointManager {
private final BreakpointManager myManager;
public RemoteBreakpointManagerImpl(BreakpointManager manager) throws RemoteException {
super();
myManager = manager;
}
public RemoteBreakpoint setBreakpoint(File file, int line) throws RemoteException {
return new RemoteBreakpointImpl(myManager.setBreakpoint(file, line));
}
public RemoteBreakpoint setBreakpoint(String uri, int line) throws RemoteException {
return new RemoteBreakpointImpl(myManager.setBreakpoint(uri, line));
}
public void removeBreakpoint(String uri, int line) {
myManager.removeBreakpoint(uri, line);
}
public List<RemoteBreakpoint> getBreakpoints() throws RemoteException {
return RemoteBreakpointImpl.convert(myManager.getBreakpoints());
}
public RemoteBreakpoint getBreakpoint(String uri, int lineNumber) throws RemoteException {
return new RemoteBreakpointImpl(myManager.getBreakpoint(uri, lineNumber));
}
}
@@ -0,0 +1,104 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 24.05.2007
*/
public interface RemoteDebugger extends Remote {
boolean ping() throws RemoteException;
void stop(boolean force) throws RemoteException;
Debugger.State waitForStateChange(Debugger.State currentState) throws RemoteException;
boolean waitForDebuggee() throws RemoteException;
boolean start() throws RemoteException;
void step() throws RemoteException;
void stepInto() throws RemoteException;
void resume() throws RemoteException;
boolean isStopped() throws RemoteException;
Frame getCurrentFrame() throws RemoteException;
Frame getSourceFrame() throws RemoteException;
Value eval(String expr) throws RemoteException, Debugger.EvaluationException;
List<Variable> getGlobalVariables() throws RemoteException;
RemoteBreakpointManager getBreakpointManager() throws RemoteException;
Debugger.State getState() throws RemoteException;
void pause() throws RemoteException;
EventQueue getEventQueue() throws RemoteException;
interface EventQueue extends Remote {
List<OutputEventQueue.NodeEvent> getEvents() throws RemoteException;
void setEnabled(boolean b) throws RemoteException;
}
interface Frame extends Remote {
int getLineNumber() throws RemoteException;
String getURI() throws RemoteException;
Frame getNext() throws RemoteException;
Frame getPrevious() throws RemoteException;
String getXPath() throws RemoteException;
Value eval(String expr) throws RemoteException, Debugger.EvaluationException;
List<Variable> getVariables() throws RemoteException;
String getInstruction() throws RemoteException;
}
public interface Variable extends Remote {
boolean isGlobal() throws RemoteException;
Debugger.Variable.Kind getKind() throws RemoteException;
String getName() throws RemoteException;
Value getValue() throws RemoteException;
String getURI() throws RemoteException;
int getLineNumber() throws RemoteException;
}
}
@@ -0,0 +1,545 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.*;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.net.SocketException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 23.05.2007
*/
public class RemoteDebuggerClient implements Debugger {
private final RemoteDebugger myRemote;
private final BreakpointManager myBreakpointManager;
private final OutputEventQueue myEventQueue;
public RemoteDebuggerClient(int port) throws IOException, NotBoundException {
myRemote = (RemoteDebugger)Naming.lookup("rmi://127.0.0.1:" + port + "/XsltDebugger");
final RemoteBreakpointManager manager = myRemote.getBreakpointManager();
myBreakpointManager = new MyBreakpointManager(manager);
final RemoteDebugger.EventQueue eventQueue = myRemote.getEventQueue();
myEventQueue = new MyOutputEventQueue(eventQueue);
}
public boolean ping() {
try {
return myRemote.ping();
} catch (RemoteException e) {
return false;
}
}
public State getState() {
try {
return myRemote.getState();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void stop(boolean force) {
try {
myRemote.stop(force);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
static RuntimeException handleRemoteException(RemoteException e) {
Throwable t = e.getCause();
while (t != null) {
if (t instanceof SocketException || t instanceof EOFException) {
throw new DebuggerStoppedException();
}
t = t.getCause();
}
return e.getCause() instanceof RuntimeException ? (RuntimeException)e.getCause() : new RuntimeException(e);
}
public Debugger.State waitForStateChange(State state) {
try {
return myRemote.waitForStateChange(state);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public boolean waitForDebuggee() {
try {
return myRemote.waitForDebuggee();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public boolean start() {
try {
return myRemote.start();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void step() {
try {
myRemote.step();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void stepInto() {
try {
myRemote.stepInto();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void resume() {
try {
myRemote.resume();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void pause() {
try {
myRemote.pause();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public boolean isStopped() {
try {
return myRemote.isStopped();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public StyleFrame getCurrentFrame() {
try {
return MyFrame.create(myRemote.getCurrentFrame());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public SourceFrame getSourceFrame() {
try {
return MySourceFrame.create(myRemote.getSourceFrame());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public Value eval(String expr) throws EvaluationException {
try {
return myRemote.eval(expr);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public List<Variable> getGlobalVariables() {
try {
return MyVariable.convert(myRemote.getGlobalVariables());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public BreakpointManager getBreakpointManager() {
return myBreakpointManager;
}
public OutputEventQueue getEventQueue() {
return myEventQueue;
}
private static class MyBreakpointManager implements BreakpointManager {
private final RemoteBreakpointManager myManager;
public MyBreakpointManager(RemoteBreakpointManager manager) {
myManager = manager;
}
public Breakpoint setBreakpoint(File file, int line) {
try {
return new MyBreakpoint(myManager.setBreakpoint(file, line));
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public Breakpoint setBreakpoint(String uri, int line) {
try {
return new MyBreakpoint(myManager.setBreakpoint(uri, line));
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void removeBreakpoint(Breakpoint bp) {
try {
myManager.removeBreakpoint(bp.getUri(), bp.getLine());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void removeBreakpoint(String uri, int line) {
try {
myManager.removeBreakpoint(uri, line);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public List<Breakpoint> getBreakpoints() {
try {
final List<RemoteBreakpoint> list = myManager.getBreakpoints();
final ArrayList<Breakpoint> breakpoints = new ArrayList<Breakpoint>(list.size());
for (RemoteBreakpoint breakpoint : list) {
breakpoints.add(new MyBreakpoint(breakpoint));
}
return breakpoints;
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public Breakpoint getBreakpoint(String uri, int lineNumber) {
try {
final RemoteBreakpoint breakpoint = myManager.getBreakpoint(uri, lineNumber);
return breakpoint != null ? new MyBreakpoint(breakpoint) : null;
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
private static class MyBreakpoint implements Breakpoint {
private final RemoteBreakpoint myBreakpoint;
public MyBreakpoint(RemoteBreakpoint breakpoint) {
myBreakpoint = breakpoint;
}
public String getUri() {
try {
return myBreakpoint.getUri();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public int getLine() {
try {
return myBreakpoint.getLine();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public boolean isEnabled() {
try {
return myBreakpoint.isEnabled();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public String getCondition() {
try {
return myBreakpoint.getCondition();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public String getLogMessage() {
try {
return myBreakpoint.getLogMessage();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void setCondition(String expr) {
try {
myBreakpoint.setCondition(expr);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void setEnabled(boolean enabled) {
try {
myBreakpoint.setEnabled(enabled);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void setLogMessage(String expr) {
try {
myBreakpoint.setLogMessage(expr);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public String getTraceMessage() {
try {
return myBreakpoint.getTraceMessage();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void setTraceMessage(String expr) {
try {
myBreakpoint.setTraceMessage(expr);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public boolean isSuspend() {
try {
return myBreakpoint.isSuspend();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public void setSuspend(boolean suspend) {
try {
myBreakpoint.setSuspend(suspend);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
}
}
private static abstract class MyAbstractFrame<F extends Frame> implements Frame<F> {
protected final RemoteDebugger.Frame myFrame;
protected MyAbstractFrame(RemoteDebugger.Frame frame) {
myFrame = frame;
}
public int getLineNumber() {
try {
return myFrame.getLineNumber();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public String getURI() {
try {
return myFrame.getURI();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public F getNext() {
try {
return createImpl(myFrame.getNext());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public F getPrevious() {
try {
return createImpl(myFrame.getPrevious());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
protected abstract F createImpl(RemoteDebugger.Frame frame);
public String getXPath() {
try {
return myFrame.getXPath();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public Value eval(String expr) throws EvaluationException {
try {
return myFrame.eval(expr);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public List<Variable> getVariables() {
try {
return MyVariable.convert(myFrame.getVariables());
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
}
private static class MyFrame extends MyAbstractFrame<StyleFrame> implements StyleFrame {
protected MyFrame(RemoteDebugger.Frame frame) {
super(frame);
}
public String getInstruction() {
try {
return myFrame.getInstruction();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
protected StyleFrame createImpl(RemoteDebugger.Frame frame) {
return create(frame);
}
public static StyleFrame create(RemoteDebugger.Frame currentFrame) {
return currentFrame != null ? new MyFrame(currentFrame) : null;
}
}
private static class MySourceFrame extends MyAbstractFrame<SourceFrame> implements SourceFrame {
protected MySourceFrame(RemoteDebugger.Frame frame) {
super(frame);
}
public SourceFrame createImpl(RemoteDebugger.Frame frame) {
return create(frame);
}
public static SourceFrame create(RemoteDebugger.Frame currentFrame) {
return currentFrame != null ? new MySourceFrame(currentFrame) : null;
}
}
private static class MyVariable implements Variable {
private final RemoteDebugger.Variable myVariable;
public MyVariable(RemoteDebugger.Variable variable) {
myVariable = variable;
}
public String getURI() {
try {
return myVariable.getURI();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public int getLineNumber() {
try {
return myVariable.getLineNumber();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public boolean isGlobal() {
try {
return myVariable.isGlobal();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public Kind getKind() {
try {
return myVariable.getKind();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public String getName() {
try {
return myVariable.getName();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public Value getValue() {
try {
return myVariable.getValue();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
static List<Variable> convert(List<RemoteDebugger.Variable> list) {
final ArrayList<Variable> variables = new ArrayList<Variable>(list.size());
for (final RemoteDebugger.Variable variable : list) {
variables.add(new MyVariable(variable));
}
return variables;
}
}
private static class MyOutputEventQueue implements OutputEventQueue {
private final RemoteDebugger.EventQueue myEventQueue;
public MyOutputEventQueue(RemoteDebugger.EventQueue eventQueue) {
myEventQueue = eventQueue;
}
public void setEnabled(boolean b) {
try {
myEventQueue.setEnabled(b);
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
public List<NodeEvent> getEvents() {
try {
return myEventQueue.getEvents();
} catch (RemoteException e) {
throw handleRemoteException(e);
}
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2002-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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import javax.rmi.PortableRemoteObject;
import java.rmi.RemoteException;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 08.06.2007
*/
public class RemoteEventQueueImpl extends PortableRemoteObject implements RemoteDebugger.EventQueue {
private final OutputEventQueue myQueue;
public RemoteEventQueueImpl(OutputEventQueue queue) throws RemoteException {
myQueue = queue;
}
public List<OutputEventQueue.NodeEvent> getEvents() throws RemoteException {
return myQueue.getEvents();
}
public void setEnabled(boolean b) throws RemoteException {
myQueue.setEnabled(b);
}
}
@@ -0,0 +1,75 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger.Frame;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import javax.rmi.PortableRemoteObject;
import java.rmi.RemoteException;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 28.05.2007
*/
class RemoteFrameImpl extends PortableRemoteObject implements RemoteDebugger.Frame {
private final Frame myFrame;
private RemoteFrameImpl(Frame frame) throws RemoteException {
myFrame = frame;
}
public int getLineNumber() {
return myFrame.getLineNumber();
}
public String getURI() {
return myFrame.getURI();
}
public RemoteDebugger.Frame getNext() throws RemoteException {
return create(myFrame.getNext());
}
public RemoteDebugger.Frame getPrevious() throws RemoteException {
return create(myFrame.getPrevious());
}
public String getXPath() throws RemoteException {
return ((Debugger.SourceFrame)myFrame).getXPath();
}
public ValueImpl eval(String expr) throws Debugger.EvaluationException {
final Value value = ((Debugger.StyleFrame)myFrame).eval(expr);
return new ValueImpl(value.getValue(), value.getType());
}
public List<RemoteDebugger.Variable> getVariables() throws RemoteException {
return RemoteVariableImpl.convert(((Debugger.StyleFrame)myFrame).getVariables());
}
public String getInstruction() throws RemoteException {
return ((Debugger.StyleFrame)myFrame).getInstruction();
}
public static RemoteFrameImpl create(Frame frame) throws RemoteException {
return frame != null ? new RemoteFrameImpl(frame) : null;
}
}
@@ -0,0 +1,71 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import javax.rmi.PortableRemoteObject;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 28.05.2007
*/
class RemoteVariableImpl extends PortableRemoteObject implements RemoteDebugger.Variable {
private final Debugger.Variable myVariable;
public RemoteVariableImpl(Debugger.Variable variable) throws RemoteException {
myVariable = variable;
}
public String getURI() throws RemoteException {
return myVariable.getURI();
}
public int getLineNumber() throws RemoteException {
return myVariable.getLineNumber();
}
public boolean isGlobal() {
return myVariable.isGlobal();
}
public Debugger.Variable.Kind getKind() throws RemoteException {
return myVariable.getKind();
}
public String getName() {
return myVariable.getName();
}
public Value getValue() {
final Value value = myVariable.getValue();
return new ValueImpl(value.getValue(), value.getType());
}
static List<RemoteDebugger.Variable> convert(List<Debugger.Variable> list) throws RemoteException {
final ArrayList<RemoteDebugger.Variable> variables = new ArrayList<RemoteDebugger.Variable>(list.size());
for (final Debugger.Variable variable : list) {
variables.add(new RemoteVariableImpl(variable));
}
return variables;
}
}
@@ -0,0 +1,48 @@
/*
* 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.rt.engine.remote;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import java.io.Serializable;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 28.05.2007
*/
class ValueImpl implements Value {
private final Serializable myValue;
private final Type myType;
public ValueImpl(Object value, Type type) {
if (value instanceof Serializable) {
myValue = (Serializable)value;
} else {
myValue = String.valueOf(value);
}
myType = type;
}
public Serializable getValue() {
return myValue;
}
public Type getType() {
return myType;
}
}
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.5" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="xslt-rt" />
<orderEntry type="module-library">
<library name="RMI Stubs">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/rmi-stubs.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Saxon-9HE">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/saxon9he.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Saxon-6.5.5">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/saxon.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="Xalan-2.7.1">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/xalan.jar!/" />
<root url="jar://$MODULE_DIR$/lib/serializer.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="Trove4j" level="project" />
</component>
</module>
@@ -0,0 +1,32 @@
<idea-plugin version="2" url="http://www.jetbrains.net/confluence/display/CONTEST/XSLT-Debugger">
<name>XSLT-Debugger</name>
<id>XSLT-Debugger</id>
<description><![CDATA[
Interactive XSLT Debugger. Allows debugging of XSLT stylesheets in IntelliJ IDEA.
]]></description>
<version>1.4</version>
<vendor email="sascha.weinreuter@cit.de">Sascha Weinreuter</vendor>
<idea-version since-build="96.1"/>
<depends>XPathView</depends>
<change-notes>
Xalan Support. To debug with Xalan instead of SAXON, a supported Xalan version (2.7.x) should be present in the
classpath or "-Dxslt.transformer.type=xalan" should be added as VM argument for the run configuration. Debugging
with SAXON can be forced by adding "-Dxslt.transformer.type=saxon".
</change-notes>
<extensions defaultExtensionNs="com.intellij">
<xdebugger.breakpointType implementation="org.intellij.plugins.xsltDebugger.XsltBreakpointType"/>
<programRunner implementation="org.intellij.plugins.xsltDebugger.XsltDebuggerRunner"/>
</extensions>
<extensions defaultExtensionNs="XPathView">
<xsltRunnerExtension implementation="org.intellij.plugins.xsltDebugger.XsltDebuggerExtension"/>
</extensions>
<helpset file="help.jar" path="/Help.hs"/>
</idea-plugin>
@@ -0,0 +1,53 @@
package org.intellij.plugins.xsltDebugger;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import org.intellij.lang.xpath.XPathFile;
import org.intellij.lang.xpath.context.VariableContext;
import org.intellij.lang.xpath.context.XPathQuickFixFactoryImpl;
import org.intellij.lang.xpath.psi.XPathElement;
import org.intellij.lang.xpath.psi.XPathVariableReference;
import org.intellij.lang.xpath.validation.inspections.quickfix.XPathQuickFixFactory;
import org.intellij.lang.xpath.xslt.context.XsltContextProvider;
import org.intellij.lang.xpath.xslt.context.XsltVariableContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BreakpointContext extends XsltContextProvider {
public BreakpointContext(PsiElement contextElement) {
super((XmlElement)contextElement);
}
@Override
@NotNull
public XPathQuickFixFactory getQuickFixFactory() {
return XPathQuickFixFactoryImpl.INSTANCE;
}
@Override
public PsiFile[] getRelatedFiles(XPathFile file) {
return PsiFile.EMPTY_ARRAY;
}
@Override
@NotNull
public VariableContext getVariableContext() {
return new XsltVariableContext() {
@Override
@Nullable
protected XmlTag getContextTagImpl(XPathElement element) {
return PsiTreeUtil.getParentOfType(getContextElement(), XmlTag.class, false);
}
@Override
@NotNull
public IntentionAction[] getUnresolvedVariableFixes(XPathVariableReference reference) {
return IntentionAction.EMPTY_ARRAY;
}
};
}
}
@@ -0,0 +1,68 @@
/*
* 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.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import org.intellij.plugins.xsltDebugger.rt.engine.DebuggerStoppedException;
/**
* ProcessListener that manages the connection to the debugged XSLT-process
*/
class DebugProcessListener extends ProcessAdapter {
private final Project myProject;
private final int myPort;
public DebugProcessListener(Project project, int port) {
myProject = project;
myPort = port;
}
@Override
public void startNotified(ProcessEvent event) {
final DebuggerConnector connector = new DebuggerConnector(myProject, event.getProcessHandler(), myPort);
ApplicationManager.getApplication().executeOnPooledThread(connector);
}
@Override
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
try {
final XsltDebuggerSession session = XsltDebuggerSession.getInstance(event.getProcessHandler());
if (session != null) {
session.stop();
}
} catch (VMPausedException e) {
// VM is paused, no way for a "clean" shutdown
} catch (DebuggerStoppedException e) {
// OK
}
super.processWillTerminate(event, willBeDestroyed);
}
@Override
public void processTerminated(ProcessEvent event) {
super.processTerminated(event);
final XsltDebuggerSession session = XsltDebuggerSession.getInstance(event.getProcessHandler());
if (session != null) {
session.close();
}
}
}
@@ -0,0 +1,130 @@
/*
* 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.execution.process.ProcessOutputTypes;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import org.intellij.plugins.xsltDebugger.impl.XsltDebugProcess;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import org.intellij.plugins.xsltDebugger.rt.engine.remote.RemoteDebuggerClient;
import org.intellij.plugins.xsltDebugger.ui.StructureTabComponent;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.rmi.ConnectException;
import java.rmi.NotBoundException;
/**
* Establishes the debugger-connection to the started XSLT-process, starts the debugger-session
* and attaches the debugger-UI.
*/
class DebuggerConnector implements Runnable {
private final Project myProject;
private final ProcessHandler myProcess;
private final int myPort;
public DebuggerConnector(Project project, ProcessHandler process, int port) {
myProject = project;
myProcess = process;
myPort = port;
}
public void run() {
final Debugger client = connect();
if (client == null) {
// client will be null if the process terminated prematurely for some reason. no need for an error message
if (!myProcess.isProcessTerminated()) {
myProcess.notifyTextAvailable("Failed to connect to debugged process. Terminating.\n", ProcessOutputTypes.SYSTEM);
myProcess.destroyProcess();
}
return;
}
final XsltDebuggerSession session = XsltDebuggerSession.create(myProject, myProcess, client);
final XsltDebugProcess dbgp = XsltDebugProcess.getInstance(myProcess);
assert dbgp != null;
dbgp.init(client);
session.addListener(new XsltDebuggerSession.Listener() {
@Override
public void debuggerSuspended() {
final OutputEventQueue queue = client.getEventQueue();
StructureTabComponent.getInstance(myProcess).getEventModel().update(queue.getEvents());
}
@Override
public void debuggerResumed() {
}
@Override
public void debuggerStopped() {
try {
final OutputEventQueue queue = client.getEventQueue();
StructureTabComponent.getInstance(myProcess).getEventModel().finalUpdate(queue.getEvents());
} catch (Exception e) {
// can fail when debugger is manually terminated
}
}
});
session.start();
}
@Nullable
private Debugger connect() {
Throwable lastException = null;
for (int i = 0; i < 10; i++) {
try {
final Debugger realClient = EDTGuard.create(new RemoteDebuggerClient(myPort), myProcess);
myProcess.notifyTextAvailable("Connected to XSLT debugger on port " + myPort + "\n", ProcessOutputTypes.SYSTEM);
return realClient;
} catch (ConnectException e) {
lastException = e;
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
break;
}
} catch (NotBoundException e) {
lastException = e;
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
break;
}
} catch (IOException e) {
lastException = e;
break;
}
}
if (lastException != null) {
Logger.getInstance(getClass().getName()).info("Could not connect to debugger", lastException);
if (lastException.getMessage() != null) {
myProcess.notifyTextAvailable("Connection error: " + lastException.getMessage() + "\n", ProcessOutputTypes.SYSTEM);
}
}
return null;
}
}
@@ -0,0 +1,294 @@
/*
* Copyright 2002-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.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.util.Alarm;
import gnu.trove.THashMap;
import gnu.trove.TObjectHashingStrategy;
import org.intellij.plugins.xsltDebugger.rt.engine.Watchable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Utility class that tries to prevent hanging the whole IDE because some call on the EDT waits too long on the debugged
* VM, which can especially happen when the VM has been paused (either manually or by a breakpoint on Java code).
* <p/>
* This is just the second best solution though as it would be better to avoid any interaction with the debuggee on the
* EDT, but, at least right now, it seems to be more reliable against bad surprises.
*/
class EDTGuard implements InvocationHandler {
// maximum time to wait for a result on the EDT
private static final long MAX_TIMEOUT = 10 * 1000;
@SuppressWarnings({ "unchecked" })
private final Map<Object, Object> myInstanceCache = new THashMap<Object, Object>(TObjectHashingStrategy.IDENTITY);
private final Object myTarget;
private final Pair<LinkedBlockingQueue<Call>, LinkedBlockingQueue<Call.Result>> myQueue;
private final AtomicBoolean myPausedRef;
private EDTGuard(Object target,
Pair<LinkedBlockingQueue<Call>, LinkedBlockingQueue<Call.Result>> queue,
AtomicBoolean ref) {
myTarget = target;
myQueue = queue;
myPausedRef = ref;
}
@Nullable
public Object invoke(Object proxy, @NotNull Method method, Object[] args) throws Throwable {
if (SwingUtilities.isEventDispatchThread()) {
return invokeAsync(method, args);
}
return invoke(method, args);
}
@Nullable
private Object invokeAsync(Method method, Object[] args) throws Throwable {
final Call call = new Call(method, args);
if (!myQueue.first.offer(call)) {
throw new VMPausedException();
}
Call.Result result;
final long start = System.currentTimeMillis();
do {
do {
result = myQueue.second.poll(200, TimeUnit.MILLISECONDS);
if (myPausedRef.get() || result == null && System.currentTimeMillis() - start > MAX_TIMEOUT) {
throw new VMPausedException();
}
}
while (result == null);
}
while (!result.isFromCall(call));
return result.getValue();
}
@Nullable
private Object invoke(@NotNull Method method, Object[] args) throws Throwable {
try {
return convert(method.invoke(myTarget, args));
} catch (InvocationTargetException e) {
final Throwable t = e.getTargetException();
if (t instanceof RuntimeException) {
throw (RuntimeException)t;
} else if (t instanceof Error) {
throw (Error)t;
} else {
throw t;
}
}
}
@Nullable
@SuppressWarnings({ "unchecked" })
private Object convert(@Nullable Object o) {
if (o != null && !(o instanceof Serializable)) {
synchronized (myInstanceCache) {
Object instance = myInstanceCache.get(o);
if (instance == null) {
final ClassLoader loader = o.getClass().getClassLoader();
final Class<?>[] interfaces = o.getClass().getInterfaces();
final EDTGuard guard = new EDTGuard(o, myQueue, myPausedRef);
myInstanceCache.put(o, instance = Proxy.newProxyInstance(loader, interfaces, guard));
}
return instance;
}
} else if (o instanceof List) {
final List list = (List)o;
for (int i = 0; i < list.size(); i++) {
final Object e = list.remove(i);
list.add(i, convert(e));
}
} else if (o instanceof Set) {
final Set set = (Set)o;
final List s2 = new ArrayList();
for (Iterator iterator = set.iterator(); iterator.hasNext(); ) {
Object o1 = iterator.next();
final Object o2 = convert(o1);
if (o1 != o2) {
iterator.remove();
s2.add(o2);
}
}
set.addAll(s2);
}
return o;
}
@NotNull
public static <T, O extends Watchable> T create(@NotNull final O target, final ProcessHandler process) {
final Pair<LinkedBlockingQueue<Call>, LinkedBlockingQueue<Call.Result>> queue =
Pair.create(new LinkedBlockingQueue<Call>(10), new LinkedBlockingQueue<Call.Result>());
final Thread thread = new Thread("Async Invocation Thread for " + process) {
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
final Call call = queue.first.take();
if (call != null) {
queue.second.offer(call.invoke());
}
}
} catch (InterruptedException e) {
// break
}
}
};
thread.start();
final AtomicBoolean ref = new AtomicBoolean();
final Disposable d = new Disposable() {
boolean disposed;
@Override
public void dispose() {
if (!disposed) {
disposed = true;
ref.set(true);
thread.interrupt();
}
}
};
process.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
synchronized (d) {
Disposer.dispose(d);
}
}
@Override
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
if (!willBeDestroyed) {
synchronized (d) {
Disposer.dispose(d);
}
}
}
});
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, d);
final Alarm alarm2 = new Alarm(Alarm.ThreadToUse.OWN_THREAD, alarm);
final Runnable watchdog = new Runnable() {
@Override
public void run() {
ref.set(true);
}
};
final Runnable ping = new Runnable() {
@Override
public void run() {
synchronized (d) {
if (alarm.isDisposed()) {
return;
}
alarm2.addRequest(watchdog, 200);
try {
ref.set(!target.ping());
} catch (Exception e) {
ref.set(true);
} finally {
alarm2.cancelRequest(watchdog);
}
}
}
};
alarm.addRequest(ping, 500);
final EDTGuard guard = new EDTGuard(target, queue, ref);
final ClassLoader classLoader = target.getClass().getClassLoader();
final Class<?>[] interfaces = target.getClass().getInterfaces();
//noinspection unchecked
return (T)Proxy.newProxyInstance(classLoader, interfaces, guard);
}
class Call {
private final Method myMethod;
private final Object[] myArguments;
class Result {
private final Object myObject;
private final Throwable myThrowable;
public Result(Object o) {
myObject = o;
myThrowable = null;
}
public Result(Throwable o) {
myObject = null;
myThrowable = o;
}
public boolean isFromCall(Call call) {
return call == Call.this;
}
@Nullable
public Object getValue() throws Throwable {
if (myThrowable != null) {
throw myThrowable;
}
return myObject;
}
}
public Call(Method method, Object[] arguments) {
myMethod = method;
myArguments = arguments;
}
@NotNull
public Result invoke() {
try {
return new Result(EDTGuard.this.invoke(myMethod, myArguments));
} catch (Throwable e) {
return new Result(e);
}
}
}
}
@@ -0,0 +1,23 @@
/*
* Copyright 2002-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;
/**
* Thrown by the EDTGuard when some method cannot be completed due to the target VM being paused.
*/
public class VMPausedException extends RuntimeException {
}
@@ -0,0 +1,71 @@
package org.intellij.plugins.xsltDebugger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
import com.intellij.xdebugger.breakpoints.XLineBreakpointType;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.ui.DebuggerIcons;
import org.intellij.lang.xpath.xslt.XsltSupport;
import org.intellij.plugins.xsltDebugger.impl.XsltDebuggerEditorsProvider;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 03.03.11
*/
public final class XsltBreakpointType extends XLineBreakpointType<XBreakpointProperties> {
private final XsltDebuggerEditorsProvider myMyEditorsProvider = new XsltDebuggerEditorsProvider();
public XsltBreakpointType() {
super("xslt", "XSLT Breakpoints");
}
@Override
public boolean canPutAt(@NotNull VirtualFile file, int line, @NotNull Project project) {
final Document document = FileDocumentManager.getInstance().getDocument(file);
if (document == null) return false;
final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (psiFile == null) {
return false;
}
final FileType fileType = psiFile.getFileType();
if (fileType != StdFileTypes.XML || !XsltSupport.isXsltFile(psiFile)) {
return false;
}
return true;
}
@Override
public XDebuggerEditorsProvider getEditorsProvider() {
return myMyEditorsProvider;
}
@NotNull
@Override
public Icon getEnabledIcon() {
return XsltSupport.createXsltIcon(DebuggerIcons.ENABLED_BREAKPOINT_ICON);
}
@NotNull
@Override
public Icon getDisabledIcon() {
return XsltSupport.createXsltIcon(DebuggerIcons.DISABLED_BREAKPOINT_ICON);
}
@Override
public XBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) {
return null;
}
}
@@ -0,0 +1,273 @@
/*
* Copyright 2002-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.compiler.impl.CompilerUtil;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.AdditionalTabComponentManager;
import com.intellij.execution.configurations.SimpleJavaParameters;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessListener;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Icons;
import com.intellij.util.net.NetUtils;
import com.intellij.xdebugger.impl.ui.DebuggerSessionTabBase;
import org.intellij.lang.xpath.xslt.XsltSupport;
import org.intellij.lang.xpath.xslt.impl.XsltChecker;
import org.intellij.lang.xpath.xslt.run.XsltRunConfiguration;
import org.intellij.lang.xpath.xslt.run.XsltRunnerExtension;
import org.intellij.plugins.xsltDebugger.ui.OutputTabComponent;
import org.intellij.plugins.xsltDebugger.ui.StructureTabComponent;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* Extension for XPathView that hooks into the execution of XSLT-scripts. Manages the creation of the XSLT-Debugger UI
* and ensures the debugged process is started with the required JVM properties.
*/
public class XsltDebuggerExtension extends XsltRunnerExtension {
private static final Logger LOG = Logger.getInstance(XsltDebuggerExtension.class.getName());
private static final Key<Integer> PORT = Key.create("PORT");
private static final Key<Manifest> MANIFEST = Key.create("MANIFEST");
@NonNls
private static final String SAXON_6_JAR = "saxon.jar";
@NonNls
private static final String SAXON_9_JAR = "saxon9he.jar";
protected boolean supports(XsltRunConfiguration config, boolean debugger) {
return (debugger || XsltDebuggerRunner.ACTIVE.get() == Boolean.TRUE) &&
config.getOutputType() == XsltRunConfiguration.OutputType.CONSOLE; // ?
}
public ProcessListener createProcessListener(Project project, UserDataHolder extensionData) {
final Integer port = extensionData.getUserData(PORT);
assert port != null;
return new DebugProcessListener(project, port);
}
public boolean createTabs(Project project,
AdditionalTabComponentManager manager,
AdditionalTabComponent outputConsole,
ProcessHandler process) {
if (manager instanceof DebuggerSessionTabBase) {
final DebuggerSessionTabBase mgr = (DebuggerSessionTabBase)manager;
mgr.addAdditionalTabComponent(new OutputTabComponent(outputConsole), "XSLT-Output", IconLoader.getIcon("/debugger/console.png"));
mgr.addAdditionalTabComponent(StructureTabComponent.create(process, outputConsole), "XSLT-Structure", Icons.FLATTEN_PACKAGES_ICON);
} else {
manager.addAdditionalTabComponent(new OutputTabComponent(outputConsole), "XSLT-Output");
manager.addAdditionalTabComponent(StructureTabComponent.create(process, outputConsole), "XSLT-Structure");
}
return true;
}
public void patchParameters(final SimpleJavaParameters parameters, XsltRunConfiguration configuration, UserDataHolder extensionData)
throws CantRunException {
final XsltRunConfiguration.OutputType outputType = configuration.getOutputType();
final Sdk jdk = configuration.getEffectiveJDK();
assert jdk != null;
final String ver = jdk.getVersionString();
if (!(CompilerUtil.isOfVersion(ver, "1.5") ||
CompilerUtil.isOfVersion(ver, "5.0") ||
CompilerUtil.isOfVersion(ver, "1.6") ||
CompilerUtil.isOfVersion(ver, "1.7"))) {
throw new CantRunException("The XSLT Debugger can only be used with JDK 1.5+");
}
// TODO: fix and remove
if (outputType != XsltRunConfiguration.OutputType.CONSOLE) {
throw new CantRunException("XSLT Debugger requires Output Type == CONSOLE");
}
try {
final int port = NetUtils.findAvailableSocketPort();
parameters.getVMParametersList().defineProperty("xslt.debugger.port", String.valueOf(port));
extensionData.putUserData(PORT, port);
} catch (IOException e) {
LOG.info(e);
throw new CantRunException("Unable to find a free network port");
}
final char c = File.separatorChar;
final PluginId pluginId = PluginManager.getPluginByClassName(getClass().getName());
assert pluginId != null || System.getProperty("xslt-debugger.plugin.path") != null;
final File pluginPath;
if (pluginId != null) {
final IdeaPluginDescriptor descriptor = PluginManager.getPlugin(pluginId);
assert descriptor != null;
pluginPath = descriptor.getPath();
} else {
pluginPath = new File(System.getProperty("xslt-debugger.plugin.path"));
}
File rtClasspath = new File(pluginPath, "lib" + c + "xslt-debugger-engine.jar");
if (rtClasspath.exists()) {
parameters.getClassPath().addTail(rtClasspath.getAbsolutePath());
} else {
if (!(rtClasspath = new File(pluginPath, "classes")).exists()) {
if (ApplicationManagerEx.getApplicationEx().isInternal() && new File(pluginPath, "org").exists()) {
rtClasspath = pluginPath;
} else {
throw new CantRunException("Runtime classes not found");
}
}
parameters.getClassPath().addTail(rtClasspath.getAbsolutePath());
parameters.getClassPath().addTail(new File(rtClasspath, "rmi-stubs.jar").getAbsolutePath());
}
File trove4j = new File(PathManager.getLibPath() + c + "trove4j.jar");
if (!trove4j.exists()) {
trove4j = new File(PathManager.getHomePath() + c + "community" + c + "lib" + c + "trove4j.jar");
}
parameters.getClassPath().addTail(trove4j.getAbsolutePath());
final String type = parameters.getVMParametersList().getPropertyValue("xslt.transformer.type");
if ("saxon".equalsIgnoreCase(type)) {
addSaxon(parameters, pluginPath, SAXON_6_JAR);
} else if ("saxon9".equalsIgnoreCase(type)) {
addSaxon(parameters, pluginPath, SAXON_9_JAR);
} else if ("xalan".equalsIgnoreCase(type)) {
final Boolean xalanPresent = isValidXalanPresent(parameters);
if (xalanPresent == null) {
addXalan(parameters, pluginPath);
} else if (!xalanPresent) {
throw new CantRunException("Unsupported Xalan version is present in classpath.");
}
} else if (type != null) {
throw new CantRunException("Unsupported Transformer type '" + type + "'");
} else if (parameters.getClassPath().getPathsString().toLowerCase().contains("xalan")) {
if (isValidXalanPresent(parameters) == Boolean.TRUE) {
parameters.getVMParametersList().defineProperty("xslt.transformer.type", "xalan");
}
}
if (!parameters.getVMParametersList().hasProperty("xslt.transformer.type")) {
// add saxon for backward-compatibility
final VirtualFile xsltFile = configuration.findXsltFile();
final PsiManager psiManager = PsiManager.getInstance(configuration.getProject());
if (xsltFile != null && XsltSupport.getXsltLanguageLevel(psiManager.findFile(xsltFile)) == XsltChecker.LanguageLevel.V2)
{
parameters.getVMParametersList().defineProperty("xslt.transformer.type", "saxon9");
addSaxon(parameters, pluginPath, SAXON_9_JAR);
} else {
parameters.getVMParametersList().defineProperty("xslt.transformer.type", "saxon");
addSaxon(parameters, pluginPath, SAXON_6_JAR);
}
}
parameters.getVMParametersList().defineProperty("xslt.main", "org.intellij.plugins.xsltDebugger.rt.XSLTDebuggerMain");
}
@Nullable
private static Boolean isValidXalanPresent(SimpleJavaParameters parameters) {
final List<VirtualFile> files = parameters.getClassPath().getVirtualFiles();
for (VirtualFile file : files) {
if (file.getName().matches(".*xalan.*\\.jar")) {
final VirtualFile root = JarFileSystem.getInstance().getJarRootForLocalFile(file);
final VirtualFile manifestFile = root != null ? root.findFileByRelativePath("META-INF/MANIFEST.MF") : null;
if (manifestFile != null) {
try {
Manifest manifest = manifestFile.getUserData(MANIFEST);
if (manifest == null) {
manifest = new Manifest(manifestFile.getInputStream());
manifestFile.putUserData(MANIFEST, manifest);
}
Attributes attributes = manifest.getAttributes("org/apache/xalan/");
if (attributes == null) {
attributes = manifest.getAttributes("org/apache/xalan");
}
if (attributes == null) {
LOG.info("No manifest attributes for 'org/apache/xalan/' in " + manifestFile.getPresentableUrl());
continue;
}
final String version = attributes.getValue("Implementation-Version");
if (version != null) {
final String[] parts = version.split("\\.");
if (parts.length >= 2) {
if (Integer.parseInt(parts[0]) >= 2 && Integer.parseInt(parts[1]) >= 6) {
return true;
}
}
LOG.info("Unsupported Xalan version: " + version);
} else {
LOG.info("No Xalan version information in " + file.getPath());
}
} catch (IOException e) {
LOG.warn("Unable to read manifest from " + file.getName(), e);
}
} else {
LOG.info("No manifest file in " + file.getPath());
}
return false;
}
}
return null;
}
private static void addXalan(SimpleJavaParameters parameters, File pluginPath) {
final char c = File.separatorChar;
File xalan = new File(pluginPath, "lib" + c + "rt" + c + "xalan.jar");
if (!xalan.exists()) {
if (!(xalan = new File(pluginPath, "lib" + c + "xalan.jar")).exists()) {
xalan = new File(pluginPath, "xalan.jar");
assert xalan.exists();
}
}
parameters.getClassPath().addTail(xalan.getAbsolutePath());
parameters.getClassPath().addTail(new File(xalan.getParentFile(), "serializer.jar").getAbsolutePath());
}
private static void addSaxon(SimpleJavaParameters parameters, File pluginPath, final String saxonJar) {
final char c = File.separatorChar;
File saxon = new File(pluginPath, "lib" + c + "rt" + c + saxonJar);
if (!saxon.exists()) {
if (!(saxon = new File(pluginPath, "lib" + c + saxonJar)).exists()) {
saxon = new File(pluginPath, saxonJar);
assert saxon.exists();
}
}
parameters.getClassPath().addTail(saxon.getAbsolutePath());
}
}
@@ -0,0 +1,84 @@
package org.intellij.plugins.xsltDebugger;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.JavaPatchableProgramRunner;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugProcessStarter;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import org.intellij.lang.xpath.xslt.run.XsltRunConfiguration;
import org.intellij.plugins.xsltDebugger.impl.XsltDebugProcess;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 16.11.10
*/
public class XsltDebuggerRunner extends JavaPatchableProgramRunner {
static final ThreadLocal<Boolean> ACTIVE = new ThreadLocal<Boolean>();
@NonNls
private static final String ID = "XsltDebuggerRunner";
@NotNull
@Override
public String getRunnerId() {
return ID;
}
@Override
public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
return executorId.equals("Debug") && profile instanceof XsltRunConfiguration;
}
@Override
protected RunContentDescriptor doExecute(Project project,
Executor executor,
RunProfileState state,
RunContentDescriptor contentToReuse,
ExecutionEnvironment env) throws ExecutionException {
FileDocumentManager.getInstance().saveAllDocuments();
return createContentDescriptor(project, executor, state, contentToReuse, env);
}
@Override
public void patch(JavaParameters javaParameters, RunnerSettings settings, boolean beforeExecution) throws ExecutionException {
javaParameters.setJdk(((XsltRunConfiguration)settings.getRunProfile()).getEffectiveJDK());
}
protected RunContentDescriptor createContentDescriptor(Project project,
final Executor executor,
final RunProfileState runProfileState,
RunContentDescriptor contentToReuse,
ExecutionEnvironment executionEnvironment) throws ExecutionException {
final XDebugSession debugSession =
XDebuggerManager.getInstance(project).startSession(this, executionEnvironment, contentToReuse, new XDebugProcessStarter() {
@NotNull
public XDebugProcess start(@NotNull final XDebugSession session) {
ACTIVE.set(Boolean.TRUE);
try {
final ExecutionResult result = runProfileState.execute(executor, XsltDebuggerRunner.this);
return new XsltDebugProcess(session, result);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} finally {
ACTIVE.remove();
}
}
});
return debugSession.getRunContentDescriptor();
}
}
@@ -0,0 +1,259 @@
/*
* 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.pom.Navigatable;
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 PsiFile file, final int offset) {
return XsltBreakpointHandler.getActualLineNumber(myProject, new MyXSourcePosition(file, offset)) != -1;
}
public void runTo(final PsiFile file, final int offset) {
assert myTempBreakpoint == null;
final int lineNumber = XsltBreakpointHandler.getActualLineNumber(myProject, new MyXSourcePosition(file, offset));
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();
}
private static class MyXSourcePosition implements XSourcePosition {
private final PsiFile myFile;
private final int myOffset;
public MyXSourcePosition(PsiFile file, int offset) {
myFile = file;
myOffset = offset;
}
@Override
public int getLine() {
return -1;
}
@Override
public int getOffset() {
return myOffset;
}
@NotNull
@Override
public VirtualFile getFile() {
return myFile.getVirtualFile();
}
@NotNull
@Override
public Navigatable createNavigatable(@NotNull Project project) {
throw new UnsupportedOperationException();
}
}
}
@@ -0,0 +1,88 @@
/*
* 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.impl;
import com.intellij.psi.xml.XmlElement;
import com.intellij.util.ArrayUtil;
import org.intellij.lang.xpath.context.*;
import org.intellij.lang.xpath.psi.XPathElement;
import org.intellij.lang.xpath.xslt.context.XsltContextProvider;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 06.06.2007
*/
public class EvalContextProvider extends ContextProvider {
private final List<Debugger.Variable> myVariables;
public EvalContextProvider(List<Debugger.Variable> model) {
myVariables = model;
}
@NotNull
public ContextType getContextType() {
return XsltContextProvider.TYPE;
}
@Nullable
public XmlElement getContextElement() {
return null;
}
@Override
protected boolean isValid() {
return true;
}
@Nullable
public NamespaceContext getNamespaceContext() {
return null;
}
public VariableContext getVariableContext() {
return new SimpleVariableContext() {
@NotNull
public String[] getVariablesInScope(XPathElement element) {
final int size = myVariables.size();
final ArrayList<String> vars = new ArrayList<String>(size);
for (Debugger.Variable myVariable : myVariables) {
vars.add(myVariable.getName());
}
return ArrayUtil.toStringArray(vars);
}
};
}
@Nullable
public Set<QName> getAttributes(boolean forValidation) {
return null; // TODO
}
@Nullable
public Set<QName> getElements(boolean forValidation) {
return null; // TODO
}
}
@@ -0,0 +1,173 @@
package org.intellij.plugins.xsltDebugger.impl;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
import com.intellij.xdebugger.ui.DebuggerIcons;
import org.intellij.plugins.xsltDebugger.VMPausedException;
import org.intellij.plugins.xsltDebugger.XsltBreakpointType;
import org.intellij.plugins.xsltDebugger.rt.engine.Breakpoint;
import org.intellij.plugins.xsltDebugger.rt.engine.BreakpointManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class XsltBreakpointHandler extends XBreakpointHandler<XLineBreakpoint<XBreakpointProperties>> {
private XsltDebugProcess myXsltDebugProcess;
public XsltBreakpointHandler(XsltDebugProcess xsltDebugProcess) {
super(XsltBreakpointType.class);
myXsltDebugProcess = xsltDebugProcess;
}
@Override
public void registerBreakpoint(@NotNull XLineBreakpoint<XBreakpointProperties> breakpoint) {
final XSourcePosition sourcePosition = breakpoint.getSourcePosition();
if (sourcePosition == null) {
// ???
return;
}
final VirtualFile file = sourcePosition.getFile();
final Project project = myXsltDebugProcess.getSession().getProject();
final String fileURL = getFileURL(file);
final int lineNumber = getActualLineNumber(breakpoint, project);
try {
final BreakpointManager manager = myXsltDebugProcess.getBreakpointManager();
Breakpoint bp;
if ((bp = manager.getBreakpoint(fileURL, lineNumber)) != null) {
bp.setEnabled(true);
} else {
manager.setBreakpoint(fileURL, lineNumber);
}
} catch (VMPausedException e) {
final XDebugSession session = myXsltDebugProcess.getSession();
session.reportMessage("Target VM is not responding. Breakpoint can not be set", MessageType.ERROR);
session.updateBreakpointPresentation(breakpoint, DebuggerIcons.INVALID_BREAKPOINT_ICON,
"Target VM is not responding. Breakpoint can not be set");
}
}
public static String getFileURL(VirtualFile file) {
return VfsUtil.virtualToIoFile(file).toURI().toASCIIString();
}
@Override
public void unregisterBreakpoint(@NotNull XLineBreakpoint<XBreakpointProperties> breakpoint, final boolean temporary) {
final XSourcePosition sourcePosition = breakpoint.getSourcePosition();
if (sourcePosition == null) {
// ???
return;
}
final VirtualFile file = sourcePosition.getFile();
final Project project = myXsltDebugProcess.getSession().getProject();
final String fileURL = getFileURL(file);
final int lineNumber = getActualLineNumber(breakpoint, project);
try {
final BreakpointManager manager = myXsltDebugProcess.getBreakpointManager();
if (temporary) {
final Breakpoint bp = manager.getBreakpoint(fileURL, lineNumber);
if (bp != null) {
bp.setEnabled(false);
}
} else {
manager.removeBreakpoint(fileURL, lineNumber);
}
} catch (VMPausedException e) {
myXsltDebugProcess.getSession().reportMessage("Target VM is not responding. Breakpoint can not be removed", MessageType.ERROR);
}
}
public static int getActualLineNumber(XLineBreakpoint breakpoint, Project project) {
return getActualLineNumber(project, breakpoint.getSourcePosition());
}
public static int getActualLineNumber(Project project, @Nullable XSourcePosition position) {
if (position == null) {
return -1;
}
final PsiElement element = findContextElement(project, position);
if (element == null) {
return -1;
}
if (element instanceof XmlToken) {
final IElementType tokenType = ((XmlToken)element).getTokenType();
if (tokenType == XmlTokenType.XML_START_TAG_START || tokenType == XmlTokenType.XML_NAME) {
final PsiManager psiManager = PsiManager.getInstance(project);
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
final PsiFile psiFile = psiManager.findFile(position.getFile());
if (psiFile == null) {
return -1;
}
final Document document = documentManager.getDocument(psiFile);
if (document == null) {
return -1;
}
if (document.getLineNumber(element.getTextRange().getStartOffset()) == position.getLine()) {
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class, false);
if (tag != null) {
final ASTNode node = tag.getNode();
assert node != null;
// TODO: re-check if/when Xalan is supported
final ASTNode end = XmlChildRole.START_TAG_END_FINDER.findChild(node);
if (end != null) {
return document.getLineNumber(end.getTextRange().getEndOffset()) + 1;
} else {
final ASTNode end2 = XmlChildRole.EMPTY_TAG_END_FINDER.findChild(node);
if (end2 != null) {
return document.getLineNumber(end2.getTextRange().getEndOffset()) + 1;
}
}
}
}
}
}
return -1;
}
@Nullable
public static PsiElement findContextElement(Project project, @Nullable XSourcePosition position) {
if (position == null) {
return null;
}
final PsiFile file = PsiManager.getInstance(project).findFile(position.getFile());
if (file == null) {
return null;
}
int offset = -1;
final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
if (document != null) {
offset = document.getLineStartOffset(position.getLine());
}
if (offset < 0) {
offset = position.getOffset();
}
PsiElement contextElement = file.findElementAt(offset);
while (contextElement != null && !(contextElement instanceof XmlElement)) {
contextElement = PsiTreeUtil.nextLeaf(contextElement);
}
return contextElement;
}
}
@@ -0,0 +1,189 @@
package org.intellij.plugins.xsltDebugger.impl;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.frame.XExecutionStack;
import com.intellij.xdebugger.frame.XSuspendContext;
import org.intellij.plugins.xsltDebugger.XsltDebuggerSession;
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.local.BreakpointManagerImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class XsltDebugProcess extends XDebugProcess implements Disposable {
private static final Key<XsltDebugProcess> KEY = Key.create("PROCESS");
private final XsltDebuggerEditorsProvider myEditorsProvider;
private final ProcessHandler myProcessHandler;
private final ExecutionConsole myExecutionConsole;
private BreakpointManager myBreakpointManager = new BreakpointManagerImpl();
private final XBreakpointHandler<?>[] myXBreakpointHandlers = new XBreakpointHandler<?>[]{
new XsltBreakpointHandler(this)
};
private XsltDebuggerSession myDebuggerSession;
public XsltDebugProcess(XDebugSession session, ExecutionResult executionResult) {
super(session);
myProcessHandler = executionResult.getProcessHandler();
myProcessHandler.putUserData(KEY, this);
myExecutionConsole = executionResult.getExecutionConsole();
myEditorsProvider = new XsltDebuggerEditorsProvider();
Disposer.register(myExecutionConsole, this);
}
@Override
public XBreakpointHandler<?>[] getBreakpointHandlers() {
return myXBreakpointHandlers;
}
public BreakpointManager getBreakpointManager() {
return myBreakpointManager;
}
public void init(Debugger client) {
myDebuggerSession = XsltDebuggerSession.getInstance(myProcessHandler);
myDebuggerSession.addListener(new XsltDebuggerSession.Listener() {
@Override
public void debuggerSuspended() {
final XDebugSession session = XsltDebugProcess.this.getSession();
final Debugger c = myDebuggerSession.getClient();
session.positionReached(new MySuspendContext(myDebuggerSession, c.getCurrentFrame(), c.getSourceFrame()));
}
@Override
public void debuggerResumed() {
}
@Override
public void debuggerStopped() {
}
});
final BreakpointManager mgr = client.getBreakpointManager();
if (myBreakpointManager != mgr) {
final List<Breakpoint> breakpoints = myBreakpointManager.getBreakpoints();
for (Breakpoint breakpoint : breakpoints) {
final Breakpoint bp = mgr.setBreakpoint(breakpoint.getUri(), breakpoint.getLine());
bp.setEnabled(breakpoint.isEnabled());
bp.setLogMessage(breakpoint.getLogMessage());
bp.setTraceMessage(breakpoint.getTraceMessage());
bp.setCondition(breakpoint.getCondition());
bp.setSuspend(breakpoint.isSuspend());
}
myBreakpointManager = mgr;
}
}
@Nullable
public static XsltDebugProcess getInstance(ProcessHandler handler) {
return handler.getUserData(KEY);
}
@NotNull
@Override
public ExecutionConsole createConsole() {
return myExecutionConsole;
}
@Override
protected ProcessHandler doGetProcessHandler() {
return myProcessHandler;
}
@NotNull
@Override
public XDebuggerEditorsProvider getEditorsProvider() {
return myEditorsProvider;
}
@Override
public void startStepOver() {
myDebuggerSession.stepOver();
}
@Override
public void startStepInto() {
myDebuggerSession.stepInto();
}
@Override
public void startStepOut() {
}
@Override
public void stop() {
if (myDebuggerSession != null) {
myDebuggerSession.stop();
}
}
@Override
public void resume() {
myDebuggerSession.resume();
}
@Override
public void dispose() {
}
@Override
public void runToPosition(@NotNull XSourcePosition position) {
final PsiFile psiFile = PsiManager.getInstance(getSession().getProject()).findFile(position.getFile());
assert psiFile != null;
if (myDebuggerSession.canRunTo(psiFile, position.getOffset())) {
myDebuggerSession.runTo(psiFile, position.getOffset());
} else {
StatusBar.Info.set("Not a valid position in file '" + psiFile.getName() + "'", psiFile.getProject());
final Debugger c = myDebuggerSession.getClient();
getSession().positionReached(new MySuspendContext(myDebuggerSession, c.getCurrentFrame(), c.getSourceFrame()));
}
}
private static class MySuspendContext extends XSuspendContext {
private final XsltDebuggerSession myDebuggerSession;
private final Debugger.StyleFrame myStyleFrame;
private final Debugger.SourceFrame mySourceFrame;
public MySuspendContext(XsltDebuggerSession debuggerSession, Debugger.StyleFrame styleFrame, Debugger.SourceFrame sourceFrame) {
myDebuggerSession = debuggerSession;
myStyleFrame = styleFrame;
mySourceFrame = sourceFrame;
}
@Override
public XExecutionStack getActiveExecutionStack() {
return new XsltExecutionStack("XSLT Frames", myStyleFrame, myDebuggerSession);
}
public XExecutionStack getSourceStack() {
return new XsltExecutionStack("Source Frames", mySourceFrame, myDebuggerSession);
}
@Override
public XExecutionStack[] getExecutionStacks() {
return new XExecutionStack[]{
getActiveExecutionStack(),
getSourceStack()
};
}
}
}
@@ -0,0 +1,48 @@
package org.intellij.plugins.xsltDebugger.impl;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.util.LocalTimeCounter;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import org.intellij.lang.xpath.XPathFileType;
import org.intellij.plugins.xsltDebugger.BreakpointContext;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class XsltDebuggerEditorsProvider extends XDebuggerEditorsProvider {
@NotNull
@Override
public FileType getFileType() {
return XPathFileType.XPATH;
}
@NotNull
@Override
public Document createDocument(@NotNull Project project, @NotNull String text, @Nullable XSourcePosition sourcePosition) {
final PsiFile psiFile = PsiFileFactory.getInstance(project)
.createFileFromText("XPathExpr.xpath", XPathFileType.XPATH, text, LocalTimeCounter.currentTime(), true);
if (sourcePosition instanceof XsltSourcePosition && ((XsltSourcePosition)sourcePosition).getLocation() instanceof Debugger.StyleFrame) {
final Debugger.Locatable location = ((XsltSourcePosition)sourcePosition).getLocation();
final EvalContextProvider context = new EvalContextProvider(((Debugger.StyleFrame)location).getVariables());
context.attachTo(psiFile);
} else {
final PsiElement contextElement = XsltBreakpointHandler.findContextElement(project, sourcePosition);
if (contextElement != null) {
final BreakpointContext context = new BreakpointContext(contextElement);
context.attachTo(psiFile);
}
}
final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
assert document != null;
return document;
}
}
@@ -0,0 +1,45 @@
package org.intellij.plugins.xsltDebugger.impl;
import com.intellij.xdebugger.frame.XExecutionStack;
import com.intellij.xdebugger.frame.XStackFrame;
import org.intellij.plugins.xsltDebugger.XsltDebuggerSession;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class XsltExecutionStack extends XExecutionStack {
private final XsltStackFrame myTopFrame;
private final XsltDebuggerSession myDebuggerSession;
public XsltExecutionStack(String name, Debugger.Frame topFrame, XsltDebuggerSession debuggerSession) {
super(name);
myDebuggerSession = debuggerSession;
myTopFrame = new XsltStackFrame(topFrame, myDebuggerSession);
}
@Override
public XStackFrame getTopFrame() {
return myTopFrame;
}
@Override
public void computeStackFrames(int firstFrameIndex, XStackFrameContainer container) {
if (myDebuggerSession.getCurrentState() == Debugger.State.SUSPENDED) {
Debugger.Frame frame = myTopFrame.getFrame();
final List<XStackFrame> frames = new ArrayList<XStackFrame>();
while (frame != null) {
frame = frame.getPrevious();
if (frame != null) {
frames.add(new XsltStackFrame(frame, myDebuggerSession));
}
}
if (firstFrameIndex <= frames.size()) {
container.addStackFrames(frames.subList(firstFrameIndex - 1, frames.size()), true);
} else {
container.addStackFrames(Collections.<XStackFrame>emptyList(), true);
}
}
}
}
@@ -0,0 +1,65 @@
package org.intellij.plugins.xsltDebugger.impl;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.xdebugger.XSourcePosition;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.URI;
public class XsltSourcePosition implements XSourcePosition {
private final Debugger.Locatable myLocation;
private final VirtualFile myFile;
private final int myLine;
XsltSourcePosition(Debugger.Locatable location, VirtualFile file, int line) {
myLocation = location;
myFile = file;
myLine = line;
}
@Nullable
public static XSourcePosition create(Debugger.Locatable location) {
final VirtualFile file;
try {
file = VfsUtil.findFileByURL(new URI(location.getURI()).toURL());
} catch (Exception e) {
// TODO log
return null;
}
final int line = location.getLineNumber() - 1;
return line >= 0 ? new XsltSourcePosition(location, file, line) : null;
}
@Override
public int getLine() {
return myLine;
}
@Override
public int getOffset() {
return 0;
}
@NotNull
@Override
public VirtualFile getFile() {
return myFile;
}
@NotNull
@Override
public Navigatable createNavigatable(@NotNull Project project) {
return new OpenFileDescriptor(project, getFile(), getLine(), 0);
}
public Debugger.Locatable getLocation() {
return myLocation;
}
}
@@ -0,0 +1,235 @@
package org.intellij.plugins.xsltDebugger.impl;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Icons;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.*;
import org.intellij.plugins.xsltDebugger.XsltDebuggerSession;
import org.intellij.plugins.xsltDebugger.rt.engine.Debugger;
import org.intellij.plugins.xsltDebugger.rt.engine.DebuggerStoppedException;
import org.intellij.plugins.xsltDebugger.rt.engine.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.net.URI;
import java.util.List;
public class XsltStackFrame extends XStackFrame {
private final Debugger.Frame myFrame;
private final XsltDebuggerSession myDebuggerSession;
private XSourcePosition myPosition;
public XsltStackFrame(Debugger.Frame frame, XsltDebuggerSession debuggerSession) {
myFrame = frame;
myDebuggerSession = debuggerSession;
myPosition = XsltSourcePosition.create(frame);
}
@Override
public Object getEqualityObject() {
return super.getEqualityObject();
}
@Override
public XDebuggerEvaluator getEvaluator() {
return myFrame instanceof Debugger.StyleFrame ? new MyEvaluator((Debugger.StyleFrame)myFrame) : null;
}
@Override
public XSourcePosition getSourcePosition() {
return myPosition;
}
@Override
public void customizePresentation(SimpleColoredComponent component) {
if (myDebuggerSession.getCurrentState() == Debugger.State.SUSPENDED) {
try {
_customizePresentation(component);
} catch (DebuggerStoppedException ignore) {
}
}
}
private void _customizePresentation(SimpleColoredComponent component) {
final Debugger.Frame frame = myFrame;
if (frame instanceof Debugger.StyleFrame) {
component.append(((Debugger.StyleFrame)frame).getInstruction(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
} else if (frame instanceof Debugger.SourceFrame) {
component.append(((Debugger.SourceFrame)frame).getXPath(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
}
component.append(" ", SimpleTextAttributes.REGULAR_ATTRIBUTES);
try {
final VirtualFile file = VfsUtil.findFileByURL(new URI(frame.getURI()).toURL());
if (file != null) {
component.append(file.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
if (frame.getLineNumber() > 0) {
component.append(":" + frame.getLineNumber(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
component.setToolTipText(file.getPresentableUrl());
} else {
component.append(frame.getURI() + ":" + frame.getLineNumber(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
} catch (Exception e) {
component.append(frame.getURI() + ":" + frame.getLineNumber(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
}
@Override
public void computeChildren(@NotNull XCompositeNode node) {
if (myFrame instanceof Debugger.StyleFrame) {
final List<Debugger.Variable> variables = ((Debugger.StyleFrame)myFrame).getVariables();
final XValueChildrenList list = new XValueChildrenList();
for (final Debugger.Variable variable : variables) {
list.add(variable.getName(), new MyValue(variable));
}
node.addChildren(list, true);
} else {
super.computeChildren(node);
}
}
public Debugger.Frame getFrame() {
return myFrame;
}
private static class MyValue extends XValue {
private final Debugger.Variable myVariable;
public MyValue(Debugger.Variable variable) {
myVariable = variable;
}
@Override
public void computePresentation(@NotNull XValueNode node) {
final Debugger.Variable.Kind kind = myVariable.getKind();
Icon icon = null;
if (myVariable.isGlobal()) {
if (kind == Debugger.Variable.Kind.VARIABLE) {
icon = Icons.FIELD_ICON;
} else {
icon = Icons.PROPERTY_ICON;
}
} else if (kind == Debugger.Variable.Kind.VARIABLE) {
icon = Icons.VARIABLE_ICON;
} else if (kind == Debugger.Variable.Kind.PARAMETER) {
icon = Icons.PARAMETER_ICON;
}
final Value v = myVariable.getValue();
if (v.getType() == Value.XPathType.STRING) {
node.setPresentation(icon, v.getType().getName(), "'" + String.valueOf(v.getValue()) + "'", false);
} else {
final boolean hasChildren = myVariable.getValue().getValue() instanceof Value.NodeSet;
node.setPresentation(icon, v.getType().getName(), String.valueOf(v.getValue()), hasChildren);
}
}
@Override
public void computeChildren(@NotNull XCompositeNode node) {
if (myVariable.getValue().getValue() instanceof Value.NodeSet) {
final Value.NodeSet set = (Value.NodeSet)myVariable.getValue().getValue();
final XValueChildrenList list = new XValueChildrenList();
for (final Value.Node n : set.getNodes()) {
list.add(n.myXPath, new NodeValue(n));
}
node.addChildren(list, false);
}
super.computeChildren(node);
}
@Override
public String getEvaluationExpression() {
return "$" + myVariable.getName();
}
@Override
public void computeSourcePosition(@NotNull XNavigatable navigatable) {
navigatable.setSourcePosition(XsltSourcePosition.create(myVariable));
}
static String clipValue(String stringValue) {
return stringValue.length() < 100 ? stringValue : stringValue.substring(0, 100) + "...";
}
private static class NodeValue extends XValue {
private final Value.Node myNode;
public NodeValue(Value.Node n) {
myNode = n;
}
@Override
public void computeSourcePosition(@NotNull XNavigatable navigatable) {
navigatable.setSourcePosition(XsltSourcePosition.create(myNode));
}
@Override
public void computePresentation(@NotNull XValueNode node) {
node.setPresentation(null, "node", myNode.myStringValue, false);
}
}
}
private static class MyEvaluator extends XDebuggerEvaluator {
private final Debugger.StyleFrame myFrame;
public MyEvaluator(Debugger.StyleFrame frame) {
myFrame = frame;
}
@Override
public boolean isCodeFragmentEvaluationSupported() {
return false;
}
@Override
public void evaluate(@NotNull String expression, XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition) {
try {
final Value eval = myFrame.eval(expression);
callback.evaluated(new MyValue(new ExpressionResult(eval)));
} catch (Debugger.EvaluationException e) {
callback.errorOccurred(e.getMessage());
}
}
private static class ExpressionResult implements Debugger.Variable {
private final Value myValue;
public ExpressionResult(Value value) {
myValue = value;
}
@SuppressWarnings({ "ConstantConditions" })
public String getURI() {
return null;
}
public int getLineNumber() {
return -1;
}
public boolean isGlobal() {
return false;
}
public Kind getKind() {
return Kind.EXPRESSION;
}
public String getName() {
return "result";
}
public Value getValue() {
return myValue;
}
}
}
}
@@ -0,0 +1,47 @@
package org.intellij.plugins.xsltDebugger.ui;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
import javax.swing.*;
/*
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 08.03.11
*/
abstract class AbstractTabComponent extends AdditionalTabComponent {
private final String myTabTitle;
public AbstractTabComponent(String tabTitle) {
myTabTitle = tabTitle;
}
@Override
public String getTabTitle() {
return myTabTitle;
}
@Override
public JComponent getSearchComponent() {
return null;
}
@Override
public String getToolbarPlace() {
return null;
}
@Override
public JComponent getToolbarContextComponent() {
return null;
}
@Override
public boolean isContentBuiltIn() {
return false;
}
@Override
public void dispose() {
}
}
@@ -0,0 +1,322 @@
/*
* Copyright 2002-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.ui;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.pom.Navigatable;
import com.intellij.util.SmartList;
import com.intellij.util.containers.StringInterner;
import org.intellij.plugins.xsltDebugger.XsltDebuggerSession;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 09.06.2007
*/
public class GeneratedStructureModel extends DefaultTreeModel {
@NonNls
private static final String PENDING = "...";
private static WeakReference<StringInterner> ourSharedInterner;
private final LinkedList<DefaultMutableTreeNode> myCurrentPath = new LinkedList<DefaultMutableTreeNode>();
private final List<DefaultMutableTreeNode> myLastNodes = new LinkedList<DefaultMutableTreeNode>();
private final StringInterner myInterner = getInterner();
// we keep a shared string interner across all currently running xslt debugger instances. it should go away once
// all instances (and their toolwindow contents) are gone. This should minimize the memory usage of the generated
// structure tree.
private static StringInterner getInterner() {
StringInterner interner;
if (ourSharedInterner == null || (interner = ourSharedInterner.get()) == null) {
interner = new StringInterner();
ourSharedInterner = new WeakReference<StringInterner>(interner);
}
return interner;
}
private boolean myFilterWhitespace;
private boolean myListenersDisabled;
public GeneratedStructureModel() {
super(new MyRootNode());
final DefaultMutableTreeNode root = (DefaultMutableTreeNode)getRoot();
myCurrentPath.add(root);
root.add(new DefaultMutableTreeNode(PENDING));
}
public void update(final List<OutputEventQueue.NodeEvent> eventQueue) {
if (!SwingUtilities.isEventDispatchThread()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
updateImpl(eventQueue);
}
});
return;
}
updateImpl(eventQueue);
}
@Override
public Object getChild(Object parent, int index) {
if (!myFilterWhitespace) {
return super.getChild(parent, index);
}
return getFilteredChildren((DefaultMutableTreeNode)parent, false).get(index);
}
@Override
public int getChildCount(Object parent) {
if (!myFilterWhitespace) {
return super.getChildCount(parent);
}
return getFilteredChildren((DefaultMutableTreeNode)parent, false).size();
}
@Override
public boolean isLeaf(Object node) {
if (!myFilterWhitespace) {
return super.isLeaf(node);
}
return super.isLeaf(node) || getFilteredChildren((DefaultMutableTreeNode)node, true).size() == 0;
}
private static List getFilteredChildren(DefaultMutableTreeNode node, boolean checkOnly) {
if (node.getChildCount() == 0) {
return Collections.emptyList();
}
final List<DefaultMutableTreeNode> nodes = checkOnly ?
new SmartList<DefaultMutableTreeNode>() :
new ArrayList<DefaultMutableTreeNode>(node.getChildCount());
DefaultMutableTreeNode child = (DefaultMutableTreeNode)node.getFirstChild();
while (child != null) {
if (child instanceof StructureNode) {
final OutputEventQueue.NodeEvent event = (OutputEventQueue.NodeEvent)child.getUserObject();
if (event != null && event.getType() == OutputEventQueue.CHARACTERS) {
if (event.getValue().trim().length() == 0) {
child = child.getNextSibling();
continue;
}
}
}
nodes.add(child);
if (checkOnly) return nodes;
child = child.getNextSibling();
}
return nodes;
}
private void updateImpl(List<OutputEventQueue.NodeEvent> nodeEvents) {
if (nodeEvents.size() > 0) {
for (DefaultMutableTreeNode node : myLastNodes) {
if (node instanceof StructureNode) {
((StructureNode)node).refresh();
}
}
myLastNodes.clear();
}
for (OutputEventQueue.NodeEvent event : nodeEvents) {
event = intern(event);
final DefaultMutableTreeNode node = myCurrentPath.getFirst();
switch (event.getType()) {
case OutputEventQueue.START_DOCUMENT:
break;
case OutputEventQueue.START_ELEMENT:
final StructureNode child = new StructureNode(event);
myLastNodes.add(child);
final int index = getChildCount(node) - 1;
node.insert(child, node.getChildCount() - 1);
child.add(new DefaultMutableTreeNode(PENDING));
myCurrentPath.addFirst(child);
nodesWereInserted(node, new int[]{ index });
break;
case OutputEventQueue.END_ELEMENT:
if (node instanceof MyRootNode) {
// unknown xalan bug: start/end is sometimes unbalanced. should be fixed somewhere else...
continue;
}
case OutputEventQueue.END_DOCUMENT:
final DefaultMutableTreeNode c = myCurrentPath.removeFirst();
final int childIndex = getChildCount(c) - 1;
final int realChildIndex = c.getChildCount() - 1;
if (realChildIndex >= 0) {
final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)c.getChildAt(realChildIndex);
assert childNode.getUserObject() == PENDING;
c.remove(realChildIndex);
nodesWereRemoved(c, new int[]{ childIndex }, new Object[]{ childNode });
}
break;
case OutputEventQueue.TRACE_POINT:
case OutputEventQueue.ATTRIBUTE:
case OutputEventQueue.CHARACTERS:
case OutputEventQueue.COMMENT:
case OutputEventQueue.PI:
final StructureNode ch = new StructureNode(event);
myLastNodes.add(ch);
final int i = getChildCount(node) - 1;
node.insert(ch, node.getChildCount() - 1);
nodesWereInserted(node, new int[]{ i });
}
}
}
private OutputEventQueue.NodeEvent intern(OutputEventQueue.NodeEvent event) {
event.myURI = intern(event.myURI);
event.myQName = intern(event.myQName);
event.myValue = intern(event.myValue);
return event;
}
@Nullable
private OutputEventQueue.NodeEvent.QName intern(OutputEventQueue.NodeEvent.QName name) {
if (name == null) return null;
name.myPrefix = intern(name.myPrefix);
name.myLocalName = intern(name.myLocalName);
name.myURI = intern(name.myURI);
return name;
}
@Nullable
private String intern(String s) {
if (s != null) {
if (s.length() == 0) return s.intern();
return myInterner.intern(s);
} else {
return null;
}
}
public boolean isFilterWhitespace() {
return myFilterWhitespace;
}
public void setFilterWhitespace(boolean b) {
final boolean old = myFilterWhitespace;
myFilterWhitespace = b;
if (b != old) {
nodeStructureChanged((TreeNode)getRoot());
}
}
public void finalUpdate(final List<OutputEventQueue.NodeEvent> events) {
Runnable runnable = new Runnable() {
public void run() {
myListenersDisabled = true;
try {
updateImpl(events);
} finally {
myListenersDisabled = false;
nodeStructureChanged((TreeNode)getRoot());
}
}
};
ApplicationManager.getApplication().invokeLater(runnable);
}
@Override
protected void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
if (myListenersDisabled) return;
super.fireTreeNodesChanged(source, path, childIndices, children);
}
@Override
protected void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) {
if (myListenersDisabled) return;
super.fireTreeNodesInserted(source, path, childIndices, children);
}
@Override
protected void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) {
if (myListenersDisabled) return;
super.fireTreeNodesRemoved(source, path, childIndices, children);
}
@Override
protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
if (myListenersDisabled) return;
super.fireTreeStructureChanged(source, path, childIndices, children);
}
private static class MyRootNode extends DefaultMutableTreeNode {
public MyRootNode() {
super("ROOT");
}
}
public static class StructureNode extends DefaultMutableTreeNode implements Navigatable {
private boolean isNew = true;
public StructureNode(OutputEventQueue.NodeEvent event) {
super(event);
}
private void refresh() {
isNew = false;
}
public boolean isNew() {
return isNew;
}
@Override
public OutputEventQueue.NodeEvent getUserObject() {
return (OutputEventQueue.NodeEvent)super.getUserObject();
}
public void navigate(boolean requestFocus) {
final OutputEventQueue.NodeEvent event = getUserObject();
final Project project = (Project)DataManager.getInstance().getDataContext().getData(PlatformDataKeys.PROJECT.getName());
XsltDebuggerSession.openLocation(project, event.getURI(), event.getLineNumber() - 1);
}
public boolean canNavigate() {
return getUserObject().getLineNumber() > 0;
}
public boolean canNavigateToSource() {
return canNavigate();
}
}
}
@@ -0,0 +1,104 @@
/*
* Copyright 2002-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.ui;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Icons;
import com.intellij.xdebugger.ui.DebuggerIcons;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 09.06.2007
*/
class GeneratedStructureRenderer extends ColoredTreeCellRenderer {
private static final Icon XML_COMMENT_ICON = IconLoader.getIcon("xmlComment.png");
public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
final DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
final Object o = node.getUserObject();
if (o == null || "ROOT".equals(o)) {
// invisible
} else if (o instanceof String) {
// "..." node
append((String)o, SimpleTextAttributes.SYNTHETIC_ATTRIBUTES);
setToolTipText("Element is not finished yet");
} else if (o instanceof OutputEventQueue.NodeEvent) {
final OutputEventQueue.NodeEvent event = (OutputEventQueue.NodeEvent)o;
final OutputEventQueue.NodeEvent.QName qname = event.getQName();
switch (event.getType()) {
case OutputEventQueue.START_ELEMENT:
setIcon(Icons.XML_TAG_ICON);
append(qname.getQName(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
if (qname.myURI != null && qname.myURI.length() > 0) {
append(" {", SimpleTextAttributes.GRAYED_ATTRIBUTES);
append(qname.myURI, SimpleTextAttributes.GRAYED_ATTRIBUTES);
append("}", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
break;
case OutputEventQueue.ATTRIBUTE:
setIcon(Icons.ANNOTATION_TYPE_ICON);
append(qname.getQName(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
if (qname.myURI != null && qname.myURI.length() > 0) {
append(" {" + qname.myURI + "}", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
append(" = \"", SimpleTextAttributes.REGULAR_ATTRIBUTES);
append(event.getValue(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
append("\"", SimpleTextAttributes.REGULAR_ATTRIBUTES);
break;
case OutputEventQueue.CHARACTERS:
append("#text ", SimpleTextAttributes.GRAYED_ATTRIBUTES);
append(clipValue(event.getValue()), SimpleTextAttributes.REGULAR_ATTRIBUTES);
break;
case OutputEventQueue.COMMENT:
setIcon(XML_COMMENT_ICON);
append("#comment ", SimpleTextAttributes.GRAYED_ATTRIBUTES);
append(event.getValue(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
break;
case OutputEventQueue.PI:
append("#processing-instruction ", SimpleTextAttributes.GRAYED_ATTRIBUTES);
append(qname.myLocalName, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
append(" " + event.getValue(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
break;
case OutputEventQueue.TRACE_POINT:
setIcon(DebuggerIcons.ENABLED_BREAKPOINT_ICON);
append("Tracepoint at line " + event.getLineNumber(), SimpleTextAttributes.GRAY_ATTRIBUTES);
if (event.getValue() != null) {
append(" " + event.getValue(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
break;
}
if (node instanceof GeneratedStructureModel.StructureNode) {
if (((GeneratedStructureModel.StructureNode)node).isNew()) {
append(" *", SimpleTextAttributes.SYNTHETIC_ATTRIBUTES);
}
}
}
}
static String clipValue(String stringValue) {
return stringValue.length() < 80 ? stringValue : stringValue.substring(0, 80) + "...";
}
}
@@ -0,0 +1,39 @@
package org.intellij.plugins.xsltDebugger.ui;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import org.intellij.plugins.xsltDebugger.ui.actions.OpenOutputAction;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class OutputTabComponent extends AbstractTabComponent {
private final DefaultActionGroup myOutputActions;
private final AdditionalTabComponent myOutputConsole;
public OutputTabComponent(AdditionalTabComponent outputConsole) {
super("Output");
myOutputConsole = outputConsole;
final DefaultActionGroup outputActions = new DefaultActionGroup();
outputActions.add(new OpenOutputAction(outputConsole));
myOutputActions = outputActions;
}
@NotNull
@Override
public JComponent getComponent() {
return myOutputConsole;
}
@Override
public JComponent getPreferredFocusableComponent() {
return myOutputConsole.getPreferredFocusableComponent();
}
@Override
public ActionGroup getToolbarActions() {
return myOutputActions;
}
}
@@ -0,0 +1,96 @@
/*
* Copyright 2002-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.ui;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.Alarm;
import com.intellij.util.ui.tree.TreeModelAdapter;
import com.intellij.util.ui.tree.TreeUtil;
import javax.swing.*;
import javax.swing.event.TreeModelEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 09.06.2007
*/
public class SmartStructureTracker extends TreeModelAdapter {
private final JTree myEventTree;
private final Alarm myAlarm;
public SmartStructureTracker(JTree eventTree, Disposable disposable) {
myEventTree = eventTree;
myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, disposable);
}
@Override
public void treeNodesInserted(TreeModelEvent e) {
final TreePath path = e.getTreePath();
final Object child = e.getChildren()[0];
if (path != null && child != null) {
myAlarm.cancelAllRequests();
final Runnable runnable = new Runnable() {
public void run() {
myEventTree.expandPath(path);
TreeUtil.showRowCentered(myEventTree, myEventTree.getRowForPath(TreeUtil.getPathFromRoot((TreeNode)child)), false);
}
};
myAlarm.addRequest(runnable, 300);
}
}
@Override
public void treeNodesRemoved(TreeModelEvent e) {
final TreePath p = e.getTreePath();
if (p != null) {
if (p.getPathCount() > 1) {
final Runnable runnable = new Runnable() {
public void run() {
DefaultMutableTreeNode last = (DefaultMutableTreeNode)p.getLastPathComponent();
if (last.getChildCount() > 0) {
DefaultMutableTreeNode next = (DefaultMutableTreeNode)last.getFirstChild();
while (next != null) {
boolean collapse = true;
// final int count = next.getChildCount();
// if (count > 0) {
// for (int i = 0; i < count; i++) {
// final DefaultMutableTreeNode child = (DefaultMutableTreeNode)next.getChildAt(i);
// if (child instanceof GeneratedStructureModel.StructureNode) {
// if (((GeneratedStructureModel.StructureNode)child).isNew()) {
// collapse = false;
// }
// }
// }
// }
if (collapse) {
myEventTree.collapsePath(TreeUtil.getPathFromRoot(next));
}
next = next.getNextSibling();
}
}
}
};
ApplicationManager.getApplication().invokeLater(runnable);
}
}
}
}
@@ -0,0 +1,68 @@
package org.intellij.plugins.xsltDebugger.ui;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.ide.CommonActionsManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.util.Key;
import com.intellij.ui.treeStructure.Tree;
import org.intellij.plugins.xsltDebugger.ui.actions.HideWhitespaceAction;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class StructureTabComponent extends AbstractTabComponent {
private static final Key<StructureTabComponent> KEY = Key.create("STRUCTURE");
private final DefaultActionGroup myToolbarActions;
private final Tree myStructureTree;
private final GeneratedStructureModel myEventModel;
private StructureTabComponent(Disposable disposable) {
super("Structure");
myEventModel = new GeneratedStructureModel();
myStructureTree = new StructureTree(myEventModel);
myEventModel.addTreeModelListener(new SmartStructureTracker(myStructureTree, disposable));
final DefaultActionGroup structureActions = new DefaultActionGroup();
final StructureTreeExpander expander = new StructureTreeExpander(myStructureTree);
final CommonActionsManager actionsManager = CommonActionsManager.getInstance();
structureActions.add(new HideWhitespaceAction(myStructureTree, myEventModel));
structureActions.add(actionsManager.createExpandAllAction(expander, myStructureTree));
structureActions.add(actionsManager.createCollapseAllAction(expander, myStructureTree));
myToolbarActions = structureActions;
}
public GeneratedStructureModel getEventModel() {
return myEventModel;
}
public static StructureTabComponent create(ProcessHandler process, Disposable disposable) {
final StructureTabComponent component = new StructureTabComponent(disposable);
process.putUserData(KEY, component);
return component;
}
public static StructureTabComponent getInstance(ProcessHandler process) {
return process.getUserData(KEY);
}
@NotNull
@Override
public JComponent getComponent() {
return myStructureTree;
}
@Override
public JComponent getPreferredFocusableComponent() {
return getComponent();
}
@Override
public ActionGroup getToolbarActions() {
return myToolbarActions;
}
}
@@ -0,0 +1,65 @@
/*
* Copyright 2002-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.ui;
import com.intellij.openapi.actionSystem.*;
import com.intellij.pom.Navigatable;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.treeStructure.Tree;
import org.intellij.plugins.xsltDebugger.ui.actions.CopyValueAction;
import org.intellij.plugins.xsltDebugger.ui.actions.NavigateAction;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 17.06.2007
*/
public class StructureTree extends Tree implements TypeSafeDataProvider {
public StructureTree(GeneratedStructureModel model) {
super(model);
setCellRenderer(new GeneratedStructureRenderer());
setRootVisible(false);
setShowsRootHandles(true);
final DefaultActionGroup structureContextActions = new DefaultActionGroup("StructureContext", true);
structureContextActions.add(NavigateAction.getInstance());
structureContextActions.add(new CopyValueAction(this));
PopupHandler.installFollowingSelectionTreePopup(this, structureContextActions, "XSLT.Debugger.GeneratedStructure", ActionManager.getInstance());
}
public void calcData(DataKey key, DataSink sink) {
if (key.equals(PlatformDataKeys.NAVIGATABLE)) {
final TreePath selection = getSelectionPath();
if (selection != null) {
final Object o = selection.getLastPathComponent();
if (o instanceof Navigatable) {
sink.put(PlatformDataKeys.NAVIGATABLE, (Navigatable)o);
}
}
} else if (key.equals(CopyValueAction.SELECTED_NODE)) {
final TreePath selection = getSelectionPath();
if (selection != null) {
final Object o = selection.getLastPathComponent();
sink.put(CopyValueAction.SELECTED_NODE, (DefaultMutableTreeNode)o);
}
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2002-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.ui;
import com.intellij.ide.TreeExpander;
import com.intellij.util.ui.tree.TreeUtil;
import javax.swing.*;
/**
* Created by IntelliJ IDEA.
* User: sweinreuter
* Date: 28.11.2007
*/
public class StructureTreeExpander implements TreeExpander {
private final JTree myTree;
public StructureTreeExpander(JTree tree) {
myTree = tree;
}
public void expandAll() {
TreeUtil.expandAll(myTree);
}
public boolean canExpand() {
return true;
}
public void collapseAll() {
TreeUtil.collapseAll(myTree, 1);
}
public boolean canCollapse() {
return true;
}
}
@@ -0,0 +1,69 @@
/*
* Copyright 2002-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.ui.actions;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.ide.CopyPasteManager;
import org.intellij.plugins.xsltDebugger.rt.engine.OutputEventQueue;
import org.intellij.plugins.xsltDebugger.ui.GeneratedStructureModel;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.datatransfer.StringSelection;
@SuppressWarnings({ "ComponentNotRegistered" })
public class CopyValueAction extends AnAction {
public static final DataKey<DefaultMutableTreeNode> SELECTED_NODE = DataKey.create("SELECTED_NODE");
public CopyValueAction(JComponent component) {
final AnAction action = ActionManager.getInstance().getAction("$Copy");
if (action != null) {
copyFrom(action);
registerCustomShortcutSet(getShortcutSet(), component);
}
}
@Override
public void update(AnActionEvent e) {
e.getPresentation().setEnabled(isEnabled(e));
}
public void actionPerformed(AnActionEvent e) {
final DefaultMutableTreeNode node = e.getData(SELECTED_NODE);
if (node instanceof GeneratedStructureModel.StructureNode) {
final GeneratedStructureModel.StructureNode structureNode = (GeneratedStructureModel.StructureNode)node;
final OutputEventQueue.NodeEvent event = structureNode.getUserObject();
setClipboardData(event.getValue());
}
}
private static void setClipboardData(String value) {
CopyPasteManager.getInstance().setContents(new StringSelection(value));
}
protected static boolean isEnabled(AnActionEvent e) {
final DefaultMutableTreeNode node = e.getData(SELECTED_NODE);
if (node instanceof GeneratedStructureModel.StructureNode) {
final GeneratedStructureModel.StructureNode structureNode = (GeneratedStructureModel.StructureNode)node;
final OutputEventQueue.NodeEvent event = structureNode.getUserObject();
return event != null && event.getValue() != null;
}
return false;
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2002-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.ui.actions;
import com.intellij.ide.util.treeView.TreeState;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.treeStructure.Tree;
import org.intellij.plugins.xsltDebugger.ui.GeneratedStructureModel;
@SuppressWarnings({ "ComponentNotRegistered" })
public class HideWhitespaceAction extends ToggleAction {
private final Tree myStructureTree;
private final GeneratedStructureModel myEventModel;
public HideWhitespaceAction(Tree structureTree, GeneratedStructureModel eventModel) {
super("Hide Whitespace Nodes");
myStructureTree = structureTree;
myEventModel = eventModel;
getTemplatePresentation().setIcon(IconLoader.getIcon("filterWhitespace.png"));
}
public boolean isSelected(AnActionEvent e) {
return myEventModel.isFilterWhitespace();
}
public void setSelected(AnActionEvent e, boolean state) {
final TreeState treeState = TreeState.createOn(myStructureTree);
myEventModel.setFilterWhitespace(state);
treeState.applyTo(myStructureTree);
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2002-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.ui.actions;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.IdeActions;
public class NavigateAction {
private NavigateAction() {
}
public static AnAction getInstance() {
return ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE);
}
}
@@ -0,0 +1,65 @@
/*
* Copyright 2002-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.ui.actions;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vcs.vfs.VcsFileSystem;
import com.intellij.openapi.vcs.vfs.VcsVirtualFile;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
@SuppressWarnings({ "ComponentNotRegistered" })
public class OpenOutputAction extends AnAction {
private final AdditionalTabComponent myConsole;
public OpenOutputAction(AdditionalTabComponent console) {
super("Open in Editor");
myConsole = console;
getTemplatePresentation().setIcon(IconLoader.getIcon("/actions/export.png"));
}
public void actionPerformed(AnActionEvent e) {
final Editor editor = PlatformDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext(myConsole.getComponent()));
if (editor != null) {
try {
final byte[] content = editor.getDocument().getText().getBytes("UTF-8");
final String extension = "xml"; // TODO: get from output type
final VcsVirtualFile file = new VcsVirtualFile("XSLT Output." + extension, content, null, VcsFileSystem.getInstance()) {
@Override
public Charset getCharset() {
return Charset.forName("UTF-8");
}
};
FileEditorManager.getInstance(PlatformDataKeys.PROJECT.getData(e.getDataContext())).openFile(file, true);
} catch (UnsupportedEncodingException e1) {
throw new AssertionError(e);
}
}
}
public void update(AnActionEvent e) {
final Editor editor = PlatformDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext(myConsole.getComponent()));
e.getPresentation().setEnabled(editor != null && editor.getDocument().getTextLength() > 0);
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/out" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="xpath" />
<orderEntry type="module" module-name="xslt-debugger-rt" />
<orderEntry type="module" module-name="lang-api" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="xdebugger-api" />
<orderEntry type="module" module-name="xdebugger-impl" />
<orderEntry type="module" module-name="xml-openapi" />
<orderEntry type="module" module-name="compiler-impl" />
<orderEntry type="module" module-name="openapi" />
<orderEntry type="module" module-name="xml" />
<orderEntry type="module" module-name="execution-openapi" />
<orderEntry type="module" module-name="debugger-impl" />
<orderEntry type="module" module-name="platform-impl" />
</component>
</module>