If you've looked at my recent posts, you know I'm working on a plugin for VisualVM, a very useful tool supplied with the JDK. In one example, I showed how to attach to a waiting Java application using a socket-based AttachingConnector. At that time I said that there were two primary ways of attaching to a process with JDI -- via shared memory, and with a socket.

It turns out there is a "third way". Following is an example of why this way is useful, and why it was provided.

When I last wrote JDI programs (in Java 5), I would notice that my target application would start up and print (to stdout) the port on which it was listening, as in the following:
Listening for transport dt_socket at address: 55779
In Java 5, if you detached your debugger from this process, you would get another line to stdout in the target's console, like this:
Listening for transport dt_socket at address: 55779
and this would go on for as long as you chose to attach and detach, etc.

At some point (and I don't know when this started happening), the port on which the target is listening started changing on each detach of an external debugger. If in Java 6 (I'm using u20), you repeatedly attach and detach from the target process, you'll see the following out in the target's console:
Listening for transport dt_socket at address: 55837
ERROR: transport error 202: recv error: Connection reset by peer
Listening for transport dt_socket at address: 55844
ERROR: transport error 202: recv error: Connection reset by peer
Listening for transport dt_socket at address: 55846
ERROR: transport error 202: recv error: Connection reset by peer
Listening for transport dt_socket at address: 55911
If you're writing an application that attaches using the debug port, each time you attach you need to find out what port the target is using. This information is not available from the process itself; in other words, you have to play the usual unpleasant game of capturing console output to know what the port is. Even if you specify a port at target start, you still need to get your hands on the value.

You can still find the original request for a feature to attach to a process by its process ID if you search around the old Java bug reports. The long and short of it: a new AttachingConnector was created, one which attaches by PID. As you know, sometimes it isn't much fun finding a process's PID either. In my case, however, I am writing a plugin for VisualVM, and one thing you get for free when you do that is Visual VM's API, which as you might expect includes calls to get the PID. My goal, then, is to use this new connector in my VisualVM plugin, and I thought it might be appreciated if I shared the details.

I've adapted my test program from an earlier post so that it now outputs the details of each AttachingConnector; the changed code fragment is shown here:
List<AttachingConnector> attachingConnectors = vmMgr.attachingConnectors();
for (AttachingConnector ac: attachingConnectors)
{
Map paramsMap = ac.defaultArguments();
Iterator keyIter = paramsMap.keySet().iterator();
System.out.println("AttachingConnector: '" + ac.getClass().getName() + "'");
System.out.println(" name: '" + ac.name() + "'");
System.out.println(" description: '" + ac.description() + "'");
System.out.println(" transport name: '" + ac.transport().name() + "'");
System.out.println(" default arguments:");
while (keyIter.hasNext())
{
String nextKey = keyIter.next();
System.out.println(" key: '" + nextKey + "'; value: '" + paramsMap.get(nextKey) + "'");
}
}
The output from this code is shown below:
AttachingConnector:  'com.sun.tools.jdi.SocketAttachingConnector'
name: 'com.sun.jdi.SocketAttach'
description: 'Attaches by socket to other VMs'
transport name: 'dt_socket'
default arguments:
key: 'timeout'; value: 'timeout='
key: 'hostname'; value: 'hostname=AdamsResearch'
key: 'port'; value: 'port='
AttachingConnector: 'com.sun.tools.jdi.SharedMemoryAttachingConnector'
name: 'com.sun.jdi.SharedMemoryAttach'
description: 'Attaches by shared memory to other VMs'
transport name: 'dt_shmem'
default arguments:
key: 'timeout'; value: 'timeout='
key: 'name'; value: 'name='
AttachingConnector: 'com.sun.tools.jdi.ProcessAttachingConnector'
name: 'com.sun.jdi.ProcessAttach'
description: 'Attaches to debuggee by process-id (pid)'
transport name: 'local'
default arguments:
key: 'pid'; value: 'pid='
key: 'timeout'; value: 'timeout='
A couple of things I hadn't noticed before is that the socket-based connector comes with the hostname argument pre-set to my machine's hostname, and that all three connectors have a timeout default argument. The first observation brings up an interesting point: if you use the local, PID-based connector, remember that you'll only be attaching to processes on your debugger's host.

I changed my test program to use the local connector and it works as before! Well, no, actually, it does not. Here's what I now get:
java.lang.UnsatisfiedLinkError: no attach in java.library.path
Exception in thread "main" java.io.IOException: no providers installed
at com.sun.tools.jdi.ProcessAttachingConnector.attach(ProcessAttachingConnector.java:86)
at com.adamsresearch.jdiDemo.JDIDemo.main(JDIDemo.java:70)
Does this mean the local connector isn't exactly ready for use? No, but I have been burned by the same issue that has plagued a number of others (scroll down in that page -- the issue was found by a reader of that post and was solved, partially, by another reader of that post). I'm working on a Windows platform, and when you do that you have to be a little careful ;-> . In this case, the problem is caused by 1) using the java interpreter as found on the system path, and 2) not making sure that path points directly to your JDK or JRE directory. The executable will look in a path relative to itself for the needed libraries, and when Windows copies the java executable to C:\Windows\system32 (or similar) -- and if you use that executable -- that relative path is broken. I believe this is the true issue, unlike described in the comments on the above post, where the distinction is made between using the JRE java and the JDK java. I don't think that's the issue. For example, below are the results of my attach test in 3 different scenarios:
  1. Using java from my path, the first hit of which comes from C:\Windows\system32:

    java -cp c:\jdk1.6.0_20\lib\tools.jar;. com.adamsresearch.jdiDemo.JDIDemo 10816 863 fileName
    ...
    java.lang.UnsatisfiedLinkError: no attach in java.library.path
    Exception in thread "main" java.io.IOException: no providers installed
    at com.sun.tools.jdi.ProcessAttachingConnector.attach(ProcessAttachingConnector.java:86)
    at com.adamsresearch.jdiDemo.JDIDemo.main(JDIDemo.java:70)

  2. Using the full path to the JRE bin java:

    c:\jdk1.6.0_20\jre\bin\java -cp c:\jdk1.6.0_20\lib\tools.jar;. com.adamsresearch.jdiDemo.JDIDemo 10816 863 fileName
    ...
    Attached to process 'Java HotSpot(TM) 64-Bit Server VM'

  3. Using the full path to the JDK bin java:
    c:\jdk1.6.0_20\bin\java -cp c:\jdk1.6.0_20\lib\tools.jar;. com.adamsresearch.jdiDemo.JDIDemo 10816 863 fileName
    ...
    Attached to process 'Java HotSpot(TM) 64-Bit Server VM'
As you can see, the above seems to support my theory that it's not the JRE vs the JDK, but rather the context-poor placement of the java executable in the "usual" Windows binaries directory, that caused the problem. That posting is several years old, so it is possible that at that time, the needed JDI libraries actually were not included in the JRE, but it is clear that today, you will see the same exception if you use the java executable found in Windows' default binaries directory.

Now, if I run my JDI application against my JarView utility, searching for AttachingConnector in the JDK installation directory, I get the following output:
Breakpoint at line 863:
fileName = 'AttachingConnector.class'
Breakpoint at line 863:
fileName = 'GenericAttachingConnector$1.class'
Breakpoint at line 863:
fileName = 'GenericAttachingConnector.class'
Breakpoint at line 863:
fileName = 'ProcessAttachingConnector$1.class'
Breakpoint at line 863:
fileName = 'ProcessAttachingConnector$2.class'
Breakpoint at line 863:
fileName = 'ProcessAttachingConnector.class'
Breakpoint at line 863:
fileName = 'SharedMemoryAttachingConnector$1.class'
Breakpoint at line 863:
fileName = 'SharedMemoryAttachingConnector.class'
Breakpoint at line 863:
fileName = 'SocketAttachingConnector$1.class'
Breakpoint at line 863:
fileName = 'SocketAttachingConnector.class'
and so have done what I set out to do, which is 1) debug-attach by process ID, and 2) thrash through the inevitable hiccups and share the solutions. Hopefully this will be useful to you, too.

Note: actually, there are even more ways to attach to a Java process. JPDA Connection and Invocation is the definitive guide, from Oracle. If you're going to be writing debuggers, you can't go wrong reading this page first.

For nearly two years, I've been trying to branch out and add another programming language to my brain.  I read and blogged about Seven Languages in Seven Weeks, by Brian Tate, an excellent book that I blasted through in seven days to save a little time.  If you read my blog, you'll know that I finally settled on Haskell, started posting about my experience as an object-oriented programmer writing in a functional language, and then things kind of fizzled out.

I really like Haskell.  However, I think I'm one of those people who tend to learn better when under pressure.  Since I didn't have a job requirement to learn Haskell or an otherwise motivating situation, I never really quite got in to it.  I still plan to, some day.

I've been experimenting with using Pig on some Fannie-Mae MBS data lately.  While I don't mind writing MapReduce programs to process data (especially the fairly simple tasks I'm doing now), I really do appreciate the "magic" Pig does under the blanket, you might say.  If you don't know, Pig, a member of the Hadoop ecosystem (and now a first-class Apache project at pig.apache.org), is a framework for analyzing large data sets.

I've recently been writing JMS clients for an application I'm building and keep finding myself having to re-learn some basic configuration. While some standalone JMS servers are still quite simple to configure, the JMS resources of some application servers have become somewhat complex to configure over the years. I'm quite sure I remember, in an earlier version of WebLogic Server, going to a JMS page and configuring a topic or queue on-the-spot. Those days are gone.

A few years ago, I posted a how-to on Java-SE-based Web Services. More recently, I've become interested in asynchronous web-service invocation, and, as it turns out, Java SE supports that, too. This post, then, is the asynchronous version of that older post. How I got to the structure of this post is a story in itself. To make things simpler, I will first go through all the steps to deploy

an asynchronous Java SE web service.

In an earlier post, we stepped through the building of an asynchronous web service, deployed in Java SE. I saved my comments for this post to keep things a little cleaner. But there are some loose ends to discuss, especially when you hear my motivation for building an asynchronous web service in the first place.

Normally, you want to invoke a service asynchronously because you expect potentially long server response times.

As I have mentioned in earlier posts, I am using the Java Debug Interface (JDI) to create a Java process-monitoring tool. I'm retracing my steps from an earlier such effort a few years ago, and as I wade through the details, I'm posting details in the hope they'll be helpful to someone else out there. I sometimes wonder who would really be interested in this material, but I have been noticing that my old posts on JDI, DTrace, etc.

In my Part-1 post on this topic, we actually did all the I/O I'm going to do here. We lazily read in the entire sample data file, a file containing data describing events generated by a process monitor. My next goal was to re-hydrate my Events from the Strings serialized to the file. These Strings were generated by calling the function show on my List of Events.

Time to back up a little. We got show for free, but we had to ask for it.

I'm about halfway through Real World Haskell, and I've spent a week trying to decide when to write this post. As the authors point out, Haskell I/O is easy to work with. However, understanding the significance of what is going on in Haskell I/O requires a little more than simply outputting "Hello, World". The reason: once you include I/O, you start mixing pure and impure code, and a good understanding of what's going on will additionally include some discussion of monads.

For the last few weeks, I have been building a Java process monitoring tool based on the Java Debug Interface. Although I've done much of this work before, it has been a few years, and so now I'm retracing my steps. As I remember the details and pitfalls, I've been posting my notes in the hope that you'll find them useful.

Today I'm going to talk about ClassPrepareEvents, after a little background.

After my last post scrolled off the bottom of the page, I realized I missed a couple of opportunities: one related to some additional code optimization, and one related to the topic of lazy (or nonstrict) evaluation.

First, let me review what I was doing. I was processing a data structure I was using to represent events generated from a process monitor. The structure includes a timestamp, a class name and source line number, a text message, and a set of properties.
About Me
About Me
My Photo
I'm a software architect/consultant in Boulder, Colorado.
Picture
Picture
Blog Archive
Loading
Dynamic Views theme. Powered by Blogger. Report Abuse.