xslt debugger initial commit
authorSascha Weinreuter <sascha.weinreuter@gmail.com>
Tue, 24 May 2011 09:02:47 +0000 (11:02 +0200)
committerSascha Weinreuter <sascha.weinreuter@gmail.com>
Tue, 24 May 2011 09:05:50 +0000 (11:05 +0200)
85 files changed:
.idea/modules.xml
community-main.iml
plugins/xslt-debugger/build.properties [new file with mode: 0644]
plugins/xslt-debugger/build.xml [new file with mode: 0644]
plugins/xslt-debugger/rt/lib/rmi-stubs.jar [new file with mode: 0644]
plugins/xslt-debugger/rt/lib/saxon-conditions.html [new file with mode: 0644]
plugins/xslt-debugger/rt/lib/saxon.jar [new file with mode: 0644]
plugins/xslt-debugger/rt/lib/saxon9he.jar [new file with mode: 0644]
plugins/xslt-debugger/rt/lib/serializer.jar [new file with mode: 0644]
plugins/xslt-debugger/rt/lib/xalan.jar [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/XSLTDebuggerMain.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Breakpoint.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/BreakpointManager.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Debugger.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/DebuggerStoppedException.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/OutputEventQueue.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Value.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Watchable.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/AbstractFrame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/BreakpointImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/BreakpointManagerImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/LocalDebugger.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/OutputEventQueueImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/VariableComparator.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/VariableImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/AbstractSaxonFrame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonFrameImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonSourceFrame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonSupport.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonTraceListener.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/AbstractSaxon9Frame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9SourceFrame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9Support.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9TraceListener.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/TracingOutputter.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/TracingSerializationHandler.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XObjectValue.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanStyleFrame.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanSupport.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanTraceListener.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/DebuggerServer.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpoint.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointManager.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointManagerImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebuggerClient.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteEventQueueImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteFrameImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteVariableImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/ValueImpl.java [new file with mode: 0644]
plugins/xslt-debugger/rt/xslt-debugger-rt.iml [new file with mode: 0644]
plugins/xslt-debugger/src/META-INF/plugin.xml [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/BreakpointContext.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/DebugProcessListener.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/DebuggerConnector.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/EDTGuard.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/VMPausedException.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltBreakpointType.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerSession.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/EvalContextProvider.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltBreakpointHandler.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltDebugProcess.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltDebuggerEditorsProvider.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltSourcePosition.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/GeneratedStructureModel.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/GeneratedStructureRenderer.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/OutputTabComponent.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/SmartStructureTracker.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTabComponent.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTree.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTreeExpander.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/CopyValueAction.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/HideWhitespaceAction.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/NavigateAction.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/OpenOutputAction.java [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/filterWhitespace.png [new file with mode: 0644]
plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/xmlComment.png [new file with mode: 0644]
plugins/xslt-debugger/xslt-debugger.iml [new file with mode: 0644]

index 19e68530442f3b1770b7932d9b3b96b7c1f28b84..1c82aaa53ea974b7d54dc88d4e9a05cb2fa0235b 100644 (file)
       <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>
index e3109b8263bfcc89a308cd38943abf861fee5484..4b5a9e3fa21d090ed165631e86c1442948f3904e 100644 (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" />
diff --git a/plugins/xslt-debugger/build.properties b/plugins/xslt-debugger/build.properties
new file mode 100644 (file)
index 0000000..ea2fd1e
--- /dev/null
@@ -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
diff --git a/plugins/xslt-debugger/build.xml b/plugins/xslt-debugger/build.xml
new file mode 100644 (file)
index 0000000..e0b869c
--- /dev/null
@@ -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>
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/lib/rmi-stubs.jar b/plugins/xslt-debugger/rt/lib/rmi-stubs.jar
new file mode 100644 (file)
index 0000000..cb5ad8a
Binary files /dev/null and b/plugins/xslt-debugger/rt/lib/rmi-stubs.jar differ
diff --git a/plugins/xslt-debugger/rt/lib/saxon-conditions.html b/plugins/xslt-debugger/rt/lib/saxon-conditions.html
new file mode 100644 (file)
index 0000000..cd33c42
--- /dev/null
@@ -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>
diff --git a/plugins/xslt-debugger/rt/lib/saxon.jar b/plugins/xslt-debugger/rt/lib/saxon.jar
new file mode 100644 (file)
index 0000000..15aa83a
Binary files /dev/null and b/plugins/xslt-debugger/rt/lib/saxon.jar differ
diff --git a/plugins/xslt-debugger/rt/lib/saxon9he.jar b/plugins/xslt-debugger/rt/lib/saxon9he.jar
new file mode 100644 (file)
index 0000000..5d86f50
Binary files /dev/null and b/plugins/xslt-debugger/rt/lib/saxon9he.jar differ
diff --git a/plugins/xslt-debugger/rt/lib/serializer.jar b/plugins/xslt-debugger/rt/lib/serializer.jar
new file mode 100644 (file)
index 0000000..99f98db
Binary files /dev/null and b/plugins/xslt-debugger/rt/lib/serializer.jar differ
diff --git a/plugins/xslt-debugger/rt/lib/xalan.jar b/plugins/xslt-debugger/rt/lib/xalan.jar
new file mode 100644 (file)
index 0000000..458fa73
Binary files /dev/null and b/plugins/xslt-debugger/rt/lib/xalan.jar differ
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/XSLTDebuggerMain.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/XSLTDebuggerMain.java
new file mode 100644 (file)
index 0000000..4e578a8
--- /dev/null
@@ -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());
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Breakpoint.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Breakpoint.java
new file mode 100644 (file)
index 0000000..18d8e1b
--- /dev/null
@@ -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);
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/BreakpointManager.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/BreakpointManager.java
new file mode 100644 (file)
index 0000000..ea9b01e
--- /dev/null
@@ -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);
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Debugger.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Debugger.java
new file mode 100644 (file)
index 0000000..af12ff3
--- /dev/null
@@ -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);
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/DebuggerStoppedException.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/DebuggerStoppedException.java
new file mode 100644 (file)
index 0000000..0b00bdb
--- /dev/null
@@ -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 {
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/OutputEventQueue.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/OutputEventQueue.java
new file mode 100644 (file)
index 0000000..da03a1c
--- /dev/null
@@ -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;
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Value.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Value.java
new file mode 100644 (file)
index 0000000..090146f
--- /dev/null
@@ -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 + '\'' +
+             '}';
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Watchable.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/Watchable.java
new file mode 100644 (file)
index 0000000..9518232
--- /dev/null
@@ -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();
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/AbstractFrame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/AbstractFrame.java
new file mode 100644 (file)
index 0000000..87bd44f
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/BreakpointImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/BreakpointImpl.java
new file mode 100644 (file)
index 0000000..8b7388e
--- /dev/null
@@ -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 +
+           '}';
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/BreakpointManagerImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/BreakpointManagerImpl.java
new file mode 100644 (file)
index 0000000..9b51450
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/LocalDebugger.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/LocalDebugger.java
new file mode 100644 (file)
index 0000000..c0dfabc
--- /dev/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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/OutputEventQueueImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/OutputEventQueueImpl.java
new file mode 100644 (file)
index 0000000..04ccf25
--- /dev/null
@@ -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();
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/VariableComparator.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/VariableComparator.java
new file mode 100644 (file)
index 0000000..638674d
--- /dev/null
@@ -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());
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/VariableImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/VariableImpl.java
new file mode 100644 (file)
index 0000000..fdde205
--- /dev/null
@@ -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();
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/AbstractSaxonFrame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/AbstractSaxonFrame.java
new file mode 100644 (file)
index 0000000..1719b6a
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonFrameImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonFrameImpl.java
new file mode 100644 (file)
index 0000000..9f93824
--- /dev/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();
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonSourceFrame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonSourceFrame.java
new file mode 100644 (file)
index 0000000..1125b5f
--- /dev/null
@@ -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);
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonSupport.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonSupport.java
new file mode 100644 (file)
index 0000000..21961e4
--- /dev/null
@@ -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();
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonTraceListener.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon/SaxonTraceListener.java
new file mode 100644 (file)
index 0000000..b19e63e
--- /dev/null
@@ -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);
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/AbstractSaxon9Frame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/AbstractSaxon9Frame.java
new file mode 100644 (file)
index 0000000..8018944
--- /dev/null
@@ -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;
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9SourceFrame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9SourceFrame.java
new file mode 100644 (file)
index 0000000..1b8385e
--- /dev/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);
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java
new file mode 100644 (file)
index 0000000..15363a8
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9Support.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9Support.java
new file mode 100644 (file)
index 0000000..c871a99
--- /dev/null
@@ -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;
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9TraceListener.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9TraceListener.java
new file mode 100644 (file)
index 0000000..19e132a
--- /dev/null
@@ -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();
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/TracingOutputter.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/TracingOutputter.java
new file mode 100644 (file)
index 0000000..74171cf
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/TracingSerializationHandler.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/TracingSerializationHandler.java
new file mode 100644 (file)
index 0000000..9d0026c
--- /dev/null
@@ -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();
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XObjectValue.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XObjectValue.java
new file mode 100644 (file)
index 0000000..4d1a39d
--- /dev/null
@@ -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);
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanStyleFrame.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanStyleFrame.java
new file mode 100644 (file)
index 0000000..047a638
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanSupport.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanSupport.java
new file mode 100644 (file)
index 0000000..66cd89c
--- /dev/null
@@ -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;
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanTraceListener.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/local/xalan/XalanTraceListener.java
new file mode 100644 (file)
index 0000000..dbb5ad3
--- /dev/null
@@ -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;
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/DebuggerServer.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/DebuggerServer.java
new file mode 100644 (file)
index 0000000..674029d
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpoint.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpoint.java
new file mode 100644 (file)
index 0000000..181cfa3
--- /dev/null
@@ -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;
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointImpl.java
new file mode 100644 (file)
index 0000000..08724c1
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointManager.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointManager.java
new file mode 100644 (file)
index 0000000..2d4b317
--- /dev/null
@@ -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;
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointManagerImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteBreakpointManagerImpl.java
new file mode 100644 (file)
index 0000000..15255be
--- /dev/null
@@ -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));
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java
new file mode 100644 (file)
index 0000000..31d875c
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebuggerClient.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebuggerClient.java
new file mode 100644 (file)
index 0000000..35f04d6
--- /dev/null
@@ -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);
+      }
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteEventQueueImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteEventQueueImpl.java
new file mode 100644 (file)
index 0000000..9c182ba
--- /dev/null
@@ -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);
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteFrameImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteFrameImpl.java
new file mode 100644 (file)
index 0000000..e11056f
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteVariableImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteVariableImpl.java
new file mode 100644 (file)
index 0000000..8e83c9b
--- /dev/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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/ValueImpl.java b/plugins/xslt-debugger/rt/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/ValueImpl.java
new file mode 100644 (file)
index 0000000..4862ab3
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/rt/xslt-debugger-rt.iml b/plugins/xslt-debugger/rt/xslt-debugger-rt.iml
new file mode 100644 (file)
index 0000000..f78948e
--- /dev/null
@@ -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>
+
diff --git a/plugins/xslt-debugger/src/META-INF/plugin.xml b/plugins/xslt-debugger/src/META-INF/plugin.xml
new file mode 100644 (file)
index 0000000..2966ef8
--- /dev/null
@@ -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>
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/BreakpointContext.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/BreakpointContext.java
new file mode 100644 (file)
index 0000000..7cc43e2
--- /dev/null
@@ -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;
+      }
+    };
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/DebugProcessListener.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/DebugProcessListener.java
new file mode 100644 (file)
index 0000000..a4a20d8
--- /dev/null
@@ -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();
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/DebuggerConnector.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/DebuggerConnector.java
new file mode 100644 (file)
index 0000000..3d78317
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/EDTGuard.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/EDTGuard.java
new file mode 100644 (file)
index 0000000..8e68a6f
--- /dev/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);
+      }
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/VMPausedException.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/VMPausedException.java
new file mode 100644 (file)
index 0000000..90c6ed9
--- /dev/null
@@ -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 {
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltBreakpointType.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltBreakpointType.java
new file mode 100644 (file)
index 0000000..dbfb1b0
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java
new file mode 100644 (file)
index 0000000..275ff94
--- /dev/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());
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java
new file mode 100644 (file)
index 0000000..f683c03
--- /dev/null
@@ -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();
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerSession.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerSession.java
new file mode 100644 (file)
index 0000000..97ec837
--- /dev/null
@@ -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();
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/EvalContextProvider.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/EvalContextProvider.java
new file mode 100644 (file)
index 0000000..095a674
--- /dev/null
@@ -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
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltBreakpointHandler.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltBreakpointHandler.java
new file mode 100644 (file)
index 0000000..7f6a02d
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltDebugProcess.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltDebugProcess.java
new file mode 100644 (file)
index 0000000..5d0c16a
--- /dev/null
@@ -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()
+      };
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltDebuggerEditorsProvider.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltDebuggerEditorsProvider.java
new file mode 100644 (file)
index 0000000..9e4a1df
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java
new file mode 100644 (file)
index 0000000..e32a209
--- /dev/null
@@ -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);
+      }
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltSourcePosition.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltSourcePosition.java
new file mode 100644 (file)
index 0000000..6d6be7a
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java
new file mode 100644 (file)
index 0000000..5e13ae8
--- /dev/null
@@ -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;
+      }
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java
new file mode 100644 (file)
index 0000000..5e9182b
--- /dev/null
@@ -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() {
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/GeneratedStructureModel.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/GeneratedStructureModel.java
new file mode 100644 (file)
index 0000000..09fa963
--- /dev/null
@@ -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();
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/GeneratedStructureRenderer.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/GeneratedStructureRenderer.java
new file mode 100644 (file)
index 0000000..ae9f572
--- /dev/null
@@ -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) + "...";
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/OutputTabComponent.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/OutputTabComponent.java
new file mode 100644 (file)
index 0000000..8e24851
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/SmartStructureTracker.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/SmartStructureTracker.java
new file mode 100644 (file)
index 0000000..4673d55
--- /dev/null
@@ -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);
+      }
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTabComponent.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTabComponent.java
new file mode 100644 (file)
index 0000000..0d871b4
--- /dev/null
@@ -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;
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTree.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTree.java
new file mode 100644 (file)
index 0000000..79773bf
--- /dev/null
@@ -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);
+      }
+    }
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTreeExpander.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/StructureTreeExpander.java
new file mode 100644 (file)
index 0000000..7e94e6c
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/CopyValueAction.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/CopyValueAction.java
new file mode 100644 (file)
index 0000000..6bc6a40
--- /dev/null
@@ -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;
+  }
+}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/HideWhitespaceAction.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/HideWhitespaceAction.java
new file mode 100644 (file)
index 0000000..10899b5
--- /dev/null
@@ -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);
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/NavigateAction.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/NavigateAction.java
new file mode 100644 (file)
index 0000000..f30df10
--- /dev/null
@@ -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);
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/OpenOutputAction.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/OpenOutputAction.java
new file mode 100644 (file)
index 0000000..f4ad221
--- /dev/null
@@ -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);
+  }
+}
\ No newline at end of file
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/filterWhitespace.png b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/filterWhitespace.png
new file mode 100644 (file)
index 0000000..6efd277
Binary files /dev/null and b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/actions/filterWhitespace.png differ
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/xmlComment.png b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/xmlComment.png
new file mode 100644 (file)
index 0000000..4863600
Binary files /dev/null and b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/xmlComment.png differ
diff --git a/plugins/xslt-debugger/xslt-debugger.iml b/plugins/xslt-debugger/xslt-debugger.iml
new file mode 100644 (file)
index 0000000..4f5ffab
--- /dev/null
@@ -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>
+