I wish I didn’t have to: Decompiling Java

“I wish I didn’t have to” sounds like a category on its own, sort of like a complement to The Daily WTF. But, alas, I do — I need to understand what the differences are between two JARs, and I haven’t looked into Java decompilers since JAD (goes to show… something). But after some brief googling — Procyon rules! So here’s a script to do JAR diffs.

P.S. The humility of the author in designating a pretty good product as a 0 version (a propos — this is silly) led me to dig further into this project and it is cool stuff. Look forward to digging some more.

Poor Man’s Tracepoints and a call sequence of a C program

My C is quite rusty, so to help me figure out the flow of a program, I thought I’d do with gdb what Tony Loton did with JPDA. Quickly giving myself a refresher on gdb, I thought tracepoints are the easiest way to go. Except that they are available only for
remote targets, and

  1. There’s no gdbserver on my host platform (Cygwin)
  2. The target platform does have it (good news!), but it doesn’t support tracepoints (and some say, that few if any stubs even support it

So I wrote a silly Perl script to read ctags information, create breakpoints on every function entry, print the arguments and resume. I haven’t bothered to figure out where to use pure MI vs. CLI commands, and in general I have no clue…

Now, what I think would be interesting is making this an add-on, using CDT (or, more generically, via Eclipse Debug Framework) and GEF… I envision something like a call graph (with exclusions of course, because it will become too big), which grows as you step through, displaying arguments. Could be a quick way to get a picture of how a program works before just reading the code and keeping stuff in your head…


In related news, upgrading to Eclipse 3.2.2 I lost the “Remote debugging” launch configuration. (Ironically, the reason for the attempted upgrade was to see whether a bug with hardcoded remote port has been fixed (it appeared that it’s always 4305, no matter what you put in; while the default one is 1234, which is the kind of thing an idiot would have on his luggage.). Which brings me to the “Zero information content” of various blogs/articles out there (which this blog is trying not to be). Thank you, Bill Graham, for pointing out that “the ‘vanilla’ CDT from http://www.eclipse.org […] doesn’t support remote target debugging”, thus leading me in my Google search to your article which doesn’t tell me how to fix it, nor does it tell me much of anything… There, I vented. (The answer, BTW, is to get Target Management, who knew…)

Silly Flex trick of the day

Since “only top-level components in the application can have context menus“, how would one make a different ContextMenu for every type of item in a tree? In particular, I want tree leaves to have different menu items enabled than the branches; e.g., the leaves should have “Properties” menu enabled, and the “Create new” menu disabled, and vice versa for the branches. Mac Martine mentions using
rollovers, which is cute, but it looks like a more robust way is to use
MOUSE_OVER (yeah, I tried both).

To do this, use the following TreeItemRenderer in the tree in question (obviously, you can choose to add/remove things
from the ContextMenu.customItems rather than enabling/disabling them…):


public class ServerTreeRenderer extends TreeItemRenderer {

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(super.data) {
if (TreeListData(super.listData)) {
leaf:Boolean = !TreeListData(super.listData).hasChildren ;
super.label.addEventListener(
MouseEvent.MOUSE_OVER,
function(evt:MouseEvent):void {
// This will disable all items in my context menu (it's declared somewhere
// else, this is not a TreeItemRenderer method, duh...
disableAll();
if (leaf) {
// propertiesItem is a ContextMenuItem...
propertiesItem.enabled = true;
} else {
contextMenuContainer.createNewItem.enabled = true;
}
[...]

All of this is in anticipation of a promised exegesis on how a
custom ContextMenu works anyway (I have no time for this
at the moment), but works for now…

P.S. I just like the word “exegesis”. The more exegeses, the merrier…

KISS

A propos that meme/urban legend/тема/байка about the space pen and a pencil

I’m using Alexei Sokolov’s version, not the SVG one, but close enough… So, just like commenter Stefan, I was wondering about using text with GWT Canvas. So when Robert Hanson responded that “That is definately on my to-do list, but I don’t have a timeframe for doing it”, I envisioned some weird stuff like sending vector font definitions and rendering them or some such thing…

And then I think, PopupPanels will do… Don’t forget to override onEventPreview() like so:

public boolean onEventPreview(Event event) { return true; }

Tips

  • Cygwin productivity tips
  • It is possible to do ASP/JavaScript debugging without using the Visual Inter Dev by using IIS script debugger
  • If you ever see an error like “Java Plug-in for Netscape Navigator Should Not Be Used with Microsoft Microsoft Internet Explorer. Please Use Java Plug-in for Microsoft Internet Explorer”, see http://home.att.net/~cherokee67/ffjavaerror.html
  • Creating Windows EXE from Java (don’t ask):I found NativeJ the best for my task. I also tried JexePack, but it didn’t seem to do well with IBM JVM (it says that unregistered version will just show a modal dialog box on startup, and it did on my machine, but when I tried running it on the WebSphere box, it seemed to create an endless loop with those modal dialogs. Finally, Excelsior JET is good, but too complex for a little task like this — creating an executable involves too many steps skipping over things I don’t need. The interface is not the best either — too much like a wizard, too little like an IDE that it really is. But maybe it’s good for bigger, more involved projects.

configureWebserverDefinition.jacl

Per Web
server plug-in installation doc (step 19)
, we should copy the
configureweb_server_name.bat script, generated by
the plugin installer, to the WAS_HOME/bin directory and run it
in order to map the installed applications to the Web server. This was giving us problems on Windows 2003, such as this:

Configuration save is not complete, exception = com.ibm.ws.scripting.ScriptingException:
com.ibm.websphere.management.exception.ConfigServiceException:
WKSP0008E RepositoryException while checking the state of
cells/mycell/applications/application.ear/deployments/application/foo.jar/META-INF/ibm-ejb-jar-ext.xmi
in the master repository -com.ibm.ws.sm.workspace.WorkSpaceException:
WKSP0016E Error get digest for cells/mycell/applications/application.ear/deployments/application/foo.jar/META-INF/ibm-ejb-jar-ext.xmi.workspace_save – java.io.IOException: The system cannot find the specified file, either the filename is too long on Windows system or run out of file descriptor on UNIX platform. java.io.FileNotFoundException: D:optWebSphereAppServerprofilesAppSrv01wstempScript10afa2477bfworkspacecellsmycellapplicationsapplication.eardeploymentsapplicationfoo.jarMETA-INFibm-ejb-jar-ext.xmi.workspace_save (The handle is invalid.)

WASX7309W: No “save” was performed before the script “D:optWebSphereAppServerbinconfigureWebserverDefinition.jacl” exited; configuration changes will not be saved.

What is happening is twofold.

First, the
configureWebserverDefinition.jacl does a save only at the end, which fails for all installed applications. To narrow the problem down, I put $AdminConfig reset after foreach Application $ApplicationList {, and moved the

 if {[catch {$AdminConfig save} result]} {
 puts "Configuration save is not complete, exception = $result"
 } else {
 puts "Configuration save is complete."
 }
 

block from the end of the script into the else clause of

 if {[catch {$AdminApp edit $Application [subst {-MapModulesToServers {$targetMapList } } ]} result]} {
 puts "Target mapping is not updated for the application $Application, exception = $result"
 } else {
 puts "Target mapping is updated for the application $Application"
 ...
 

I think saving this per-application is better, at least for narrowing the problematic apps down, but I suppose it’s a matter of preference…

Now we see that all applications except for two are being updated. Without digging into what exactly is special about those two, it’s enough to go to the “Map modules to servers” in WAS console for any other app to see that the JACL script mapped all modules to the web server – including the EJB modules. Not only is that silly and useless, but also is causing “the filename is too long” thing. So we add another condition into the configureWebserverDefinition.jacl to only map Web modules to the web server, by
changing the block where we set targetMapList as follows:

 #--------------------------------------------------------------
 # Check if web server is already defined as the target
 #--------------------------------------------------------------
 set index [string first $newTarget $currentTargets]
 
 set targetMapList "$targetMapList { {$moduleName} $moduleUri $currentTargets }"
 if {($index < 0) } {
 set isWebModule [string first ".war,WEB-INF/web.xml" $moduleUri]
 if {( $isWebModule < 0)} {
 puts "$moduleUri is not a Web module, skipping..."
 } else { 
 puts "Will map $moduleUri to $newTarget"
 set targetMapList "$targetMapList { {$moduleName} $moduleUri $currentTargets+$newTarget }" 
 }
 }
 

The configureWebserverDefinition.jacl modified as above is at
Misc
module of jSewer project on SourceForge
.

ReflectiveVisitor

Inigo Surguy presents< an implementation of Visitor pattern based on reflection. I found useful a slight modification of it, that allows for visiting not only the narrowest type, but every type possible , based on the visitAll flag: ReflectiveVisitor.java. This functionality comes in quite handy for tasks such as, for instance, validation. For example, if one has a complex class hierarchy (especially with multiple< inheritance) and different types have different requirements for it to be valid, and a concrete instance may implement a number of those, these validations can be well separated out.

See also:

  1. Visiting Collection elements
  2. Depth-first polymorphism