Wednesday, November 4, 2009

Build Automatically Destroys Merge

This afternoon we ran into a serious stumbling block when trying to merge changes up to a branch using svn (in eclipse via subclipse).

The merge would proceed for a while, and then all of a sudden we'd get an error message reading something like this:


org.tigris.subversion.javahl.ClientException: The process cannot access the file because it is being used by another process.
svn: Can't remove file 'C:\cygwin\home\euzuro\dev\TT\Project\war\WEB-INF\lib\some_jar_file.jar': The process cannot access the file because it is being used by another process.
RA layer request failed
svn: Error reading spooled REPORT request response


We tried all sorts of tricks like:

  • restarting Eclipse

  • blowing away our working copy and re-updating from svn

  • trying to track the rogue jar-user down using ProcessExplorer

  • renaming the jar file and restarting the process



...all to no avail. It seemed clear that something in eclipse was using that jar file, but what?

Turns out, the culprit was the "Build Automatically" feature that we had turned on.

By turning "Build Automatically" off and restarting Eclipse, we were able to perform the merge with no errors.

Problem Solved!

Seems simple enough: auto-build process is running, has a lock on the jar, svn tries to delete jar and fails.

What I can't believe is that we are the only people to have ever come across this sort of error. Googling turned nothing up.

Shouldn't subclipse know better?

Thursday, October 8, 2009

Easy Way to Catch Double Clicks in GWT

Today I decided that I wanted to add some code to one of my widgets that would execute when a HorizontalPanel was double-clicked.

First thing I did was to type the variable name for the HorizontalPanel, then ".add" and scroll down the list for something like addDblClickHandler() or something like that.



No beans. There wasn't even a addClickHandler()! I researched that a little bit and realized that I had to wrap the HorizontalPanel in a FocusPanel in order to get the addClickHandler().

O.K. fine. But what about my addDblClickHandler()? I poked around a bit in the Official GWT JavaDocs, and I found the HasDoubleClickHandlers interface... but it listed not a single class that implements it. Wierd.

A lot of painful googling finally got me to a helpful post on osdir.com titled Double Click in GWT 1.6?

The suggestion put forth there was to create a new class extending the desired existing GWT Widget, something like this:
public class DoubleClickListBox extends ListBox implements
HasDoubleClickHandlers{

public DoubleClickListBox(boolean isMultipleSelect) {
super(isMultipleSelect);
}

public DoubleClickListBox() {
super();
}

public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
return addDomHandler(handler, DoubleClickEvent.getType());
}
}
(Note: they choose to extend the ListBox)

Well, I tried that and it did work... but creating a whole new class, just for that nonsense? Seemed like way too much hassle. Has to be a better way.

My first thought was to just add the handler manually, using an Anonymous Class. Something like this:



HorizontalPanel vHorizontalPanel = new HorizontalPanel();

/* this doesn't work */
vHorizontalPanel.addDomHandler(new DoubleClickHandler() {
@Override
public void onDoubleClick(
DoubleClickEvent pDoubleClickEvent) {

Window.alert("chicken");
}
}, DoubleClickEvent.getType());



...but it turns out that the addDomHandler() function on the HorizontalPanel class is protected, meaning I can't call it publicly.

So I did some research, and found that there is a way to do it all in one swing, using an initializer. This time, it was JAVA In a Nutshell to the rescue with Anonymous Classes. The tip that helped was this:
Since an anonymous class has no name, it is not possible to define a constructor for an anonymous class. If your class requires a constructor, you must use a local class instead. However, you can often use an instance initializer as a substitute for a constructor. In fact, instance initializers were introduced into the language for this very purpose.


I gave that a try, and came up with this simple solution:

HorizontalPanel vHorizontalPanel = new HorizontalPanel() {
{
addDomHandler(new DoubleClickHandler() {

@Override
public void onDoubleClick(DoubleClickEvent pEvent) {
Window.alert("chicken");
}

}, DoubleClickEvent.getType());
}
};

.....and that works!

The rest of the context on that nutshell page makes me think maybe this isn't the best use of an anonymous class... I'm still new to Java, but to me, it sure seems to beat making a separate java file and class, just to catch a double-click.

Am I totally wrong? Is there a better way to do this?

I'd love to hear what you think.

Tuesday, September 22, 2009

Omniture and document.write()






We had been having serious trouble deploying Omniture code on some of our reservation pages.

For many pages, everything worked fine, the pages loaded as normal, the Omniture code executed, everyone was happy. But for some pages, we would see the page load quickly, then flash blank (white) and hang.



The problem was occurring in both Firefox and Internet Explorer, in different pages with similar customizations... in short, we had no clue.

The only way to really debug the problem was to step through it using a debugger. Luckily, the problem was occurring on a certain page in Firefox, which meant that we could use our high-power, trusty Firebug debugger.



Unfortunately for us the debuggers, the Omniture code is both minimized and obfuscated. Not only that, but much of the code is wrapped into long strings and then later eval()'d. In a nutshell, this was some very tricky code to follow.

When stepping through it in firebug, you can't go "line-by-line" like with normal code, because the code is either all in one line, or it's actually being eval()'d from a string. And even then, all the variable names are meaningless jibberish.

The way we ended up figuring it out was to use a About.com's JavaScript Formatter. While this doesn't de-obfuscate the code, it at least made it readable. What I did was to copy/paste the source for the code into notepad, then delete each instance of " + ", leaving us with the actual code, which I pasted into the textarea on the about.com page.

Then, back in firebug, I could step through the code and even though I couldn't see the line-by-line, I was able to determine which function I was in based on the list of local variables in the Watch window:



I just grep'd for those variables within the page of formatted code in the about.com window until I found a match.

Eventually, after a lot of back and forth, I was able to track the offending function which made the screen turn blank down to this:


s.ca = function() {
var s = this, imn = 's_i_' + s.fun;
if(s.d.images && s.apv >= 3 &&!s.isopera && (s.ns6 <>= 6.1)) {
s.ios = 1;
if(!s.d.images[imn] && (!s.isns || (s.apv <>= 5))) {
s.d.write('<im' + 'g name=' + imn + ' height=1 width=1 border=0 alt=>');
if(!s.d.images[imn])s.ios = 0}
}
};



Firebug told me that "s.d" had been assigned to "document" earlier in the code, so basically this line:

s.d.write('<im' + 'g name=' + imn + ' height=1 width=1 border=0 alt=>');


...was really


document.write('<img name=' + imn + ' height=1 width=1 border=0 alt=>');


At that point, a little googling on the vulnerability of document.write() usage led me a really useful page (again from about.com) aptly titled document.write.

The key takeaway from this page was this line:

Any document.write statement that runs after the page finishes loading will create a new page and overwrite all of the content of the current page.




Eureka! That was exactly the problem... the page was already loaded when this line of code was being called, so it was blowing away the whole page.

... and the pages that *weren't* getting blown away had heavier html code that was not getting loaded in time. A good old fashioned race condition!

To solve the problem, we realized that when we were adding the Omniture script to the page, we were doing so as follows:


var scriptElem = document.createElement("script");
scriptElem.src = 'https://www.reztrip.com/Rezimages/extra/4259331/s_code_remote.js';
scriptElem.language = "JavaScript";
document.body.appendChild(scriptElem);


this was obviously not loading the script fast enough... it was waiting until the very end of the page.

What we really wanted to do was something more like:


document.write("<script>https://www.reztrip.com/Rezimages/extra/4259331/s_code_remote.js</script>");


..but we'd come across problems with directly adding the script tag that way.

Finally, to solve the problem once and for all, we found some tips on a post in a Webmaster World Forum entitled document.write("<SCR" + "IPT>"), why?.

The idea they suggest is to break up the actual "<script>" tag, for this reason:


Depending on the browser, the amount of other preceding javascript, and how well-formed the overall code is, this is done to prevent the parser from interpreting the <script> and </script> tags as executeable code rather than as a string to be written.


...we did that and it worked like a charm! Problem solved.


document.write("<scri" + "pt>https://www.reztrip.com/Rezimages/extra/4259331/s_code_remote.js</script>");

Tuesday, March 31, 2009

Upgrading an SVN Vendor Branch

The dojo toolkit just announced the final 1.3.0 release of their toolkit today, which is great news for us, as we've been waiting on some 1.3.0-specific functionalities to deploy in our site.

In our SVN repository, we've got a "vendor" branch set up according to the instructions laid out in the Vendor Branches Section of the Branching and Merging Chapter of the SVN Book. In it, of course, we have a /dojo directory.

So the deal now was to follow the instructions from the SVN Book and upgrade to 1.3.0 release.

Much to my dismay, I got hung up on the very first stage:

To perform this upgrade, we check out a copy of our vendor branch and replace the code in the current directory with the new libcomplex 1.1 source code. We quite literally copy new files on top of existing files, perhaps exploding the libcomplex 1.1 release tarball atop our existing files and directories. The goal here is to make our current directory contain only the libcomplex 1.1 code and to ensure that all that code is under version control. Oh, and we want to do this with as little version control history disturbance as possible.

What I did was

  • download the latest release
  • unzip it into a local checkout of /vendor/dojo as /vendor/dojo/1.3.0-release
  • mv /vendor/dojo/1.3.0-release /vendor/dojo/current
But then when I did 'svn stat', instead of showing me a list of all the changed and new files, it just said:

    ~current

and svn stat help tells us:

    '~' versioned item obstructed by some item of a different kind

...which makes sense, but unfortunately didn't really help. It said to "copy new files on top of existing files", and that's what I was doing.

Obviously, the problem is that by just copying the directory over, all the special .svn information was getting blown away. What I needed was a way to copy all the *files* into that /current directory... without destroying the existing directory structure.

Well, after a lot of searching, I finally found the answer in a video on the gotdrupal.com website. In a nutshell, it is a very detailed, patient walk through of the "Vendor Branches" section from the SVN book (see above).

Turns out, the trick (or at least one of them) to getting those files to overwrite without confusing SVN is to download a tarball of the release and then un-tar it right into the /current directory, but using a special --strip-components=1 flag.

If you are curious about the "right" way to set up a vendor branch, I highly recommend reading the Vendor Branches Section of the SVN Book and then watching this great video.


Thursday, March 26, 2009

Off to a Bad Start with GWT


So I've just spent the last few hours battling with an obscure Eclipse/GWT bug. 

The official bug report for this beast I find very appropriately titled: GWT project creation indefinetly creates folder recursively.

If you're new to GWT (like me) and you find your machine spinning in circles as you innocently follow the instructions listed in the Getting Started - Quick Start section of the otherwise generally helpful docs section of the Main GWT page, CLICK CANCEL IMMEDIATELY!!!

Confused code is creating a rabbit hole as deep as your wildest imagination on your computer.

Once the damage has been done, the tricky part is cleaning up the mess. The crucial problem here is that Windows can not deal with file names longer than 256 characters. "So what?!" you say, "Can't you just delete the directory and be done with it?"

Shouldn't it be so easy. No, Windows is so freaked out it can't even deal with deleting the thing.

Most of the suggestions I could find on the web as to how to delete these undeletable files suggesting a wierd trick where you map a network drive to one of the folders deep in the hierarchy... effectively chopping off all the preceding path and replacing it with a single drive letter. One friendly helper on the ticket/thread for this bug notes, helpfully, that "You may have to do this more than once."

Exactly. More than once indeed! This is recursion we are talking about here. Computers are fast... and yours truly multitasked the Eclipse window out of sight and mind for a good five minutes before checking back and kiling it. As you can imagine, this netted me a very, very, very, very deep mess of recursive directories.

So I figured, the best way to solve this issue was to take matters into my own hands. So I wrote a little batch script to fight fire with fire: recursively move and delete until all gone. 


:LoopStart
IF EXIST MyProject/MyProject GOTO :KillAChunk
GOTO End

:KillAChunk
move MyProject/MyProject foo
rmdir /s /q MyProject
move foo MyProject
GOTO LoopStart

:End
IF EXIST MyProject rmdir /s /q MyProject

...create a new notepad file called "killer.bat" or something of the sort, paste that text into it, and save it in the directory where you find the first "MyProject" directory. Now just double-click killer.bat or run it from the cmd prompt and voila! All cleaned up.

I hope that helps someone/anyone out there who ran into this problem. Very annoying! It would be kind of the good people at Google to at least add a warning in their documentation to prevent others from falling into this trap.

Tuesday, March 17, 2009

Invisible Dojo 1.3 Calendar in Chrome, Safari

So we've been experimenting a bit recently with the Dojo Framework, a Web 2.0 JavaScript toolkit.

Specifically, we were interested in the Calendar widget, which is part of the Dijit package.

After a bit of poking and prodding, we were able to get the widget working. Great!


Much to our dismay, however, in the Chrome and Safari browsers, we were getting script errors and our slick new calendar was not showing up at all.

My first crack at fixing this issue (and in fact my motivation to write this blog entry) was to run some Google searches to see if anyone else was having the same problem. I am the first to admit that I am no Google wizard, but my best shots at combining "dojo", "dojo 1.3", "calendar", "chrome", "safari", "bug", "invisible".... all turned up unhelpful links.

Thus, it was time to step into the code. This was my first foray into debugging in Chrome, and with a lot of banging at the console command line and a little help from a post by Eric Pascarello, I was able to trace the bug down to a null return from the dojo.query() function.

Now a second round of Google searches incorporating "dojo.query" instead of "calendar", and bang! The first result was a link to Ticket 8775 in the Dojo TRAC, whose title is "REGRESSION: Camel Cased classname queries fail on Safary [sic] 3.2.2 and Chrome".

Well what do you know. It turns out we were just a little behind the times. We were working off of the 1.3 beta 1 release. The bug had since been tracked down and fixed... and all we had to do to get our calendar to show up in Chrome and Safari was to upgrade to 1.3 RC1 (The most recent release at the time of this posting).

So voila! Hopefully there's enough relevant keywords in here that all the other folks out there running on one of the 1.3 betas might find this and realize it's time to upgrade!

Cheers to the dojo community for putting together such a great product, and for really being on the ball with finding and fixing bugs like this.


Welcome



Welcome to the Travel Tripper Tech Blog!

In this space we will be posting thoughts, discoveries, insights, rants, etc. regarding the different tools and technologies that we are using to build cutting edge web software.

A little background about Travel Tripper, we are a small company of about fifteen employees, based in New York but scattered around the world. We build software to help hotels improve their web distribution/sales. You can find out more about us at website at www.traveltripper.com.