[Java] Remote debugging of scripts in Java

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
hol.sten
Volunteer
Posts: 495
Joined: Mon Oct 08, 2007 1:31 am
Location: Hamburg, Germany

[Java] Remote debugging of scripts in Java

Post by hol.sten »

Introduction

This post covers how to debug a script in Java running as a macro in OpenOffice.org.

OpenOffice.org provides a Scripting Framework which enables writing macros in a number of programming and scripting languages including BeanShell, JavaScript, Java and OpenOffice.org Basic. The Scripting Framework chapter of the OOo Developer's Guide tells, that debugging of a script in Java is not possible. But it is possible, anyway.

Just to prevent confusion: This post covers remote debugging of a script or macro in Java. It does not cover debugging JavaScript. This is possible from within OOo without an additional setup.


Prerequisite

To start remote debugging, you should know, how to develop, deploy and execute Java scripts in OOo. If you have never done anything like that, you should read first [Java] OOo Writer and Calc macro examples.

I've used OOo 2.3.1, NetBeans IDE 6.0 and Eclipse 3.3.2, Java 1.6_04 and Windows XP to get Java remote debugging started. Although it might work with other versions, too.

For Java remote debugging of macros in Java it is not necessary to install the OOo SDK or the OpenOffice.org plugin module for NetBeans.


Java script source code example

To keep this as simple as possible, we use only a very small macro in Java:

Code: Select all

package ooo.scripting;

import com.sun.star.awt.ActionEvent;
import com.sun.star.awt.KeyEvent;
import com.sun.star.awt.MouseEvent;
import com.sun.star.script.provider.XScriptContext;
import com.sun.star.text.XText;
import com.sun.star.text.XTextDocument;
import com.sun.star.text.XTextRange;
import com.sun.star.uno.UnoRuntime;

public class HelloRemoteDebuggingWorld {

  private XTextDocument xtextdocument;

  public HelloRemoteDebuggingWorld (XTextDocument xtextdocument) {

      this.xtextdocument = xtextdocument;
  }

  private void print() {

    XText xText = xtextdocument.getText();
    XTextRange xTextRange = xText.getEnd();
    String message = "Hello Remote Debugging Java World!";
    xTextRange.setString(message);
  }

  /**
   * Called from a toolbar.
   */
  public static void print(XScriptContext xScriptContext, Short ignored) {
    print(xScriptContext);
  } 

  /**
   * Called from a button with an action.
   */
  public static void print(XScriptContext xScriptContext, ActionEvent ignored) {
    print(xScriptContext);
  }

  /**
   * Called from a button with a key.
   */
  public static void print(XScriptContext xScriptContext, KeyEvent ignored) {
    print(xScriptContext);
  }

  /**
   * Called from a button with the mouse.
   */
  public static void print(XScriptContext xScriptContext, MouseEvent ignored) {
    print(xScriptContext);
  }

  /**
   * Called from a menu or the "Run Macro..." menu.
   */
  public static void print(XScriptContext xScriptContext) {

    XTextDocument xtextdocument = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class, xScriptContext.getDocument());

    HelloRemoteDebuggingWorld hello = new HelloRemoteDebuggingWorld(xtextdocument);
    hello.print();
  }

  public static void main(String[] args) {
  }
}
All this macro does is to write the string "Hello Remote Debugging Java World!" at the end of the current writer document.

This class provides no methods to call this Java macro from outside OOo, because only OOo can provide an XScriptContext.

The only curious method in this example code is the static main() method. Without this method it is not possible during remote debugging to change the value of the String "message". At least not on my Windows XP and NetBeans IDE 6.0. I have not the slightest clue, why this empty method is needed. Deleting main() and redeploying the compiled class file results in an error message "Class java.lang.String not loaded" in the NetBeans IDE, if you try to change "message" after it has been assigned in line 22. The same Java source code without main() works without this problem during remote debugging with Eclipse.

To add a Java script to OOo we need a "parcel-descriptor.xml" file. The following contains all specifications for our Java script example above:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<parcel language="Java" xmlns:parcel="scripting.dtd">
  <script language="Java">
    <locale lang="en">
      <displayname value="HelloRemoteDebuggingWorld"/>
      <description>Prints "Hello Remote Debugging Java World!".</description>
    </locale>
    <logicalname value="HelloRemoteDebuggingWorld"/>
    <functionname value="ooo.scripting.HelloRemoteDebuggingWorld.print"/>
    <languagedepprops>
      <prop name="classpath" value=".:RemoteDebugging.jar"/>
    </languagedepprops>
  </script>
</parcel>
In this "parcel-descriptor.xml" I assigned "HelloRemoteDebuggingWorld" to the the "logicalname" and the "displayname" (although this name is not used as display name, as the name might suggest). The "functionname" is a little longer and contains additionally the package name "ooo.scripting" and the method name with the "XScriptContext" parameter "print".

Furthermore in the "languagedepprops" I assigned ".:RemoteDebugging.jar" to the "classpath" for this Java script. So the classpath of this Java script consists of the current directory ("."), which is the folder, the "parcel-descriptor.xml" itself is located, and the JAR file "RemoteDebugging.jar". Putting "." in the classpath enables to put class files in a folder structure fitting to the package name of the java class. So in this example, OOo's Scripting Framework looks for "HelloRemoteDebuggingWorld.class" in the subfolder "ooo/scripting" of the folder, the "parcel-descriptor.xml" is located, and in the JAR file "RemoteDebugging.jar" in the same folder. Putting "." first in the classpath enables to quickly overwrite a class file in one of the later JAR files in the classpath. Although it is dangerous to forget a class file in one of the subfolders, it is sometimes handy, not to have to rebuild all the JAR files after you made a change in a Java source code file.

If you have no idea, how to get this example running, you should read [Java] OOo Writer and Calc macro examples.


Prepare Java remote debugging

Preparing Java remote debugging consist of two steps:
  • Enable Java remote debugging in OOo: Start OOo, and call "Tools" > "Options..." > "OpenOffice.org" branch > "Java". Select the JRE OOo uses and press the button "Parameter...". Enter now the Java start parameters

    Code: Select all

    -Xrunjdwp:transport=dt_socket,server=y,address=12999,suspend=n
    and press "Assign". Thats all, you have to do in OOo to enable remote debugging. If you call now a Java macro, for example through "Tools" > "Macros" > "Run Macro...", you can see, for example with "TCPView", that the process "soffice.BIN" opens the port 12999 for TCP and waits with LISTENING. If you see nothing like that, you should check your network settings or firewall. For example you might need to enable OOo to get through the Windows Firewall. At least that was necessary for me, because I have the Windows XP Firewall running and I always login with a restricted account. So I had once to login as administrator, call the Windows XP Firewall settings and grant OOo access through the firewall.
  • Set up NetBeans IDE for remote debugging: Start NetBeans IDE, and call "Run" > "Attach Debugger...". Select the Debugger "JPDA Debugger", the Connector "SocketAttach (Attaches by socket to the other VMs)", the Host "localhost" or "YOUR_HOSTNAME", the Port "12999" and leave the Timout empty.
  • Set up Eclipse for remote debugging: Start Eclipse and call "Run" > "Open Debug Dialog...". Scroll down the list of debug launch settings, select "Remote Java Application", press the right mouse button there and select "New" from the context menu. Now fill in the remote debug launch settings: Enter for example "OOo remote debugging" as Name, select the Project with the Java macro source code, select the Connection Type "Standard (SocketAttach)", enter the Host "localhost" or "YOUR_HOSTNAME" and the Port "12999". Press "Apply" next and finally "Close".
  • If you want to know more about the remote debugging settings read Java(TM) Platform Debugger Architecture and JPDA Connection and Invocation Details

Remote debugging of the Java script example

Presuming that the Java script example is correctly installed and that it works as explained, we can now start debugging:
  • Start OOo and call "Tools" > "Macros" > "Run Macro...". Don't select a macro at this point!
For remote debugging with NetBeans IDE proceed here:
  • Start NetBeans IDE, call "Run" > "Attach Debugger..." and select the above listed debugger settings. If everything is ok, you can observe two things: In NetBeans IDE you can read on the Debugger Console "Attaching to localhost:12999, User program running". And for example with "TCPView" you can see, that the process "soffice.BIN" has changed from LISTENING to ESTABLISHED.
  • Set a breakpoint in the Java source code of the macro for example in line 28. Quite often you can read immediately on the Debugger Console "LineBreakpoint HelloRemoteDebuggingWorld.java : 28 successfully submitted."
  • Select now in OOo the macro "ooo.scripting.HelloRemoteDebuggingWorld.print" in the macro dialog and call "Run".
  • In NetBeans IDE you can read no on the Debugger Console "Breakpoint hit at line 28 in class ooo.scripting.HelloRemoteDebuggingWorld by thread Thread-407. Thread Thread-407 stopped at HelloRemoteDebuggingWorld.java:28."
  • Debug through your code with for example "Step Over" (F8) and "Step In" (F7) and change the message before calling "Continue" (F5).
  • If you had changed the message, you should see the altered message in your writer document in OOo.
  • Terminate remote debugging by either exiting OOo or selecting "Finish Debugger Session" (Shift+F5) in NetBeans IDE.
And if you prefer Eclipse, continue remote debugging this way:
  • Start Eclipse, call "Run" > "Open Debug Dialog...", select the above created remote debug launch settings and press "Debug". If everything is ok, you can observe with for example "TCPView", that the process "soffice.BIN" has changed from LISTENING to ESTABLISHED.
  • Set a breakpoint in the Java source code of the macro for example in line 28 and switch to the Debug Perspective.
  • Select now in OOo the macro "ooo.scripting.HelloRemoteDebuggingWorld.print" in the macro dialog and call "Run".
  • In Eclipse the debugger now stopps at line 28 in "HelloRemoteDebuggingWorld".
  • Debug through your code with for example "Step Over" (F6) and "Step Into" (F5) and change the message before calling "Resume" (F8).
  • If you had changed the message, you should see the altered message in your writer document in OOo.
  • Terminate remote debugging by either exiting OOo or selecting "Terminate" (Ctrl+F5) in Eclipse.

Credits

I've got the idea of remote debugging from remembering that I did it once with a web application running in Tomcat using Eclipse. So I googled for OpenOffice.org remote debugging and found the following encouraging links which help me setting it up: For getting remote debugging working with Eclipse, the following link helped me:
Last edited by hol.sten on Sun Mar 09, 2008 9:04 pm, edited 4 times in total.
OOo 3.2.0 on Ubuntu 10.04 • OOo 3.2.1 on Windows 7 64-bit and MS Windows XP
hol.sten
Volunteer
Posts: 495
Joined: Mon Oct 08, 2007 1:31 am
Location: Hamburg, Germany

Change log

Post by hol.sten »

09. Mar. 2008: Enhanced Java code example that can be called from a toolbar and a button, too (http://www.rugludallur.com/index.php?id=31)
03. Mar. 2008: Remote debugging with Eclipse added
02. Mar. 2008: Explanation of the "classpath" in the "languagedepprops" and links to SUN's documentation of JPDA added
02. Mar. 2008: Creation of the Java remote debugging macro
OOo 3.2.0 on Ubuntu 10.04 • OOo 3.2.1 on Windows 7 64-bit and MS Windows XP
Post Reply